JDBC对事务的处理
-
什么是事务
在一条或多条DML语句执行时,确保同时成功或者同时失败
-
如何处理以上发生的情况
确保一组DML语句不中途提交,等所有指令执行完毕后统一提交
-
什么情况会出现自动提交
- DDL语句永远都是自动提交
- DML语句默认是自动提交,可以设置autocommit改变属性
- 数据库关闭连接,连接之前的操作自动提交
-
解决方案
先来看一下没有处理之前发生的情况
例子:A向B转账100元,如果程序中途报错,A的余额少100,但B的余额没有增加
@Test public void test1(){ String sqlA = "UPDATE user_table set balance = balance-100 where user = ? "; UpdateUtils.UpdateUtils(sqlA,"AA"); System.out.println(10/0); //模拟中途报错的情况 String sqlB = "UPDATE user_table set balance = balance+100 where user = ? "; UpdateUtils.UpdateUtils(sqlB,"BB"); System.out.println("转账成功"); }
我们来看一下UpdateUtils的实现
这里我们可以看到处理DML的语句流程是:创建连接——处理sql——关闭连接
public static int UpdateUtils(String sql,Object ...args){ Connection conn = null; PreparedStatement ps = null; int i = 0; try { conn = JDBCUtils.getConnection(); ps = conn.prepareStatement(sql); for (int j = 0; j < args.length; j++) { ps.setObject(j+1,args[j]); } i = ps.executeUpdate(); return i; } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeConnection(conn,ps); } return 0; }
上面提到关闭连接也会自动提交sql,所以需要对这个工具类进行改进
我们调用时将connection作为参数传入此工具类,再在外部执行关闭的操作
public static int UpdateUtilsWithTransaction(Connection conn,String sql,Object ...args){ PreparedStatement ps = null; int i = 0; try { ps = conn.prepareStatement(sql); for (int j = 0; j < args.length; j++) { ps.setObject(j+1,args[j]); } i = ps.executeUpdate(); return i; } catch (Exception e) { e.printStackTrace(); } finally { JDBCUtils.closeConnection(null,ps); } return 0; }
最后我们要关闭DML语句的自动提交
@Test public void test2(){ Connection conn = null; try { //1.创建连接 conn = JDBCUtils.getConnection(); //2.关闭自动提交 conn.setAutoCommit(false); String sqlA = "UPDATE user_table set balance = balance-100 where user = ? "; UpdateUtils.UpdateUtilsWithTransaction(conn,sqlA,"AA"); String sqlB = "UPDATE user_table set balance = balance+100 where user = ? "; UpdateUtils.UpdateUtilsWithTransaction(conn,sqlB,"BB"); System.out.println("转账成功"); //3.提交sql conn.commit(); } catch (Exception e) { e.printStackTrace(); try { //4.回滚sql conn.rollback(); } catch (SQLException throwables) { throwables.printStackTrace(); } } finally { try { //5.开启自动提交(此步骤用于之后的JDBC连接池技术) conn.setAutoCommit(true); } catch (SQLException throwables) { throwables.printStackTrace(); } //6.关闭连接 JDBCUtils.closeConnection(conn,null); } }
-
设置数据库的隔离级别
conn = JDBCUtils.getConnection(); conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);