您的位置:首页 > 编程语言 > Java开发

在使用Spring的事务注解@Transactional的时候遇到几个坑

2016-03-20 16:16 751 查看
    今天在用@Transactional的时候遇到几个很奇怪的问题,一段从旧程序上拷过来的代码结果死活不执行,让我百思不得其解。

    旧的代码是这样的,一直运行正常

@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去懒加载数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: