使用JDBC连接MySQL数据库的5种方式

JDBC介绍

  • JDBC(Java Database Connectivity)是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这些类库可以以一种标准的方法、方便地访问数据库资源。
  • JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。
  • JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程。

JDBC体系结构

JDBC接口(API)包括两个层次:

  • 面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,执行SQL语句,获得结果)。
  • 面向数据库的API:Java Driver API,供开发商开发数据库驱动程序使用。

JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。

不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的驱动。 ————面向接口编程

获取数据库连接

准备工作:下载jar包,可以通过这个网站下载(Maven仓库),搜索mysql-connector-java,选择需要的版本,下载jar包即可,本文使用的是mysql-connector-java-8.0.28

获取数据库连接的三要素:Driver接口的实现类,URL以及数据库的用户名密码。

Driver接口

java.sql.Driver接口是所有JDBC驱动程序需要实现的接口。这个接口是提供给数据库厂商使用的,不同数据库厂商提供不同的实现。在程序中不需要直接去访问实现了Driver接口的类,而是由驱动程序管理器类(java.sql.DriverManager)去调用这些Driver实现。

  • Oracle的驱动:oracle.jdbc.driver.OracleDriver
  • MySQL的驱动:com.mysql.jdbc.Driver

注册与加载驱动

加载驱动:加载 JDBC 驱动需调用Class类的静态方法forName(),向其传递要加载的JDBC驱动的类名。

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

注册驱动:DriverManager类是驱动程序管理器类,负责管理驱动程序。

  • 使用DriverManager.registerDriver(com.mysql.jdbc.Driver)来注册驱动

URL

JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。

官方文档中URL的通用格式:

protocol//[hosts][/database][?properties]
  协议   //主机名称 /数据库名称  ?其他参数

也有把JDBC URL的标准看成是由三部分组成,各部分间用冒号分隔:

  • jdbc(协议):子协议:子名称
    • 协议(jdbc):JDBC URL中的协议总是jdbc
    • 子协议:子协议用于标识一个数据库驱动程序,如:mysql、oracle
    • 子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名

几种常用的数据库的JDBC URL

  • MySQL的连接URL编写方式:

    jdbc:mysql://主机名称:mysql服务端口号/数据库名称?参数=值&参数=值
    jdbc:mysql://localhost:3306/test
    jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8(如果JDBC程序与服务器端的字符集不一致,会导致乱码,那么可以通过参数指定服务器端的字符集)
    jdbc:mysql://localhost:3306/test?user=root&password=root
    
  • Oracle 9i的连接URL编写方式:

    jdbc:oracle:thin:@主机名称:oracle服务端口号:数据库名称
    jdbc:oracle:thin:@localhost:1521:test
    
  • SQLServer的连接URL编写方式:

    jdbc:sqlserver://主机名称:sqlserver服务端口号:DatabaseName=数据库名称
    jdbc:sqlserver://localhost:1433:DatabaseName=test
    

用户名和密码

userpassword可以用属性名=属性值的方式告诉数据库

也可以通过调用DriverManager类的getConnection(url, user, password)方法将用户名和密码告诉数据库,与数据库建立连接。

连接数据库的方式

声明:不是说有很多种连接方式,而是为了展示一步一步对连接数据库的写法进行迭代,为了区分,才说成有多种方式,最后我们会得出一个最终(最优)的写法

连接方式一

@Test
public void testConnection() throws SQLException {

    // 1. 获取Driver实现类对象,使用数据库厂商提供的类
    Driver driver = new com.mysql.jdbc.Driver();

    /*
        * jdbc:mysql    协议
        * localhost     ip地址
        * 3306          默认的mysql的端口号
        * test          test数据库
        * */
    String url = "jdbc:mysql://localhost:3306/test";
    Properties info = new Properties();

    // 将用户名和密码封装在Properties中
    info.setProperty("user", "root");
    info.setProperty("password", "root");

    Connection conn = driver.connect(url, info);
    System.out.println(conn);
}

注意,这里有个问题,如果使用的连接器(mysql-connector-java)版本在6以下,使用的驱动类就是com.mysql.jdbc.Driver,如果连接器版本是6以及6以上,使用的驱动类就是com.mysql.cj.jdbc.Driver,如果依然使用过的是com.mysql.jdbc.Driver,那么就会有个警告性的错误提示:

Loading class 'com.mysql.jdbc.Driver'. This is deprecated. The new driver class is 'com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.

出现这个提示,并不是说com.mysql.jdbc.Driver完全不能使用,而是不推荐使用,官方更推荐使用com.mysql.cj.jdbc.Driver。使用com.mysql.jdbc.Driver也可以连接上数据库并进行操作,如果使用的连接器是6以上的版本,还是按照官方推荐的,使用com.mysql.cj.jdbc.Driver较好。

连接器版本在6以下,com.mysql.jdbc.Driver类的源码:

// com.mysql.jdbc.Driver实现了java.sql.Driver
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

连接器版本在6以上,com.mysql.jdbc.Driver类的源码:

// com.mysql.jdbc.Driver继承了com.mysql.cj.jdbc.Driver,所以com.mysql.jdbc.Driver类依然可以使用,但是不推荐。
public class Driver extends com.mysql.cj.jdbc.Driver {
    public Driver() throws SQLException {
    }

    static {
        System.err.println("Loading class `com.mysql.jdbc.Driver'. This is deprecated. The new driver class is `com.mysql.cj.jdbc.Driver'. The driver is automatically registered via the SPI and manual loading of the driver class is generally unnecessary.");
    }
}

com.mysql.cj.jdbc.Driver的源码:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }

    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}

注意事项

如果使用com.mysql.cj.jdbc.Driver驱动类,URL中没有设置useSSL=false,则会在连接数据库的时候出现以下提示:

WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements
SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate
property is set to 'false'.You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate
verification.

URL中如果没有设置serverTimezone=Asia/Shanghai,则会在连接数据库的时候出现以下提示:

The server time zone value '???ú±ê×??±??' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.

为什么不设置serverTimezone=UTC,是因为UTC(世界标准时间)和北京时间相差8个小时,所以具体设置哪个时区的时间,请根据实际需求设置。

我在例子中URL并没有设置useSSL和serverTimezone,并没有报错。我也没有深究原因(我猜测是没有使用框架),如果出现了上述提到的错误,那就加上相应的参数即可。

连接方式二

方式一中的代码,我直接使用了new com.mysql.jdbc.Driver()第三方的API,程序的依赖性强。

现在对方式一进行迭代:

// 方式二:对方式一的迭代,在如下程序中不出现第三方的api,使得程序具有更好的可移植性
@Test
public void testConnection2() throws Exception {
    // 1. 获取Driver实现类对象,使用反射
    Class<?> clazz = Class.forName("com.mysql.jdbc.Driver");
    Driver driver = (Driver) clazz.newInstance();

    // 2. 提供链接需要的用户名和密码
    String url = "jdbc:mysql://localhost:3306/test";

    // 3. 提供链接需要的用户名和密码
    Properties info = new Properties();
    info.setProperty("user", "root");
    info.setProperty("password", "root");

    // 4. 获取链接
    Connection conn = driver.connect(url, info);
    System.out.println(conn);

}

连接方式三

对方式二的迭代:

// 方式三:使用DriverManager替换Driver
@Test
public void testConnection3() throws Exception {
    // 1. 获取Driver实现类对象,使用反射
    Class<?> clazz = Class.forName("com.mysql.jdbc.Driver");
    Driver driver = (Driver) clazz.newInstance();

    // 2. 提供另外三个连接的基本信息
    String url = "jdbc:mysql://localhost:3306/test";
    String user = "root";
    String password = "root";

    // 3. 注册驱动
    DriverManager.registerDriver(driver);

    // 4. 获取链接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
}

DriverManager顾名思义是驱动管理类,使用它比直接使用Driver更为方便。

连接方式四

对方式三进行迭代:

// 方式四:可以只是加载驱动,不用显示的注册驱动了。
@Test
public void testConnection4() throws Exception {
    // 1. 获取Driver实现类对象
    Class.forName("com.mysql.jdbc.Driver");
    //相较于方式3,可以省略注册驱动的操作
    // 2. 注册驱动
    // DriverManager.registerDriver(driver);
    // 为什么?
    /*
        在 mysql的Driver实现类中,声明了如下的操作:
        static {
            try {
                DriverManager.registerDriver(new Driver());
            } catch (SQLException var1) {
                throw new RuntimeException("Can't register driver!");
            }
        }
         */

    // 2. 提供另外三个连接的基本信息
    String url = "jdbc:mysql://localhost:3306/test";
    String user = "root";
    String password = "root";

    // 3. 获取链接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);
}

连接方式五(最终方案)

在src目录下新建配置文件jdbc.properties,将数据库连接需要的4个基本信息声明在配置文件中:

user=root
password=root
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

注意,如果使用的连接器(mysql-connector-java)是6及6以上的版本,driverClass应使用com.mysql.cj.jdbc.Driver

// 方式五:终极方案,将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式获取链接
@Test
public void getConnection() throws Exception {
    // 1. 读取配置文件中的4个基本信息
    InputStream is = ConnectionTest.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");

    // 2. 加载驱动
    Class.forName(driverClass);

    // 3. 获取链接
    Connection conn = DriverManager.getConnection(url, user, password);
    System.out.println(conn);

}

使用这种方式的好处:

  • 实现了数据与代码的分离,实现了解耦。
  • 如果需要修改配置文件中的信息,可以避免程序重新编译打过。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容