@Autowired
private PropertyService propertyService;
@Override
public String execute() throws Exception {
model = propertyService.getProperty(1L);
return null;
}
重新发布,调用,检查连接数,发现无被占用连接存在。
小结:如果正确配置了事务管理器,getSession是安全的。
这时要清楚spring是通过AOP来实现事务控制的,而@PostConstruct方法不会受AOP控制,因此上面的init方法等于无事务管理器。
那么再回头来说,是否只要dao中使用getHibernateTemplate就不会有问题呢?
假定service中的@PostConstruct方法如下:
@PostConstruct
public void init(){
SysProperty p = new SysProperty();
p.setName("test_property_1");
propertyDAO.save(p);
}
强调一下,前面已经提到这个方法不受spring的事务管理器控制。
假定DAO中的save方法如下:
public void save(SysProperty o){
getSession().save(o);
}
启动一下应用,检查一下连接数,再检查一下数据是否有存储到数据库中。因为我们直接使用了getSession,因此连接不会释放,这点前面已经提到,但同时我们还将发现数据没有被存储,当然这个也好理解,因为上面已经提到这个方法未配置事务管理器。
小结:通过getSession().save()保存数据时,事务不会自动提交。
现在再修改下DAO中的save方法:
public void save(SysProperty o){
getHibernateTemplate().save(o);
}
启动一下应用,检查一下连接数,再检查一下数据是否有存储到数据库中。因为我们使用hibernateTemplate,因此连接有释放,这点前面已经提到,但同时我们还发现数据也已存储到数据库中,说明hibernateTemplate会自动提交事务。
小结:如果未配置事务管理器,通过hibernateTemplate操作时,会自动创建并提交事务。
所以如果你觉得使用hibernateTemplate就OK了,那就要小心下面的代码了:
@PostConstruct
public void init(){
//1. 从你的账号A中扣除一万块
//2. 这里的代码抛出了异常
//3. 将你的账号B中增加一万块
}
如果上面的第2步出现了异常,那么因为1的事务已经提交,而3却没有执行,最终导致了数据的不一致,后果和连接泄漏一样严重!
除了@PostConstruct,还有其它原因会导致@Transactional无效,假定我们的service配置了事务管理器,但存在如下代码:
pubic void someServiceMethod(){
new Thread(){
public void run(){
doSomethingLater();
}
}
}
public void doSomethingLater(){
//做一系列数据库操作
}
那么你可以去验证下doSomethingLater是否受事务管理器控制,事实上并不会,所以你需要理解spring AOP的机制,否则一个小坑会酿成灾难。
这里还有一种情况,你不是在类上面配置@Transactional,而是在方法上面配置,假定存在如下的代码:
//该方法不需要事务控制
public void method1(){
method2();
}
//下面的方法需要事务控制
@Transactional
public void method2(){
//do something
}
因为你需要给不同的方法配置不同的事务机制,因此你没有在类上面进行配置,然后你在客户端进行了如下调用:service.method1(); method2中的方法会受事务管理吗?可悲的是并不会。
上面讲到的线程调用和内部方法调用可以这样来处理:
@Autowired
private ApplicationContext context;
public void method1(){
PropertyService service = context.getBean(PropertyService.class);
service.method2();
}
小结:注意spring的AOP机制
4. Service合理配置事务管理器
最后补充一下,如果事务管理器配置正确的话会发生什么。这时不管你是用getSession还是getHibernateTemplate,结果都是一样,session将在thread级别共享,session只有一个。
总结:难得这周开始工作变得清闲,上班时间还能写写博客,想想前段日子真是自己何苦为难自己。回到话题,使用getSession没什么大错,因为你本应正确配置事务管理器。使用hibernateTemplate能解决所有连接泄漏的问题,但要小心他可能隐藏的事务问题。另外就是spring中内部方法调用时AOP的问题,创建新线程时的事务问题。最后希望这篇有点绕的文章能给你带来帮助。