⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_42405666/article/details/108258820 「Hello什么来着?」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

这个问题我疑问了很久很久,主要如下截图。

我先说为什么引入threadlocal,其实是为了解决数据库事务,而事务是和连接有关的,每个连接对应一个事务,多个连接的事务是不一样的,先大概了解一下,往下看👇

本人是在学threadlocal的时候,网上大部分人都是说数据库连接池是典型的用了threadloca的例子,然后我就又查数据库连接池和threadloca的关系,但是,99%都说threadlocal是为了在并发的情况下,为了保证线程安全,创建了副本什么的,其实这只是threadlocal的用法之一,它还有个用法就是确保同一线程之间参数传递的方便(扯远了)

回归正题,还是拿上面的图来说事。。。。

我只讲两个关键点,明白人一看就懂:

1、两者有根本性的区别,用处不一样!

  • 连接池是缓存并托管数据库连接,主要是为了提高性能。

  • 而ThreadLocal缓存连接,是为了把同一个数据库连接“分享”给同一个线程的不同调用方法。(不管调用哪个方法,都是使用的同一个连接,方便进行“跨方法”的事务控制)

举个栗子:

如果一个请求中涉及多个 DAO 操作,而如果这些DAO中的Connection都是独立的话,就没有办法完成一个事务。但是如果DAO 中的 Connection 是从 ThreadLocal 中获得的(意味着都是同一个对象), 那么这些 DAO 就会被纳入到同一个 Connection 之下。

2、重点要理解“连接池”。

连接池里面有一定数量的连接资源,比如最大20个连接。

题外话:如果直接通过 Java原生API 获取“直连”的话:

(底层方法一般都是这样写的:

java.sql.DriverManager.getConnection(url, props);

java.sql.Driver.connect(url, props);

特点是:要传入url、用户名和密码等信息)

这种方式,肯定就没有使用数据库连接池。

使用数据库连接池,通常都是得到一个所谓的javax.sql.DataSource[接口]的实例对象,它里面包含了Connection,并且数据库连接池工具类(比如C3P0、JNDI、DBCP等),肯定是重新定义了getConnection、closeConnection等方法,所以你每次得到的Connection,几乎都不是新建立的连接(而是已经建立好并放到缓存里面的连接),你调用closeConnection方法,也不是真正的关闭连接(一般都是起到一个标识作用,标识当前连接已经使用完毕,归还给连接池,让这个连接处于待分配状态)【PS:所以说:使用数据库连接池时,还是要显式的调用数据库连接池API提供的关闭连接的方法】。

理解一下这句话:

不同的线程在同一个时间( 或者 同一个线程在多个地方)从连接池中拿到的Connection,肯定不是同一个连接。(反过来讲:不同时间的两个线程,一前一后,则有可能拿到同一个连接)

总结:

再好好理解一下上面的一段话,我再最后解释亿下。。。


  • 首先,我们为了避免单一数据库连接的创建和关闭耗费时间和性能,引入了数据库连接池,提前创建好了n条连接放入池中,如果是单线程情况下,那这样挺好的
  • 那如果是多线程情况下呢?还是上面那段话,假设同一时间多个线程从数据库连接池获取连接,那肯定拿的是不同的连接,我当前线程和别的线程拿的连接不一样,那我当前在crud的时候,不在一个事务之内。
  • 假设不同时间的多个线程要从数据库连接池拿连接,那这个时候就可能拿到的是同一个连接了,那我多个线程线程拿到的是同一个连接,也就是说在多个线程在同一个事务之内,线程a执行了插入还没来得及提交,线程b此时来了个更新,在线程a还未操作完之前,线程b更新完了后,直接把连接给close了,线程a插了一半发现插不了了。。。此时肯定在想,这™是谁在搞我。
  • 为了确保不同时间多个线程可能拿到的是同一个连接,那么此时threadlocal闪亮登场,就算我拿的是“同一个连接”,在引入了threadlocal后,每个线程之间都会创建独立的连接副本,将collection各自copy一份,这样就互相不干扰了。

以上是我的个人见解。

文章目录
  1. 1. 回归正题,还是拿上面的图来说事。。。。
    1. 1.1. 1、两者有根本性的区别,用处不一样!
    2. 1.2. 2、重点要理解“连接池”。
  2. 2. 总结: