1。错误的访问权限@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalprivatevoidadd(UserModeluserModel){userMapper.insertUser(userModel);}}我们可以看到add方法的访问权限定义成了private,会导致事务失败,而spring要求代理方法必须是public的。在AbstractFallbackTransactionAttributeSource类的computeTransactionAttribute方法中有判断。如果目标方法不是public,TransactionAttribute返回null,即不支持事务。protectedTransactionAttributecomputeTransactionAttribute(Methodmethod,@NullableClass>targetClass){//根据需要不允许非公共方法。如果(allowPublicMethodsOnly()&&!Modifier.isPublic(method.getModifiers())){返回null;}//该方法可能位于接口上,但我们需要目标类的属性。//如果目标类为null,则方法不变。方法specificMethod=AopUtils.getMostSpecificMethod(method,targetClass);//首先尝试的是目标类中的方法。TransactionAttributetxAttr=findTransactionAttribute(specificMethod);如果(txAttr!=null){返回txAttr;}//第二次尝试是目标类上的事务属性。txAttr=findTransactionAttribute(specificMethod.getDeclaringClass());如果(txAttr!=null&&ClassUtils.isUserLevelMethod(method)){returntxAttr;}如果(特定方法!=方法){//Fallback就是看原来的方法。txAttr=findTransactionAttribute(方法);如果(txAttr!=null){返回txAttr;}//最后一个回退是原始方法的类。txAttr=findTransactionAttribute(method.getDeclaringClass());如果(txAttr!=null&&ClassUtils.isUserLevelMethod(method)){returntxAttr;}}返回空值;}2.方法定义为final@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalpublicfinalvoidadd(UserModeluserModel){userMapper.insertUser(userModel);}}我们可以看到add方法定义为final,这会导致springaop生成的代理对象无法重写该方法,导致事务无效3.调用@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalpublicvoidadd(UserModeluserModel){userMapper.insertUser(userModel);更新状态(用户模型);}@TransactionalpublicvoidupdateStatus(UserModeluserModel){//doSameThing();}}我们看到在事务方法add中,直接调用了事务方法updateStatus。从上面介绍的内容我们可以知道,updateStatus方法是有事务的能力的,因为springaop生成了代理对象,但是这个方法直接调用了这个对象的方法,所以updateStatus方法是不会生成事务的。4.当前实体不是spring管理的//@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalpublicvoidadd(UserModeluserModel){userMapper.insertUser(userModel);}}我们可以看到UserService类没有定义@Service注解,也就是没有交给spring管理bean实例,所以它的add方法不会产生事务。5.错误的spring事务传播特性@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactional(propagation=Propagation.NEVER)publicvoidadd(UserModeluserModel){userMapper.insertUser(userModel);}}我们可以看到add方法的事务传播特性定义为Propagation.NEVER。这种传播特性不支持事务,有事务就会抛异常。只有这三个传播特性会创建新事务:PROPAGATION_REQUIRED、PROPAGATION_REQUIRES_NEW、PROPAGATION_NESTED。6.数据库不支持事务。msql8之前版本的数据库引擎支持myslam和innerdb。我以前也用过。对于查询多写少的单表操作,表的数据库引擎可以定义为myslam,可以提高查询效率。但是,必须记住一件事,myslam只支持表锁,不支持事务。因此,写入此类表的事务将无效。7.我自己吞下了异常@Slf4j@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalpublicvoidadd(UserModeluserModel){try{userMapper.insertUser(userModel);}catch(Exceptione){log.error(e.getMessage(),e);}}}这种情况下,事务不会回滚,因为开发者自己捕获了异常,并没有抛出。事务的AOP无法捕获异常,所以即使发生异常,事务也不会回滚。8.抛出的异常不正确@Slf4j@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@Transactionalpublicvoidadd(UserModeluserModel)throwsException{try{userMapper.insertUser(userModel);}catch(Exceptione){log.error(e.getMessage(),e);抛出新的异常(e);}}}这种情况下,开发者自己捕获异常,抛出异常:Exception,事务不会回滚。因为spring事务,默认情况下只会回滚RuntimeException(运行时异常)和Error(错误),不会回滚Exception。9、多线程调用@Slf4j@ServicepublicclassUserService{@AutowiredprivateUserMapperuserMapper;@AutowiredprivateRoleService角色服务;@Transactionalpublicvoidadd(UserModeluserModel)throwsException{userMapper.insertUser(userModel);newThread(()->{roleService.doOtherThing();}).start();}}@ServicepublicclassRoleService{@TransactionalpublicvoiddoOtherThing(){System.out.println("保存角色表数据");}}我们可以看到事务在方法add中调用了事务方法doOtherThing,但是事务方法doOtherThing是在另一个线程调用的,这会导致两个事务方法不在同一个线程,获取到的数据库连接是不同的,因此是两个不同的事务。如果要在doOtherThing方法中抛出异常,add方法是不可能回滚的。如果你看过springtransactions的源码,你可能知道springtransactions是通过数据库连接实现的。当前线程中保存了一个map,key是数据源,value是数据库连接。privatestaticfinalThreadLocal
