前言
首先了解什么是事务:事务就是一组逻辑操作单元,是不可分割的(一般包括一个或多个 DML 操作)。
举个例子:A 给 B 转账 100 元,那么在数据库中,A 的账户就要少 100,B 的账户就要多 100。如果在 A 转账之后(默认情况下,已经提交给数据库),由于程序出现异常中断,那么增加 B 账户余额的程序还没执行,这时,双方余额就出现了错误。我们知道,减少 A 余额操作和增加 B 余额操作这两个操作应该是都执行成功,或者其中一个失败的话,两个都要失败。这两个操作就是一个事务,是捆绑的。
解决方法:一个事务共用一个连接。事务执行完毕后,再关闭连接。也就是说,一个连接把一个事务所有的操作串起来。
数据一旦提交,就不可回滚。
哪些操作会导致数据的自动提交?
* 》DDL 操作一旦执行,都会自动提交。set autocommit = false 对于 DDL 操作是失效的。
* 》DML 操作,默认情况下,一旦执行就会自动提交,但是我们可以通过设置 set autocommit = false 的方式取消 DML 操作的自动提交。
* 》默认在关闭连接时,会自动提交数据。
考虑事务下的通用的增删改方法
// 考虑事务时通用的增删改----version 2.0
// 连接从外部传进来
public int update(Connection conn, String sql, Object ...args) {// sql语句中占位符的个数等于可变形参的个数
PreparedStatement ps = null;
try {
// 1.预编译
ps = conn.prepareStatement(sql);
// 2.填充占位符
for (int i = 0; i < args.length; i++) {
ps.setObject(i+1, args[i]);
}
// 3.执行
return ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
//4. 关闭资源时,不要把连接关闭,因此填写null
JDBC_Utils.closeResource(null,ps);
}
return 0;
}
复制代码
测试考虑事务时的通用增删改方法
@Test
public void testUpdateWithTx() {
Connection conn = null;
try {
// 获得一个连接
conn = JDBC_Utils.getConnection();
//1. 取消数据的自动提交功能
conn.setAutoCommit(false);
String sql_aa = "update user_table set balance = balance - 100 where user = ?";
int update_aa = update(conn, sql_aa, "AA");
// 模拟网络出现异常
System.out.println(10/0);
String sql_bb = "update user_table set balance = balance + 100 where user = ?";
int update_bb = update(conn, sql_bb, "BB");
System.out.println("转账成功");
// 2.提交数据
conn.commit();
} catch (Exception e) {
e.printStackTrace();
//3. 回滚数据
try {
conn.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
} finally {
// 结束后,再关闭连接
JDBC_Utils.closeResource(conn, null);
}
}
复制代码
评论