当前位置:   article > 正文

JDBC数据库访问底层逻辑(桥接模式)_jdbc bridge

jdbc bridge

概述

大部分情况下,我们只需要在配置文件中配置数据库的连接,包括url、username、password等基本连接信息,还可以配置数据库连接池大小、最小连接数、超时时间等信息。之后就能连接到数据库进行一系列的操作了。底层是如何做到的并不关心,本节主要是帮助我们了解在我们的代码和数据库之间的一小部分内容。

JDBC和数据库

先解释桥接模式

假使A是接口, SubA()是实现,类的属性赋值使用多态的方式

//伪代码
class Bridge{
    private A a = null;
    setA(){ a = SubA()}
    
    method(){
        a.method();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

某个类Bridge定义A接口的属性,在方法里面调用接口的方法,实际调用的是实现类的接口

上述就可以在只实现SubA类的情况下,达到抽象和实现分离的目的,JDBC的设计完全符合我们对不同数据库的统一封装,实现则是由各个厂商负责的解耦的风格。

通过setA()的方法对属性进行赋值,最终调用的就是实现了A接口的类的方法了!

JDK提供的JDBC数据库访问接口API正是经典的桥接模式的实现者,接口内部可以通过实现接口来扩展针对不同数据库的具体实现来进行扩展,而对外的仅仅只是一个统一的接口调用,调用方实现抽象复杂,可以将其看做每一个JDBC调用程序。

桥接模式是设计Java虚拟机和实现JDBC等驱动程序的核心模式之一,应用较为广泛

下面重点来看JDBC流程,证明JDBC的桥接模式

jdk 提供实现的接口

jdk提供接口,厂商按照接口实现

在这里插入图片描述
这里只截取了jdk1.8的java.sql 下的Interface 和 class
其中有几个熟悉的

  • Statement PrepareStatement 和 CallableStatement,这些是JDBC和它的三大对象,它们有各自的含义

  • ResultSet结果集,主要是存储上述三大对象查询出来的结果。

  • Connection 和 Driver 比较重要

javax.sql.* 下

  • DataSource

厂商实现

通常我们使用的Mysql的驱动都是com.mysql.cj.jdbc.Driver

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

可能有些童鞋对com.mysql.jdbc.Driver也很熟悉。 它是com.mysql.cj.jdbc.Driver的子类


各厂商负责实现接口
mysql-connector-java/8.0.18/mysql-connector-java-8.0.18.jar 这个就是JDBC的驱动,我们既可以直接使用驱动去连接数据库(不推荐),也可以将连接交给连接池去维护,还可以将数据源datasource交给框架去管理。

过程

com.mysql.cj.jdbc.Driver

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
 static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

    public Driver() throws SQLException {
        // Required for Class.forName().newInstance()
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • java.sql.DriverManager.registerDriver是jdk DriverManager类的方法,将com.mysql.cj.jdbc.Driver注册到DriverManager
  • registeredDrivers.addIfAbsent(new DriverInfo(driver, da));添加到一个线程安全的属性名为registeredDrivers的List中

那什么时候能触发到com.mysql.cj.jdbc.Driver的创建呢?

因为是静态代码块,所以只要Driver类被加载到虚拟机中,那么静态代码块中的代码就会执行!

手写: 通过驱动连接数据库

public static Connection getConnection() throws Exception {
    InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
    Properties pros = new Properties();
    pros.load(is);
    String user = pros.getProperty("user");
    String password = pros.getProperty("password");
    String url = pros.getProperty("url");
    String driverClass = pros.getProperty("driverClass");
    Connection conn = DriverManager.getConnection(url, user, password);// 这个只有mysql驱动 
    return conn;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

DriverManager.getConnection方法,遍历registeredDrivers,这个是之前驱动Driver最终注册到的属性,所以实际在方法调用了驱动中实现类的方法 == 恰恰符合了桥接模式,只不过上面是类,这里是List。核心思想是相同的

CopyOnWriteArrayList registeredDrivers = new CopyOnWriteArrayList<>();


//==getConnection==方法
for(DriverInfo aDriver : registeredDrivers) {
            // If the caller does not have permission to load the driver then
            // skip it.
            if(isDriverAllowed(aDriver.driver, callerCL)) {
                try {
                    println("    trying " + aDriver.driver.getClass().getName());
                    Connection con = aDriver.driver.connect(url, info);
                    if (con != null) {
                        // Success!
                        println("getConnection returning " + aDriver.driver.getClass().getName());
                        return (con);
                    }
                } catch (SQLException ex) {
                    if (reason == null) {
                        reason = ex;
                    }
                }

            } else {
                println("    skipping: " + aDriver.getClass().getName());
            }

        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

创建驱动Driver的时机

下面是驱动mysql-connector-java包下的文件,采用SPI的方式启动的。在DriverManager类的静态代码块中,触发了SPI方式的创建,加载Driver类,会执行Driver中的静态代码块,将本类注册到了DriverManager的属性中

  static {
        loadInitialDrivers();
        println("JDBC DriverManager initialized");
    }
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述上述是数据库直连的方式实现的。当然也可以使用c3p0、dbcp、druid、Hikari等方式。

结论

至此,我们大致了解了Mysql数据库驱动是如何协同在JDBC下工作的,也了解JDBC桥接模式实现的方式。这可以更好的帮助我们理解JDBC和数据库整合在一起的方式。我认为有些知识是为了更好的理解更高深的内容存在的,不是你学会它就一定能解决什么样的问题。这也是我为什么使用直连的方式的原因,更加直观和清晰。希望能对您有帮助!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/569078
推荐阅读
相关标签
  

闽ICP备14008679号