zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    }
    
  • 相关阅读:
    私有构造函数(C# 编程指南)
    unshift(), push(),shift(),pop()函数的运用
    flex转载
    二叉树各节点的实现
    关于删除树中指定节点的实例分析
    树的各种操作代码实现
    关于二叉查找树的++迭代器的实现
    利用map,以一个单词为键,以与它相差一个字母的单词组集作为值的算法编程
    逆向单项链表的算法
    给Vector类添加insert
  • 原文地址:https://www.cnblogs.com/jing-an-feng-shao/p/9231941.html
Copyright © 2011-2022 走看看