利用ThreadLocal & Filter 實現事務處理

關於 ThreadLocal

?       通過ThreadLocal.set() 將對象的引用保存到各線程的自己的一個 map ,每個線程都有這樣一個map,執行ThreadLocal.get()時,各線程從自己的map中取出放進去的對象,因此取出來的是各自自己線程中的對象,ThreadLocal 實例是作爲mapkey來使用的

?      一般情況下,通過ThreadLocal.set() 到線程中的對象是該線程自己使用的對象,其他線程是不需要訪問的

?       ThreadLocal 不是用來解決共享對象的多線程訪問問題的:如果ThreadLocal.set() 進去的東西本來就是多個線程共享的同一個對象,那麼多個線程的 ThreadLocal.get() 取得的還是這個共享對象本身,還是有併發訪問問題。

?       ThreadLocal的應用場合:按線程多實例(每個線程對應一個實例)的對象的訪問。

 

 

ThreadLocalContext.java

package com.sherman.bookstore.web;

 

import java.sql.Connection;

 

public class ThreadLocalContext {

    private ThreadLocal<Connection> connectionThreadLocal = new ThreadLocal<>();

    private static ThreadLocalContext instance = newThreadLocalContext();

    private ThreadLocalContext(){}

    public static ThreadLocalContext getInstance(){

       return instance;

    }

    public void bind(Connection connection){

       connectionThreadLocal.set(connection);

    }

   

    public Connection getConnetion(){

       return connectionThreadLocal.get();

    }

   

    public void remove(){

       connectionThreadLocal.remove();

    }

}

TransactionFilter.java

package com.sherman.bookstore.filter;

import java.io.IOException;

import ……;

import com.sherman.bookstore.db.JDBCUtils;

import com.sherman.bookstore.web.ThreadLocalContext;

 

/**

 * Servlet Filter implementation classTransactionFilter

 */

@WebFilter("/*")

public class TransactionFilter implements Filter {

    public TransactionFilter() {

        // TODO Auto-generated constructor stub

    }

    public void destroy() {

       // TODO Auto-generatedmethod stub

    }

    /**

     * @seeFilter#doFilter(ServletRequest, ServletResponse, FilterChain)

     */

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException {

       Connection connection = null;

       try {

           //1. 獲取連接

           connection = JDBCUtils.getConnection();

           //2. 開啓事務

           connection.setAutoCommit(false);

           //3. 利用 ThreadLocal 把當前線程與數據庫連接綁定

           ThreadLocalContext.getInstance().bind(connection);

           //4. 把請求轉發給對應的 Servlet

           chain.doFilter(request, response);

           //5. 提交事務

           connection.commit();

       } catch (Exception e) {

           //6. 捕獲異常,回滾事務,跳轉至錯誤頁面

           e.printStackTrace();

           try {

              connection.rollback();

           } catch (SQLException e1) {

              e1.printStackTrace();

           }

           HttpServletRequest req = (HttpServletRequest) request;

           HttpServletResponse resp = (HttpServletResponse) response;

           resp.sendRedirect(req.getContextPath() + "/error-1.jsp");

       }finally{

           //7. 解除綁定

           ThreadLocalContext.getInstance().remove();

           //8. 關閉連接

           JDBCUtils.release(connection);

       }

    }

    public void init(FilterConfig fConfig) throws ServletException{

       // TODO Auto-generatedmethod stub

    }

 

}

BaseDAO.java

package com.sherman.bookstore.dao.impl;

 

import java.lang.reflect.ParameterizedType;

import ……;

 

public class BaseDAO<T> implements DAO<T> {

    private QueryRunner queryRunner = new QueryRunner();

    private Class<T> genericType = null;

   

    @SuppressWarnings("unchecked")

    public BaseDAO(){

       Type type = this.getClass().getGenericSuperclass();

       if(type instanceof ParameterizedType){

           ParameterizedType paraType = (ParameterizedType)type;

           genericType = (Class<T>)paraType.getActualTypeArguments()[0];

       }

    }

   

    @Override

    public long insert(String sql, Object... args) {

       int id = 0;

      

       Connection conn = null;

       PreparedStatement psmt = null;

       ResultSet rs = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           psmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);

           if(args != null){

              for (int i = 0; i < args.length; i++) {

                  psmt.setObject(i+1, args[i]);

              }

           }

           psmt.executeUpdate();

           rs = psmt.getGeneratedKeys();

           if(rs.next()){

              id = rs.getInt(1);

           }

       } catch (Exception e) {

           throw new DBException();

       } finally{

           JDBCUtils.release(rs, psmt);

       }

       return id;

    }

 

    @Override

    public void update(String sql, Object... args) {

       Connection conn = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           queryRunner.update(conn, sql, args);

       } catch (Exception e) {

           throw new DBException();

       }

    }

 

    @Override

    public T query(String sql, Object... args) {

       T entity = null;

       Connection conn = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           entity = queryRunner.query(conn, sql, new BeanHandler<>(genericType), args);

          

       } catch (Exception e) {

           throw new DBException();

       }

       return entity;

    }

 

    @Override

    public List<T> queryForList(String sql, Object... args) {

       List<T> entityList = null;

       Connection conn = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           entityList = queryRunner.query(conn, sql, new BeanListHandler<>(genericType), args);

          

       } catch (Exception e) {

           throw new DBException();

       }

       return entityList;

    }

 

    @Override

    public <V> V getSingleVal(String sql, Object... args) {

       Connection conn = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           return queryRunner.query(conn, sql, new ScalarHandler<V>(), args);

       } catch (Exception e) {

           throw new DBException();

       }

    }

 

    @Override

    public void batch(String sql, Object[]... params) {

       Connection conn = null;

      

       try {

           conn = ThreadLocalContext.getInstance().getConnetion();

           queryRunner.batch(conn, sql, params);

       } catch (Exception e) {

           throw new DBException();

       }

    }

 

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章