前言
首先了解什么是事务:事务就是一组逻辑操作单元,是不可分割的(一般包括一个或多个 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); }
}
复制代码
评论