JDBC
什么是 JDBC?
JDBC 规范定义接口,具体的实现由各大数据库厂商来实现。
JDBC 是 Java 访问数据库的标准规范,真正怎么操作数据库还需要具体的实现类,也就是数据库驱动。每个数据库厂商根据自家数据库的通信格式编写好自己数据库的驱动。所以我们只需要会调用 JDBC 接口中的方法即可,数据库驱动由数据库厂商提供。 使用 JDBC 的好处:
- 程序员如果要开发访问数据库的程序,只需要会调用 JDBC 接口中的方法即可,不用关注类是如何实现的。
- 使用同一套 Java 代码,进行少量的修改就可以访问其他 JDBC 支持的数据库
JDBC会使用到的包
JDBC的核心API
准备工作:导入jar包
五个步骤实现对数据库的操作:
1.加载和注册驱动
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception{
Class.forName("com.mysql.jdbc.Driver");
}
}
2.DriverManager类
(1)DriverManager的作用
- 管理和注册驱动
- 创建数据库的连接
(2)类中的方法
(3)参数的含义
-
1)url:要连接的数据库(格式:jdbc:mysql://localhost:3306/数据库名)
-
2)用户名与密码:数据库的用户名和密码
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/first_db","root","123");
}
}
3.Connection接口
(1)Connection接口作用
Connection 接口,具体的实现类由数据库的厂商实现,代表一个连接对象。
(2)接口实现的方法
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/first_db","root","123");
String sql = "update student set 成绩=45 where 学科='math'";
Statement stmt = conn.createStatement();
}
}
4.Statement接口
(1)Statement 作用:
代表一条语句对象,用于发送 SQL 语句给服务器,用于执行静态 SQL 语句并返回它所生成结果的对象。
(2)Statement 中的方法:
5.释放资源
- 需要释放的对象:ResultSet 结果集,Statement 语句,Connection 连接
- 释放原则:先开的后关,后开的先关。ResultSet Statement Connection
- 放在哪个代码块中:finally 块
最终代码:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
public class jdbc {
public static void main(String[] args) throws Exception{
Class.forName("com.mysql.jdbc.Driver");
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/first_db","root","123");
String sql = "update student set 成绩=45 where 学科='math'";
Statement stmt = conn.createStatement();
int cout = stmt.executeUpdate(sql);
System.out.println(cout);
stmt.close();
conn.close();
}
}
示例:
(1)执行DDL语句
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 创建一张学生表
*/
public class DDL {
public static void main(String[] args) {
//1. 创建连接
Connection conn = null;
Statement statement = null;
try {
conn = DriverManager.getConnection("jdbc:mysql:///day24", "root", "root");
//2. 通过连接对象得到语句对象
statement = conn.createStatement();
//3. 通过语句对象发送 SQL 语句给服务器
//4. 执行 SQL
statement.executeUpdate("create table student (id int PRIMARY key auto_increment, " +
"name varchar(20) not null, gender boolean, birthday date)");
//5. 返回影响行数(DDL 没有返回值)
System.out.println("创建表成功");
} catch (SQLException e) {
e.printStackTrace();
}
//6. 释放资源
finally {
//关闭之前要先判断
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
}
(2)执行DML语句
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 向学生表中添加 4 条记录,主键是自动增长
*/
public class DML {
public static void main(String[] args) throws SQLException {
// 1) 创建连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql:///day24", "root",
"root");
// 2) 创建 Statement 语句对象
Statement statement = connection.createStatement();
// 3) 执行 SQL 语句:executeUpdate(sql)
int count = 0;
// 4) 返回影响的行数
count += statement.executeUpdate("insert into student values(null, '孙悟空', 1, '1993-03-24')");
count += statement.executeUpdate("insert into student values(null, '白骨精', 0, '1995-03-24')");
count += statement.executeUpdate("insert into student values(null, '猪八戒', 1, '1903-03-9 / 21 24')");
count += statement.executeUpdate("insert into student values(null, '嫦娥', 0, '1993-03-
11')");
System.out.println("插入了" + count + "条记录");
// 5) 释放资源
statement.close();
connection.close();
}
}
(3)执行DQL语句
需要使用ResultSet语句
- 作用:封装数据库查询的结果集,对结果集进行遍历,取出每一条记录。
- 接口中的方法:
数据转换表:
import java.sql.*;
/**
* 查询所有的学生信息
*/
public class DQL {
public static void main(String[] args) throws SQLException {
//1) 得到连接对象
Connection connection =
DriverManager.getConnection("jdbc:mysql://localhost:3306/day24","root","root");
//2) 得到语句对象
Statement statement = connection.createStatement();
//3) 执行 SQL 语句得到结果集 ResultSet 对象
ResultSet rs = statement.executeQuery("select * from student");
//4) 循环遍历取出每一条记录
while(rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
boolean gender = rs.getBoolean("gender");
Date birthday = rs.getDate("birthday");
//5) 输出的控制台上
System.out.println("编号:" + id + ", 姓名:" + name + ", 性别:" + gender + ", 生日:" +
birthday);
}
//6) 释放资源
rs.close();
statement.close();
connection.close();
}
}
关于 ResultSet 接口中的注意事项:
- 如果光标在第一行之前,使用 rs.getXX()获取列值,报错:Before start of result set
- 如果光标在最后一行之后,使用 rs.getXX()获取列值,报错:After end of result set
- 使用完毕以后要关闭结果集 ResultSet,再关闭 Statement,再关闭 Connection
数据库工具类 JdbcUtils
什么时候自己创建工具类?
如果一个功能经常要用到,我们建议把这个功能做成一个工具类,可以在不同的地方重用。
需求:
上面写的代码中出现了很多重复的代码,可以把这些公共代码抽取出来。
创建类 JdbcUtil 包含 3 个方法:
- 可以把几个字符串定义成常量:用户名,密码,URL,驱动类
- 得到数据库的连接:getConnection()
- 关闭所有打开的资源:close(Connection conn, Statement stmt),close(Connection conn, Statement stmt, ResultSet rs)
import java.sql.*;
/**
* 访问数据库的工具类
*/
public class JdbcUtils {
//可以把几个字符串定义成常量:用户名,密码,URL,驱动类
private static final String USER = "root";
private static final String PWD = "root";
private static final String URL = "jdbc:mysql://localhost:3306/day24";
private static final String DRIVER= "com.mysql.jdbc.Driver";
/**
* 注册驱动
*/
static {
try {
Class.forName(DRIVER);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 得到数据库的连接
*/
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(URL,USER,PWD);
}
/**
* 关闭所有打开的资源
*/
public static void close(Connection conn, Statement stmt) {
if (stmt!=null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (conn!=null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 关闭所有打开的资源
*/
public static void close(Connection conn, Statement stmt, ResultSet rs) {
if (rs!=null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
close(conn, stmt);
}
}
PreparedStatement 接口
1.继承结构与作用:
PreparedStatement 是 Statement 接口的子接口,继承于父接口中所有的方法。它是一个预编译的 SQL 语句
2.PreparedSatement 的执行原理
- 因为有预先编译的功能,提高 SQL 的执行效率。
- 可以有效的防止 SQL 注入的问题,安全性更高。
3.Connection 创建 PreparedStatement 对象
4.PreparedStatement 接口中的方法:
5.PreparedSatement 的好处
- prepareStatement()会先将 SQL 语句发送给数据库预编译。PreparedStatement 会引用着预编译后的结果。
可以多次传入不同的参数给 PreparedStatement 对象并执行。减少 SQL 编译次数,提高效率。 - 安全性更高,没有 SQL 注入的隐患。
- 提高了程序的可读性
6. 使用 PreparedStatement 的步骤:
- 编写 SQL 语句,未知内容使用?占位:“SELECT * FROM user WHERE name=? AND password=?”;
- 获得 PreparedStatement 对象
- 设置实际参数:setXxx(占位符的位置, 真实的值)
- 执行参数化 SQL 语句
- 关闭资源
示例:
JDBC 事务的处理
之前我们是使用 MySQL 的命令来操作事务,接下来我们使用 JDBC 来操作事务。
步骤:
- 获取连接
- 开启事务
- 获取到 PreparedStatement
- 使用 PreparedStatement 执行两次更新操作
- 正常情况下提交事务
- 出现异常回滚事务
- 最后关闭资源
rollback回到setAutoCommit处