JDBC 数据库事务


数据库事务,一般包含多个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,会在数据库中插入两条数据。



(本文完)


JDBC 教程