ThreadLocal简单使用案例

        业务场景:保存业务数据表的时候,同时记录下日志。


import java.sql.Connection;
import java.sql.DriverManager;


public class DBUtil {
    // 数据库配置
    private static final String driver = "com.mysql.jdbc.Driver";
    private static final String url = "jdbc:mysql://localhost:3306/test";
    private static final String username = "root";
    private static final String password = "root";
 
    private static Connection conn = null;
    
    public static Connection getDbConnection() {
        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    // 关闭数据库连接
    public static void closeDbConnection() {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

import com.example.springboottest.util.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadLocalTest3 {

    private static final String UPDATE_SQL = "update t_test set num = ? where id = ?";
    private static final String INSERT_SQL = "insert into log (id, desc) values (?, ?)";

    public static void main(String[] args) {
        ThreadLocalTest3 service = new ThreadLocalTest3();
        service.updateBusiness(1, 3000);
    }

    public void updateBusiness(int id, int num) {
        try {
            // 获取连接
            Connection conn = DBUtil.getDbConnection();
            conn.setAutoCommit(false); // 关闭自动提交事务(开启事务)
            // 执行操作
            updateBizData(conn, UPDATE_SQL, id, num);
            // 插入日志
            insertLog(conn, INSERT_SQL, "描述"); 
            // 提交事务
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭连接
            DBUtil.closeDbConnection();
        }
    }

    private void updateBizData(Connection conn, String updateSQL, int id, int num) throws Exception {
        PreparedStatement pstmt = conn.prepareStatement(updateSQL);
        pstmt.setInt(1, id);
        pstmt.setLong(2, num);
        int rows = pstmt.executeUpdate();
        if (rows != 0) {
            System.out.println("业务数据更新成功!");
        }
    }

    private void insertLog(Connection conn, String insertSQL, String desc) throws Exception {
        PreparedStatement pstmt = conn.prepareStatement(insertSQL);
        pstmt.setString(1, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date()));
        pstmt.setString(2, desc);
        int rows = pstmt.executeUpdate();
        if (rows != 0) {
            System.out.println("日志插入成功!");
        }
    }
}

        上面的代码直接运行肯定是没有问题的,但是如果在多线程下面去跑,就会报数据库连接关闭的错误。原因很简单,多线程下执行,可能一个线程刚获取到连接另一个线程就已经把连接关闭了,所以就会导致这样的问题,要解决这个问题,ThreaLocal就是一个很好的选择,只需要改调整下DBUtil里面获取连接的代码即可。如下代码所示:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;


public class DBUtil {
    // 数据库配置
    private static final String driver = "com.mysql.jdbc.Driver";
    private static final String url = "jdbc:mysql://localhost:3306/test";
    private static final String username = "root";
    private static final String password = "root";
    private static ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>(){
        //初始化connContainer里面的值,如果不重写则为null;
        @Override
        protected Connection initialValue() {
            try {
                Class.forName(driver);
                return  DriverManager.getConnection(url, username, password);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    };
    // 获取连接
    public static Connection getDbConnection() {
        Connection conn = connContainer.get();
        try {
            if (conn == null) {
                Class.forName(driver);
                conn = DriverManager.getConnection(url, username, password);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connContainer.set(conn);
        }
        return conn;
    }
    // 关闭连接
    public static void closeDbConnection() {
        Connection conn = connContainer.get();
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connContainer.remove();
        }
    }
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ThreadLocal 是 Java 中的一个线程局部变量,它提供了一种线程安全的方式来存储和访问线程特定的数据。下面是一个使用 ThreadLocal 的示例案例: ```java public class ThreadLocalExample { // 创建一个 ThreadLocal 对象 private static ThreadLocal<String> threadLocal = new ThreadLocal<>(); public static void main(String[] args) { // 创建并启动两个线程 Thread thread1 = new Thread(() -> { // 在线程1中设置线程局部变量的值 threadLocal.set("Thread 1"); System.out.println("Thread 1: " + threadLocal.get()); // 清除线程局部变量的值 threadLocal.remove(); }); Thread thread2 = new Thread(() -> { // 在线程2中设置线程局部变量的值 threadLocal.set("Thread 2"); System.out.println("Thread 2: " + threadLocal.get()); // 清除线程局部变量的值 threadLocal.remove(); }); thread1.start(); thread2.start(); } } ``` 在这个例子中,我们创建了一个 ThreadLocal 对象 `threadLocal`。在每个线程中,我们使用 `threadLocal.set(value)` 来设置线程局部变量的值,使用 `threadLocal.get()` 来获取该值,最后使用 `threadLocal.remove()` 清除该线程局部变量的值。 运行这个例子,你会看到两个线程分别设置和获取了不同的线程局部变量的值。由于每个线程都有自己独立的线程局部变量,它们之间的值不会相互干扰。 ThreadLocal使用案例包括但不限于: - 在多线程环境中,为每个线程保存独立的状态信息,如数据库连接、用户身份等。 - 在 Web 应用程序中,为每个请求线程保存请求相关的数据,如用户认证信息、请求参数等。 - 在线程池等复用线程的场景中,为每个线程保存独立的上下文信息,避免线程之间的冲突。 总之,ThreadLocal 提供了一种方便且线程安全的方式来处理多线程环境下的线程局部变量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值