当前位置: 首页 > news >正文

可以做音基题的音乐网站可以做哪些网站有哪些

可以做音基题的音乐网站,可以做哪些网站有哪些,银川网站建设哪家优,米拓做网站图片在哪里删掉文章目录 spring 事务失效的 12 种场景一、事务不生效1.访问权限问题2. 方法用 final 修饰3.方法内部调用#xff08;自己玩自己#xff09;3.1 新加一个 Service 方法3.2 在该 Service 类中注入自己3.3 通过 AopContent 类 4.Bean没有纳入Spring IOC容器管理5.多线程调用自己玩自己3.1 新加一个 Service 方法3.2 在该 Service 类中注入自己3.3 通过 AopContent 类 4.Bean没有纳入Spring IOC容器管理5.多线程调用事务方法内启动新线程进行异步操作6.表不支持事务7.未开启事务 二、事务不回滚8.错误的传播特性9.自己吞了异常捕获异常未抛出10.异常类型不匹配手动抛了别的异常11.自定义了回滚异常12.嵌套事务回滚多了 三、其他1、大事务问题2.编程式事务 spring 事务失效的 12 种场景 在某些业务场景下如果一个请求中需要同时写入多张表的数据。为了保证操作的原子性要么同时成功要么同时失败避免数据不一致的情况我们一般都会用到 spring 事务。 确实spring 事务用起来很方便就用一个简单的注解 Transactional 就能轻松搞定事务。我猜大部分小伙伴也是这样用的而且一直用一直爽。 但如果你使用不当它也会坑你于无形。 一、事务不生效 1.访问权限问题 众所周知java 的访问权限主要有四种private、default、protected、public它们的权限从左到右依次变大。 但如果我们在开发过程中把某些事务方法定义了错误的访问权限就会导致事务功能出问题例如 Service public class UserService {Transactionalprivate void add(UserModel userModel) {saveData(userModel);updateData(userModel);} }我们可以看到 add 方法的访问权限被定义成了 private 这样会导致事务失效spring 要求被代理方法必须是public的。 说白了在 AbstractFallbackTransactionAttributeSource 类的 computeTransactionAttribute 方法中有个判断如果目标方法不是 public则 TransactionAttribute 返回 null即不支持事务。 protected TransactionAttribute computeTransactionAttribute(Method method, Nullable Class? targetClass) {// Dont allow no-public methods as required.if (allowPublicMethodsOnly() !Modifier.isPublic(method.getModifiers())) {return null;}// The method may be on an interface, but we need attributes from the target class.// If the target class is null, the method will be unchanged.Method specificMethod AopUtils.getMostSpecificMethod(method, targetClass);// First try is the method in the target class.TransactionAttribute txAttr findTransactionAttribute(specificMethod);if (txAttr ! null) {return txAttr;}// Second try is the transaction attribute on the target class.txAttr findTransactionAttribute(specificMethod.getDeclaringClass());if (txAttr ! null ClassUtils.isUserLevelMethod(method)) {return txAttr;}if (specificMethod ! method) {// Fallback is to look at the original method.txAttr findTransactionAttribute(method);if (txAttr ! null) {return txAttr;}// Last fallback is the class of the original method.txAttr findTransactionAttribute(method.getDeclaringClass());if (txAttr ! null ClassUtils.isUserLevelMethod(method)) {return txAttr;}}return null;}也就是说如果我们自定义的事务方法即目标方法它的访问权限不是 public 而是 private、default 或 protected 的话spring 则不会提供事务功能。 2. 方法用 final 修饰 有时候某个方法不想被子类重写这时可以将该方法定义成 final 的。普通方法这样定义是没问题的但如果将事务方法定义成 final例如 Service public class UserService {Transactionalpublic final void add(UserModel userModel){saveData(userModel);updateData(userModel);} }我们可以看到 add 方法被定义成了 final 的这样会导致事务失效。 为什么 如果你看过 spring 事务的源码可能会知道 spring 事务底层使用了 aop也就是通过 jdk 动态代理或者 cglib帮我们生成了代理类在代理类中实现的事务功能。 但如果某个方法用 final 修饰了那么在它的代理类中就无法重写该方法而添加事务功能。 注意如果某个方法是 static 的同样无法通过动态代理变成事务方法。 3.方法内部调用自己玩自己 有时候我们需要在某个 Service 类的某个方法中调用另外一个事务方法比如 Service public class UserService {Autowiredprivate UserMapper userMapper;public void add(UserModel userModel) {userMapper.insertUser(userModel);updateStatus(userModel);}Transactionalpublic void updateStatus(UserModel userModel) {doSameThing();} }我们看到在事务方法 add 中直接调用事务方法 updateStatus。从前面介绍的内容可以知道updateStatus 方法拥有事务的能力是因为 spring aop 生成代理了对象但是这种方法直接调用了 this 对象的方法所以 updateStatus 方法不会生成事务。 由此可见在同一个类中的方法直接内部调用会导致事务失效。 那么问题来了如果有些场景确实想在同一个类的某个方法中调用它自己的另外一个方法该怎么办呢 3.1 新加一个 Service 方法 这个方法非常简单只需要新加一个 Service 方法把 Transactional 注解加到新 Service 方法上把需要事务执行的代码移到新方法中。具体代码如下 Servcie public class ServiceA {Autowiredprvate ServiceB serviceB;public void save(User user) {queryData1();queryData2();serviceB.doSave(user);}}Servciepublic class ServiceB {Transactional(rollbackForException.class)public void doSave(User user) {addData1();updateData2();}}3.2 在该 Service 类中注入自己 如果不想再新加一个 Service 类在该 Service 类中注入自己也是一种选择。具体代码如下 Servcie public class ServiceA {Autowiredprvate ServiceA serviceA;public void save(User user) {queryData1();queryData2();serviceA.doSave(user);}Transactional(rollbackForException.class)public void doSave(User user) {addData1();updateData2();}}可能有些人会有这样的疑问这种做法会不会出现循环依赖问题 答案不会。 其实 spring ioc 内部的三级缓存保证了它不会出现循环依赖问题。 3.3 通过 AopContent 类 在该 Service 类中使用 AopContext.currentProxy() 获取代理对象。 上面的方法 2 确实可以解决问题但是代码看起来并不直观还可以通过在该 Service 类中使用 AOPProxy 获取代理对象实现相同的功能。具体代码如下 Servcie public class ServiceA {public void save(User user) {queryData1();queryData2();((ServiceA)AopContext.currentProxy()).doSave(user);}Transactional(rollbackForException.class)public void doSave(User user) {addData1();updateData2();}}4.Bean没有纳入Spring IOC容器管理 在我们平时开发过程中有个细节很容易被忽略即使用 spring 事务的前提是对象要被 spring 管理需要创建 bean 实例。 通常情况下我们通过 Controller、Service、Component、Repository 等注解可以自动实现 bean 实例化和依赖注入的功能。 如果有一天你匆匆忙忙地开发了一个 Service 类但忘了加 Service 注解比如 //Service public class UserService {Transactionalpublic void add(UserModel userModel) {saveData(userModel);updateData(userModel);} }从上面的例子我们可以看到 UserService 类没有加 Service 注解那么该类不会交给 spring 管理所以它的 add 方法也不会生成事务。 5.多线程调用事务方法内启动新线程进行异步操作 在实际项目开发中多线程的使用场景还是挺多的。如果 spring 事务用在多线程场景中会有问题吗 Slf4j Service public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);new Thread(() - {roleService.doOtherThing();}).start();} }Service public class RoleService {Transactionalpublic void doOtherThing() {System.out.println(保存role表数据);} }从上面的例子中我们可以看到事务方法 add 中调用了事务方法 doOtherThing但是事务方法 doOtherThing 是在另外一个线程中调用的。 这样会导致两个方法不在同一个线程中获取到的数据库连接不一样从而是两个不同的事务。如果想 doOtherThing 方法中抛了异常add 方法也回滚是不可能的。 如果看过 spring 事务源码的朋友可能会知道 spring 的事务是通过数据库连接来实现的。当前线程中保存了一个 mapkey 是数据源value 是数据库连接。 private static final ThreadLocalMapObject, Object resources new NamedThreadLocal(Transactional resources);我们说的同一个事务其实是指同一个数据库连接只有拥有同一个数据库连接才能同时提交和回滚。如果在不同的线程拿到的数据库连接肯定是不一样的所以是不同的事务。 6.表不支持事务 众所周知在 mysql5 之前默认的数据库引擎是 myisam 。 它的好处就不用多说了索引文件和数据文件是分开存储的对于查多写少的单表操作性能比 innodb 更好。 有些老项目中可能还在用它。 在创建表的时候只需要把 ENGINE 参数设置成 MyISAM 即可 CREATE TABLE category (id bigint NOT NULL AUTO_INCREMENT,one_category varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,two_category varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,three_category varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,four_category varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,PRIMARY KEY (id) ) ENGINEMyISAM AUTO_INCREMENT4 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_binmyisam 好用但有个很致命的问题是 不支持事务 。 如果只是单表操作还好不会出现太大的问题。但如果需要跨多张表操作由于其不支持事务数据极有可能会出现不完整的情况。 此外myisam 还不支持行锁和外键。 所以在实际业务场景中myisam 使用的并不多。在 mysql5 以后myisam 已经逐渐退出了历史的舞台取而代之的是 innodb。 有时候我们在开发的过程中发现某张表的事务一直都没有生效那不一定是 spring 事务的锅最好确认一下你使用的那张表是否支持事务。 7.未开启事务 有时候事务没有生效的根本原因是没有开启事务。 为什么还会没有开启事务 没错如果项目已经搭建好了事务功能肯定是有的。 但如果你是在搭建项目 demo 的时候只有一张表而这张表的事务没有生效。那么会是什么原因造成的呢 当然原因有很多但没有开启事务这个原因极其容易被忽略。 如果你使用的是 springboot 项目那么你很幸运。因为 springboot 通过 DataSourceTransactionManagerAutoConfiguration 类已经默默地帮你开启了事务。 你所要做的事情很简单只需要配置 spring.datasource 相关参数即可。 但如果你使用的还是传统的 spring 项目则需要在 applicationContext.xml 文件中手动配置事务相关参数。如果忘了配置事务肯定是不会生效的。 具体配置信息如下 !-- 配置事务管理器 -- bean classorg.springframework.jdbc.datasource.DataSourceTransactionManager idtransactionManager property namedataSource refdataSource/property /bean tx:advice idadvice transaction-managertransactionManager tx:attributes tx:method name* propagationREQUIRED//tx:attributes /tx:advice !-- 用切点把事务切进去 -- aop:config aop:pointcut expressionexecution(* com.susan.*.*(..)) idpointcut/ aop:advisor advice-refadvice pointcut-refpointcut/ /aop:config 默默地说一句如果在 pointcut 标签中的切入点匹配规则配错了的话有些类的事务也不会生效。 二、事务不回滚 8.错误的传播特性 其实我们在使用 Transactional 注解时是可以指定 propagation 参数的。 该参数的作用是指定事务的传播特性spring 目前支持 7 种传播特性 REQUIRED 如果当前上下文中存在事务则加入该事务如果不存在事务则创建一个事务这是默认的传播属性值。SUPPORTS 如果当前上下文中存在事务则支持事务加入事务如果不存在事务则使用非事务的方式执行。MANDATORY 当前上下文中必须存在事务否则抛出异常。REQUIRES_NEW 每次都会新建一个事务并且同时将上下文中的事务挂起执行当前新建事务完成以后上下文事务恢复再执行。NOT_SUPPORTED 如果当前上下文中存在事务则挂起当前事务然后新的方法在没有事务的环境中执行。NEVER 如果当前上下文中存在事务则抛出异常否则在无事务环境上执行代码。NESTED 如果当前上下文中存在事务则嵌套事务执行如果不存在事务则新建事务。 如果我们在手动设置 propagation 参数的时候把传播特性设置错了比如 Service public class UserService {Transactional(propagation Propagation.NEVER)public void add(UserModel userModel) {saveData(userModel);updateData(userModel);} }我们可以看到 add 方法的事务传播特性定义成了 Propagation.NEVER这种类型的传播特性不支持事务如果有事务则会抛异常。 目前只有这三种传播特性才会创建新事务REQUIREDREQUIRES_NEWNESTED。 9.自己吞了异常捕获异常未抛出 事务不会回滚最常见的问题是开发者在代码中手动 try…catch 了异常。比如 Slf4j Service public class UserService {Transactionalpublic void add(UserModel userModel) {try {saveData(userModel);updateData(userModel);} catch (Exception e) {log.error(e.getMessage(), e);}} }这种情况下 spring 事务当然不会回滚因为开发者自己捕获了异常又没有手动抛出换句话说就是把异常吞掉了。 如果想要 spring 事务能够正常回滚必须抛出它能够处理的异常。如果没有抛异常则 spring 认为程序是正常的。 10.异常类型不匹配手动抛了别的异常 即使开发者没有手动捕获异常但如果抛的异常不正确spring 事务也不会回滚。 Slf4j Service public class UserService {Transactionalpublic void add(UserModel userModel) throws Exception {try {saveData(userModel);updateData(userModel);} catch (Exception e) {log.error(e.getMessage(), e);throw new Exception(e);}} }上面的这种情况开发人员自己捕获了异常又手动抛出了异常Exception事务同样不会回滚。 Transactional 注解默认只处理运行时异常 RuntimeException 和 error而不会处理受检异常 Exception 的子类。 当抛出未被捕获的运行时异常时Spring 会触发事务回滚操作将之前的操作撤销而对于未被捕获的受检异常Spring 不会触发事务回滚操作。 如果需要处理受检异常并触发事务回滚可以通过 rollbackFor 和 noRollbackFor 属性来指定需要回滚或不需要回滚的异常类型。 11.自定义了回滚异常 在使用 Transactional 注解声明事务时有时我们想自定义回滚的异常spring 也是支持的。可以通过设置 rollbackFor 参数来完成这个功能。 但如果这个参数的值设置错了就会引出一些莫名其妙的问题例如 Slf4j Service public class UserService { Transactional(rollbackFor BusinessException.class)public void add(UserModel userModel) throws Exception {saveData(userModel);updateData(userModel);} }如果在执行上面这段代码保存和更新数据时程序报错了抛了 SqlException、DuplicateKeyException 等异常。而 BusinessException 是我们自定义的异常报错的异常不属于 BusinessException所以事务也不会回滚。 即使 rollbackFor 有默认值但阿里巴巴开发者规范中还是要求开发者重新指定该参数。 这是为什么呢 因为如果使用默认值一旦程序抛出了 Exception事务不会回滚这会出现很大的 bug。所以建议一般情况下将该参数设置成Exception 或 Throwable。 12.嵌套事务回滚多了 public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);roleService.doOtherThing();} }Service public class RoleService {Transactional(propagation Propagation.NESTED)public void doOtherThing() {System.out.println(保存role表数据);} }这种情况使用了嵌套的内部事务原本是希望调用 roleService.doOtherThing 方法时如果出现了异常只回滚 doOtherThing 方法里的内容不回滚 userMapper.insertUser 里的内容即回滚保存点。但事实是insertUser 也回滚了。 why? 因为 doOtherThing 方法出现了异常没有手动捕获会继续往上抛到外层 add 方法的代理方法中捕获了异常。所以这种情况是直接回滚了整个事务不只回滚单个保存点。 怎么样才能只回滚保存点呢 Slf4j Service public class UserService {Autowiredprivate UserMapper userMapper;Autowiredprivate RoleService roleService;Transactionalpublic void add(UserModel userModel) throws Exception {userMapper.insertUser(userModel);try {roleService.doOtherThing();} catch (Exception e) {log.error(e.getMessage(), e);}} }可以将内部嵌套事务放在 try/catch 中并且不继续往上抛异常。这样就能保证如果内部嵌套事务中出现异常只回滚内部事务而不影响外部事务。 三、其他 1、大事务问题 在使用 spring 事务时有个让人非常头疼的问题就是大事务问题。 通常情况下我们会在方法上加 Transactional 注解添加事务功能比如 Service public class UserService { Autowired private RoleService roleService; Transactionalpublic void add(UserModel userModel) throws Exception {query1();query2();query3();roleService.save(userModel);update(userModel);}Service public class RoleService { Autowired private RoleService roleService;Transactionalpublic void save(UserModel userModel) throws Exception {query4();query5();query6();saveData(userModel);} }但 Transactional 注解如果被加到方法上有个缺点就是整个方法都包含在事务当中了。 上面的这个例子中在 UserService 类中其实只有这两行才需要事务 roleService.save(userModel); update(userModel);在 RoleService 类中只有这一行需要事务 saveData(userModel);现在的这种写法会导致所有的 query 方法也被包含在同一个事务当中。 如果 query 方法非常多调用层级很深而且有部分查询方法比较耗时的话会造成整个事务非常耗时而从造成大事务问题。 2.编程式事务 上面聊的这些内容都是基于 Transactional 注解的主要说的是它的事务问题我们把这种事务叫做 声明式事务 。 其实spring 还提供了另外一种创建事务的方式即通过手动编写代码实现的事务我们把这种事务叫做 编程式事务。例如 Autowiredprivate TransactionTemplate transactionTemplate;...public void save(final User user) {queryData1();queryData2();transactionTemplate.execute((status) {addData1();updateData2();return Boolean.TRUE;})}在 spring 中为了支持编程式事务专门提供了一个类TransactionTemplate在它的 execute 方法中就实现了事务的功能。 相较于 Transactional 注解声明式事务我更建议大家使用基于 TransactionTemplate 的编程式事务。主要原因如下 避免由于 spring aop 问题导致事务失效的问题。 能够更小粒度地控制事务的范围更直观。 建议在项目中少使用 Transactional 注解开启事务。但并不是说一定不能用它如果项目中有些业务逻辑比较简单而且不经常变动使用Transactional 注解开启事务也无妨因为它更简单开发效率更高但是千万要小心事务失效的问题。
http://www.zqtcl.cn/news/563952/

相关文章:

  • 地方o2o同城网站源码微信app开发价格表
  • 花木公司网站源码双语外贸网站源码
  • 什么公司做网站会提供源代码创业做招商加盟类网站赚钱
  • 东莞网站建设排名基因数据库网站开发价格
  • 天河区营销型网站建设科技自立自强
  • 网站域名账号江苏百度推广代理商
  • 专题网站建站对网站分析
  • 外贸出口网站建设如何搭建自己的网站服务器
  • 云南省建设厅网站职称评审房地产推广方案和推广思路
  • 湘潭建设路街道网站app的设计与开发
  • 《网站开发实践》 实训报告广告策划书案例完整版
  • 一级 爰做片免费网站做中学学中做网站
  • 网站排名如何提升网络营销的有哪些特点
  • 巨腾外贸网站建设个人主页网站模板免费
  • 有哪些网站免费做推广淄博网站电子商城平台建设
  • 网站建设的技术支持论文做网站买什么品牌笔记本好
  • 凡科网站后台在哪里.工程与建设
  • 静态网站源文件下载建设手机网站价格
  • 苏州做网站优化的网站开发邮件
  • 做网站怎么搭建环境阿里云大学 网站建设
  • 网站改版业务嵌入式培训推荐
  • 腾讯云 怎样建设网站网站开发 报价
  • 网络科技公司门户网站免费人脉推广官方软件
  • 建和做网站网络营销推广可以理解为
  • 太原市网站建设网站人防工程做资料的网站
  • 怎么做免费推广网站做网站第一部
  • 橙色网站后台模板WordPress的SEO插件安装失败
  • 做网站好还是做微信小程序好外包加工网外放加工活
  • 中国建设银行网站查征信电子商务网站建设及推广
  • 扫描网站漏洞的软件php网站后台验证码不显示