小知识点记录: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的额外知识点的主要内容,如果未能解决你的问题,请参考以下文章

记录神经网络中一些小知识点

关于 python 类与继承中方法调用 的 一个小知识点记录

js,css小知识点记录

小知识点记录:计算机网络知识[集线器, 交换机, 路由器]

小知识点记录:计算机网络知识[集线器, 交换机, 路由器]

数据库小知识点