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):JDBC URL中的协议总是
几种常用的数据库的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
用户名和密码
user
和password
可以用属性名=属性值
的方式告诉数据库
也可以通过调用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);
}
使用这种方式的好处:
- 实现了数据与代码的分离,实现了解耦。
- 如果需要修改配置文件中的信息,可以避免程序重新编译打过。
网友评论