事务
基本介绍
- JDBC程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一个SQL语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
- JDBC程序中为了多个SQL语句作为一个整体执行,需要使用事务
- 调用Connection 的 setAutoCommit(false)可以取消自动提交事务
- 在所有的SQL语句都成功执行后,调用Connection 的 commit();方法提交事务
- 在其中某个操作失败或出现异常时,调用rollback();方法回滚事务
模拟JDBC账户转账(无事务回滚)
原表
运行代码
模拟id 100 用户向 id 200用户转账100元
package com.taotao.jdbc.transaction_;
import com.mysql.cj.protocol.Resultset;
import com.taotao.jdbc.utils.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@SuppressWarnings({"all"})
public class Transaction_ {
@Test
public void noTransaction(){
Connection connection = null;
String sql = "update account set money = money - 100 where id = 100";
String sql2 = "update account set money = money + 100 where id = 200";
PreparedStatement preparedStatement = null;
ResultSet set = null;
try {
connection = JDBCUtils.getConnection();
preparedStatement = connection.prepareStatement(sql);
preparedStatement.executeUpdate();
int i = 1 / 0;
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
JDBCUtils.close(null,preparedStatement,connection);
}
}
}
抛出异常
运行转账代码后的表
800减了100,但是1800并没有变成1900
结论
事务解决转账问题
代码
package com.taotao.jdbc.transaction_;
import com.taotao.jdbc.utils.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
@SuppressWarnings({"all"})
public class Transaction_ {
@Test
public void useTransaction(){
Connection connection = null;
String sql = "update account set money = money - 100 where id = 100";
String sql2 = "update account set money = money + 100 where id = 200";
PreparedStatement preparedStatement = null;
ResultSet set = null;
try {
connection = JDBCUtils.getConnection();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(sql);
preparedStatement.executeUpdate();
int i = 1 / 0;
preparedStatement = connection.prepareStatement(sql2);
preparedStatement.executeUpdate();
connection.commit();
} catch (Exception e) {
System.out.println("执行发生了异常,撤销执行的sql");
try {
connection.rollback();
} catch (SQLException ex) {
ex.printStackTrace();
}
e.printStackTrace();
} finally {
JDBCUtils.close(null,preparedStatement,connection);
}
}
}
结论
如果不报异常,那么双方转账成功,否则双方金钱都不会变化
得到connection后,直接调用setAutoCommit方法
只要catch住异常,就回滚
批处理
基本介绍
- 当需要成批插入或者更新记录时。可以采用Java的批量更新机制,这一机制允许多条语句一次性提交数据库批量处理。通常情况下比单独提交处理更有效率。
- JDBC的批处理语句包括下面方法:
- addBatch():添加需要批处理的SQL语句或参数
- executeBatch():执行批量处理语句
- clearBatch():清空批处理包的语句
- JDBC连接MySQL时,如果要使用批处理功能,请在url中加参数
- rewriteBatchedStatements = true
- 批处理往往和PreparedStatement一起搭配使用,可以减少编译次数,又减少运行次数,效率大大提高
未使用批处理(添加5000条数据)
代码案例
package com.taotao.jdbc.batch;
import com.taotao.jdbc.utils.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@SuppressWarnings({"all"})
public class Batch_ {
@Test
public void noBatch() throws SQLException {
Connection connection = JDBCUtils.getConnection();
String sql = "insert into admin values(?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
System.out.println("开始执行");
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++){
preparedStatement.setString(1,"tao" + i);
preparedStatement.setString(2,"666");
preparedStatement.executeUpdate();
}
long end = System.currentTimeMillis();
System.out.println("传统的sql耗时:" + (end - start));
JDBCUtils.close(null,preparedStatement,connection);
}
}
使用批处理(添加5000条数据)
代码案例
package com.taotao.jdbc.batch;
import com.taotao.jdbc.utils.JDBCUtils;
import org.junit.Test;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
@SuppressWarnings({"all"})
public class Batch_ {
@Test
public void Batch() throws SQLException {
Connection connection = JDBCUtils.getConnection();
String sql = "insert into admin values(?,?)";
PreparedStatement preparedStatement = connection.prepareStatement(sql);
System.out.println("开始执行");
long start = System.currentTimeMillis();
for (int i = 0; i < 5000; i++){
preparedStatement.setString(1,"tao" + i);
preparedStatement.setString(2,"666");
preparedStatement.addBatch();
if ((i + 1) % 1000 == 0){
preparedStatement.executeBatch();
preparedStatement.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println("批处理的sql耗时:" + (end - start));
JDBCUtils.close(null,preparedStatement,connection);
}
}
注意
-
配置文件添加
?rewriteBatchedStatements=true
结论
|