-
双亲委派模型,加载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利用线程池节约链接的创建开销。
两者结合提高性能。