ThreadLocal
在"事务传递Connection"参数案例中,我们必须传递Connection对象,才可以完成整个事务操作.如果不传递参数,是否可以完成?在JDK中给我们提供了一个工具类ThreadLocal.此类可以在一个线程中共享数据
java.lang.ThreadLocal:该类提供了线程局部(thread-local)变量,用于在当前线程中共享数据.
ThreadLocal
java.lang.ThreadLocal该类提供了线程局部(thread-local)变量,用于在当前线程中共享数据,ThreadLocal工具类底层就是一个相当于一个Map,key存放的当前线程,value存放需要共享的数据.
package com.qingmu; /** * @Auther:qingmu * @Description:脚踏实地,只为出人头地 * @Date:Created in 16:08 2019/5/25 */ public class ThreadLocalTest { public static void main(String[] args) { ThreadLocal<String> stringThreadLocal = new ThreadLocal<>(); stringThreadLocal.set("青木"); System.out.println(stringThreadLocal.get()); new Thread(()-> System.out.println(stringThreadLocal.get())).start(); } }
结果为:
总结:向ThreadLocal中添加的数据只能在当前线程中使用.
小案例的应用:
工具类
public class C3P0Utils { //创建一个C3P0的连接池对象(使用c3p0-config.xml中default-config标签中对应的参数) public static DataSource ds = new ComboPooledDataSource(); //给当前线程绑定 连接 private static ThreadLocal<Connection> local = new ThreadLocal<Connection>(); /** * 获得一个连接 */ public static Connection getConnection(){ try { //#1从当前线程中, 获得已经绑定的连接 service层 Connection conn = local.get(); if(conn == null){ //#2 第一次获得,绑定内容 – 从连接池获得 conn = ds.getConnection(); //#3 将连接存 ThreadLocal local.set(conn); } return conn; //获得连接 } catch (Exception e) { //将编译时异常 转换 运行时 , 以后开发中运行时异常使用比较多的。 throw new RuntimeException(e); /* 类与类之间 进行数据交换时,可以使用return返回值。也可以使用自定义异常返回值,调用者try{} catch(e){ e.getMessage() 获得需要的数据} 此处可以编写自定义异常。 */ //throw new MyConnectionException(e); } } }
service层
public class AccountService { /** * 事务管理方式:向下传递Connection。有侵入性。使用DBUtils * 业务层事务管理转账的方法 * @param from * @param to * @param money */ public void transfer(String from, String to, double money) { //调用dao层 AccountDao accountDao = new AccountDao(); //DBUtils进行事务处理的原理,是在Service层获得连接,以保证事务处理过程中的Connection对象为同一个Connection。 //因为必须保证连接为同一个连接,所以在业务层获得连接,再将连接传递到持久层,代码具有侵入性。 //DBUtils使用的方法 Connection conn = null; try { //获得连接 conn = C3P0Utils.getConnection(); //设置事务不自动提交 conn.setAutoCommit(false); //调用持久层 accountDao.outMoney(from,money); //如果有异常 //int a = 1 / 0 ; accountDao.inMoney(to,money); //提交事务,并安静的关闭连接 DbUtils.commitAndCloseQuietly(conn); } catch (SQLException e) { //有异常出现时,回滚事务,并安静的关闭连接 DbUtils.rollbackAndCloseQuietly(conn); e.printStackTrace(); } } }
dao层
public class AccountDao { /** * 付款方法 * @param from 付款人 * @param money 金额 */ public void outMoney(String from, double money) { QueryRunner qr = new QueryRunner(); try { Connection conn = C3P0Utils.getConnection(); String sql = "update account set money = money - ? where name = ?"; qr.update(conn, sql, money,from); } catch (SQLException e) { e.printStackTrace(); } } /** * 收款方法 * @param to 收款人 * @param money 金额 */ public void inMoney(String to, double money) { QueryRunner qr = new QueryRunner(); try { Connection conn = C3P0Utils.getConnection(); String sql = "update account set money = money + ? where name = ?"; qr.update(conn, sql, money,to); } catch (SQLException e) { e.printStackTrace(); } } }