当事务所包含的全部数据库操作都成功执行后,应该提交事务,使这些修改永久生效。
事务提交有两种方式:显示提交和自动提交。显示提交:使用commit提交 自动提交:执行DLL或DCL,或者程序正常退出 当事务包含的任意一个数据库操作执行失败后,应该回滚(rollback)事务,使该事务中所作的修改全部失效。事务的回滚方式有两种:显示回滚和自动回滚。显示回滚:使用rollback 自动回滚:系统错误或强行退出 二、 JDBC的事务的支持 JDBC的Connection也支持事务,Connection默认打开自动提交,即关闭事务。 也就是说,每条SQL语句执行就会立即提交到数据库,永久生效,无法对其进行操作。 关闭Connection的自动提交,开启事务。Connection的setAutoCommit方法即可:connection.setAutoCommit(false); 通过connection.getAutoCommit()来获取事务的模式。 当我们开启事物后,在当前Connection中完成的数据库操作,都不会立即提交到数据库,需要调用Connection的commit方法才行。 如果有语句执行失败,可以调用rollback来回滚。 注意:如果Connection遇到未处理的SQLException异常时,系统将非正常退出,系统会自动回滚该事务。如果程序捕捉了该异常,则需要在异常处理中显示回滚事务。 Connection提供了设置事务中间保存点的方法:setSavepoint,有2个方法可以设置中间点: Savepoint setSavepoint():在当前事务中创建一个未命名的中间点,并返回该中间点的Savepoint对象。 Savepoint setSavepoint(String name):当前事务中创建一个具有指定名称的中间点,并返回该中间点的Savepoint对象 通常setSavepoint(String name)设置中间点的名称,事务回滚并不是通过中间点的名称进行回滚的,而是根据中间点对象进行回滚的。 设置名称只是更好的区分中间点对象,用Connection的rollback(Savepoint savepoint)方法即可完成回滚到指定中间点。
public class TransactionTest{ private String driver; private String url; private String user; private String pass; public void initParam(String paramFile)throws Exception { // 使用Properties类来加载属性文件 Properties props = new Properties(); props.load(new FileInputStream(paramFile)); driver = props.getProperty("driver"); url = props.getProperty("url"); user = props.getProperty("user"); pass = props.getProperty("pass"); } public void insertInTransaction(String[] sqls) throws Exception { // 加载驱动 Class.forName(driver); try( Connection conn = DriverManager.getConnection(url , user , pass)) { // 关闭自动提交,开启事务 conn.setAutoCommit(false); try( // 使用Connection来创建一个Statment对象 Statement stmt = conn.createStatement()) { // 循环多次执行SQL语句 for (String sql : sqls) { stmt.executeUpdate(sql); } } // 提交事务 conn.commit(); } } public static void main(String[] args) throws Exception { TransactionTest tt = new TransactionTest(); tt.initParam("mysql.ini"); String[] sqls = new String[]{ "insert into student_table values(null , 'aaa' ,1)", "insert into student_table values(null , 'bbb' ,1)", "insert into student_table values(null , 'ccc' ,1)", // 下面这条SQL语句将会违反外键约束, // 因为teacher_table中没有ID为5的记录。 "insert into student_table values(null , 'ccc' ,5)" //① }; tt.insertInTransaction(sqls); }}三、 JDBC的批量更新 批量更新就是可以同时进行多条SQL语句,将会被作为一批操作被同时执行、同时提交。 批量更新需要得到数据底层的支持,可以通过调研DataBaseMetaData的supportsBatchUpdates方法来查看底层数据库是否支持批量更新。 批量更新也需要创建一个Statement对象,然后通过该对象的addBatch方法将多条SQL语句同时收集在一起, 然后通过Statement对象的executeBatch同时执行这些SQL语句,如下代码: Statement sm = conn.createStatement(); sm.addBatch(sql); sm.addBatch(sql2); sm.addBatch(sql3); … //同时执行多条SQL语句 sm.executeBatch(); 执行executeBatch将返回一个int[]的数组,因为使用Statement执行DDL、DML都将返回一个int的值, 而执行多条DDL、DML也将返回一个int数组。批量更新中不允许出现select查询语句,一旦出现程序将出现异常。 如果要批量更新正确、批量完成,需要用单个事务,如果批量更新过程中有失败,则需要用事务回滚到原始状态。 如果要达到这样的效果,需要关闭事务的自动提交,当批量更新完成再提交事务,如果出现异常将回滚事务。 然后将连接恢复成自动提交模式。
public int[] executeBatch(String[] sql) throws SQLException { int[] result = null; conn = DBHelper.getConnection(); try { //获得当前Connection的提交模式 boolean autoCommit = conn.getAutoCommit(); //关闭自动提交模式 conn.setAutoCommit(false); sm = conn.createStatement(); for (String s : sql) { sm.addBatch(s); } //执行批量更新 result = sm.executeBatch(); //提交事务 conn.commit(); //还原提交模式 conn.setAutoCommit(autoCommit); } catch (Exception e) { e.printStackTrace(); conn.rollback(); } finally { if (sm != null) { sm.close(); } DBHelper.close(); } return result;}
想了解JDBC的总结,可查看这篇文章: