一.​​​​​​简述

为什么要讲解ThreadLocal?

  • 为了项目解耦合,更好地维护项目
  • 耦合会使得项目维护难度增加
  • 解耦合。 直接去掉更多的import

 

ThreadLocal:本质MAP集合。

  绑定了线程的map集合。

作用:在线程中进行数据共享。

 

原理:

  • 一个ThreadLocal在一个线程中,只能保存一个键值对

 

 

二.API

ThreadLocal

方法名

描述

set(Object obj)

为当前线程存放一个共享数据。

参数:Object 为共享数据。

 

第二次调用就是覆盖

 

相当于map.put(key,value);

Key:是线程ID,无需程序员手动赋值。

 

 

get()

获取当前线程的共享数据

 

返回值:Object

相当于map.get(key);

 

如果获取不到,返回为null

remove()

删除当前线程的共享数据

 

相当于map.remove(key);

 

 

public static void main(String[] args) {
    //1、创建一个ThreadLocal对象
    ThreadLocal<String> local = new ThreadLocal<String>();
    //2、保存键值对,并取出展示
    local.set("老王");
    System.out.println(local.get());
    //3、再次保存键值对,并取出展示
    local.set("小王");//覆盖
    System.out.println(local.get());
    //4、删除键值对,并再尝试取出展示
    local.remove();
    System.out.println(local.get());
}

 

案例重构:转账案例

需求说明

Service需要和Connection对象解耦合。

解耦之后,service仍然可以正常进行提交和回滚。

需求分析

1、不能在service获取connection对象

(在JDBCUtils工具中,获取Connection时,设置为手动事务)

(在相同线程中 共享 Connection对象。 ThreadLocal)

 

2、dao的第一个参数没有Connection对象

3、在JDBCUtils中,写一个提交并关闭连接方法、回滚并关闭连接方法

 

 

 

代码实现

JDBCUtils

public class JDBCUtils {
    public static final String DRIVERCLASS="com.mysql.jdbc.Driver";
    public static final String URL="jdbc:mysql://127.0.0.1:3306/day03_db";
    public static final String USERNAME="root";
    public static final String PASSWORD="1234";

    //定义好了一个绑定线程的map集合
    private static final ThreadLocal<Connection> LOCAL = new ThreadLocal<Connection>();
    static{
        //1、注册驱动
        try {
            Class.forName(DRIVERCLASS);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    /*
    * 获取连接:
    *   原则:1、同一个线程中,使用同一个Connection对象
    *         2、每次获取到的Connection对象,都开启了 手动事务
    * */
    public static Connection getConnection() throws SQLException {
        //1、尝试从ThreadLocal中获取,当前线程共享的connection
        Connection con = LOCAL.get();
        //2、如果当前线程没有绑定connection对象,创建connection对象,保存到threadLocal中
        if(con==null){
            //2.1、创建con对象
            con = DriverManager.getConnection(URL,USERNAME,PASSWORD);
            //2.2、开启手动事务
            con.setAutoCommit(false);
            //2.3、绑定到当前线程中,保存到ThreadLocal中
            LOCAL.set(con);
        }
        return con;
    }
    /*
    * 关闭资源
    * */
    public static void closeAll(Connection con, PreparedStatement ps, ResultSet rs) throws SQLException {
        if(rs!=null)
            rs.close();
        if(ps!=null)
            ps.close();
        if(con!=null){
            //1、先从当前线程解绑
            LOCAL.remove();
            //2、关闭资源
            con.close();
        }
    }
    /**
     * 提交事务,并关闭资源
     */
    public static void commitAndClose(){
        //1、先尝试从ThreadLocal中获取con对象
        Connection con = LOCAL.get();
        //2、如果能获取到con,提交事务,并关闭资源
        if(con!=null){
            try {
                con.commit();
                closeAll(con,null,null);
            } catch (SQLException e) {
            }
        }
    }
    /**
     * 回滚事务,并关闭资源
     */
    public static void rollbackAndClose(){
        //1、先尝试从ThreadLocal中获取con对象
        Connection con = LOCAL.get();
        //2、如果能获取到con,回滚事务,并关闭资源
        if(con!=null){
            try {
                con.rollback();
                closeAll(con,null,null);
            } catch (SQLException e) {
            }
        }
    }
}

 

AccountService

public class AccountService {
    private AccountDao dao = new AccountDao();
    /**
     * 转账功能
     * @param userIn
     * @param userOut
     * @param money
     * @return
     */
    public boolean account(String userIn, String userOut, double money) {
        try {
            //1、付款人 付款
            dao.userOut(userOut, money);
//            int a = 1 / 0;
            //2、收款人 收款
            dao.userIn(userIn, money);
            //没出异常,提交
            JDBCUtils.commitAndClose();
        } catch (Exception e) {
            //出了异常,转账失败
            JDBCUtils.rollbackAndClose();
            return false;
        }
        //没出异常,转账成功
        return true;
    }
}

 

AccountDao

/**
 * 付款人 付款
 * @param userOut
 * @param money
 */
public void userOut(String userOut, double money) throws SQLException {
    //1、获取连接
    Connection con = JDBCUtils.getConnection();
    //2、获取发送SQL语句对象
    PreparedStatement ps = con.prepareStatement("update account set money=money-? where name=?");
    ps.setDouble(1,money);
    ps.setString(2,userOut);
    //3、发送SQL语句
    ps.executeUpdate();
    //4、关闭资源
    JDBCUtils.closeAll(null,ps,null);
}

/**
 * 收款人 收款
 * @param userIn
 * @param money
 */
public void userIn(String userIn, double money) throws SQLException {
    //1、获取连接
    Connection con = JDBCUtils.getConnection();
    //2、获取发送SQL语句对象
    PreparedStatement ps = con.prepareStatement("update account set money=money+? where name=?");
    ps.setDouble(1,money);
    ps.setString(2,userIn);
    //3、发送SQL语句
    ps.executeUpdate();
    //4、关闭资源
    JDBCUtils.closeAll(null,ps,null);
}

 

 

 

看完恭喜你,又知道了一点点!!!

你知道的越多,不知道的越多! 

~感谢志同道合的你阅读,  你的支持是我学习的最大动力 ! 加油 ,陌生人一起努力,共勉!!

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐