ThreadLocal的使用事例

作者: 5e30faa7d323 | 来源:发表于2017-11-28 16:30 被阅读42次

    列举几个使用ThreadLocal的事例,能更好的理解ThreadLocal。

    1、运用ThreadLocal实现TransactionManager类

    1. 写一个TransactionManager类:
    /** 
     * 管理事务 
     */  
    public class TransactionManager {  
        //使用ThreadLocal, 确保相同的线程获取到的是同一个连接.
        private static ThreadLocal<Connection> local = new ThreadLocal<Connection>();  
      
        // 开启事务  
        public static void beginTransaction() throws SQLException {  
            Connection conn = JDBCUtils.getConnection();  
            conn.setAutoCommit(false);   
            // 将连接存入threadLocal  
            local.set(conn);  
        }  
      
        // 回滚事务  
        public static void rollback() throws SQLException {  
            Connection conn = local.get();  
            if (conn != null) {  
                conn.rollback();  
                conn.close();  
                // 清空threadLocal  
                local.remove();  
            }  
        }  
      
        // 提交事务  
        public static void commit() throws SQLException {  
            Connection conn = local.get();  
            if (conn != null) {  
                conn.commit();  
                // 清空threadLocal  
                local.remove();  
            }  
        }  
          
        // 关闭连接  
        public static void close() throws SQLException {  
            Connection conn = local.get();  
            if (conn != null) {  
                conn.close();  
                // 清空threadLocal  
                local.remove();  
            }  
        }  
      
        // 获取数据库连接  
        public static Connection getConnection() {  
            return local.get();  
        }  
    }  
    
    2、修改业务处理类
    /** 
     * 业务逻辑层 
     */  
    public class AccountService {  
      
        public void transfer(Account outAccount, Account inAccount, int money) throws SQLException {  
            // 开启 事务   
            TransactionManager.beginTransaction();  
      
            // 查询两个账户  
            AccountDAO accountDAO = new AccountDAO();  
            outAccount = accountDAO.findAccountById(outAccount.getId());  
            inAccount = accountDAO.findAccountById(inAccount.getId());  
      
            // 转账 - 修改原账户金额   
            outAccount.setMoney(outAccount.getMoney() - money);  
            inAccount.setMoney(inAccount.getMoney() + money);  
      
            try {  
                // 更新账户金额  
                accountDAO.update(outAccount);  
                accountDAO.update(inAccount);  
      
                // 转账成功, 提交事务  
                TransactionManager.commit();  
            } catch (Exception e) {  
                // 转账失败, 回滚事务  
                TransactionManager.rollback();  
                e.printStackTrace();  
            } finally {  
                // 关闭连接  
                TransactionManager.close();  
            }  
        }  
    }  
    
    3、Dao类
    /** 
     * DAO层: CRUD 
     */  
    public class AccountDAO {  
        // 查询账户  
        public Account findAccountById(int id) throws SQLException {  
            String sql = "select * from account where id = ?";  
            Object[] params = {id};  
            QueryRunner queryRunner = new QueryRunner(JDBCUtils.getDataSource());  
            return queryRunner.query(sql, new BeanHandler<Account>(Account.class), params);  
        }  
          
        // 更新账户  
        public void update(Account account) throws SQLException {  
            String sql = "update account set name = ?, money = ? where id = ?";  
            Object[] params = {account.getName(), account.getMoney(), account.getId()};  
              
            // 从threadLocal中获取连接, 同一个线程拿到的是同一个连接  
            Connection conn = TransactionManager.getConnection();  
            QueryRunner queryRunner = new QueryRunner();  
            queryRunner.update(conn, sql, params);  
        }  
    }  
    

    不需要传递Connection,直接从TransactionManager中获取连接。

    service和dao都是通过TransactionManager来获取Connection, 同一个线程中, 它们在整个事务处理过程中使用了相同的Connection对象, 所以事务会处理成功, dao中没有接受和业务无关的对象, 消除了api污染, 另外使用TransactionManager来管理事务, 使service层的代码变简洁了.

    2、工具类HibernateUtil运用ThreadLocal来管理Session

    import org.hibernate.*;  
    import org.hibernate.cfg.*;  
    import org.hibernate.service.*;  
    import org.hibernate.boot.registry.*;  
    /** 
     * Description: 
     * @author  VipMao 
     * @version  1.0 
     */  
      
      
    /** 
     * 该工具类提供了一个属性:SessionFactory sessionFactory  
     * 并创建了sessionFactory 将它设置成static 这样其他程序就可以直接通过此工具类引用 
     * 提供了二个方法: 
     * 1:通过线程创建Session-->currentSession() 
     * 2:关闭Session-->closeSession() 
     * 需要在主类中手动关闭sessionFactory 
     */  
    public class HibernateUtil  
    {  
        public static final SessionFactory sessionFactory;  
        //创建sessionFactory  
        static  
        {  
            try  
            {  
                // 采用默认的hibernate.cfg.xml来启动一个Configuration的实例  
                Configuration cfg = new Configuration()  
                    .configure();  
                // 以Configuration实例来创建SessionFactory实例  
                ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()  
                    .applySettings(cfg.getProperties()).build();  
                sessionFactory = cfg.buildSessionFactory(serviceRegistry);  
            }  
            catch (Throwable ex)  
            {  
                System.err.println("Initial SessionFactory creation failed." + ex);  
                throw new ExceptionInInitializerError(ex);  
            }  
        }  
      
        // ThreadLocal可以隔离多个线程的数据共享,因此不再需要对线程同步  
        public static final ThreadLocal<Session> session  
            = new ThreadLocal<Session>();  
        //创建Session  
        public static Session currentSession()  
            throws HibernateException  
        {  
            //通过线程对象.get()方法安全创建Session  
            Session s = session.get();  
            // 如果该线程还没有Session,则创建一个新的Session  
            if (s == null)  
            {  
                s = sessionFactory.openSession();  
                // 将获得的Session变量存储在ThreadLocal变量session里  
                session.set(s);  
            }  
            return s;  
        }  
        //关闭Session  
        public static void closeSession()  
            throws HibernateException  
        {  
            Session s = session.get();  
            if (s != null)  
                s.close();  
            session.set(null);  
        }  
    }  
    

    该工具类提供了一个属性:SessionFactory sessionFactory , 并将创建sessionFactory写在了static代码块里, 这样其他程序就可以直接通过HibernateUtil.sessionFactory引用,而不是再通过一系列的代码创建SessionFactory对象。
    另外工具类还提供了二个方法:

    1:通过线程创建Session-->currentSession()
    工具类中通过ThreadLocal创建Session ,可以隔离多个线程的数据共享

    2:关闭Session-->closeSession()

    可以看出工具类将创建SessionFactory对象、Session对象以及关闭Session放在了不同的代码块以及方法里,这样以后咱们需要创建什么或者关闭什么直接通过HibernateUtil.XXX实现即可,大大缩减了代码量,提高代码复用性。

    相关文章

      网友评论

        本文标题:ThreadLocal的使用事例

        本文链接:https://www.haomeiwen.com/subject/yqkebxtx.html