注册mySQL到JDBC驱动程序方法浅谈

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介:

一、注册方法(4种)

1)服务提供者框架:

符合JDBC 4.0规范的驱动程序包含了一个文件META-INF/services/java.sql.Driver,在这个文件中提供了JDBC驱动实现的类名。

例如:mysql-connector-java-5.1.40-bin.jar文件中就可以找到java.sql.Driver文件,用文本编辑器打开文件就可以看到:com.mysql.jdbc.Driver类。

JVM的服务提供者框架在启动应用时就会注册服务,例如:mySQL的JDBC驱动就会被注册,而原代码中的Class.forName("com.mysql.jdbc.Driver")仍然可以存在,但是不会起作用。

 

2)Class.forName("com.mysql.jdbc.Driver");

通过对类com.mysql.jdbc.Driver初始化,执行静态初始化代码,调用DriverManager注册JDBC驱动。

注:通过setProperty的测试,确认类com.mysql.jdbc.Driver也没有加载,那么静态初始化代码肯定被执行了,但是如果服务提供者框架已经注册的服务,这里注册会失败,编程的预期是这样的,可是理论上DriverManager.registerDriver可以重复注册的,为什么这里不能重复注册呢?

3)System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver";);

设置JVM的系统属性,当JVM第一次加载DriverManager类时,会执行类的静态初始化代码,代码中调用loadInitialDrivers()方法,就会加载设置的属性对应的类,执行类的静态初始化代码完成注册。

注:因为注册的机制无法深入理解,只知道没有加载过的类可以注册成功,加载过的就不能重复注册了。

注:setProperty必须在DriverManager第一次运行前才有效,说明”服务提供者”框架注册服务时并没有加载类,因为一旦加载类就会执行类的静态初始化代码,那么注册JDBC驱动就一定会调用DriverManager类的静态初始化代码,那么setProperty就会失效,所以说明注册服务是不加载类的。

4)DriverManager.registerDriver(new com.mysql.jdbc.Driver());

其实前面的2)和3)最终都是通过这个方法注册的,但是这个方法就可以重复注册。

注:对于重复注册后,建立链接时使用哪个驱动我就不明白了,可以取消注册,取消的关键字是基于创建的对象的,所以就算重名也不会出错。

注:这种注册方式没有前面几种好,因为这种注册方式会在代码中与需要注册的驱动程序的类绑定,前面都可以通过配置参数实现注册。

二、各自特点:

1)全自动。只要提供符合规范的JAR文件就可以了。

2)利用反射机制,将驱动类注入到代码中,不需要与代码绑定。

3)基于系统的属性设置方法,将驱动类注入到代码中,但是好像只能绑定一个JDBC驱动。

4)最终的注册机制。会出现重复注册,但是好像对程序没影响,还需要与代码绑定,驱动变了,必须修改代码,维护成本过高,当然也是灵活性最好,管理最方便的。

以下是测试代码:

import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;

/**
 * @author 朱远翔.Tom 测试JDBC驱动注册
 */
public class JDBCDriverTest {

    public static void main(String[] args) {
        Driver aDriver;
        Connection connection;
        Enumeration em;
        // “org.gjt.mm.mysql.Driver”是“com.mysql.jdbc.Driver”的子类,其构造函数就是调用父类的构造函数。
        String driverString = "com.mysql.jdbc.Driver";
        // String driverString = "org.gjt.mm.mysql.Driver";
        String url = "jdbc:mysql://localhost/ElectricalStore?useSSL=false";
        String username = "admin";
        String password = "123456";

        try {
           // 将DriverManager的日志流输出到Console窗口中,方便监控
           // DriverManager.setLogStream(System.out);
           // DriverManager.println("------DriverManager logs start!------");

           // 只是设置了一个JVM的系统属性,并不建立JDBC驱动程序。
            // 建立JDBC驱动是依赖系统第一次调用DriverManager类时,执行了这个类的静态初始化代码中的loadInitialDrivers(),
            // 加载驱动的方法会把设置的jdbc.drivers属性对应的驱动类通过DriverManager.registerDriver注册到JDBC中。
            // 因此,必须放在DriverManager被第一次调用之间,也就是需要将前面那两行代码注释掉
            System.out.println("1.1> Tried to use setProperty.");
            System.setProperty("jdbc.drivers", driverString);
            System.out.println("---List of all jdbc drivers---");
            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("There is no JDBC drivers");
            } else {
                while (em.hasMoreElements()) {
                    aDriver = (Driver) em.nextElement();
                    System.out.println(aDriver);
                }
            }

            System.out.println("1.2> we tried to use Class.forName");
            // Class.forName(driverString)在JavaSE 6.0后符合JDBC 4.0规范的驱动可以不用
            // 基于服务提供机制( Service Provider mechanism),
            // 系统会自动搜索mysql-connector-java-???-bin.jar中的META-INF/services/java.sql.Driver
            // 这个文件会包含mysql jdbc驱动程序的入口:com.mysql.jdbc.Driver
            // 应用程序调用Class.forName()也不会出错,只是什么都不会执行。
            // 因为Class.forName()就是执行静态初始化代码,已经初始化过的类就无法激活这段代码了
            // System.setProperty("jdbc.drivers",driverString);与Class.forName()一样。
            try {
                Class.forName("com.mysql.fabric.jdbc.FabricMySQLDriver");
            } catch (ClassNotFoundException e) {
                System.out.println("Driver not found");
            }

            System.out.println("---List of all jdbc drivers---");
            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("There is no JDBC drivers");
            } else {
                while (em.hasMoreElements()) {
                    aDriver = (Driver) em.nextElement();
                    System.out.println(aDriver);
                }
            }

            System.out.println("1.3> we tried to use DriverManager.registerDriver");
            // 手工注册mySQL的JDBC驱动程序,也就出现了与mySQL绑定过紧的问题,如果以后需要更换驱动,就需要修改代码。
            // 系统容许出现重复注册同样的jdbc驱动类
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            DriverManager.registerDriver(new com.mysql.fabric.jdbc.FabricMySQLDriver());
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            System.out.println("---List of all jdbc drivers---");
            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            while (em.hasMoreElements()) {
                aDriver = (Driver) em.nextElement();
                System.out.println(aDriver);
            }

            System.out.println("<1.5> Deregister all JDBC drivers");
            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            while (em.hasMoreElements()) {
                aDriver = (Driver) em.nextElement();
                DriverManager.deregisterDriver(aDriver); // 将已经注册的驱动程序取消注册
            }

            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("2.1> Now, there is no JDBC driver");
            }

            System.out.println("2.2> we tried to use Class.forName again");
            try {
                Class.forName(driverString);
            } catch (ClassNotFoundException e) {
                System.out.println("Driver not found");
            }
            try {
                Class.forName("com.mysql.fabric.jdbc.FabricMySQLDriver");
            } catch (ClassNotFoundException e) {
                System.out.println("Driver not found");
            }
            try {
                Class.forName(driverString);
            } catch (ClassNotFoundException e) {
                System.out.println("Driver not found");
            }

            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("There is no JDBC drivers");
            } else {
                System.out.println("---List of all jdbc drivers---");
                while (em.hasMoreElements()) {
                    aDriver = (Driver) em.nextElement();
                    System.out.println(aDriver);
                }
            }

            System.out.println("2.3> we tried to use setProperty again");
            System.setProperty("jdbc.drivers", "com.mysql.fabric.jdbc.FabricMySQLDriver");

            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("There is no JDBC drivers");
            } else {
                System.out.println("---List of all jdbc drivers---");
                while (em.hasMoreElements()) {
                    aDriver = (Driver) em.nextElement();
                    System.out.println(aDriver);
                }
            }

            System.out.println("2.3> Tried to use DriverManager.registerDriver again");

            DriverManager.registerDriver(new com.mysql.jdbc.Driver());
            DriverManager.registerDriver(new com.mysql.fabric.jdbc.FabricMySQLDriver());
            DriverManager.registerDriver(new com.mysql.jdbc.Driver());

            System.out.println("---List of all jdbc drivers---");
            em = DriverManager.getDrivers(); // 获取已加载JDBC驱动程序的Enumeration
            if (!em.hasMoreElements()) {
                System.out.println("There is no JDBC drivers");
            } else {
                while (em.hasMoreElements()) {
                    aDriver = (Driver) em.nextElement();
                    System.out.println(aDriver);
                }
            }

            System.out.print("3.1> Tried to establish a connection: ");
            connection = DriverManager.getConnection(url, username, password);
            System.out.println(connection);
        } catch (SQLException e) {
            System.out.println("Cannot registered the mysql jdbc driver");
        }

        System.out
                .println("jdbc.drivers property: " + System.getProperty("jdbc.drivers", "nothing"));

    }

}

本文转自BlogJava朱远翔的博客,原文链接:注册mySQL到JDBC驱动程序方法浅谈,如需转载请自行联系原博主。

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
打赏
0
0
0
0
5351
分享
相关文章
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
MySQL细节优化:关闭大小写敏感功能的方法。
通过这种方法,你就可以成功关闭 MySQL 的大小写敏感功能,让你的数据库操作更加便捷。
52 19
【YashanDB知识库】MySQL field 函数的改写方法
【YashanDB知识库】MySQL field 函数的改写方法
【YashanDB知识库】共享从 MySQL异常处理CONTINUE HANDLER的改写方法
本文介绍了MySQL中`CONTINUE HANDLER FOR NOT FOUND`的用法及其在YashanDB中的改写方法。通过一个示例存储过程,展示了如何使用游标和异常处理机制来应对“未找到数据”的情况。在MySQL中,`CONTINUE HANDLER`用于捕获此类异常;而在YashanDB中,则需改用游标的`%NOTFOUND`属性和`NO_DATA_FOUND`异常处理。文章对比了两者的执行效果,帮助用户顺利完成从MySQL到YashanDB的业务迁移。
环比、环比增长率、同比、同比增长率 ,占比,Mysql 8.0 实例(最简单的方法之一)(sample database classicmodels _No.2 )
环比、环比增长率、同比、同比增长率 ,占比,Mysql 8.0 实例(最简单的方法之一)(sample database classicmodels _No.2 )
319 1
【YashanDB知识库】MySQL field 函数的改写方法
本文来自YashanDB官网,介绍将MySQL的FIELD函数改写到YashanDB的方法。MySQL中,FIELD函数用于自定义排序;而在YashanDB中,可使用DECODE或CASE语句实现类似功能。示例展示对表`t1`按指定顺序排序的过程,提供两种改写方式,结果均符合预期。
【YashanDB知识库】MySQL返回结果集的存储过程的改写方法
本文介绍了将MySQL存储过程改写至YashanDB的解决方案。由于MySQL存储过程可直接返回结果集,而YashanDB需通过返回SYS_REF_CURSOR的函数实现类似功能,因此需要对代码进行转换。示例中展示了如何将MySQL存储过程`proc1`改写为YashanDB函数,并调整JDBC应用代码以适配REF_CURSOR输出参数,从而正确获取查询结果。此方法确保了跨数据库场景下的兼容性与功能性。
Python中使用MySQL模糊查询的方法
本文介绍了两种使用Python进行MySQL模糊查询的方法:一是使用`pymysql`库,二是使用`mysql-connector-python`库。通过这两种方法,可以连接MySQL数据库并执行模糊查询。具体步骤包括安装库、配置数据库连接参数、编写SQL查询语句以及处理查询结果。文中详细展示了代码示例,并提供了注意事项,如替换数据库连接信息、正确使用通配符和关闭数据库连接等。确保在实际应用中注意SQL注入风险,使用参数化查询以保障安全性。
MySQL/SqlServer跨服务器增删改查(CRUD)的一种方法
通过上述方法,MySQL和SQL Server均能够实现跨服务器的增删改查操作。MySQL通过联邦存储引擎提供了直接的跨服务器表访问,而SQL Server通过链接服务器和分布式查询实现了灵活的跨服务器数据操作。这些技术为分布式数据库管理提供了强大的支持,能够满足复杂的数据操作需求。
181 12
MySQL的count()方法慢
MySQL的 `COUNT()`方法在处理大数据量时可能会变慢,主要原因包括数据量大、缺乏合适的索引、InnoDB引擎的设计以及复杂的查询条件。通过创建合适的索引、使用覆盖索引、缓存机制、分区表和预计算等优化方案,可以显著提高 `COUNT()`方法的执行效率,确保数据库查询性能的提升。
947 12

热门文章

最新文章

推荐镜像

更多
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等