您的位置 首页 > 德语词汇

transactional是什么意思?原理及不生效原因分析

这篇文章给大家聊聊关于transactional是什么意思,以及原理及不生效原因分析对应的知识点,希望对各位有所帮助,不要忘了收藏本站哦。

1、看了网上很多篇介绍Spring事务注解@Transactional不生效的文章,

2、大都只是讲了不生效的场景,对于不生效的原因都是一笔带过。

transactional是什么意思?原理及不生效原因分析

3、下面我们一步步地分析一下为什么有些场景该注解的事务是不生效的。

4、要想知道原因我们首先要了解该方式的事务是如何实现的。

5、一、Spring事务注解@Transactional的实现原理:

6、Spring中事务注解@Transactional是AOP编程思想的一种体现,

7、AOP(AspectOrientedProgramming)面向切面编程的具体实现方式之一就是动态代理技术。

8、Spring中AOP的底层实现方式就是动态代理,也就是说@Transactional事务注解是使用动态代理技术实现的。

9、关于动态代理技术,请参考我的另一篇文章:Java中代理的理解及其实现方式(2)-动态代理

10、当我们某个类的某个方法上使用了@Transactional注解时,我们在调用这个这个类的这个方法的时候,

11、Spring给我们使用的对象实际上是一个代理对象,调用的方法也是代理对象的方法,从而可以做到在代理对象的方法中先开启事务,再调用真实对象的方法做数据更新,最后做事务的提交和回滚

12、Spring中对使用JDK和CGLib两种方式的动态代理技术都进行了实现,下面我们分别使用这两种方式实现一下面向切面的事务。

13、假设我们有这么一个业务类UserService,方法update中有三步数据更新,我们可以通过代理让这三步放入一个事务中:

14、interfaceUserService{\nvoidupdate();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n\n/**\n*此方法中没有任何事务相关的逻辑,\n*事务的实现我们通过动态代理,在代理类中实现\n**/\n@Override\npublicvoidupdate(){\n//数据更新操作1\nuserDao.update();\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}\n\n//JDK方式\nclassJdkProxy{\n\n@Autowired\n@Qualifier("userServiceImpl")\nprivateUserServiceuserService;\n@Autowired\nprivateConnectionconnection;\n\n@Bean\npublicUserServicecreateJdkProxy(){\nreturn(UserService)Proxy.newProxyInstance(userService.getClass().getClassLoader(),\nuserService.getClass().getInterfaces(),\nnewInvocationHandler(){\n@Override\npublicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{\nObjectobj=null;\ntry{\n//开启事务\nconnection.setAutoCommit(false);\n//调用被代理对象的方法进行数据更新\nobj=method.invoke(userService,args);\n//提交事务\nconnection.commit();\n}catch(RuntimeExceptionex){\n//回滚事务\nconnection.rollback();\n}finally{\n//关闭连接\nconnection.close();\n}\nreturnobj;\n}\n});\n}\n}\n\n//CGLib方式\nclassCglibProxy{\n\n@Autowired\n@Qualifier("userServiceImpl")\nprivateUserServiceuserService;\n@Autowired\nprivateConnectionconnection;\n\n@Bean\npublicUserServicecreateCglibProxy(){\nreturn(UserService)Enhancer.create(UserService.class,newMethodInterceptor(){\n@Override\npublicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{\nObjectobj=null;\ntry{\n//开启事务\nconnection.setAutoCommit(false);\n//调用被代理对象的方法进行数据更新\nobj=method.invoke(userService,args);\n//提交事务\nconnection.commit();\n}catch(RuntimeExceptionex){\n//回滚事务\nconnection.rollback();\n}finally{\n//关闭连接\nconnection.close();\n}\nreturnobj;\n}\n});\n}\n}

我们调用时候只需要使用两个代理类的代理对象即可。

15、注:上面的代码只是对原理的描述,直接使用无法运行(Connection类我这里是没有实现的)。

16、从上面的例子中我们可以看出,只有调用了代理类中的方法才能使事务生效,如果直接调用UserService.update,是没有事务的逻辑的。

17、事实上,Spring中的@Transactional就是这么一个原理实现的。大家可以自行去扒源码,我这里只是做一个理解性的原理解析。

18、二、为什么有时我们加了事务注解也不生效

19、根据上面的原理分析,我们可以得到如下的结论:

20、下面我们举几个常见的场景例子进行说明。

21、interfaceUserService{\nvoidupdate();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n\n@Override\npublicvoidupdate(){\nupdate2();\n}\n\n@Transactional//此处事务注解\nprivatevoidupdate2(){\n//数据更新操作1\nuserDao.update();\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}

私有方法由于无法在代理类中访问,所以一定是不生效的。

22、interfaceUserService{\nvoidupdate();\nvoidupdate2();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n\n@Override\npublicvoidupdate(){\nupdate2();\n}\n\n@Transactional//此处加事务注解\n@Override\npublicvoidupdate2(){\n//数据更新操作1\nuserDao.update();\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}

此场景中:

23、interfaceUserService{\nvoidupdate();\nvoidupdate2();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n\n@Transactional//此处加事务注解\n@Override\npublicvoidupdate(){\nupdate2();\n}\n\n@Transactional//此处也加事务注解\n@Override\npublicvoidupdate2(){\n//数据更新操作1\nuserDao.update();\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}

此场景中:

24、interfaceUserService{\nvoidupdate();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n\n@Transactional//此处添加事务注解\n@Override\npublicvoidupdate(){\nupdate2();\n}\n\npublicvoidupdate2(){\n//数据更新操作1\nuserDao.update();\nupdate3();\n}\n\nprivatevoidupdate3(){\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}

此场景中:

25、interfaceUserService{\nvoidupdate();\nvoidupdate2();\n}\n\nclassUserSericeImplimplementsUserService{\n\n@Resource\nprivateUserDaouserDao;\n@Resource\nprivateRoleDaoroleDao;\n@Resource\nprivateXxxDaoxxxDao;\n@Resource\nprivateUserServiceuserService;\n\n@Override\npublicvoidupdate(){\nuserService.update2();\n}\n\n@Transactional\n@Override\npublicvoidupdate2(){\n//数据更新操作1\nuserDao.update();\n//数据更新操作2\nroleDao.update();\n//数据更新操作3\nxxxDao.update();\n}\n}

此场景中:

26、更多场景不再列举了,如果你的Spring事务不生效,请从我们总结的三点结论中寻找答案:

27、注:@Transactional(rollbackFor=Exception.class),大家还需要注意rollbackFor的条件,如果省略不写,Spring默认触发回滚的异常是运行时异常(RuntimeException)。所以,如果你的事务没回滚时,请先确认发生的异常类型和rollbackFor属性指定的是否一致。如果不匹配,即使你的事务是生效的,也不会触发回滚。

OK,本文到此结束,希望对大家有所帮助。

本站涵盖的内容、图片、视频等数据,部分未能与原作者取得联系。若涉及版权问题,请及时通知我们并提供相关证明材料,我们将及时予以删除!谢谢大家的理解与支持!

Copyright © 2023