数据库事务,一般包含多个SQL语句,具有ACID特性。
以下是维基百科给出的四个特性的解释:
- 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
- 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态的含义是数据库中的数据应满足完整性约束。
- 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行。
- 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。
以下是JDBC使用事务的示例:
package demo;
import org.junit.Test;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class TransactionExample {
private static final String USER = "root";
private static final String PASSWORD = "123456";
private static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/bank";
public Connection getConnection() throws ClassNotFoundException, SQLException {
Class.forName(JDBC_DRIVER);
return DriverManager.getConnection(DB_URL, USER, PASSWORD);
}
public void insert(Connection connection, String name, Long balance) throws SQLException {
PreparedStatement pstmt = null;
try {
pstmt = connection.prepareStatement("INSERT INTO user_balance(name, balance) VALUES(?, ?)");
pstmt.setString(1, name);
pstmt.setLong(2, balance);
int affectRowsNum = pstmt.executeUpdate();
System.out.println("影响的行数:" + affectRowsNum);
} finally {
if (pstmt != null) {
pstmt.close();
}
}
}
public void raiseException(boolean raise) {
if (raise) {
throw new RuntimeException("异常");
}
}
@Test
public void test01() throws SQLException, ClassNotFoundException {
Connection connection = getConnection();
connection.setAutoCommit(false);
insert(connection, "letian", 10000L);
}
@Test
public void test02() throws SQLException, ClassNotFoundException {
Connection connection = getConnection();
connection.setAutoCommit(false);
try {
insert(connection, "letian", 10000L);
insert(connection, "xiaosi", 10000L);
raiseException(true); // 产生一个异常
System.out.println("commit");
connection.commit();
} catch (Exception ex) {
System.out.println("rollback");
connection.rollback();
}
}
@Test
public void test03() throws SQLException, ClassNotFoundException {
Connection connection = getConnection();
connection.setAutoCommit(false);
try {
insert(connection, "letian", 10000L);
insert(connection, "xiaosi", 10000L);
raiseException(false); // 不产生异常
System.out.println("commit");
connection.commit();
} catch (Exception ex) {
System.out.println("rollback");
connection.rollback();
}
}
}
connection.setAutoCommit(false)
:开启事务。
connection.commit();
:提交事务。
connection.rollback();
回滚事务。
默认情况下 connection 的 autoCommit 属性为 true,可以理解为任何一个SQL的执行,都会马上生效,都是在一个事务里,这种是隐式的事务,不需要写rollback、commit的代码。
当通过connection.setAutoCommit(false)
开启事务后,必须要显式的进行 commit 或者 rollback。rollback 一般在出现异常时进行。
上面的示例代码中,test01
的写法是不对的,因为没有commit或者rollback,插入的数据不会存入MySQL。
test02
通过 raiseException(true);
抛出了一个异常,所以走不到commit
,而是走到了rollback
,插入的数据不会存入MySQL。
test03
会走到commit,会在数据库中插入两条数据。