首页 > 图灵资讯 > 技术篇>正文

Apache_DBUtils框架教程学习笔记(四)_事务处理

2023-04-16 09:27:03

  4.3、用Threadlocal绑定对象处理事务

  以上处理事务的方式在businessservice层仍然不够优雅。为了使事务处理更加优雅,我们使用threadlocal类进行改造。threadlocal是一个容器,存储在该容器中的对象可以在当前线程范围内获得,存储在threadlocal中的东西是存储在其中的Map中的东西,然后Threadlocal将这个Map挂在当前线程下,这样Map就只属于这个线程了

  Threadlocal类的使用范例如下: package wkcto.com.test; //线程绑定对象 public class ThreadLocalTest { public static void main(String[] args) { ///当得到程序运行时的当前线程 Thread currentThread = Thread.currentThread(); System.out.println(currentThread); ///Threadlocal一个容器,存储在这个容器中的对象可以在当前线程范围内获得 ThreadLocal t = new ThreadLocal(); ///将对象绑定到当前线程上 对象以键值对的形式存储在Map集中,对象的key是当前的线程,如: map(currentThread,"aaa") t.set("aaa"); ///获得绑定到当前线程的对象 String value = t.get(); ///输出value的值为aaaaa System.out.println(value); } }

  使用Threadlocal类对数据库连接工具类Jdbcutils进行改造,改造后的代码如下: package wkcto.com.util; import java.sql.Connection; import java.sql.SQLException; import javax.sql.DataSource; import com.mchange.v2.c3p0.ComboPooledDataSource; /** * @ClassName: Jdbcutils2 * @Description: 数据库连接工具类 */ public class Jdbcutils2 { private static ComboPooledDataSource ds = null; ///使用ThreadLocal存储当前线程中的Conection对象 private static ThreadLocal threadLocal = new ThreadLocal(); ///在静态代码块中创建数据库连接池 static{ try{ ///通过代码创建C3P0数据库 /*ds = new ComboPooledDataSource(); ds.setDriverClass("com.mysql.jdbc.Driver"); ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy"); ds.setUser("root"); ds.setPassword("root"); ds.setInitialPoolSize(10); ds.setMinPoolSize(5); ds.setMaxPoolSize(20);*/ //通过阅读C3P0xml配置文件创建数据源,c3p0c3p0xml配置文件-config.必须将xml放在src目录下 //ds = new ComboPooledDataSource();///使用C3P0的默认配置创建数据源 ds = new ComboPooledDataSource("MySQL");///使用C3P0命名配置创建数据源 }catch (Exception e) { throw new ExceptionInInitializerError(e); } } /** * @Method: getConnection * @Description: 从数据源中获取数据库连接 * @return Connection * @throws SQLException */ public static Connection getConnection() throws SQLException{ ///从当前线程中获得Conection Connection conn = threadLocal.get(); if(conn==null){ ///从数据源中获取数据库连接 conn = getDataSource().getConnection(); ///将conn绑定到当前线程 threadLocal.set(conn); } return conn; } /** * @Method: startTransaction * @Description: 开启事务 * */ public static void startTransaction(){ try{ Connection conn = threadLocal.get(); if(conn==null){ conn = getConnection(); //把 conn绑定到当前线程 threadLocal.set(conn); } //开始事务 conn.setAutoCommit(false); }catch (Exception e) { throw new RuntimeException(e); } } /** * @Method: rollback * @Description:回滚事务 * */ public static void rollback(){ try{ ///从当前线程中获得Conection Connection conn = threadLocal.get(); if(conn!=null){ //回滚事务 conn.rollback(); } }catch (Exception e) { throw new RuntimeException(e); } } /** * @Method: commit * @Description:提交事务 */ public static void commit(){ try{ ///从当前线程中获得Conection Connection conn = threadLocal.get(); if(conn!=null){ ///提交事务 conn.commit(); } }catch (Exception e) { throw new RuntimeException(e); } } /** * @Method: close * @Description:关闭数据库连接(注意,不是真的关闭,相反,将连接返回数据库连接池) * */ public static void close(){ try{ ///从当前线程中获得Conection Connection conn = threadLocal.get(); if(conn!=null){ conn.close(); ///解除当前线程绑定conn threadLocal.remove(); } }catch (Exception e) { throw new RuntimeException(e); } } /** * @Method: getDataSource * @Description: 获取数据源 * @return DataSource */ public static DataSource getDataSource(){ ///从数据源中获取数据库连接 return ds; } }

  对于Accountdao进行改造,数据库连接对象不再需要service层传输,而是直接从Jdbcutils2提供的getconection方法中获取,改造后的accountdao如下: package wkcto.com.dao; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.handlers.BeanHandler; import wkcto.com.domain.Account; import wkcto.com.util.JdbcUtils; import wkcto.com.util.Jdbcutils2; /* create table account( id int primary key auto_increment, name varchar(40), money float )character set utf8 collate utf8_general_ci; insert into account(name,money) values('A',1000); insert into account(name,money) values('B',1000); insert into account(name,money) values('C',1000); */ /** * @ClassName: AccountDao * @Description: CRUD针对Account对象 * */ public class AccountDao2 { public void update(Account account) throws SQLException{ QueryRunner qr = new QueryRunner(); String sql = "update account set name=?,money=?,money=? where id=?"; Object params[] = {account.getName(),account.getMoney(),account.getId()}; //Jdbcutils2.getConnection()在当前线程中获取Conection对象 qr.update(Jdbcutils2.getConnection(),sql, params); } public Account find(int id) throws SQLException{ QueryRunner qr = new QueryRunner(); String sql = "select * from account where id=?"; //Jdbcutils2.getConnection()在当前线程中获取Conection对象 return (Account) qr.query(Jdbcutils2.getConnection(),sql, id, new BeanHandler(Account.class)); } }

  对于AccountService进行改造,Service层不再需要将数据库连接到Conection到Dao层,改造后的AccountService如下: package wkcto.com.service; import java.sql.SQLException; import wkcto.com.dao.AccountDao2; import wkcto.com.domain.Account; import wkcto.com.util.Jdbcutils2; public class Accountservice2 { /** * @Method: transfer * @Description:在业务层处理两个账户之间的转账问题 * @param sourceid * @param tartgetid * @param money * @throws SQLException */ public void transfer(int sourceid,int tartgetid,float money) throws SQLException{ try{ //开始事务,在业务层处理事务,确保dao层的多个操作在同一事务中进行 Jdbcutils2.startTransaction(); AccountDao2 dao = new Accountdao2(); Account source = dao.find(sourceid); Account target = dao.find(tartgetid); source.setMoney(source.getMoney()-money); target.setMoney(target.getMoney()+money); dao.update(source); ///模拟程序异常导致事务回滚 int x = 1/0; dao.update(target); ////SQL正常执行后提交事务 Jdbcutils2.commit(); }catch (Exception e) { e.printStackTrace(); ///出现异常后,回滚事务 Jdbcutils2.rollback(); }finally{ ///关闭数据库连接 Jdbcutils2.close(); } } }

  所以在service层处理事务看起来更优雅。Threadlocal类在开发中被广泛使用。如果程序运行中产生的数据想要在一个线程范围内共享,只需要使用Threadlocal存储数据即可。

  Apache_dbutils框架教程学习笔记(5)_filter处理事务

上一篇 Apache_DBUtils框架教程学习笔记(五)_Filter 处理事务
下一篇 Apache_DBUtils框架教程学习笔记(三)_事务处理

文章素材均来源于网络,如有侵权,请联系管理员删除。