1. 什么是事务?
在数据库操作中,事务(Transaction)是一组 SQL 语句的集合,这些语句作为一个整体执行,要么全部成功提交(Commit),要么全部回滚(Rollback)。事务的作用是保证数据库的完整性和一致性。
事务具有 ACID 特性:
-
原子性(Atomicity):事务中的操作要么全部完成,要么全部撤销。
-
一致性(Consistency):事务执行前后,数据库必须保持一致性。
-
隔离性(Isolation):多个事务之间互不影响。
-
持久性(Durability):事务提交后,数据永久存储。
2.相关方法:
-
JDBC 程序中当一个 Connection 对象创建时,默认情况下是自动提交事务:每次执行一个 SQL 语句时,如果执行成功,就会向数据库自动提交,而不能回滚。
-
JDBC 程序中为了让多个 SQL 语句作为一个整体执行,需要使用事务。
-
调用 Connection 的
setAutoCommit(false)
可以取消自动提交事务。 -
在所有的 SQL 语句都成功执行后,调用 Connection 的
commit()
方法提交事务。 -
在其中某个操作失败或出现异常时,调用 Connection 的
rollback()
方法回滚事务。
3.实例演示
3.1 创建数据库
CREATE TABLE Trans(
NAME VARCHAR(32) NOT NULL UNIQUE,
mount INT
)CHARACTER SET utf8;
插入数据:
INSERT INTO Trans VALUES('wangya',20000);
INSERT INTO Trans VALUES('xulei',10000);
查询得到:
3.2 演示:不用事务进行更新操作:
写一个测试方法:(该业务模拟2个客户间的转账):
package JDBC;
import org.junit.Test;
import untils.JDBCutils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Transaction_ {
@Test
public void Tran_without_tran() {
Connection connection = JDBCutils.getConnection();
String sql1 = "update Trans set mount =mount-1000 where name='王雅'";
String sql2 = "update Trans set mount =mount+1000 where name='xulei'";
PreparedStatement preparedStatement=null;
try {
preparedStatement = connection.prepareStatement(sql1); //自动提交业务
int i = preparedStatement.executeUpdate();
int a=1/0; //设置一个意外的报错,演示实际业务中的意外
preparedStatement = connection.prepareStatement(sql2);
int i1 = preparedStatement.executeUpdate();
} catch (SQLException e) {
throw new RuntimeException(e);
}finally {
JDBCutils.close(connection,preparedStatement,null);
}
}
执行结果:
数据库:
即一方收到转账,但另一方并未及时扣除。这也体现了事务在实际开发业务中的原子性,事务中的操作要么全部完成,要么全部撤销。
3.3 运用事务后的处理:
@Test
public void Tran_with_tran() {
Connection connection = null;
String sql1 = "update Trans set mount =mount-1000 where name='王雅'";
String sql2 = "update Trans set mount =mount+1000 where name='xulei'";
PreparedStatement preparedStatement=null;
try {
connection = JDBCutils.getConnection();
connection.setAutoCommit(false);
preparedStatement = connection.prepareStatement(sql1); //自动提交业务
int i = preparedStatement.executeUpdate();
// int a=1/0;
preparedStatement = connection.prepareStatement(sql2);
int i1 = preparedStatement.executeUpdate();
// 提交业务
connection.commit();
} catch (SQLException e) {
try {
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
throw new RuntimeException(e);
}finally {
JDBCutils.close(connection,preparedStatement,null);
}
}
在 JDBC 中,当 Connection
对象创建时,默认情况下事务是自动提交的,即每次执行一个 SQL 语句,如果执行成功,就会自动提交到数据库,无法回滚。
关闭自动提交模式:为了让多个 SQL 语句作为一个整体执行,需要手动管理事务。可以使用 setAutoCommit(false)
关闭自动提交模式:
connection.setAutoCommit(false);
回滚事务:如果某个 SQL 语句失败或者发生异常,可以调用 rollback()
方法撤销所有未提交的更改。
catch (SQLException e) {
try {
connection.rollback();
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
throw new RuntimeException(e);
提交事务:当所有 SQL 语句成功执行后,调用 commit()
方法提交事务,使修改永久生效。
// 提交业务
connection.commit();
数据库(错误发生,自动回滚到事务开始状态,不会自动提交业务):
4. 总结:
-
setAutoCommit(false)
关闭自动提交,确保事务生效。 -
使用
PreparedStatement
代替Statement
,提高性能并防止 SQL 注入。 -
commit()
提交事务,使所有更改永久生效。 -
rollback()
遇到异常时回滚事务,避免数据不一致。 -
finally
代码块中关闭资源,确保连接正确释放,避免资源泄漏。
通过事务管理和 PreparedStatement
结合,可以实现 安全、高效、可靠 的数据库操作,是实际开发中的常见模式。