网站首页 > 教程分享 正文
以前我们说过,Spring通过ThreadLocal机制解除了事务管理模块与数据访问层的紧密耦合,提高了模块的可重用性,也保证了多线程环境下的对connection资源的有效管理,实现了线程安全。而要将事务管理代码从整个业务逻辑中抽离出来,提供系统性的服务,就要使用Spring aop,在使用过程中,我们千万不可忘记了其动态代理的实质,不然在使用过程你会不知不觉掉进陷阱里,请看以下例子:
(1) 正常情况
外部调用:
orderService.addOrder(order,orderDto);
Service内的addOrder方法:
@Override
@Transactional
publicvoid addOrder(Order order,OrderDto orderDto) throws Exception {
orderDAO.addOrder(order);
OrderDetail orderDetail = new OrderDetail();
orderDetail.setDiscount(orderDto.getDiscount());
orderDetail.setQuantity(orderDto.getQuantity());
Product productParam = new Product();
productParam.setProductId(orderDto.getProductId());
Product productGet = productService.getProducts(productParam).get(0);
orderDetail.setProduct(productGet);
productGet.getOrderDetail().add(orderDetail);
orderDetail.setOrder(order);
order.getOrderDetails().add(orderDetail);
productGet.setQuantity(productGet.getQuantity()-orderDetail.getQuantity());
orderDetailDAO.addOrderDetail(orderDetail);
thrownew RuntimeException("it's wrong");
}
添加订单前数据:
添加订单后数据:
抛出异常,事务回滚,操作后表记录未变。
(2) 非正常情况
外部调用:
orderService.addOrderWrapper(order,orderDto);
@Override
publicvoid addOrderWrapper(Order order,OrderDto orderDto) throws Exception{
//(1)中的addOrder方法,仍然有@Transactional注解
addOrder(order, orderDto);
}
执行后数据
虽然抛出异常,但事务未回滚,操作后数据改变了。
为什么在orderService的addOrderWrapper()方法内部调用addOrder(),报运行时异常时就不会回滚了呢? 实际上,在第一种情况中,程序是通过orderService的代理类上调用addOrder()方法的,这样,与该方法相关的拦截器就会对请求进行拦截处理,提供相应的事务处理机制;而在第二种情况下,addOrder()方法虽然仍然有@Transaction注解,但仅仅是在orderService上的直接调用,而不是通过代理类调用,伪代码的形式展现如下:
第一种情况:
ProxyFactory factory = new ProxyFactory(orderServiceImpl);
factory.addInterceptor(transactionInterceptor);
OrderService proxy = (orderService) factory.getProxy();
proxy.addOrder();//通过代理调用
第二种情况:
同this.addOrder();//直接通过this调用,事务拦截方法不起作用。
在事务代理类上调用方法的过程见如图:
(图1-1 来源:
spring-framework-reference)
无论Spring声明式事务使用什么形式(基于Xml配置文件或者Annotation),万变不离其宗,其底层都是使用了TransactionInterceptor。TransactionInterceptor是一个实现了MethodInterceptor接口的拦截器(Advice),具有相应的事务横切逻辑,被织入到系统中。若方法声明了相应的事务控制信息,它会在该方法执行前开启一个事务,完成时提交事务,发生异常时回滚事务,至于其中的具体规则(传播,隔离级别,超时时间,是否只读,针对何种异常进行回滚),可以通过xml或者@Transactional指定。
如图就是它实现的invoke方法的源代码:
createTransactionIfNecessary方法将会开启一个事务;断点处的proceed方法让程序沿着调用链传播(如图1-1所示)。
completeTransactionAfterThrowing和
commitTransactionAfterReturning方法则提交回滚事务。
文:卍极客
文章来源:java达人(微信公众号ID:java_daren),本文已获作者授权转载。
注:如需转载,请联系作者。
猜你喜欢
- 2025-03-25 Java面试宝典之问答系列(java面试问题大全及答案大全 word)
- 2025-03-25 Ibatis学习总结6--使用 SQL Map API 编程
- 2025-03-25 【赵强老师】数据库的事务(数据库yzj)
- 2025-03-25 事务的事务扩展TransactionSynchronizationManager
- 2025-03-25 三十一、Spring 中的策略模式深度解析
- 2025-03-25 SQL Server存储过程的使用及实例分析
- 2025-03-25 Kafka消息可靠传输之幂等、事务机制
- 2025-03-25 解密Java ThreadLocal:核心原理、最佳实践与常见陷阱全解析
- 2025-03-25 睿民大数据开发岗位面试题(大数据开发校招面试题)
- 2025-03-25 设计模式-桥接模式(设计模式桥接模式是什么意思)
你 发表评论:
欢迎- 最近发表
-
- 有了这份900多页的Android面试指南,你离大厂Offer还远吗?
- K2 Blackpearl 流程平台总体功能介绍:常规流程功能
- 零基础安卓开发起步(一)(安卓开发入门视频)
- 教程:让你的安卓像Windows一样实现程序窗口化运行
- Android事件总线还能怎么玩?(事件总线有什么好处)
- Android 面试被问“谈谈架构”,到底要怎样回答才好?
- Android开发工具Parcel和Serialize
- Android 中Notification的运用(notification widget安卓)
- Android退出所有Activity最优雅的方式
- MT管理器-简单实战-去除启动页(mt管理器怎么去除软件弹窗)
- 标签列表
-
- css导航条 (66)
- sqlinsert (63)
- js提交表单 (60)
- param (62)
- parentelement (65)
- jquery分享 (62)
- check约束 (64)
- curl_init (68)
- sql if语句 (69)
- import (66)
- chmod文件夹 (71)
- clearinterval (71)
- pythonrange (62)
- 数组长度 (61)
- javafx (59)
- 全局消息钩子 (64)
- sort排序 (62)
- jdbc (69)
- php网页源码 (59)
- assert h (69)
- httpclientjar (60)
- postgresql conf (59)
- winform开发 (59)
- mysql数字类型 (71)
- drawimage (61)
本文暂时没有评论,来添加一个吧(●'◡'●)