笔记根据此视频完成
个人博客链接:https://www.qingbo1011.top/ 点击此处前往
Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。JDBC是面向关系型数据库的。
JDBC本质:官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。
(理解:Heart接口,Person实现类。Heart h = new Person()
(多态),执行h.beat,其实执行的是Person实现类中重写的beat方法)
JDBC入门
步骤:
1.导入jar包
在项目中创建一个libs文件夹,将jar包复制到其中。
注意要将复制的jar包导入驱动:
2.注册驱动
3.获取数据库连接对象
4.定义sql语句
5.执行sql的对象Statement
6.执行sql
7.处理结果
8.释放资源
例子:
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo01 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.导入驱动jar包
// 2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 3.获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
// 4.定义sql语句
String sql = "update employees set age = 30 where name = 'jay';";
// 5.获取执行sql的对象Statement
Statement statement = connection.createStatement();
// 6.执行sql
int count = statement.executeUpdate(sql);
// 7.处理结果
System.out.println("一共执行了"+count+"条数据");
// 8.释放资源
statement.close();
connection.close();
}
}
JDBC各个类分析
- DriverManager:驱动管理对象
- Connection:数据库连接对象
- Statement:执行sql的对象
- ResultSet:结果集对象,封装查询结果
- PreparedStatement:执行sql的对象
DriverManager:驱动管理对象
功能:
1.注册驱动:告诉程序该使用哪一个数据库驱动(jar包)
static void registerDriver(Dirver driver)
:注册与给定的驱动DriverManager
使用时:Class.forName("com.mysql.jdbc.Driver");
源码:在com.mysql.jdbc.Driver类中的静态代码块如下:
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
注意:mysql5之后的驱动jar包可以省略注册驱动步骤
原因:在META-INF文件夹下有以下文件:
2.获取数据库连接
方法:static Connection getConnection(String url,String user,String password)
三个参数:
- url:指定连接的路径
- 语法:
jdbc:mysql://ip地址(域名):端口号/数据库名称
- 例子:
jdbc:mysql://localhost:3306/jdbc_study
- 细节:如果连接的是本地的mysql服务并且服务器默认端口是3306,则url可以简写为:
jdbc:mysql:///数据库名称
- 语法:
- user:用户名
- password:密码
Connection:数据库连接对象
功能:
1.执行sql的对象
- Statement createStatement()
- PreparedStatement prepareStatement(String sql)
2.管理事务
- 开启事务:
setAutoCommit(boolean autoCommit)
,调用该方法设置参数为false,即开启事务 - 提交事务:
commit()
- 回滚事务:
rollback()
Statement:执行sql的对象
功能:
1.执行sql
boolean execute(String sql)
:可以执行任意的sql(了解)int executeUpdate(String sql)
:执行DML、DDL语句。- 返回值:影响的行数,即操作的记录数。可以通过这个影响行数判断DML语句是否成功。返回值>0则表示执行成功,反之则失败。
ResultSet executeQuery(String sql)
:执行DQL语句
ResultSet:结果集对象,封装查询结果
两个方法:
boolean next()
:游标向下移动一行,并判断当前行是否是最后一行,如果是返回false
,如果不是则返回true
getXxx(参数)
:获取数据- Xxx表示数据类型,如:
int getInt()
,String getString()
- 参数:
- 参数为int:表示列的编号,从1开始,如:
getString(1)
- 参数为string:表示列的名称。如:
getInt("age")
- 参数为int:表示列的编号,从1开始,如:
- Xxx表示数据类型,如:
例子:使用jdbc查询employees表中的id=1和id=4的数据:
package day01;
import java.sql.*;
public class Demo03 {
public static void main(String[] args) throws ClassNotFoundException, SQLException {
// 1.导入驱动jar包
// 2.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 3.获取数据库连接对象
Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
// 4.定义sql语句
String sql = "select * from employees where id = 1 or id = 4;";
// 5.执行sql的对象Statement
Statement statement = connection.createStatement();
// 6.执行sql
ResultSet resultSet = statement.executeQuery(sql);
// 7.处理结果
System.out.println("查询结果为:");
while (resultSet.next()){ // 游标从第0行开始向下移动,到最后一行结束
int id = resultSet.getInt(1); // 参数为1表示返回第一列数据(游标所指向的行的)
String name = resultSet.getString("name"); // 参数为"name"表示返回列名为name的数据(游标所指向的行的)
int age = resultSet.getInt("age"); // 参数为"age"表示返回列名为age的数据(游标所指向的行的)
System.out.println(id+" "+name+" "+age);
}
// 8.释放资源
statement.close();
connection.close();
resultSet.close();
}
}
执行结果为:
PreparedStatement:执行sql的对象
sql注入问题:在拼接sql时,有一些sql的特殊关键字符参与字符串的拼接。会造成安全性问题
解决sql注入问题:使用PreparedStatement对象。
预编译的sql:sql的参数使用?
作为占位符,如:
select * from user where username = ? and password = ?;
使用步骤:
- 导入jar包
- 注册驱动
- 获取数据库连接Connection对象
- 定义sql(注意sql参数使用
?
作为占位符。如select * from user where username = ? and password = ?
;) - 获取执行sql的PreparedStatement对象:
connection.preparedStatement(String sql)
- 给
?
赋值:- 方法:setXxx(参数1,参数2) (Xxx为数据类型,如getInt)
- 参数1:
?
的位置编号,从1开始 - 参数2:
?
的值
- 参数1:
- 方法:setXxx(参数1,参数2) (Xxx为数据类型,如getInt)
- 执行sql,接受返回结果,不需要传递sql语句
- 处理结果
- 释放资源
注意:后面我们都会使用PreparedStatement来完成增删改查:
- 可以防止sql注入
- 效率更高
JDBC增删改练习
针对我们现有的employees表,我们通过JDBC进行以下操作(DML):
添加一条记录
符合规范的jdbc代码:
package day01;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
public class Demo02 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
// 2.注册驱动
try {
Class.forName("com.mysql.jdbc.Driver");
// 3.获取数据库连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
// 4.定义sql语句
String sql = " insert into employees values (4,'tom',18);";
// 5.执行sql的对象Statement
statement = connection.createStatement();
// 6.执行sql
int count = statement.executeUpdate(sql);
// 7.处理结果
System.out.println("一共执行了"+count+"条记录");
if (count>0){
System.out.println("sql执行成功!");
}else {
System.out.println("sql执行失败!");
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally { // 将释放资源放到finally代码块,保证了资源释放操作一定会执行
// 8.释放资源
// 这里的try-catch是为了避免空指针异常
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
}
修改记录
在上述代码的基础上,将String sql = " insert into employees values (4,'tom',18);";
修改为:
String sql = " update employees set age = 20 where name = 'tom';";
删除一条记录
在上述代码的基础上,将String sql = " update employees set age = 20 where name = 'tom';";
修改为:
String sql = " delete from employees where id = 2;";
JDBC查询数据(JDBC select语句)
查询emp表中所有数据并将其封装为对象,然后装载集合。将查询结果打印在控制台上。
其中emp表的数据和结构如下:
- 定义emp类
- 定义方法
public List<Emp> findAll(){}
- 实现功能
select * from emp;
我们在domain包下创建Emp.java类,代码如下:
package day01.domain;
import java.math.BigDecimal;
import java.util.Date;
/**
* 封装emp表数据的JavaBean
*/
public class Emp {
private int id; // 对应表中id字段
private String ename; // 对应表中ename字段
private int job_id; // 对应表中job_id字段
private int mgr; // 对应表中mgr字段
private Date joindate; // 对应表中joindate字段
private BigDecimal salary; // 对应表中salary字段
private BigDecimal bonus; // 对应表中bonus字段
private int dept_id; // 对应表中dept_id字段
// 此处省略Getter和Setter方法
@Override
public String toString() {
return "Emp{" +
"id=" + id +
", ename='" + ename + '\'' +
", job_id=" + job_id +
", mgr=" + mgr +
", joindate=" + joindate +
", salary=" + salary +
", bonus=" + bonus +
", dept_id=" + dept_id +
'}';
}
}
(省略Alt+Insert
快速生成的Getter和Setter方法)
然后创建主启动类Demo05.java(含findAll方法),代码如下:
package day01;
import day01.domain.Emp;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class Demo05 {
public static void main(String[] args) {
List<Emp> list = findAll();
for (Emp emp : list) {
System.out.println(emp);
}
}
// 查询所有emp对象的方法
public static List<Emp> findAll(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
List<Emp> empList = null;
try {
// 1.注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 2.获取数据库连接对象
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbc_study", "root", "1234");
// 3.定义sql语句
String sql = "select * from emp;";
// 4.获取执行sql的对象Statement
statement = connection.createStatement();
// 5.执行sql
resultSet = statement.executeQuery(sql);
// 6.遍历结果集,封装对象,装载集合
empList = new ArrayList<>(); // 在循环前创建一个集合用来存储获取的emp对象
Emp emp = null; // 放在外面,减少内存
while (resultSet.next()){
// 获取数据
int id = resultSet.getInt("id");
String ename = resultSet.getString("ename");
int job_id = resultSet.getInt("job_id");
int mgr = resultSet.getInt("mgr");
Date joindate = resultSet.getDate("joindate");
BigDecimal salary = resultSet.getBigDecimal("salary");
BigDecimal bonus = resultSet.getBigDecimal("bonus");
int dept_id = resultSet.getInt("dept_id");
// 创建emp对象,并赋值给其成员变量
emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
// 装载集合
empList.add(emp);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 释放资源
// 这里的try-catch是为了避免空指针异常
if (statement!=null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection!=null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet!=null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
return empList;
}
}
执行结果如下:
这里给出数据库类型和Java数据类型对应如下:
类型名称 | 显示长度 | 数据库类型 | JAVA类型 | JDBC类型索引(int) |
---|---|---|---|---|
VARCHAR | L+N | VARCHAR | java.lang.String | 12 |
CHAR | N | CHAR | java.lang.String | 1 |
BLOB | L+N | BLOB | java.lang.byte[] | -4 |
TEXT | 65535 | VARCHAR | java.lang.String | -1 |
INTEGER | 4 | INTEGER UNSIGNED | java.lang.Long | 4 |
TINYINT | 3 | TINYINT UNSIGNED | java.lang.Integer | -6 |
SMALLINT | 5 | SMALLINT UNSIGNED | java.lang.Integer | 5 |
MEDIUMINT | 8 | MEDIUMINT UNSIGNED | java.lang.Integer | 4 |
BIT | 1 | BIT | java.lang.Boolean | -7 |
BIGINT | 20 | BIGINT UNSIGNED | java.math.BigInteger | -5 |
FLOAT | 4+8 | FLOAT | java.lang.Float | 7 |
DOUBLE | 22 | DOUBLE | java.lang.Double | 8 |
DECIMAL | 11 | DECIMAL | java.math.BigDecimal | 3 |
BOOLEAN | 1 | 同TINYINT | ||
ID | 11 | PK (INTEGER UNSIGNED) | java.lang.Long | 4 |
DATE | 10 | DATE | java.sql.Date | 91 |
TIME | 8 | TIME | java.sql.Time | 92 |
DATETIME | 19 | DATETIME | java.sql.Timestamp | 93 |
TIMESTAMP | 19 | TIMESTAMP | java.sql.Timestamp | 93 |
YEAR | 4 | YEAR | java.sql.Date | 91 |
JDBC工具类
从上述的[查询数据](#JDBC查询数据(JDBC select语句))例子中可以发现,有很多重复的代码。
所以我们试着抽取JDBC工具类:
目的:简化代码
分析:
-
抽取注册驱动
-
抽取一个方法来获取数据库连接对象
-
需求:在getConnection()方法中不想传递参数,同时还得保证工具类的通用性
-
解决:使用配置文件
在src文件夹下创建配置文件jdbc.properties文件,代码如下:
url=jdbc:mysql://localhost:3306/jdbc_study user=root password=1234 driver=com.mysql.jdbc.Driver
-
-
抽取一个方法来释放资源
例子:我们在创建util包下创建JDBCUtils.java类,代码如下:
package day01.util;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;
// JDBC工具类
public class JDBCUtils {
private static String url;
private static String user;
private static String password;
private static String driver;
// 文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
static {
// 读取资源文件,获取值
// 以下步骤具体可看反射笔记(https://www.qingbo1011.top/2021/01/22/%E5%8F%8D%E5%B0%84/#%E6%A1%88%E4%BE%8B)
try {
// 1.创建Properties集合类
Properties properties = new Properties();
// 2.加载文件
properties.load(new FileReader("src/jdbc.properties"));
// 3.获取数据,赋值
url = properties.getProperty("url");
user = properties.getProperty("user");
password = properties.getProperty("password");
driver = properties.getProperty("driver");
// 4.注册驱动
Class.forName(driver);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
// 获取连接对象
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection(url,user,password);
}
// 释放资源(有两种情况,需要重载方法)
public static void close(Statement statement, Connection connection){
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
public static void close(Statement statement, Connection connection, ResultSet resultSet){
if (statement != null){
try {
statement.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null){
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (resultSet != null){
try {
resultSet.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
}
在src文件夹下创建配置文件jdbc.properties文件,代码如下:
url=jdbc:mysql://localhost:3306/jdbc_study
user=root
password=1234
driver=com.mysql.jdbc.Driver
然后我们创建主启动类Demo04.java,代码如下:
package day01;
import day01.domain.Emp;
import day01.util.JDBCUtils;
import java.math.BigDecimal;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
public class Demo04 {
public static void main(String[] args) {
List<Emp> list = findAll();
for (Emp emp : list) {
System.out.println(emp);
}
}
// 查询所有emp对象的方法
public static List<Emp> findAll(){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
List<Emp> empList = null;
try {
// 1.注册驱动,获取数据库连接对象
connection = JDBCUtils.getConnection();
// 2.定义sql语句
String sql = "select * from emp;";
// 3.获取执行sql的对象Statement
statement = connection.createStatement();
// 4.执行sql
resultSet = statement.executeQuery(sql);
// 5.遍历结果集,封装对象,装载集合
empList = new ArrayList<>(); // 在循环前创建一个集合用来存储获取的emp对象
Emp emp = null; // 放在外面,减少内存
while (resultSet.next()){
// 获取数据
int id = resultSet.getInt("id");
String ename = resultSet.getString("ename");
int job_id = resultSet.getInt("job_id");
int mgr = resultSet.getInt("mgr");
Date joindate = resultSet.getDate("joindate");
BigDecimal salary = resultSet.getBigDecimal("salary");
BigDecimal bonus = resultSet.getBigDecimal("bonus");
int dept_id = resultSet.getInt("dept_id");
// 创建emp对象,并赋值给其成员变量
emp = new Emp();
emp.setId(id);
emp.setEname(ename);
emp.setJob_id(job_id);
emp.setMgr(mgr);
emp.setJoindate(joindate);
emp.setSalary(salary);
emp.setBonus(bonus);
emp.setDept_id(dept_id);
// 装载集合
empList.add(emp);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
// 释放资源
JDBCUtils.close(statement,connection,resultSet);
}
return empList;
}
}
执行结果和上述的[查询数据](#JDBC查询数据(JDBC select语句))例子的结果是一样的
JDBC登录案例
需求:
- 通过键盘录入用户名和密码
- 判断用户是否登录成功(用户名和密码存储在user表中)
现有user表如下:

JDBC工具类JDBCUtils.java和jdbc.properties配置文件同上JDBC工具类。
使用createStatement()来执行sql
创建主启动类Demo06.java代码如下:
package day01.util;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;
public class Demo06 {
public static void main(String[] args) {
// 1.键盘录入接受用户名和密码
Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = scanner.nextLine();
System.out.print("请输入密码:");
String password = scanner.nextLine();
// 2.调用方法
boolean flag = login(username, password);
if (flag){
System.out.println("登陆成功!");
}else {
System.out.println("登录失败!用户名或密码错误");
}
}
public static boolean login(String username, String password){
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
if (username==null || password==null){
System.out.println("用户名或密码不能为空!");
return false;
}else {
try {
// 1.获取连接
connection = JDBCUtils.getConnection();
// 2.定义sql语句
String sql = "select * from user where username = '"+username+"' and password = '"+password+"';";
// 3.获取执行sql的对象Statement
statement = connection.createStatement();
// 4.执行sql
resultSet = statement.executeQuery(sql);
// 5.判断
return resultSet.next(); // 如果有下一行则返回true
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(statement,connection,resultSet);
}
}
return false; // 如果出现异常则返回false
}
}
这里会出现一个问题,那就是sql注入。关于sql注入在上文已经给出说明了。直接来看一个例子:
为了解决sql注入的问题,我们使用prepareStatement(sql)来执行sql
使用prepareStatement(sql)来执行sql
创建主启动类Demo07.java代码如下:
package day01;
import day01.util.JDBCUtils;
import java.sql.*;
import java.util.Scanner;
public class Demo07 {
public static void main(String[] args) {
// 1.键盘录入接受用户名和密码
Scanner scanner = new Scanner(System.in);
System.out.print("请输入用户名:");
String username = scanner.nextLine();
System.out.print("请输入密码:");
String password = scanner.nextLine();
// 2.调用方法
boolean flag = login(username, password);
if (flag){
System.out.println("登陆成功!");
}else {
System.out.println("登录失败!用户名或密码错误");
}
}
public static boolean login(String username, String password){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
if (username==null || password==null){
System.out.println("用户名或密码不能为空!");
return false;
}else {
try {
// 1.获取连接
connection = JDBCUtils.getConnection();
// 2.定义sql语句
String sql = "select * from user where username = ? and password = ?;";
// 3.获取执行sql的对象Statement
preparedStatement = connection.prepareStatement(sql); // preparedStatement生成时需要传递sql
// 4.执行sql
resultSet = preparedStatement.executeQuery(); // preparedStatement执行时可以不传递sql
// 5.判断
return resultSet.next(); // 如果有下一行则返回true
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JDBCUtils.close(preparedStatement,connection,resultSet);
}
}
return false; // 如果出现异常则返回false
}
}
执行效果为:
在后续开发中我们都会使用PreparedStatement来完成增删改查
JDBC管理事务
关于事务的讲解,之前的笔记有讲到过。这里再简单说一下:
事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
相关操作:
- 开启事务
- 提交事务
- 回滚事务
在JDBC中,我们使用Connection对象来管理事务:
- 开启事务:
setAutoCommit(boolean autoCommit)
:要调用该方法则设置参数为false,即开启事务- 在执行sql之前开启事务
- 提交事务:
commit()
- 当所有sql都执行完提交事务
- 回滚事务:
rollback()
- try-catch中在catch块里回滚事务
例子:
我们有account表如下:
JDBC工具类中添加close的重载方法如下:
public static void close(Statement statement1, Statement statement2, Connection connection) {
if (statement1 != null) {
try {
statement1.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (statement2 != null) {
try {
statement2.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
}
配置文件同上
创建主启动类Demo09.java,代码如下:
package day01;
import day01.util.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class Demo08 {
public static void main(String[] args) {
Connection connection = null;
PreparedStatement preparedStatement1 = null;
PreparedStatement preparedStatement2 = null;
ResultSet resultSet = null;
try {
// 1.获取连接
connection = JDBCUtils.getConnection();
// a.开启事务
connection.setAutoCommit(false); // 参数设置为false即为开启事务
// 2.定义sql
// 2-1 转账方扣钱
String sql1 = "update account set balance = balance - ? where NAME = ?";
// 2-2 收账方扣钱
String sql2 = "update account set balance = balance + ? where NAME = ?";
// 3.获取执行sql对象
preparedStatement1 = connection.prepareStatement(sql1);
preparedStatement2 = connection.prepareStatement(sql2);
// 4.设置参数
preparedStatement1.setDouble(1,500);
preparedStatement1.setString(2,"zhangsan");
preparedStatement2.setDouble(1,500);
preparedStatement2.setString(2,"lisi");
// 5.执行sql
preparedStatement1.executeUpdate();
// 人为制造异常
int i = 1/0;
preparedStatement2.executeUpdate();
// b.提交事务
connection.commit();
} catch (Exception exception) { // 这里的异常要改为所有异常的父类Exception,因为不管发生什么异常,都需要事务回滚
// c.事务回滚
try {
if (connection!=null){ // 回滚前要先判断connection是否为空
connection.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
}
exception.printStackTrace();
} finally {
// 释放资源
JDBCUtils.close(preparedStatement1,preparedStatement2,connection); // 注意要在在上述JDBC工具类中添加相应的close的重载方法
}
}
}