JDBC事务与批处理
一.事务
JDBC程序中当一个连接对象被创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
JDBC程序中为了让多个 SQL 语句作为一个事务执行:(重点)
- 调用 Connection 对象的 setAutoCommit(false); 以取消自动提交,并开启事务
- 在所有的 SQL 语句都成功执行后,调用 commit(); 方法提交事务
- 在其中某个操作失败或出现异常时,调用 rollback(); 方法回滚事务
- 若此时 Connection 没有被关闭, 则需要恢复其自动提交状态 setAutoCommit(true);
注意:
- 如果多个操作,每个操作使用的是自己单独的连接,则无法保证事务。
- 即同一个事务的多个操作必须在同一个连接下
实现方法:try…catch…finally…
- 1)设置该连接为手动提交:connection.setAutoCommit(false);
- 2)判断回滚还是提交:connection.rollback(); 或 connection.commit();
- 3)恢复自动提交:connection.setAutoCommit(true);
案例:
public class TestTransaction {
public static void main(String[] args){
Connection conn = null;
try {
//1、连接数据库
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:3306/test";
String user = "root";
String password = "123456";
conn = DriverManager.getConnection(url, user, password);
//2.设置手动提交
conn.setAutoCommit(false);
//3.执行增删改查
String sql1 = "update t_department set description = ? where did = ?";
PreparedStatement pst1 = conn.prepareStatement(sql1);
pst1.setObject(1, "挣大钱的");
pst1.setObject(2, 4);
int len1 = pst1.executeUpdate();
System.out.println(len1>0?"更新部门信息成功":"更新部门信息失败");
pst1.close();
String sql2 = "update t_employee set salary = salary + ? where did = ?";
PreparedStatement pst2 = conn.prepareStatement(sql2);
pst2.setObject(1, 20000);
pst2.setObject(2, 4);
int len2 = pst2.executeUpdate();
System.out.println(len2>0?"更新部门信息成功":"更新部门信息失败");
pst2.close();
//4.若成功执行到此步,则提交该事务
conn.commit();
}catch (Exception e) {
//5.若代码执行中间出现异常,则进行回滚操作
try {
if(conn!=null){
conn.rollback();
}
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally{
//6.最后,恢复连接的自动提交,并对已经开启的资源进行关闭
try {
if(conn!=null){
//恢复自动提交
conn.setAutoCommit(true);
//释放连接
conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
二.批处理
当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率。
JDBC的批量处理语句的常用方法:
- addBatch():添加需要批量处理的SQL语句或参数
- executeBatch():执行批量处理语句;
- clearBatch():清空批处理包的语句
注意:
1)JDBC连接MySQL时,如果要使用批处理功能,请再url中加参数?rewriteBatchedStatements=true
String url = "jdbc:mysql://localhost:3306/test?"
+ "rewriteBatchedStatements=true";
2)PreparedStatement作批处理插入时使用values(使用value没有效果)
通常我们会遇到两种批量执行SQL语句的情况:
1.多条SQL语句的批量处理
案例:
Statement st = conn.createStatement();
st.addBatch(sql1);
st.addBatch(sql2);
st.addBatch(sql3);
...
st.excuteBatch();
2.一个SQL语句的批量传参
案例:
public void useBatch()throws Exception{
Class.forName("com.mysql.jdbc.Driver");
//rewriteBatchedStatements=true开启批处理功能
String url = "jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true";
String user = "root";
String password = "123456";
Connection conn = DriverManager.getConnection(url, user, password);
String sql = "INSERT INTO t_department(dname,description) VALUES(?,?)";
PreparedStatement st = conn.prepareStatement(sql);
for(int i=1; i<=50000; i++){
st.setString(1, "测试部门" + i);
st.setString(2, "测试部门描述" + i);
//1.批处理添加
st.addBatch();
if(i%1000==0){
//2.批处理执行:每一千条
st.executeBatch();
//3.批处理清空
st.clear();
}
}
st.close();
conn.close();
}