在使用Spring的事务注解@Transactional的时候遇到几个坑
2016-03-20 16:16
751 查看
今天在用@Transactional的时候遇到几个很奇怪的问题,一段从旧程序上拷过来的代码结果死活不执行,让我百思不得其解。
旧的代码是这样的,一直运行正常
起初我还以为是Lambda表达式的问题,改写了一下,结果是一样的。
然后我就不停的测试,不停的改@transactional的事务级别,结果都没用。
然后我就看我的dao里面的基类,结果发现了一点不同
旧代码在dao的基类上加了@Transactional,而新代码则是加了@Transactional(readOnly=true)
所以dao里面的save方法,旧代码是有事务的,而新代码则是只读的事务。可以问题来了,为什么我在新代码的saveList上加的事务注解不起作用?
我在网上没有找到相应的解释,但是通过我的测试和对spring的认识,我觉得spring的事务是通过切面(或者也可以说是代理)实现的,当你调用一个代理类的接口,如果其标注了事务注解,则会生效,
而我这个saveList是在service里面自己的方法调用的,这个注解不会被处理。
于是我修改代码,结果使用了三种方案全部失败:
1. 在getList上加事务注解,取消saveList上的注解:这种方式可以保存数据成功,但是查询出来的数据在SpringMVC转换结果为json的时候报错,说no session.
2. 在dao基类的save方法上加注解:结果同上
3. service提供两个接口给controller,分别是getList和saveList,都加上事务注解:结果还是同上。
经验告诉我,当你的请求包含了提交事务的时候,你同时又读了数据,并且需要在controller或是view层懒加载数据,则会有问题,因为事务一提交就关闭了。
我唯一不能理解的是我先调用saveList,提交了事务,保存了数据,我再调用getList,按理应该重新生成事务,可是为什么到controller这里还是没有session了。
最后没办法,我把读写两个事情在controller层也分开为两个接口,在jsp里面做两次请求来处理。
总结一下:
1. service里面的方法如果不是对外的接口,加事务注解没有用
2. 一个请求里面如果包含了提交事务(非只读),同时又查询数据的话,查询的数据要立即加载,不能到view层再调用session去懒加载数据。
旧的代码是这样的,一直运行正常
@Override public Pager getPager(Map<String, Object> paramMap) { List<TaSjjhLog> logList = TaSjjhLog.getWaitingList(); if(logList != null && logList.size() > 0){ this.saveList(logList); } return this.dao.getPager(paramMap); } @Transactional private void saveList(List<TaSjjhLog> logList) { for (TaSjjhLog log : logList) { log.setErrorMessage(this.handleErrorMsg(log.getErrorMessage())); this.dao.save(log); } TaSjjhLog.removeAllFromWaitingList(logList); }新的代码是这样的,结果保存操作不起作用
@Override public List<ChangeLog> getList(Pager<ChangeLog> pager, String mc) { List<changelog> logList = ChangeLog.getWaitingList(); if(logList != null && logList.size() > 0){ this.service.saveList(logList); } return this.dao.getList(pager, mc); } @Transactional private void saveList(List<ChangeLog> logList) { logList.stream().forEach(log->{ log.setErrorMessage(this.handleErrorMsg(log.getErrorMessage(), log.getRecordCount(), log.getExecutedCount())); this.dao.save(log); ChangeLog.removeFromWaitingList(log); }); }</changelog>
起初我还以为是Lambda表达式的问题,改写了一下,结果是一样的。
然后我就不停的测试,不停的改@transactional的事务级别,结果都没用。
然后我就看我的dao里面的基类,结果发现了一点不同
旧代码在dao的基类上加了@Transactional,而新代码则是加了@Transactional(readOnly=true)
所以dao里面的save方法,旧代码是有事务的,而新代码则是只读的事务。可以问题来了,为什么我在新代码的saveList上加的事务注解不起作用?
我在网上没有找到相应的解释,但是通过我的测试和对spring的认识,我觉得spring的事务是通过切面(或者也可以说是代理)实现的,当你调用一个代理类的接口,如果其标注了事务注解,则会生效,
而我这个saveList是在service里面自己的方法调用的,这个注解不会被处理。
于是我修改代码,结果使用了三种方案全部失败:
1. 在getList上加事务注解,取消saveList上的注解:这种方式可以保存数据成功,但是查询出来的数据在SpringMVC转换结果为json的时候报错,说no session.
2. 在dao基类的save方法上加注解:结果同上
3. service提供两个接口给controller,分别是getList和saveList,都加上事务注解:结果还是同上。
经验告诉我,当你的请求包含了提交事务的时候,你同时又读了数据,并且需要在controller或是view层懒加载数据,则会有问题,因为事务一提交就关闭了。
我唯一不能理解的是我先调用saveList,提交了事务,保存了数据,我再调用getList,按理应该重新生成事务,可是为什么到controller这里还是没有session了。
最后没办法,我把读写两个事情在controller层也分开为两个接口,在jsp里面做两次请求来处理。
总结一下:
1. service里面的方法如果不是对外的接口,加事务注解没有用
2. 一个请求里面如果包含了提交事务(非只读),同时又查询数据的话,查询的数据要立即加载,不能到view层再调用session去懒加载数据。
相关文章推荐
- Spring属性配置
- java多线程之(Exchanger)
- 安装完win10后Eclipse好看多了
- java课堂练习,反射
- 20145230《Java程序设计》第3周学习总结
- eclipse反编译插件安装
- JAVA多线程之(CyclicBarrier)
- myeclipse2014如何创建user library
- java设计模式基础之设计原则
- Leetcode:278. First Bad Version(JAVA)
- Java学习之InputStream中read()与read(byte[] b)
- myeclipse的buildpath 和lib引入的区别
- [分拣思想]——对象计数
- 20145236 冯佳 《Java程序设计》第3周学习总结
- Java自动装箱和拆箱定义
- struts2中的constant配置
- 关于 Java 中 正则表达式的 MULTILINE 标志
- Spark读取Hbase中的数据
- JAVA多线程之(CountDownLatch)
- JS基本类型与Java的区别复习