JDBC事务
JDBC的事务由Connection提供,默认是打开的。
要开启事务,则要关闭自动提交,
1 conn.setAutoCommit(false);
提交事务使用
1 conn.commit();
回滚事务使用
1 conn.rollback();
可以在某个位置设置一个保存点,回滚时只回滚到这个点,
1 try { 2 Savepoint sp = conn.setSavepoint(); 3 ... 4 } catch (SQLException e) { 5 conn.rollback(sp); 6 }
当Connection遇到一个未处理的SQLException异常时,系统会非正常退出,事务还是会自动回滚。但如果程序捕获了该异常,则需要在异常处理块中显示地回滚。
下面演示JDBC事务的基本用法,
1 package db; 2 3 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.IOException; 7 import java.sql.Connection; 8 import java.sql.DriverManager; 9 import java.sql.SQLException; 10 import java.sql.Statement; 11 import java.util.Properties; 12 13 public class TransactionTest { 14 private String driver; 15 private String url; 16 private String user; 17 private String pass; 18 public void initParam(String paramFile) throws FileNotFoundException, IOException, ClassNotFoundException { 19 //用Properties类加载属性文件 20 Properties prop = new Properties(); 21 prop.load(new FileInputStream(paramFile)); 22 driver = prop.getProperty("driver"); 23 url = prop.getProperty("url"); 24 user = prop.getProperty("user"); 25 pass = prop.getProperty("pass"); 26 Class.forName(driver); 27 } 28 public void insertInTransaction(String[] sqls) throws SQLException{ 29 try (Connection conn = DriverManager.getConnection(url, user, pass)) { 30 //关闭自动提交,即开启事务 31 conn.setAutoCommit(false); 32 try (Statement stmt = conn.createStatement()) { 33 for (String sql : sqls) { 34 stmt.executeUpdate(sql); 35 } 36 //提交事务 37 conn.commit(); 38 }catch (SQLException e) { 39 conn.rollback(); 40 System.out.println("Exception:"); 41 System.out.println(e.getMessage()); 42 } 43 } 44 } 45 public static void main(String[] args) throws FileNotFoundException, ClassNotFoundException, IOException, SQLException { 46 TransactionTest tt = new TransactionTest(); 47 tt.initParam("mysql.ini"); 48 String[] sqls = new String[] { 49 "insert into jdbc_test values (null, 'aaa','111')", 50 "insert into jdbc_test values (null, 'bbb', '222')", 51 "insert into jdbc_test values (null, 'ccc', '333')", 52 //下面这条sql会失败,因为已经存在主键为2的记录 53 "insert into jdbc_test values (2, 'ddd','444')" 54 }; 55 tt.insertInTransaction(sqls); 56 } 57 }
上面的第53行sql会引发SQLException异常, 因此前面三个insert都会被回滚, 程序执行如下,
1 Exception: 2 Duplicate entry '2' for key 'PRIMARY'
JDBC批量更新
使用批量更新时,多条sql语句将被作为同一批操作被同时收集,同时提交。
使用Statement收集sql的方法为
1 stmt.addBatch(sql1); 2 stmt.addBatch(sql1); 3 stmt.addBatch(sql1); 4 ...
同时执行所有sql的方法为执行Statement的executeBatch(). (JDK.8中如果执行影响记录太多,则可以用executeLargeBatch()方法)
stmt.executeBatch();
之后可以提交更新,为了达到批量更新的目的,程序应该在批量操作之前关闭自动提交,然后收集sql,当批量操作执行之后,提交事务,并恢复之前的自动提交模式。
关键代码如下,
1 public void insertInTransaction(String[] sqls) throws SQLException{ 2 try ( Connection conn = DriverManager.getConnection(url, user, pass)) { 3 //关闭自动提交,即开启事务 4 conn.setAutoCommit(false); 5 try(Statement stmt = conn.createStatement()) { 6 for (String sql : sqls) { 7 stmt.addBatch(sql); 8 } 9 stmt.executeBatch(); 10 //提交事务 11 conn.commit(); 12 } catch (SQLException e) { 13 conn.rollback(); 14 System.out.println("Exception:"); 15 System.out.println(e.getMessage()); 16 } finally { 17 conn.setAutoCommit(true); 18 } 19 } 20 }