小知识点记录:JDBC的额外知识点
Posted 小智RE0
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了小知识点记录:JDBC的额外知识点相关的知识,希望对你有一定的参考价值。
其实在之前初步学习Web开发流程时,就用了JDBC维持业务代码逻辑与数据库的交互.
初次学习JDBC记录的笔记:
JDBC基础–[JDBC概述,JDBC的搭建,PreparedStatement和Statement执行SQL语句,结果集处理]
实际上JDBC还有额外的知识点:
(1)打破双亲委派机制;
(2)SPI机制
JDBC作为Java中比较重要的连接规范驱动; 其中定义了Driver
接口.
在Driver
接口中定义连接方法connect()
, 输入连接参数的字符串即可打通数据库的连接;
该方法返回一个Connection接口
的对象,使用Connection
的方法即可完成与数据库的交互.
比如说创建一个spring项目
在pom.xml
文件中进行配置;
<dependencies>
<!--H2数据库-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.200</version>
</dependency>
<!--mysql数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
试试这样一个 远古的测试类
import org.h2.Driver;
import java.sql.Connection;
import java.util.Properties;
public class DBtest1
public static void main(String[] args)
Properties info = new Properties();
info.setProperty("user","sa");
try
Connection connection = new Driver().connect("jdbc:h2:~/test",info);
System.out.println("连接成功");
catch (Exception e)
System.out.println("连接失败了诶");
可看到H2中的这个Driver类实现了sql包下的Driver接口.
直接运行,可成功连接诶
目前较为常用的一种写法,写个测试类2;
import java.sql.DriverManager;
public class DBtest2
public static void main(String[] args)
try
DriverManager.getConnection("jdbc:h2:~/test","sa","");
System.out.println("连接成功");
catch (Exception e)
System.out.println("抱歉,连接失败了诶");
DriverManager
中定义了 一个List集合
,用的是CopyOnWriteArrayList类型的
其中存储了DriverInfo类
;
private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
这个DriverInfo
类中就封装了Driver
类型;比如H2/Mysql…数据库自己的Driver
刚才使用的getConnection
连接方法,就对各种参数进行了配置;
最后实际调用的方法
其中的for循环中,对于集合registeredDrivers
的每个Driver
都尝试进行连接;
这部分原理先看到这里,那么现在思考一下,DriverManager 什么时候把H2,mysql数据库的链接包Driver加载存入到集合registeredDrivers
中的呢?
先看配置的jar包,其中的META-INF
目录下都有java.sql.Driver文件
这实际上就是SPI的用法了,可以定义一个包,在META-INF
目录下的services
目录中,然后创建一个文件;文件名就是需要实现的接口的全限定名; 比如这里用的就是java.sql.Driver
.
文件的内容就是要实现该接口的 类的全限定名
那么具体怎么加载文件内容呢?
可回到DriverManager
类的源码部分;
它采用了 ServiceLoader进行加载的;
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
由于ServiceLoader
类实现了Iterable
接口,那么也就可以通过迭代器来遍历得到.
注意迭代器中遍历得到的是对象,而不是类;
比如说new一个mysql对象,new一个h2对象.
那么又有新的疑问了,为啥new出来的对象就能被存入到集合registeredDrivers
中呢?
比如点到h2的Driver类中,
其中有个静态代码块中调用了load()
方法;
static
load();
具体看看load()
方法.
此时将INSTANCE
注册到DriverManager
里面了.
这个INSTANCE
是这样定义的,也就是new了一个自己的对象;
private static final Driver INSTANCE = new Driver();
还有一个小知识点;学jdbc的时候,前面会加这个代码;
通过Class.forName的反射效果来指定到固定全类名的对应Driver.
Class.forName("org.h2.Driver");
- 这个反射同样会触发加载
load()方法
; - 注意
SPI规范
是在jdbc4.0规范的,之前版本的话还没有这个机制,所以用老版本的话建议加上反射的代码.
最后来简单看下JDBC如何打破双亲委派机制的
- 首先
DriverManager
作为jdk自带的类;它使用的是bootstarp类加载器
(启动类加载器); - 那么在
DriverManager
类中创建Mysql/H2…的Driver,使用的也就是当前类的加载器; - 但要是当前类用的
bootstarp类加载器
去加载Mysql/H2…这样的用户类,不合适啊; 那么在加载Mysql/H2…这些类的时候就得需要将类加载器进行替换;替换为当前线程使用的类加载器(Appclassloader)应用类加载器;由于jar包在classpath下,需要Appclassloader进行加载
以上是关于小知识点记录:JDBC的额外知识点的主要内容,如果未能解决你的问题,请参考以下文章