JDBC之数据库驱动程序

前言:学习Java时间也算不短了 ,但是每次学到数据库操作部分,都要重新去学习如何加载驱动程序,如何获取连接,如何执行sql语句,如何处理结果。每次都是处于”点到即止“的水平,没有去深入理解,为什么要去加载驱动程序,为什么不直接new出来;Statement和PreparedStatement到底有什么区别,在哪些场景因该应用哪个对象?什么是预编译?结果集的rs.next()又是如何实现的?等等许多问题,在脑子里只是一个模糊的概念,无法准确的去回答这些问题。在反思了一起的学习方法,总是花费不少时间却做了同样的事,我想花一段时间去深入理解java数据库操作的相关知识,并做好总结。好记性不如烂笔头

一、基础概念

1、什么是JDBC

      SUN公司为了简化、统一对数据库的操作,定义了一套Java操作数据库的规范(接口),称之为JDBC。这套接口由数据库厂商去实现,这样,开发人员只需要学习jdbc接口,并通过jdbc加载具体的驱动,就可以操作数据库。

2、什么是驱动程序

      这里的驱动的概念和平时听到的那种驱动的概念是一样的,比如平时购买的声卡,网卡直接插到计算机上面是不能用的,必须要安装相应的驱动程序之后才能够使用声卡和网卡,同样道理,我们安装好数据库之后,我们的应用程序也是不能直接使用数据库的,必须要通过相应的数据库驱动程序,通过驱动程序去和数据库打交道。 驱动程序就像一个翻译,能将操作系统(或这里的java程序)的命令“翻译”给硬件如声卡(或这里的数据库系统),声卡接收到翻译后的自己能够明白的命令,去执行相应的动作,而操作系统和声卡无法直接打交道,“因为语言不通”。

二、数据库驱动程序

1、为什么要使用驱动管理器

      需要数据库连接对象Connection,可以通过以下方式直接获得,如下代码所示

        String url = "jdbc:mysql://localhost:3306/test";
        Properties props = new Properties();
        props.setProperty("user", "root");
        props.setProperty("password", "root");
        Connection conn = new com.mysql.jdbc.Driver().connect(url,props);

      但这样应用程序就和具体数据库耦合在一起,当系统要更换数据库时,就要去修改应用程序代码,这是显而易见的。

     为了达到根据不同参数,返回不同类型对象的目的,我们自然想到了工厂模式,如下所示:

public class DriverUtils (
// 参数props包含连接时需要的参数如user,password
 public Connection getConnection(String url, Properties props) {
 
        if (url.equals("com.mysql.jdbc.Driver")) {
           return new com.mysql.jdbc.Driver().connect(url,props);
           
        } else if (url.equals("oracle.jdbc.driver.OracleDriver")) {
           return new oracle.jdbc.driver.OracleDriver().connect(url, props);
        }
      }
    }

然而,这种方式比较刻板,必须列举出所有可能使用到的数据库种类,这是不现实的。于是Java就提供了驱动管理器DriverManager,它也像一个工厂,但是比较灵活,可以向其中动态添加(注册)你可能会用到的驱动程序。

2、如何向驱动管理器注册驱动程序

java 6 以前

     网络上老生常谈有三种方式

  1. Class.forName(“com.mysql.jdbc.Driver”);
  2. DriverManager.registerDriver(new com.mysql.jdbc.Driver())
  3. System.setProperty(“jdbc.drivers”,”com.mysql.jdbc.Driver”)

推荐使用第一种方式,原因如下:
第一种方式,在编译时不需要提供驱动程序jar包;在驱动管理器中注册一次;并且此方法以字符串类型作为参数,方便不同类型数据库的切换。
第二种方式,在编译时需要提供驱动程序jar包,在驱动管理器 中注册两次;并且次方法参数类型为java.sql.Driver,
也就是说你必须 提供一个具体的驱动程序,如com.mysql.jdbc.Driver,使应用程序和具体的数据库耦合。
第三种方式,仅作了解。

对驱动程序注册的进一步理解

首先,我们要了解类加载,其包含五个阶段:加载、验证、解析、准备、初始化。会触发类加载过程的场景包含:调用Class.forName()方法和new 对象等等。初始化阶段会进行类的静态变量的赋值和静态代码块的执行

com.mysql.jdbc.Driver 部分代码如下:

package com.mysql.jdbc;

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    // Register ourselves with the DriverManager  把自己注册进驱动管理器
    // 以下代码为 静态代码块
    static {
        try {
            java.sql.DriverManager.registerDriver(new Driver());
        } catch (SQLException E) {
            throw new RuntimeException("Can't register driver!");
        }
    }

由已知得,Class.forName(“com.mysql.jdbc.Driver”)会触发类加载过程,进而进行类的初始化,执行静态代码块,将自己注册进驱动管理器。

而对于方式二DriverManager.registerDriver(new com.mysql.jdbc.Driver()), new Driver()新建对象也会触发类加载过程,进而进行类的初始化,执行静态代码块,将自己注册进驱动管理器,然后执行DriverManager.registerDriver(new Driver())将驱动程序注册进驱动管理器,所以说注册了两次。java对于同一个驱动器不会测试两次,然而对于类型相同,不是同一个对象还是会注册的,以下图片可证,
CopyOnWriteArrayList是用来存储驱动器的集合

在这里插入图片描述

java 6 以后

不需要显示的去加载驱动程序,当你调用DriverManager.getConnection()方法获取连接对象时,驱动管理器会自动完成驱动注册
查看java.sal.DriverManager有如下注释内容

The DriverManager methods getConnection and getDrivers have been enhanced to support the Java Standard Edition Service Provider mechanism. JDBC 4.0 Drivers must include the file META-INF/services/java.sql.Driver. This file contains the name of the JDBC drivers implementation of java.sql.Driver. For example, to load thecom.mysql.jdbc.Driver , the META-INF/services/java.sql.Driver file would contain the entry: com.mysql.jdbc.Driver

驱动程序管理器方法getConnection和getDrivers得到了增强,以支持Java标准版服务提供者机制。JDBC 4.0驱动程序必须包含META-INF/services/java.sql.Driver文件。这个文件包含java.sql.Driver的驱动程序实现的名称。例如,加载com.mysql.jdbc.Driver ,META-INF/services/java.sql.Driver文件将包含以下条目:com.mysql.jdbc.Driver

在这里插入图片描述

public class DriverManager {
    // List of registered JDBC drivers 存储已注册的驱动器
    private final static CopyOnWriteArrayList<DriverInfo> registeredDrivers = new CopyOnWriteArrayList<>();
    }

驱动程序管理器方法getConnection和getDrivers得到了增强,这句话所谓的增强是字节码增强,即在java.sql.DriverManager的getConnection方法对应的字节码中插入了字节码 —— 用来判断存储驱动程序的List大小是否为0,若为0,则读取META-INF/services/java.sql.Driver中的com.mysql.jdbc.Driver信息,进行类加载,之后在初始化阶段完成注册。
下图可以证明,debug模式运行程序,点击红色箭头,本应该进入getConnection()函数内部去执行,然而却进行了类的加载
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明月几时有666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值