建设网站网,桂林 网,wordpress 邮箱留言,网站开发最好的语言一、数据库连接与线程的关系
在实际项目中#xff0c;数据库连接是很宝贵的资源#xff0c;以MySQL为例#xff0c;一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200#xff0c;再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议数据库连接是很宝贵的资源以MySQL为例一台MySQL服务器最大连接数默认是100, 最大可以达到16384。但现实中最多是到200再多MySQL服务器就承受不住了。因为mysql连接用的是tcp协议稳定的同时意味着需要消耗更多时间和性能去建立维持连接。为了能最大利用如此宝贵的数据库连接我们希望数据库连接能被复用而不需要频繁创建所以利用池化技术建立数据库连接池。
了解连接池在多线程场景中是如何工作的。 一个连接池包含多个连接对象。我们可以配置池的大小。 当多个线程需要并发访问一个数据库时它们会从连接池中请求连接对象。 如果池中仍有空闲连接线程将获取连接对象并开始其数据库操作。线程完成工作后会将连接返回到池中。 如果池中没有空闲连接线程将等待另一个线程将连接对象返回到池中。 所以一个连接在同一时间只能被一个线程所持有一个线程在同一时间也只能申请到一个连接官方也不鼓励在多个线程之间共享连接对象
明白了这点之后再看下线程我们知道一个线程在生命周期内会做很多事情比如参数校验权限验证数值计算然后持久化结果。其中可能只有持久化结果环节需要访问JDBC数据库连接,其余的时间范围内JDBC数据库连接 都是空闲状态。所以如果线程整个生命周期中独占JDBC数据库连接的话那么这个连接空闲率就很高也就变得很浪费因为一旦占用了数据库连接可以不限次数执行事务SQL请求增删查改各种sql操作请求都可以执行。为了提高数据库连接的使用率目前普遍的解决方案是当线程需要做数据库操作时才会真正请求获取JDBC数据库连接,线程使用完了之后立即释放被释放的JDBC数据库连接等待下次分配使用。
二、多线程访问同一个数据库连接
前面已经说了数据库连接在同一时间只能被一个线程所持有线程在申请数据库连接时也是线程安全的。 Java多线程访问同一个java.sql.Connection会导致事务错乱。解决多个线程访问同一个Connection对象时必须遵循两个基本原则
以资源互斥的方式访问Connection对象在线程执行结束时应当最终及时提交(commit)或回滚(rollback)对Connection的影响不允许存在尚未被提交或者回滚的语句。
ThreadLocal的原理 想了解下ThreadLocal的原理可以看下这篇文章ThreadLocal就是这么简单 ThreadLocal和Thread的关系如下图
ThreadLocal里面定义了ThreadLocalMap这个静态内部类。而Thread类里持有了ThreadLocalMap的引用。
/*** Variant of set() to establish initialValue. Used instead* of set() in case user has overridden the set() method.** return the initial value*/private T setInitialValue() {T value initialValue();Thread t Thread.currentThread();ThreadLocalMap map getMap(t);if (map ! null)map.set(this, value);elsecreateMap(t, value);return value;}/*** Create the map associated with a ThreadLocal. Overridden in* InheritableThreadLocal.** param t the current thread* param firstValue value for the initial entry of the map*/void createMap(Thread t, T firstValue) {t.threadLocals new ThreadLocalMap(this, firstValue);}ThreadLocal在初始化时会对当前线程所持有的ThreadLocalMap引用进行实例化。ThreadLocal的set方法即是拿出当前线程所持有的ThreadLocalMap引用然后将所要保存的值塞进这个map里key是ThreadLocalThreadLocal的get方法是根据当前线程所持有的ThreadLocalMap引用用ThreadLocal 这个key拿出value。
三、ThreadLocal 与多线程还有数据库连接的关系
我们经常听说ThreadLocal的目的是为了解决多线程访问资源时的共享问题。这种说法是完全错误的。 ThreadLocal的作用是提供线程内的局部变量这种变量在线程的生命周期内起作用减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
举个例子一个线程的生命周期要做这么几件事情参数校验业务逻辑1数据持久化业务逻辑2数据库切换业务逻辑3。
该线程在进行数据持久化时需要申请数据库连接当做完之后就将连接释放回线程池但之后进行数据库切换时也需要数据库连接这时候继续申请吗不是的这时ThreadLocal就派上用场了在第一次数据持久化操作做完之后将这个数据库连接暂存在ThreadLocal中在之后的数据库切换中需要用到时再拿出来用。由此可见ThreadLocal对线程来说相当于提供一个局部变量线程把资源用完之后先放到ThreadLocal里之后需要用到时再拿出来。在多租户场景下因为经常需要切换数据库所以ThreadLocal很常用。 那么在多线程场景下ThreadLocal的表现是咋样呢
如图所示多线程下不同线程会持有不同的ThreadLocalMap引用但这些ThreadLocalMap的key都是指向同个ThreadLocal对象所以可以理解为什么代码中在用到ThreadLocal时都会设为static了吧就是为了让多线程下ThreadLocalMap的key都使用的是同一个ThreadLocal这是JDK1.3之后的改进这样设计之后每个Map的Entry数量变小了之前key是ThreadThread有多少个就会导致key有多少个现在是ThreadLocal的数量能提高性能。