使用了持久化框架几乎没有使用过原生的jdbc API ,发现原来使用jdbc API来实现事务也是很简单的。
数据库的链接connection具有一个属性autocommit,这个属性默认是true,作用是控制是否把执行的命令提交给数据库。一旦命令被提交就无法回滚数据库。
而我们实现事务的方式也是很简单,就是手动设置属性autocommit的值为false,等执行完全部命令之后再手动提交所有命令就可以了。
try (Connection connection = DriverManager.getConnection(url, username, password)) {
System.out.println("数据库链接成功!");
try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) {
String command = "insert into a_dept(name) values('1'),('2')";
int count = statement.executeUpdate(command);
System.out.println("受影响行数:" + count);
String selectSql = "select * from a_dept";
String updateSql = "update a_dept set name=? where id=?";
String insertSql = "insert into a_dept(name) values(?)";
try (ResultSet resultSet = statement.executeQuery(selectSql)) {
while (resultSet.next()) {
System.out.print("修改前id " + resultSet.getInt("id") + "的值是: ");
System.out.println(resultSet.getString("name"));
}
resultSet.beforeFirst();
connection.setAutoCommit(false);
while (resultSet.next()) {
PreparedStatement updateState = connection.prepareStatement(updateSql);
updateState.setString(1, "I am new" + resultSet.getInt("id"));
updateState.setInt(2, resultSet.getInt("id"));
updateState.executeUpdate();
}
// Savepoint savepoint = connection.setSavepoint();
PreparedStatement updateState = connection.prepareStatement(insertSql);
updateState.setString(1, "我是插入的");
updateState.executeUpdate();
try {
PreparedStatement updateStateFail = connection.prepareStatement(insertSql);
updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!");
updateStateFail.executeUpdate();
} catch (Exception e) {
connection.rollback();
System.err.println(e.getMessage());
}
connection.commit();
Statement newStatement = connection.createStatement();
ResultSet newSet = newStatement.executeQuery(selectSql);
System.out.println("打印出所有的值:");
while (newSet.next()) {
System.out.print(newSet.getInt("id") + ": ");
System.out.println(newSet.getString("name"));
}
}
}
}
贴运行结果:
红色字体就是报错的信息。我们可以发现,在这个结果集当中没有进行修改,也没有进行插入,所有的修改和插入命令因为插入操作的错误都被回滚了。
但是我们发现我们的修改操作和插入操作都被回滚了,这在一些情况下我们不希望所有的操作都被回滚,那么我们可以设置回滚的节点,设置回滚的节点也很简单,在想要的地方添加如下代码,
Savepoint savepoint = connection.setSavepoint();
那么就会在该地生成一个节点,回滚把这个节点作为参数传递给回滚的方法 rollback() ,那么回滚的时候会放过该节点之前的操作,需要注意的是节点使用完之后必须释放它。
结果如下(不要在意Id亲,我清了数据库了):
Connected to the target VM, address: '127.0.0.1:17576', transport: 'socket' 数据库链接成功! 受影响行数:2 修改前id 479的值是: 1 修改前id 480的值是: 2 Data truncation: Data too long for column 'name' at row 1 打印出所有的值: 479: I am new479 480: I am new480 Disconnected from the target VM, address: '127.0.0.1:17576', transport: 'socket'
简单吧:
最后附上使用节点回滚的全部代码,可以不看~:
try (Connection connection = DriverManager.getConnection(url, username, password)) { System.out.println("数据库链接成功!"); try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)) { String command = "insert into a_dept(name) values('1'),('2')"; int count = statement.executeUpdate(command); System.out.println("受影响行数:" + count); String selectSql = "select * from a_dept"; String updateSql = "update a_dept set name=? where id=?"; String insertSql = "insert into a_dept(name) values(?)"; try (ResultSet resultSet = statement.executeQuery(selectSql)) { while (resultSet.next()) { System.out.print("修改前id " + resultSet.getInt("id") + "的值是: "); System.out.println(resultSet.getString("name")); } resultSet.beforeFirst(); connection.setAutoCommit(false); while (resultSet.next()) { PreparedStatement updateState = connection.prepareStatement(updateSql); updateState.setString(1, "I am new" + resultSet.getInt("id")); updateState.setInt(2, resultSet.getInt("id")); updateState.executeUpdate(); } Savepoint savepoint = connection.setSavepoint(); PreparedStatement updateState = connection.prepareStatement(insertSql); updateState.setString(1, "我是插入的"); updateState.executeUpdate(); try { PreparedStatement updateStateFail = connection.prepareStatement(insertSql); updateStateFail.setString(1, "我是插入的,但是我太长了,所以我是插不进去的,会报错!"); updateStateFail.executeUpdate(); } catch (Exception e) { connection.rollback(savepoint);
connection.releaseSavepoint(savepoint); System.err.println(e.getMessage()); } connection.commit(); Statement newStatement = connection.createStatement(); ResultSet newSet = newStatement.executeQuery(selectSql); System.out.println("打印出所有的值:"); while (newSet.next()) { System.out.print(newSet.getInt("id") + ": "); System.out.println(newSet.getString("name")); } } } }