隔离区别对待?如何捆绑?Java中的jdbc数据库事务及其隔离级别
文章目錄
- 一、數據庫事務簡介
- 二、JDBC事務處理
- 三、事務的ACID屬性
- 四、數據庫的隔離級別
- 五、設置隔離級別
 
一、數據庫事務簡介
事務:一組邏輯操作單元,使數據從一種狀態變換到另一種狀態。
事務處理(事務操作):保證所有事務都作為一個工作單元來執行,即使出現了故障,都不能改變這種執行方式。當在一個事務中執行多個操作時,要么所有的事務都被提交(commit),那么這些修改就永久地保存下來;要么數據庫管理系統將放棄所作的所有修改,整個事務回滾(rollback)到最初狀態。
為確保數據庫中數據的一致性,數據的操作應當是離散的邏輯單元:當它全部完成時,數據的一致性可以保持,而當這個單元中的一部分操作失敗,整個事務應全部視為錯誤,所有從起始點以后的操作應全部回退到開始狀態。
二、JDBC事務處理
數據一旦提交,就不可回滾。
數據什么時候意味著提交?
 ①當一個連接對象被創建時,默認情況下是自動提交事務:每次執行一個 SQL 語句時,如果執行成功,就會向數據庫自動提交,而不能回滾。
 ②關閉數據庫連接,數據就會自動的提交。如果多個操作,每個操作使用的是自己單獨的連接,則無法保證事務。即同一個事務的多個操作必須在同一個連接下。
JDBC程序中為了讓多個 SQL 語句作為一個事務執行:
 ①調用 Connection 對象的 setAutoCommit(false) 以取消自動提交事務
 ②在所有的 SQL 語句都成功執行后,調用 commit() 方法提交事務
 ③在出現異常時,調用 rollback() 方法回滾事務
若 Connection 沒有被關閉,還可能被重復使用,則需要恢復其自動提交狀態setAutoCommit(true)。尤其是在使用數據庫連接池技術時,執行close()方法前,建議恢復自動提交狀態。
案例:用戶AA向用戶BB轉賬100
測試類:
package jdbc;import utils.jdbcUtils;import java.sql.Connection; import java.sql.SQLException;/*** @Author: Yeman* @Date: 2022-01-30-16:04* @Description:*/ public class UpdateDate2 {public static void main(String[] args) {Connection conn = null;try {//獲取連接conn = jdbcUtils.getSqlConnection();//取消自動提交,開啟事務conn.setAutoCommit(false);//預編譯sql語句String sql1 = "update user_table set balance = balance - 100 where user = ?";jdbcUtils.updateDate(conn,sql1,"AA");//模擬網絡異常System.out.println(10 / 0);String sql2 = "update user_table set balance = balance + 100 where user = ?";jdbcUtils.updateDate(conn,sql2,"BB");//若沒有異常則提交conn.commit();} catch (Exception e) {e.printStackTrace();//若有異常則回滾try {conn.rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}finally {//恢復自動提交try {conn.setAutoCommit(true);} catch (SQLException e) {e.printStackTrace();}//關閉conn連接jdbcUtils.closeResource(conn,null);}} }工具類:
package utils;import java.io.InputStream; import java.sql.*; import java.util.Properties;/*** @Author: Yeman* @Date: 2022-01-12-14:34* @Description:操作數據庫的工具類*/ public class jdbcUtils {/*** @Description 獲取數據庫連接* @Param []* @return java.sql.Connection**/public static Connection getSqlConnection() throws Exception{//1、加載配置文件InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");Properties pros = new Properties();pros.load(is);//2、讀取配置信息String user = pros.getProperty("user");String password = pros.getProperty("password");String url = pros.getProperty("url");String driverClass = pros.getProperty("driverClass");//3、加載驅動Class.forName(driverClass);//4、獲取連接Connection conn = DriverManager.getConnection(url, user, password);return conn;}/*** @Description 關閉連接和Statement資源* @Param [conn, ps]* @return void**/public static void closeResource(Connection conn, Statement ps){try {if (ps != null) ps.close();} catch (SQLException e) {e.printStackTrace();}try {if (conn != null) conn.close();} catch (SQLException e) {e.printStackTrace();}}public static void closeResource(Connection conn, Statement ps, ResultSet res){try {if (ps != null) ps.close();} catch (SQLException e) {e.printStackTrace();}try {if (conn != null) conn.close();} catch (SQLException e) {e.printStackTrace();}try {if (res != null) res.close();} catch (SQLException e) {e.printStackTrace();}}/*** @Description 通用增刪改操作2.0* @Param* @return**/public static int updateDate(Connection conn, String sql, Object... args) {PreparedStatement ps = null;try {//預編譯sql語句,獲取PreparedStatement實例ps = conn.prepareStatement(sql);//填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i + 1, args[i]);}//執行操作return ps.executeUpdate(); //返回操作的字段數,沒有則為0} catch (Exception e) {e.printStackTrace();}finally {//關閉資源closeResource(null, ps);}return 0;} }三、事務的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 再次讀取同一個表,就會多出幾行。
數據庫事務的隔離性:數據庫系統必須具有隔離并發運行各個事務的能力,使它們不會相互影響,避免各種并發問題。
一個事務與其他事務隔離的程度稱為隔離級別。數據庫規定了多種事務隔離級別,不同隔離級別對應不同的干擾程度, 隔離級別越高, 數據一致性就越好,但并發性越弱。
Mysql 4種隔離級別:
 
Mysql 支持 4 種事務隔離級別,默認的事務隔離級別為: REPEATABLE READ。
五、設置隔離級別
案例:一個線程查詢,另一個線程更新,當更新的線程尚未提交時查詢的為初始的值,提交后查詢到的為更新后的值。(這里將隔離級別設置為READ_COMMITTED)
測試類:
package jdbc;import javabean.User; import utils.Query; import utils.jdbcUtils;import java.sql.Connection; import java.util.List;/*** @Author: Yeman* @Date: 2022-01-30-22:27* @Description:*/ public class TransactionTest {public static void main(String[] args) {//用于更新的線程TransactionThread transactionThread = new TransactionThread();Thread thread = new Thread(transactionThread);thread.start();//用于查詢的線程Connection conn = null;try {conn = jdbcUtils.getSqlConnection();String sql = "select user,password,balance from user_table where user = ?";//設置隔離級別為提交可讀conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);List<User> query1 = Query.Query(conn, User.class, sql, "CC");query1.forEach(System.out :: println);//延遲5秒后再次查詢Thread.sleep(5000);List<User> query2 = Query.Query(conn,User.class,sql,"CC");query2.forEach(System.out :: println);} catch (Exception e) {e.printStackTrace();}finally {jdbcUtils.closeResource(conn,null);}} }用于更新的線程類:
package jdbc;import utils.jdbcUtils;import java.sql.Connection;/*** @Author: Yeman* @Date: 2022-01-30-22:47* @Description:*/ public class TransactionThread implements Runnable{@Overridepublic void run() {Connection conn = null;try {conn = jdbcUtils.getSqlConnection();//取消自動提交conn.setAutoCommit(false);String sql = "update user_table set balance = ? where user = ?";jdbcUtils.updateDate(conn,sql,5000,"CC");//設置延遲3秒后再提交Thread.sleep(3000);conn.commit();} catch (Exception e) {e.printStackTrace();}finally {jdbcUtils.closeResource(conn,null);}} }工具類utils同上案例
測試結果:
 
總結
以上是生活随笔為你收集整理的隔离区别对待?如何捆绑?Java中的jdbc数据库事务及其隔离级别的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 消息称Meta重新开始招聘被裁员工 薪酬
- 下一篇: 微软 Win10 RP 19045.33
