使用ThreadLocal+filter实现JDBC的事务处理

一、首先创建一个使用单例模式的ConnectionContext类

public class ConnectionContext {

     /**
     * 构造方法私有化,将ConnectionContext设计成单例
     */
    private ConnectionContext(){

    }
    //创建ConnectionContext实例对象
    private static ConnectionContext connectionContext = new ConnectionContext();

    /**
     * @Field: connectionThreadLocal
     *         使用ThreadLocal存储数据库连接对象
     */ 
     private static ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<Connection>();

    /**
    * @Method: getInstance
    * @Description:获取ConnectionContext实例对象
    *
    * @return
    */ 
    public static ConnectionContext getInstance(){
        return connectionContext;
    }



    /**
    * @Method: bind
    * @Description:利用ThreadLocal把获取数据库连接对象Connection和当前线程绑定
    * @param connection
    */ 
    public void bind(Connection connection){
        connectionThreadLocal.set(connection);
    }

    /**
    * @Method: getConnection
    * @Description:从当前线程中取出Connection对象
    *
    * @return
    */ 
    public Connection getConnection(){
        return connectionThreadLocal.get();
    }

    /**
    * @Method: remove
    * @Description: 解除当前线程上绑定Connection
    *
    */ 
    public void remove(){
        connectionThreadLocal.remove();
    }

二、在Dao层的类StudentDaoImpl创建数据库操作方法加钱和减钱的方法,注意异常往上抛

public class StudentDaoImpl {
    public void inMoney(Integer id,Integer money) throws Exception {
        String sql = "update test set money=money+? where id=?";
        QueryRunner queryRunner = new QueryRunner();
        queryRunner.update(ConnectionContext.getInstance().getConnection(), sql,money,id);
    }
    public void outMoney(Integer id,Integer money) throws Exception {
        String sql = "update test set money=money-? where id=?";
        QueryRunner queryRunner = new QueryRunner();
        queryRunner.update(ConnectionContext.getInstance().getConnection(), sql,money,id);
    }
}

三、在Service层提供对Dao层的调用,注意异常往上抛

public class StudentServiceImpl {
    private StudentDaoImpl studentDaoImpl = new StudentDaoImpl();
    public void transfer() throws Exception {       
            studentDaoImpl.inMoney(1, 10);
            int i=1/0;
            studentDaoImpl.outMoney(2, 10);                     
    }
}

四、在控制层Servlet类StudentServlet调用Service层的方法,注意抛出一个自定义的异常,这里的自定义异常为MyException

public class StudentServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;    
    private StudentServiceImpl studentServiceImpl = new StudentServiceImpl();
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{                        
        try {
            studentServiceImpl.transfer();
        } catch (Exception e) {     
            throw new MyException();
        }                   
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

五、创建过滤器TransactionFilter,这里实现对事务的处理

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
            try {
                //1、获取数据库连接对象Connection
                Connection connection = JDBCUtils3.getConnection();

                //2、利用ThreadLocal把获取数据库连接对象Connection和当前线程绑定
                ConnectionContext.getInstance().bind(connection);               
              //3、开启事务
                JDBCUtils3.startTransaction();
                //4、把请求转发给目标Servlet
                chain.doFilter(request, response);
                //5、提交事务
                JDBCUtils3.commit();
            } catch (Exception e) {
                e.printStackTrace();
                //6、回滚事务
                JDBCUtils3.rollback();       
            }finally{
                //7、解除绑定
                ConnectionContext.getInstance().remove();
                //8、关闭数据库连接
                JDBCUtils3.close();
            }
    }

六、总结
使用ThreadLocal+filter对JDBC事务处理的原理过程是创建的ConnectionContext类使用单例模式保证Dao层调用数据库连接的对象实例和过滤器TransactionFilter绑定和解绑数据库连接的对象实例是同一个实例。过滤器TransactionFilter首先执行获取数据库连接、绑定连接到ThreadLocal、开启事务操作,然后 chain.doFilter(request, response)放行让servlet执行,而当Dao、Service和Servlet层出现异常时,由于异常是层层往上抛,所以Servlet层抛出的异常会被TransactionFilter捕获,捕获后进入TransactionFilter的catch里执行事务回滚。

猜你喜欢

转载自blog.csdn.net/chenbingbing111/article/details/80778867