JDBC如何实现线程安全以及和连接池的关系

  • 双亲委派模型,加载DriverManger时需要扫描所有Driver实现类,会找不到Driver实现类,
    此时基于SPI原理会从线程上下中拿到AppClassloader,
    然后从appclassloader中获取driver实现类,封装成driverInfo,加入registry到DriverManager.这些实现需要SPI接口和service声明文件的支持。

  • 如果不希望破坏双亲委派模型,则需要用class.forname先主动加载驱动类,然后加载drivermanager,再将driver注册到drivermanager中。

  • 获取链接既不能所有请求处理线程共享( 因为这个【 Connector非线程安全】 ),又不能每次执行SQL都创建connector浪费资源。因此,采用统一线程共享一个connector的方案(也就是每次Request请求会话里的所有数据库操作),用map作缓存,用线程ID作key,自然就想到用 Threadlocal 了。

  • connector在同一个线程的缓存功能时JDBC底层实现的,他通过对getConnector()方法进行判断,如果 threadlocal 有就不会再重新创建链接了。对于JDBC的用户来说时感知不到这个操作的。这里的用户可以是开发者也可以是mybatis框架,比如 sqlsession…openConnector 就是调用了JDBC的getConnector()。这是JDBC的特性。

  • 当然sqlsession.openConnector会【优先】调用连接池,从而获取链接,而不是直接访问JDBC,这相当于给JDBC作了一层代理缓存,进一步减少了链接创建的开销。这个是ORM框架为了避免过于依赖JDBC而实现的,这是ORM框架的特性。

  • 对于同一个线程来说,仍然获得的是同一个链接。

  • 由于threadlocal在底层JDBC作了声明,所以无论在哪里,线程都能获得这个链接,
    因此大多数连接池调用getConnector时都会优先去threadlocal中获取,当取不到的时候,才会考虑从连接池去获取,这是一个很容易忽略的细节。
    也就说完整的顺序是:

    ThreadLocal —》 线程池 -----》 JDBC

另外,弱弱的问一下,有没有觉得JDBC.getConnect()创建 Connector 有种脱裤子放屁的感觉,明明前面ORM框架先从ThreadLocal 获取不到,才会跑去线程池,然后线程池获取不到,才跑去JDBC,结果JDBC没有麻溜的创建 Connector,有跑去ThreadLocal 看了一眼,才创建不情不愿的创建 Connector, JDBC这么婆妈的原因是什么?

先说一下,这个知识点不是很重要,JDBC这么婆妈,仅仅是原则问题,因为JDBC 原则上不能假定用户使用了ORM框架去代理JDBC,所以JDBC出于原则,必须去 ThreadLocal 看一眼。

总结:

DriverManger.getConnector()方法基于ThreadLocal类的线程多例实现线程安全。
Hibernate或者Mybatis利用线程池节约链接的创建开销。

两者结合提高性能。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值