JDBC 学习笔记(十一)—— JDBC 的事务支持

1. 事务

在关系型数据库中,有一个很重要的概念,叫做事务(Transaction)。它具有 ACID 四个特性:

  • A(Atomicity):原子性,一个事务是一个不可分割的工作单位,事务中包括的诸操作要么都做,要么都不做。
  • C(Consistency):一致性,事务必须是使数据库从一个一致性状态变到另一个一致性状态。
  • I(Isolation):隔离性,一个事务的执行不能被其他事务干扰。
  • D(Durability):持久性,,指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。

 

 

2. JDBC 的事务支持

在 JDBC 学习笔记(三)—— JDBC 常用接口和类,JDBC 编程步骤,我曾经提及,JDBC 是使用 Connection 来控制事务的。

Connection 默认使用自动提交策略,即关闭事务,这种情况下,每一条 SQL 语句一旦执行,就会立即提交到数据库,无法回滚。

Connection 提供了以下三个事务相关的接口:

// 关闭自动提交,开启事务
void setAutoCommit(boolean autoCommit) throws SQLException;

// 提交事务
void commit() throws SQLException;

// 回滚事务
void rollback() throws SQLException;

setAutoCommit(boolean autoCommit) 方法其实做了两件事情:

  • 更改提交策略
  • 开启事务
commit() 方法负责将一个事务内部的所有 SQL 语句一次性提交(全部执行,或者全部不执行)。
rollback() 方法负责回滚事务。
 
对于 rollback,有一点需要特别注意,如果系统遇到一个未处理的 SQLException,程序会自动回滚;反之,如果这个异常被捕获,则需要手动回滚。
 
例如,以下写法无需手动回滚:
try (Connection conn = Connector.getSqlConnection()) {
  conn.setAutoCommit(false);
  try (Statement stmt = conn.createStatement()) {
    stmt.executeUpdate(sql1);
    stmt.executeUpdate(sql2);
  }
  conn.commit();
} catch (SQLException e) {
  e.printStackTrace();
} 

 

而以下写法则不会自动回滚:

try (Connection conn = Connector.getSqlConnection()) {
    conn.setAutoCommit(false);
    try (Statement stmt = conn.createStatement()) {
        stmt.executeUpdate(sql1);
        stmt.executeUpdate(sql2);
    } catch (SQLException e1) {
        e1.printStackTrace();
    }
    conn.commit();
} catch (SQLException e) {
    e.printStackTrace();
}        

 

 

3. Savepoint

JDBC 另外提供了一个 Savepoint 接口,用来实现事务部分提交。

有时候,我们并不希望一个事务全部执行,或者全部不执行,可能会有这样的需求:

如果执行到某一步出错,回滚的时候返回之前开启事务之后的某一个点。

这时候就需要 Savepoint(这个和 Hiberbate 的隔离级别很类似)。

 

通过以下示例代码,在执行 sql3 的时候出错,但是由于在执行完 sql1 的时候使用了 Savepoint,所以第一条 SQL 语句的执行结果会保留到数据库中:

package com.gerrard.demo;

import com.gerrard.util.Connector;
import com.gerrard.util.DriverLoader;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement;

public final class SavePointDemo {

    public static void main(String[] args) {
        String sql1 = "INSERT INTO STUDENT (STUDENT_NAME, STUDENT_PASSWORD) VALUES ('Ramsey', '999999')";
        String sql2 = "INSERT INTO STUDENT (STUDENT_NAME, STUDENT_PASSWORD) VALUES ('Wilshere', '888888')";
        // Invalidate SQL
        String sql3 = "INSERT INTO STUDENT VALUES(1, 'Ramsey', '999999')";

        DriverLoader.loadSqliteDriver();
        try (Connection conn = Connector.getSqlConnection()) {
            conn.setAutoCommit(false);
            Savepoint save1 = null;
            try (Statement stmt = conn.createStatement()) {
                stmt.executeUpdate(sql1);
                save1 = conn.setSavepoint();
                stmt.executeUpdate(sql2);
                stmt.executeUpdate(sql3);
            } catch (SQLException e) {
                conn.rollback(save1);
            }
            conn.commit();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

 

posted @ 2018-06-27 00:59  Gerrard_Feng  阅读(371)  评论(0编辑  收藏  举报