跳转到目录
事务概述
跳转到目录
JDBC完成转账功能(加入事务管理)
场景: tom 欠 jerry 1000元 使用2条update语句
1. tom-1000
2. jerry+1000
1.开启事务
2.执行sql语句,多条sql语句正常执行,没有出现问题,提交事务,把数据持久化到数据库
3.执行sql语句,多条sql语句执行过程中出现问题,回滚事务,把数据回退到开启事务之前的状态
4.关闭资源
与事务相关的方法,都定义在java.sql.Connection
接口中:
public void setAutoCommit(boolean flag)
: 将此连接的自动提交模式设置为给定状态flag。
参数:
boolean flag:
- 为 true 表示启用自动提交模式
- 为 false 表示禁用自动提交模式,手动提交,开启事务
public void commit()
: 提交事务,把数据持久化到数据库
void rollback()
: 取消在当前事务中进行的所有更改,回滚事务,把数据回退到开启事务之前的状态
步骤:
1. 获取连接Connection对象
2.Connection对象开启事务
3.Connection对象获取执行sql语句的Statement对象
4.定义2条sql语句(2条update语句:扣款,收款)
5.Statement对象执行sql语句,获取结果
6.如果sql语句正常执行,没有出现问题,提交事务
7.处理结果
8.如果sql语句执行过程中出现问题,回滚事务
9.关闭资源
伪代码:
try{
1.获取连接Connection对象
2.开启事务
con.setAutoCommit()
3.Connection对象获取执行sql语句的Statement对象
4.定义2条sql语句(2条update语句:扣款,收款)
5.Statement对象执行sql语句,获取结果
6.如果sql语句正常执行,没有出现问题,提交事务
con.commit;
7.处理结果
} catch(Exception e){
8.如果sql语句执行过程中出现问题,回滚事务
con.rollback;
} finally{
9.关闭资源
}
代码:
public class Jdbc_affairDemo8 {
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt1 = null;
PreparedStatement pstmt2 = null;
//1. 获取连接
try {
conn = JDBCUtils.getConnection();
// 建立连接后开启事务
conn.setAutoCommit(false);
//2. 定义sql
//2.1 张三 - 500
String sql1 = "update account set balance = balance - ? where id = ?";
//2.2 李四 + 500
String sql2 = "update account set balance = balance + ? where id = ?";
//3. 获取执行的sql对象
pstmt1 = conn.prepareStatement(sql1);
pstmt2 = conn.prepareStatement(sql2);
//4. 设置参数
pstmt1.setDouble(1, 500);
pstmt1.setInt(2, 1);
pstmt2.setDouble(1, 500);
pstmt2.setInt(2, 2);
//5. 执行sql
pstmt1.executeUpdate();
// 手动制造异常
int i = 3 / 0;
pstmt2.executeUpdate();
// 提交事务
conn.commit();
} catch (SQLException e) {
// 事务回滚
if (conn != null) {
try {
conn.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}
e.printStackTrace();
} finally {
JDBCUtils.close(pstmt1, conn);
JDBCUtils.close(pstmt2, null);
}
}
}
跳转到目录
使用DBUtils工具类
: 目的简化JDBC的开发步骤,不关心Connection连接对象如何获取,不关心事务管理的事情
Connection对象的方法名 | 描述 |
---|---|
conn.setAutoCommit(false) | 开启事务 |
new QueryRunner() | 创建核心类,不设置数据源(手动管理连接) |
query(conn , sql , handler, params ) 或update(conn, sql , params) | 手动传递连接, 执行SQL语句CRUD |
DbUtils.commitAndCloseQuietly(conn) | 提交并关闭连接,不抛异常 |
DbUtils.rollbackAndCloseQuietly(conn) | 回滚并关闭连接,不抛异常 |
QueryRunner核心类
public QueryRunner(): 可以直接创建对象,但是没有传递Connection连接对象
所以该对象调用方法,执行增删改查时,必须传Connection连接对象
public QueryRunner(DataSource ds) : 创建对象,必须传递连接池对象,创建QueryRunner对象时,传递连接池对象,执行增删改查的方法时,QueryRunner对象会从连接池获取连接对象,但是获取的是哪个连接对象,我们不知道,我们也看不见,所以我们不能完成事务管理的工作
步骤:
1.空参构造创建QueryRunner对象
2.获取连接对象
3.连接对象开启事务
4.QueryRunner对象执行sql语句获取结果
5.sql语句正常执行,提交事务,处理结果
6.sql语句出现问题,回滚事务
7.关闭资源
DBUtils中的工具类DbUtils,静态方法:
public static void commitAndCloseQuietly(Connection conn)
: 提交事务,关闭连接,内部进行try-catch异常处理public static void rollbackAndCloseQuietly(Connection conn)
: 回滚事务,关闭连接,内部进行try-catch异常处理public class Demo04Account {
public static void main(String[] args) {
Connection con = null;
try {
//1.空参构造创建QueryRunner对象
QueryRunner qr = new QueryRunner();
//2.获取连接对象
con = C3P0Util.getConnection();
//3.连接对象开启事务
con.setAutoCommit(false);
//定义2条sql语句(2条update语句:扣款,收款)
String tomSql = "update account set money=money-? where name=?";
String jerrySql = "update account set money=money+? where name=?";
//4.QueryRunner对象执行sql语句获取结果
int tomResult = qr.update(con, tomSql, 1000, "tom");
System.out.println(1/0);//出异常了
int jerryResult = qr.update(con, jerrySql, 1000, "jerry");
//5.sql语句正常执行,提交事务,处理结果
DbUtils.commitAndCloseQuietly(con);//提交事务,关闭连接,内部进行try-catch异常处理
if(tomResult>0) {
System.out.println("tom账户成功扣款1000元~~~");
} else {
System.out.println("tom账户扣款1000元失败~~~");
}
if(jerryResult>0) {
System.out.println("jerry账户收款1000元成功~~~");
} else {
System.out.println("jerry账户收款1000元失败~~~");
}
} catch (Exception e) {
e.printStackTrace();
//6.sql语句出现问题,回滚事务
DbUtils.rollbackAndCloseQuietly(con);//回滚事务,关闭连接,内部进行try-catch异常处理
}
}