Java事务(三) - 使用ThreadLocal

来源:互联网 发布:客户端软件的配置 编辑:程序博客网 时间:2024/05/16 18:22

一. 为什么使用ThreadLocal:

在上一篇博文中, 我们通过传递Connection的方式来控制事务, 这种方法可以达到目的, 但让人看的不爽, 

如果涉及到调用多个service, 那我是不是还得从controller层传递Connection?


ThreadLocal的用法见上一篇博客, 该类保证一个类的实例变量在各个线程中都有一份单独的拷贝, 

从而不会影响其他线程中的实例变量,所以ThreadLocal可以实现线程范围内数据共享。


二. 如何使用ThreadLocal:

1. 写一个TransactionManager类:

/** * 管理事务 */public class TransactionManager {private static ThreadLocal<Connection> local = new ThreadLocal<Connection>();// 开启事务public static void beginTransaction() throws SQLException {Connection conn = JDBCUtils.getConnection();conn.setAutoCommit(false); // 将连接存入threadLocallocal.set(conn);}// 回滚事务public static void rollback() throws SQLException {Connection conn = local.get();if (conn != null) {conn.rollback();conn.close();// 清空threadLocallocal.remove();}}// 提交事务public static void commit() throws SQLException {Connection conn = local.get();if (conn != null) {conn.commit();// 清空threadLocallocal.remove();}}// 关闭连接public static void close() throws SQLException {Connection conn = local.get();if (conn != null) {conn.close();// 清空threadLocallocal.remove();}}// 获取数据库连接public static Connection getConnection() {return local.get();}}
使用ThreadLocal, 确保相同的线程获取到的是同一个连接.


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();}}}

使用TransactionManager来管理事务, 代码变得更加简洁.


 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层的代码变简洁了.

源码下载: http://download.csdn.net/detail/zdp072/7908261


2 0
原创粉丝点击