免費錄播jdbc視頻
最全JDBC 視頻 https://ke.qq.com/course/280836#tuin=5740604a
事務
將一組業務作爲一個整體,所有的內容要麼全部成功,要麼全部不成功。那麼在數據庫當中 就是連續的sql執行
- 類似銀行取錢,要麼取出且扣款成功,要麼都不成功
- 或者轉賬(A賬號轉到B賬號 A扣款 B進賬都成功 要麼都失敗)
* 事務操作*
1. 開啓事務
2. 事務提交(全部成功)
3. 事務回滾(全部不成功)
事務的特性ACID(面試)
我們從上面的概念(要麼…,要麼…),就能概括出一些特性
1. 原子性:事務不可分割整體 (以前的物理中 原子不可分割 那麼應用到現在其他領域還表示這個事物不可分割)
2. 一致性:事務前後數據的一致。
3. 隔離性:事務的併發訪問 (一個用戶的事務不能被其它用戶的事務所幹擾,多個併發事務之間數據要相互隔離。)
4. 持久性:持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即使數據庫發生故障也不應該對其有任何影響。
事務的隔離性存在問題
1、 髒讀(Drity Read):一個事務讀到另一個事務未提交的更新數據
事務A修改了一個數據,但未提交,事務B讀到了事務A未提交的更新結果,如果事務A提交失敗,事務B讀到的就是髒數據。(A 往B卡種打100元 A還沒確認,這時候B卡已經讀到A卡打來的錢)2.不可重複讀(Non-repeatable read) :在一個事務中 連續讀取兩次,第二次讀取到另一個事務 已經提交update修改數據(update更新)
比如我一個事務中 我第一次查詢自己的賬戶是100元,然後在發出第二次查詢的sql之前 有人給我轉賬了100,這時候,第二次就查詢到了轉賬後的數據了3.虛讀(幻讀)Phantom Read) :一個事務 讀取 另一個事務已經提交的插入數據 (強調的是記錄條數的改變)
事務A新增了一條記錄,事務B在事務A提交前後各執行了一次查詢操作,發現後一次比前一次多了一條記錄。幻讀僅指由於併發事務增加記錄導致的問題,這個不能像不可重複讀通過記錄加鎖解決,因爲對於新增的記錄根本無法加鎖。需要將事務串行化,才能避免幻讀(insert錄入)
除了以上的問題還有
- 丟失更新:兩個事務同事修改數據,後提交的數據覆蓋了先提交事務的結果
丟失更新是兩個事務同時修改數據
事務的隔離級別
數據庫爲了解決事務的隔離性問題,提供了四種4中隔離級別(不是所有數據庫都支持這四種級別)
* 事務的隔離級別
* 讀未提交:read uncommitted ,存在所有問題
* 讀已提交:read committed,解決了髒讀問題,其他問題沒有解決
* 可重複讀:repeatable read ,解決了髒讀與不可重複讀問題,其他問題沒有解決
* 串行化:serializable,等價java同步代碼,單線程。解決所有問題 不准許兩個事務 同事操作一個目標數據 根本不存在併發,不存在併發問題
* 數據庫默認隔離級別
* mysql的默認值:repeatable read
* oracle的默認值:read committed
* 對比
* 性能: read uncommitted > read committed > repeatable read > serializable
* 安全: read uncommitted < read committed < repeatable read < serializable
丟失更新如何解決
悲觀鎖 和 樂觀鎖
1.悲觀鎖: 採用數據庫內部鎖機制,在一個事務操作數據時,爲數據加鎖,另一個事務無法操作
* 排它鎖 (寫鎖),數據庫中每張表只能添加一個排它鎖,排它鎖與其他鎖互斥
* 在修改數據時,自動添加排它鎖
* 在查詢數據時 添加排它鎖 select * from customers for update;
悲觀鎖解決丟失更新,效率問題 , 數據不能同時修改
hibernate中使用悲觀鎖
Customer customer = (Customer) session.load(Customer.class, 1,LockMode.UPGRADE); // MySQL
2.樂觀鎖 : 與數據庫鎖無關,在數據表中爲數據添加 版本字段,每次數據修改都會導致版本號+1
hibernate 爲Customer表 添加版本字段
1) 在customer類 添加 private Integer version; 版本字段
2) 在Customer.hbm.xml 定義版本字段
<!-- 定義版本字段 -->
<!-- name是屬性名 -->
<version name="version"></version>