java程序员首页投稿(暂停使用,暂停投稿)

ThreadLocal的使用事例

2017-11-28  本文已影响42人  5e30faa7d323

列举几个使用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实现即可,大大缩减了代码量,提高代码复用性。

上一篇下一篇

猜你喜欢

热点阅读