JDBC百裡挑一

JDBC主題

  1. JDBC初出茅廬-建立數據庫連接 https://www.7benshu.com/post/2020/03/21-1/
  2. JDBC小試牛刀-數據庫操作 https://www.7benshu.com/post/2020/03/21-2/
  3. JDBC略有建樹-二進制操作 https://www.7benshu.com/post/2020/03/21-3/
  4. JDBC出類拔萃-數據庫批量操作 https://www.7benshu.com/post/2020/03/21-4/
  5. JDBC百裡挑一|數據庫事務 https://www.7benshu.com/post/2020/03/22-1/
  6. JDBC卓越超群-DAO https://www.7benshu.com/post/2020/03/22-2/


JDBC百裡挑一|數據庫事務


介紹

事務: 是一種機制,一個操作序列,它包含了一組數據庫操作命令, 並且把所有的命令作為一個整體一起向系統提交或撤銷操作請求, 即這一組數據庫命令要麼都執行,要麼都不執行. 因此事務, 是一個不可分割的工作邏輯單元,在數據庫系統上執行併發操作時,事務是作為最小的控制單元來使用的,它特別適用多用戶同時操作的數據庫系統

事務處理

  • 數據一旦提交,就不可回滾。
  • 數據什麼時候意味著提交?當一個連接對象被創建時,默認情況下是自動提交事務:每次執行一個 SQL 語句時,如果執行成功,就會向數據庫自動提交,而不能回滾。關閉數據庫連接,數據就會自動的提交。如果多個操作,每個操作使用的是自己單獨的連接,則無法保證事務。即同一個事務的多個操作必須在同一個連接下。
  • JDBC程序中為了讓多個 SQL 語句作為一個事務執行:調用 Connection 對象的 setAutoCommit(false); 以取消自動提交事務在所有的 SQL 語句都成功執行後,調用 commit(); 方法提交事務在出現異常時,調用 rollback(); 方法回滾事務

注意: 若此時 Connection 沒有被關閉,還可能被重複使用,則需要恢復其自動提交狀態 setAutoCommit(true)。尤其是在使用數據庫連接池技術時,執行close()方法前,建議恢復自動提交狀態。

案例:用戶A向用戶B轉賬1000

<code>package com.kid.jdbc.transaction;

import com.kid.util.JDBCUtils;
import org.junit.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

/**
* 事務測試類
*
* @author tangf
* @createTime 2020 /03/22 20:12:38
*/
public class TransactionTest {


   /**
    * 測試事務異常情況
    *
    * @author tangf
    * @createTime 2020 /03/22 20:12:38
    */
   @Test
   public void test1() {
       Connection conn = null;
       try {
           // 1.獲取數據庫連接
           conn = JDBCUtils.getConnection();
           // 2.開啟事務
           conn.setAutoCommit(false);
           // 3.進行數據庫操作
           String sql1 = "update user_table set balance = balance - 1000 where user = ?";
           update(conn, sql1, "A");

           // 模擬異常
           System.out.println(1 / 0);

           String sql2 = "update user_table set balance = balance + 1000 where user = ?";
           update(conn, sql2, "B");
           // 4.若沒有異常,則提交事務
           conn.commit();
      } catch (Exception e) {
           e.printStackTrace();
           // 5.若有異常,則回滾事務
           try {
               conn.rollback();
          } catch (SQLException e1) {
               e1.printStackTrace();
          }
      } finally {
           try {
               //6.恢復每次DML操作的自動提交功能
               conn.setAutoCommit(true);
          } catch (SQLException e) {
               e.printStackTrace();
          }
           //7.關閉連接
           JDBCUtils.closeResource(conn, null, null);
      }

  }

   /**
    * 更新數據
    *
    * @param conn the conn
    * @param sql the sql
    * @param args the args
    * @author tangf
    * @createTime 2020 /03/22 20:12:38
    */
   public void update(Connection conn, String sql, Object... args) {
       PreparedStatement ps = null;
       try {
           // 1.獲取PreparedStatement的實例 (或:預編譯sql語句)
           ps = conn.prepareStatement(sql);
           // 2.填充佔位符
           for (int i = 0; i < args.length; i++) {
               ps.setObject(i + 1, args[i]);
          }
           // 3.執行sql語句
           ps.execute();
      } catch (Exception e) {
           e.printStackTrace();
      } finally {
           // 4.關閉資源
           JDBCUtils.closeResource(null, ps);

      }
  }

}/<code>


事務的ACID屬性

事務是作為單個邏輯工作單位執行的一系列操作,一個邏輯工作單位必須有四個屬性

  1. 原子性(Atomicity) 原子性是指事務是一個不可分割的工作單位,事務中的操作要麼都發生,要麼都不發生。
  2. 一致性(Consistency) 事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。
  3. 隔離性(Isolation) 事務的隔離性是指一個事務的執行不能被其他事務干擾,即一個事務內部的操作及使用的數據對併發的其他事務是隔離的,併發執行的各個事務之間不能互相干擾。
  4. 持久性(Durability) 持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來的其他操作和數據庫故障不應該對其有任何影響。

併發問題

  • 對於同時運行的多個事務, 當這些事務訪問數據庫中相同的數據時, 如果沒有采取必要的隔離機制, 就會導致各種併發問題:髒讀: 對於兩個事務 T1, T2, T1 讀取了已經被 T2 更新但還沒有被提交的字段。之後, 若 T2 回滾, T1讀取的內容就是臨時且無效的。不可重複讀: 對於兩個事務T1, T2, T1 讀取了一個字段, 然後 T2 更新了該字段。之後, T1再次讀取同一個字段, 值就不同了。幻讀: 對於兩個事務T1, T2, T1 從一個表中讀取了一個字段, 然後 T2 在該表中插入了一些新的行。之後, 如果 T1 再次讀取同一個表, 就會多出幾行。
  • 數據庫事務的隔離性: 數據庫系統必須具有隔離併發運行各個事務的能力, 使它們不會相互影響, 避免各種併發問題。
  • 一個事務與其他事務隔離的程度稱為隔離級別。數據庫規定了多種事務隔離級別, 不同隔離級別對應不同的干擾程度, 隔離級別越高, 數據一致性就越好, 但併發性越弱。

四種隔離級別

  • 數據庫提供的4種事務隔離級別:

隔離級別描述READ UNCOMMITTED(讀未提交數據)允許事務讀取未被其他事務提交的變更,髒讀,不可重複讀和幻讀的問題都會出現READ COMMITED(讀已提交數據)只允許事務讀取已經被其他事務提條的變更,可以避免髒讀,但不可重複讀和幻讀問題任然可能出現REPEATABLE READ(可重複讀)確保事務可以多次從一個字段中讀取相同的值,在這個事務持續間,禁止其他事務對這個字段進行更新, 可以避免髒讀和不可重複讀,但幻讀的問題任然存在SERIALIZABLE(串行化)確保事務可以從一個表中讀取相同的行,在這個事務持續期間,禁止其他事務對該表執行插入,更新和刪除操作,所有併發問題都可以避免,但性能十分低下


  • Oracle 支持的 2 種事務隔離級別:READ COMMITED, SERIALIZABLE。 Oracle 默認的事務隔離級別為: READ COMMITED
  • MySQL 支持 4 種事務隔離級別。MySQL 默認的事務隔離級別為: REPEATABLE READ。

MySQL中設置隔離級別

  • 每啟動一個 mysql 程序, 就會獲得一個單獨的數據庫連接. 每個數據庫連接都有一個全局變量 @@tx_isolation, 表示當前的事務隔離級別。
  • 查看當前的隔離級別: SELECT @@tx_isolation;
  • 設置當前 mySQL 連接的隔離級別: set transaction isolation level read committed;
  • 設置數據庫系統的全局的隔離級別:set global transaction isolation level read committed;
  • 補充操作:創建mysql數據庫用戶:create user tom identified by '123';授予權限#授予通過網絡方式登錄的tom用戶,對所有庫所有表的全部權限,密碼設為123
    grant all privileges on *.* to tom@'%' identified by '123';

    #給tom用戶使用本地命令行方式,授予atguigudb這個庫下的所有表的插刪改查的權限。

    grant select,insert,delete,update on atguigudb.* to tom@localhost identified by '123';

總結

往往實際使用的過程中, 事務級別和表設計搭配使用的, 來滿足業務需求的核心點


分享到:


相關文章: