如上图,我们的Controller调用了Service方法,一个Service方法中有三个DAO操作,如果我们将事务管理像图上一样写在DAO操作中,那么会出现一个问题,如果,一个Service方法被调用,DAO1成功,DAO2失败,DAO3成功,那么这个Service方法到底是成功了,还是失败了???比如银行转账的业务,我不可能扣款成功了,别人钱没到吧
因此,Service是一个整体,要么都成功,要么都失败,事务管理不能以DAO的单精度方法为单位,而是以业务层的方法为单位
因此我们有一个更好的法子,就是将这个事务的开启放在过滤器中![[过滤器事务.png]]
这样,我们在处理一个请求时,过滤器开启事务,在请求中出现异常就回滚,来保证业务的原子性
但是存在一个难点,就是,事务的管理肯定是connect.autoCommit(false)… connection.rollback嘛,那么我们就要保证,这个业务中用的connection是一条,就是DAO1,DAO2,DAO3用一条connection,这样操作的是同一个事务
这里老师提到了一个例子,流水线的例子,一个产品在纽带上流转,到第一个使用者这,他使用了这个产品,接着到第二个使用者,第二个使用者也使用这个产品…依次,所有的使用者都是用这个产品
![[流水线.png]]
这里就可以用ThreadLocal了,ThreadLocal就像这条流水线一样
ThreadLocal
- get(),set(obj);
- ThreadLocal称之为本地线程,用set方法在当前线程上存储数据,get获取数据,这里只是类比,但并不是真的用线程存储数据
- 可以将connection放进threadlocal中,那么这个线程取出来的connection是一样的
最后我们实现了使用OpenSessionInViewFilter 过滤器来统一管理事务的开启,放行给Servlet,出现异常的话,回来到过滤器时就回滚并提示操作失败