当每个执行JDBC的类都需要执行回滚和提交的操作,如下:

那么如果有的DAO成功提交,有的需要回滚。但是service的操作需要是一个整体,不能部分成功,部分失败。所以事务管理应该以业务层的方法为单位,而不能以DAO层的单精度方法为单位。
所以应该将上图中的try...catch...语句执行的内容转到service中。但因为servlet对应一个service,service又被filter拦截,所以可以将事务提交转移到filter中,如下:

Notations:DAO1、2、3中的数据库连接Connection需要同一个。因此需要ThreadLocal本地线程。里面有set和get方法,将Connection设置到线程中。
OpenSessionFilter:
先写一个开始、提交和回滚事务的工具类,如下所示:
- public class TransManager {
- //本地线程存储连接方便各个DAO方法使用
- private static ThreadLocal
threadLocal=new ThreadLocal(); -
- //开始事务
- public void startTrans() throws SQLException {
- this.getConnection().setAutoCommit(false);
- }
-
- //提交事务
- public void commitTrans() throws SQLException {
- this.getConnection().commit();
- //因为这里的提交和回滚函数都是在filter处理响应的时候才执行,所以要执行关闭连接的操作
- this.getConnection().close();
- }
-
- //回滚事务
- public void rollTrans() throws SQLException {
- this.getConnection().rollback();
- this.getConnection().close();
- }
-
- private Connection getConnection() throws SQLException{
- Connection con=threadLocal.get();
- if(con==null){
- //发现threadLocal里面没有connection,就获取并设置
- //放在threadLocal里面就是为了一个DAO调用后再给下一个调用
- con=DButil.getConnection();
- threadLocal.set(con);
- }
- return con;
- }
-
- }
然后在Filter的doFilter方法中进行事务的管理
- @Override
- public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
- TransManager tm=new TransManager();
- try {
- tm.startTrans();
- filterChain.doFilter(servletRequest,servletResponse);
- tm.commitTrans();
- } catch (SQLException e) {
- try {
- tm.rollTrans();
- } catch (SQLException ex) {
- ex.printStackTrace();
- }
- e.printStackTrace();
- }
-
- }
ThreadLocal
ThreadLocal的set(obj)方法。源码如下:
- public void set(T value) {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- map.set(this, value);
- } else {
- createMap(t, value);
- }
- }
首先获取了当前的线程。每个线程都有一个容器(ThreadLocalMap)。map.set(this)就是将ThreadLocal作为key,因为我们的组件中需要传输的对象可能有多个。后面的createMap是初始化Map。
set的源码如下:
- public T get() {
- Thread t = Thread.currentThread();
- ThreadLocalMap map = getMap(t);
- if (map != null) {
- ThreadLocalMap.Entry e = map.getEntry(this);
- if (e != null) {
- @SuppressWarnings("unchecked")
- T result = (T)e.value;
- return result;
- }
- }
- return setInitialValue();
- }
其中this指的是ThreadLocal对象,通过它才知道是哪个ThreadLocalMap。entry.value是获取工具箱。
Listener(监听器)
Servlet规范中定义的一种特殊类,它用于监听Web应用程序中的ServletContext,HttpSession 和HttpServletRequest等域对象的创建与销毁事件,以及监听这些域对象中的属性发生修改的事件。
部分示例:
1,ServletContextListener-监听ServletContext对象的创建和销毁的过程
2,HttpSessionListener-同理
3,ServletRequestListener
4,ServletContextAttributeListener-监听ServletContext的保存域的改动
5,HttpSessionBindingListener-监听某个对象在session中的绑定与移除