JDBC 常用类介绍
# 4.JDBC 常用类介绍 上一节我们快速入门了下 JDBC,并使用它做了一个小案例,现在对各个常用的类做进一步的说明:
DriverManager:驱动管理对象 Connection:数据库连接对象 Statement、PreparedStatement:执行 sql 的对象 ResultSet:结果集对象,封装查询结果
严格来说,以上这些都是接口,位于 java.sql 包下;
javax.sql 是数据库扩展包,提供数据库额外的功能,如连接池
# DriverManager:驱动管理对象 DriverManager 主要用两个功能:
注册驱动 获取数据库连接对象
# 功能 1:注册驱动 注册驱动,告诉程序该使用哪一个数据库驱动 jar。
DriverManager 是一个接口,在 API 文档中有这样一个方法:static void registerDriver(Driver driver),作用是注册与给定的驱动程序。调用这个方法,实际上才算告诉了应用程序我们要使用哪个数据库驱动类。
但我们写代码的时候,直接通过反射加载驱动类:Class.forName("com.mysql.cj.jdbc.Driver"),好像也没有执行上面的注册方法?
这是因为驱动类有个 static 静态代码块,其中就会执行 registerDriver 方法,注册驱动,因此我们只要一加载这个类,就会自动注册。
说起一加载类就执行的代码,读者们想到了什么?static (opens new window) 代码块。通过查看 MySQL 驱动类,com.mysql.cj.jdbc.Driver 源码,可以看到有 static 代码块,会执行 register 方法:
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
1234567注意点 1:读者可以直接在 IDEA 里查看 jar 包中的源码
注意点 2:mysql5 之后的驱动 jar 包可以省略注册驱动的步骤 Class.forName(.....),因为会自动注册驱动,所以可以如下省略注册的代码:
// MySQL5驱动类注册方法
Class.forName("com.mysql.jdbc.Driver");
// MySQL8驱动类注册方法
Class.forName("com.mysql.cj.jdbc.Driver");
12345自动注册的原理:寻找 jar 包的 META-INF/services/java.sql.Driver 文件,并读取里面配置的类然后加载。所以如果读者后续更换其他数据库驱动类后,想要注册但不知道驱动类的全类名,可以通过这个方法找到。
注意,MySQL 驱动 5.1.6 版本之前的 jar 包中,没有 META-INF/services 目录,因此如果用的是早期的 JDBC 驱动,还是得用 Class.forName(“com.mysql.jdbc.Driver”)
# 功能 2: 获取数据库连接对象 DriverManager 还有一个重要的方法,获取 Connection 对象:static Connection getConnection(String url, String user, String password)
参数说明:
url:指定连接的路径。注意,不同数据库的 URL 语法可能不一样。以 MySQL 为例:
语法:jdbc:mysql://ip地址(或域名):端口号/数据库名称 例子:jdbc:mysql://localhost:3306/db3 如果连接的是本机 mysql 服务器,并且 mysql 服务默认端口是 3306,则 url 可以简写为:jdbc:mysql:///数据库名称 user:用户名
password:密码
# Connection:数据库连接对象 功能:
获取执行 sql 的对象
Statement createStatement() PreparedStatement prepareStatement(String sql) 管理事务:
开启事务:void setAutoCommit(boolean autoCommit):调用该方法设置参数为 false,即开启事务 提交事务:void commit() 回滚事务:void rollback() 后续我们会介绍事务。
# Statement:执行 sql 的对象 查询文档,相关说明是:用于执行静态 SQL 语句并返回其生成的结果的对象(参数是给定值的)
PreparedStatement 对象则是执行预编译的 SQL 语句对象(参数是后续设置的)
执行 sql 相关方法:
boolean execute(String sql):可以执行任意的 sql (了解即可,较少使用),返回值是 Boolean 类型,有结果集则是 true,没有则是 false int executeUpdate(String sql):执行 DML 语句(例如 insert、update、delete)、DDL 语句(例如 create,alter、drop)。不能执行查询语句
返回值:影响的行数,可以通过这个影响的行数判断 DML 语句是否执行成功 。返回值 > 0 的则执行成功,反之,则失败。执行 DDL 语句则返回 0。 ResultSet executeQuery(String sql):执行 DQL(select)语句,返回 ResultSet 对象 之前我们仅仅使用了 executeQuery,后续我们介绍 executeUpdate 方法。
# PreparedStatement 对象:防止 SQL 注入 PreparedStatement 继承了 Statement 接口。这个类能解决 SQL 注入问题
执行的是预编译的 SQL,SQL 中参数使用 ? 作为占位符
使用步骤:
定义 sql。注意:sql 的参数使用?作为占位符。如:
string sql = select * from user where username = ? and password = ?;
1 获取执行 sql 语句的对象 PreparedStatement
pstm = Connection.prepareStatement(String sql)
1 给占位符 ?赋值,用方法: setXXX(参数 1, 参数 2),例如 setDouble() ,setString() 等一系列方法
参数 1:?的位置编号 从 1 开始 参数 2:?的值 举例:setString(1, "PeterJXL") 执行 sql,接受返回结果,不需要传递 sql 语句
# ResultSet:结果集对象,封装查询结果 ResultSet:返回结果集对象(可以看作是一个数据库表)后,默认会有个游标(或者叫指针),游标的初始位置位于第一行之前;
第一次调用 next() 方法将会把第一行设置为当前行。
第二次调用 next() 方法游标移动到第二行,以此类推。
常用方法
boolean next() : 游标向下移动一行,判断当前行是否是最后一行末尾(是否有数据),如果是,则返回 false,如果不是则返回 true。
getXXX(参数): 获取某一列的数据
XXX 代表数据类型 如:int getInt(),String getString(),double getDouble() 等等
参数:
如果是 int 类型:代表列的编号, 从 1 开始 如:getString(1) 如果是 String 类型:代表列名称。 如: getDouble("balance") 使用步骤总结:
使用 next() 方法使游标向下移动一行 通过 next() 方法的返回值判断是否还有数据,如果有则返回 true,如果没有则返回 false(可以理解为游标到了最后一行了,再往下就没数据了) 通过 getXXX(参数) 方法获取某一列的数据
如果 ResultSet 的游标已经到了最后一行,再调用一次 next(),会抛出异常: java.sql.SQLException: After end of result set
at com.mysql.jdbc.SQLError.createsQLException(SQLError.java: 959)
at com.mysql.jdbc.SOLError.createSQLException(SOLError.java: 898)
com.mysql.jdbc.SQLError.createSQLException(SOLError.java: 887)
com.mysql.jdbc.SoLError.createSQLException(SOLError.java: 862)
com.mysql.jdbc.ResultsetImpl.checkRowPos(ResultSetImpl.java: 790)
com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.iava: 2469)
.....
12345678
所以我们遍历 ResultSet 时通常是使用循环,每次判断是否到达了最后一行:
while(rs.next()){ //循环判断游标是否是最后一行末尾(判断是否有数据)
//获取数据并处理
int id = rs.getInt(1);
// .....省略其他代码
}
12345