网站首页 > 教程分享 正文
本文内容
- 首先介绍了JDBC的意义:Java提供的一套操作数据库的接口规范。
- 然后分三部分介绍了JDBC使用的方法:注册驱动、获得连接、执行SQL语句并获得结果。
- 注册驱动部分,介绍了Driver、DriverManager接口,并介绍了JDBC 4之后利用 Java SPI 自动注册驱动的原理。
- 获得连接部分,介绍了Connection、DataSource接口,并阐述了连接的一些注意点,以及为什么要使用连接池。
- 执行SQL语句部分,介绍了Statement、PreparedStatement、ResultSet接口提供给操作数据库的能力。
一张图
JDBC是什么?
我们都用过数据库,你也可能自己使用命令行连接过某个数据库,以MySQL为例:
- 首先需要有一个MySQL客户端,使用MySQL的服务器地址、端口、用户名、密码去进行连接
- 连接上之后,执行需要执行的SQL语句,MySQL会返回对应的数据
而为了使用Java语言进行上述操作,java.sql 包定义了一套标准接口,即 JDBC 规范。各个数据库方(不限于MySQL)均实现这套规范,用户引入自己想连接的数据库的规范实现,通过 Java 的这一套JDBC接口,实现连接数据库,执行SQL语句操作数据库的需求,而不用关心不同的数据库厂商对应的不同连接细节。
JDBC使用的步骤包括三个部分,注册驱动、获得连接、执行SQL语句并获得结果;我们将从这三个部分介绍。
注册驱动
注册驱动的目的
驱动(Driver)指的是java.sql包下的Driver接口,定义了两个比较重要的方法:
// 用于获取数据库连接
Connection connect(String url, java.util.Properties info) throws SQLException;
// 用于判断所配置的要连接的数据库url是否被该驱动的实现支持
boolean acceptsURL(String url) throws SQLException;
复制代码
我们在使用JDBC连接数据库时,通常会配置一个JDBC连接的Properties,中间必然包含一个url的参数:
url=jdbc:mysql://localhost:3306/db_name
复制代码
Driver的acceptsURL方法会判断配置跌url是否被该驱动支持,connect方法会使用该url去连接数据库。
JDBC接口中有一个关键的DriverManager类,后面我们会直接使用它来获取数据库连接Connection,顾名思义,DriverManager用于管理驱动Driver,而注册驱动的目的就是将我们要使用的JDBC实现(数据库厂商提供的包,如mysql-connector-java jar包)的Driver实现注册到DriverManager中,使用户(Java应用代码编写者)在获取数据库连接时,直接使用JDBC中的接口,而不用关心不同数据库的不同实现。
SPI自动注册驱动
很多老旧的代码或博客还会使用如下方式进行驱动的注册:
Class.forName("com.mysql.cj.jdbc.Driver") // 加载Dirver类,Driver类的初始化时static块会将自己注册到DriverManager
复制代码
其实JDBC4.0(对应JDK 1.6)之后,DriverManager已经支持使用SPI实现自动注册驱动。
SPI是Java提供的一套被第三方实现或者扩展的接口(调用方根据需求选择第三方实现),用户可以在项目META-INF/services目录下指定要加载的接口实现
可以看到mysql-connector-java jar包的META-INF/services目录下指定了Driver的实现类
很容易在DriverManager类中找到,DriverManager在类的初始化过程中,static块里,进行了Driver的获取
DriverManager 将加载数据库连接包的 jdbc 的 Driver 的实现;注,jdbc4 后不用显式注册,在使用 DriverManager 获得连接时将自动检测加载驱动;
// Driver.loadInitialDrivers
AccessController.doPrivileged(new PrivilegedAction<Void>() {
// 省略了一些代码
public Void run() {
// SPI加载Driver类
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
}
});
复制代码
所以,注册驱动的事情,Java SPI和mysql-connector-java驱动包已经帮我们自动做了,不需要应用代码注册。
获得连接
前面提到,Driver的一个重要方法connect,调用后返回Connection数据库连接,拿到连接,相当于我们在命令行模式下使用mysql -u -p 连接MySQL服务器成功后的效果。
关于获取连接,需要注意的是:
- 获得数据库连接是一个比较重的操作,需要进行应用与数据库服务器建立TCP连接的的三次握手、数据库校验用户名密码数据库服务器分配资源给这个连接等等操作;
- 数据库连接Connection对象不管对于应用(如MySQL客户端),还是数据库服务端(如MySQL服务端),都是一种资源占用,需要显式地进行释放,且不能大量创建。
- 同一个数据库连接可以用于执行多条SQL语句,且可以连续执行多个事务。
基于以上几点,可以得出,数据库连接可以并且应该被复用,现在的实际应用中,对于数据库连接的管理,通常会使用连接池,如常用的HikariDataSource,实现了java.sql.DataSource,应用定义好关于数据库的连接信息、用户名、密码、连接池大小、连接超时时间等侯,可以用HikariDataSource直接获取连接,它会负责数据库连接的创建、释放等生命周期管理。
DataSource是JDBC的一个接口,意思是数据源,简单定义了两个获取Connection的方法,可以用于替代DriverManager获取连接的写法;被大家实现用来做连接池等
执行SQL语句并获得结果
获取到数据库连接之后,下一步我们要使用Connection去执行SQL语句完成数据库操作了,所以看看JDBC定义的Connection接口里面定义的有什么方法:
// java.sql.Connection
// 在这个数据库连接上创建一个Statement
Statement createStatement() throws SQLException;
// 预编译一条SQL语句,PreparedStatement接口继承Statement
PreparedStatement prepareStatement(String sql) throws SQLException;
复制代码
引出了另一个执行SQL语句并获得结果比较核心的两个JDBC接口:Statement、PreparedStatement,后者继承了前者。
Statement用于执行SQL语句的直接字符串。
PreparedStatement相比Statement增加了两个重要点:
- 支持预编译SQL
- 支持参数占位符,避免了直接拼接SQL语句可能会导致的SQL注入问题
预编译是一种数据库支持的语法,MySQL即支持,好处是对于重复执行一条SQL语句但参数不同时,使用预编译可以做到语法、词法解析只执行一次,性能会有所提高
先看下Statement接口提供的方法:
// java.sql.Statement
// 用于执行SELECT类型的SQL语句,返回结果当然在ResultSet里啦
ResultSet executeQuery(String sql) throws SQLException;
// 用于执行INSERT、UPDATE、DELETED类型的SQL语句
int executeUpdate(String sql) throws SQLException;
// 用于获取语句执行自动生成的东西,如自增主键,插入返回的主键
ResultSet getGeneratedKeys() throws SQLException;
复制代码
PreparedStatement接口因为需要支持预编译,增加了设置参数相关的方法:
// java.sql.PreparedStatement
// 执行查询,因为SQL语句已经预编译,不需要传入SQL
ResultSet executeQuery() throws SQLException;
// 设置参数,根据预编译时在SQL语句中的位置索引,省略其它类型的setXXX()
void setInt(int parameterIndex, int x) throws SQLException;
void setString(int parameterIndex, String x) throws SQLException;
复制代码
获得结果
执行SQL语句后,或者返回或者通过Statement.getResultSet,都可以拿到一个ResultSet,从ResultSet中我们可以获取到语句返回的内容:
// 例,执行查询语句返回结果的遍历
ResultSet resultSet = statement.executeQuery("select * from user limit 10");
while (resultSet.next()){
formatter.format(format,resultSet.getInt("id"),resultSet.getString("name"),resultSet.getInt("age"),simpleDateFormat.format(resultSet.getDate("birth")));
System.out.println();
}
// insert语句返回结果处理
try(
PreparedStatement preparedStatement = connection.prepareStatement("insert into user(name,age,birth) values(?,?,?)", Statement.RETURN_GENERATED_KEYS)
){
preparedStatement.setString(1, name);
preparedStatement.setInt(2, age);
preparedStatement.setDate(3, new Date(birth.getTime()));
preparedStatement.execute();
ResultSet resultSet = preparedStatement.getGeneratedKeys();
if(resultSet.next()){
// 这里获取到mysql自增主键
return resultSet.getInt(1);
}else{
throw new RuntimeException("插入失败");
}
}
复制代码
后续
后面会再写一篇更接近我们平常使用的Mybatis相关的博客,看看它是怎么使用JDBC的,为我们的日常开发带来的便利。
作者:gnaiqil1
链接:https://juejin.cn/post/7053308720473702431
- 上一篇: 数据可视化服务的系统能力与确定性
- 下一篇: JDBC学会这些操作就行啦(jdbc7个步骤)
猜你喜欢
- 2024-10-14 Java之Spring4:JDBC(java之父余胜军网站)
- 2024-10-14 《JDBC》第09节:JDBC之DatabaseMetaData数据库元数据对象
- 2024-10-14 《JDBC》第18节:JDBC之数据库连接池Hikari的使用(软编码方式)
- 2024-10-14 flink教程-详解flink 1.11 中的JDBC Catalog
- 2024-10-14 肝!Spring JDBC持久化层框架“全家桶”教程
- 2024-10-14 JDBC的基础使用(jdbc 教程)
- 2024-10-14 大数据开发基础之JAVA基础-JDBC基础知识
- 2024-10-14 JDBC基础整理(jdbc 教程)
- 2024-10-14 小白都能看懂的JDBC事务(jdbc实现事务管理)
- 2024-10-14 Spring JdbcTemplate讲解(spring的jdbc模板)
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- css导航条 (66)
- sqlinsert (63)
- js提交表单 (60)
- param (62)
- parentelement (65)
- jquery分享 (62)
- check约束 (64)
- curl_init (68)
- sql if语句 (69)
- import (66)
- chmod文件夹 (71)
- clearinterval (71)
- pythonrange (62)
- 数组长度 (61)
- javafx (59)
- 全局消息钩子 (64)
- sort排序 (62)
- jdbc (69)
- php网页源码 (59)
- assert h (69)
- httpclientjar (60)
- postgresql conf (59)
- winform开发 (59)
- mysql数字类型 (71)
- drawimage (61)
本文暂时没有评论,来添加一个吧(●'◡'●)