项目中有段代码,经缩减去掉中间调用环节后如下:
XXXService.java
private void doXXX(){
......
bean.setState(1);//任务正在创建中
this.xxxDao.getHibernateTemplate().update(bean);
Runnable thread = new SaveThread(...);
pm.run(thread);//托管连接池来运行
//发送审核通知短信
......
}
SaveThread.java
......//数据入库及各种业务逻辑
bean.setState(2);//数据保存完成,修改状态为等待审核
this.xxxDao.getHibernateTemplate().update(bean);
某天系统出现问题: 用户提交任务后,记录一直处于正在创建状态。 于是细查代码,发现问题出在上面这段代码。
以上代码两处都修改了bean的state字段。由于需要入库的数据量大,所以在XXXService中先将任务设置为正在创建状态, 然后另起线程去入库,等入库完成后,将状态修改为待审核。逻辑没有问题,问题在于hibernate托管给spring来管理后,hibernate session 是在方法结束时关闭。 所以通常情况下doXXX()中主线程会比SaveThread线程先结束,这样任务状态最终是2(等待审核),这样是正确的。 而当 “ 发送审核通知短信”出现延时,那么doXXX()主线成有可能比SaveThread线程后结束,并且doXXX()在结束时才会关闭其session,所以SaveThread设置的state(2)被doXXX(1)所覆盖, 导致任务总是处于正在创建状态。
解决方式:强制清理hibernate session 缓存,在doXXX()方法的this.xxxDao.getHibernateTemplate().update(bean);
代码后加上:this.mmsTaskDao.getHibernateTemplate().flush();即可。