1. 程式人生 > >mysql 多個select需要放入一個事務嗎?

mysql 多個select需要放入一個事務嗎?

from ali 臟讀 trac atom 設置 存在 .get ria

第一次寫博客,還請大家多多支持技術分享圖片



今天同事問了個問題:在多個select的時候,用不用放入同一個事務?

首先先看個例子:

[java] view plain copy print?
  1. public class JDBCClient {
  2. public static void main(String[] args) {
  3. Connection conn = null;
  4. try {
  5. Class.forName("com.mysql.jdbc.Driver");
  6. conn = DriverManager.getConnection("jdbc:mysql://localhost/test"
    ,"root","123456");
  7. if(conn != null) {
  8. //將本次會話的事務隔離級別設置為TRANSACTION_READ_COMMITTED,mysql默認的是REPEATABLE_READ
  9. conn.setTransactionIsolation(2);
  10. //關閉事務的自動提交
  11. conn.setAutoCommit(false);
  12. PreparedStatement ps = conn.prepareStatement("select student_no from student where student_id = 1 "
    );
  13. ResultSet rs = ps.executeQuery();
  14. while(rs.next()) {
  15. System.out.println(rs.getString(1));
  16. }
  17. //設置斷點,並將數據庫中執行 update student set student_no = ‘新的值‘ where student_id = 1;然後繼續執行
  18. System.out.println("-----------"
    );
  19. rs = ps.executeQuery();
  20. while(rs.next()) {
  21. //這裏打印出新賦值的值
  22. System.out.println(rs.getString(1));
  23. }
  24. //提交事務
  25. //conn.commit();
  26. }
  27. } catch (Exception e) {
  28. e.printStackTrace();
  29. if(conn != null) {
  30. try {
  31. conn.rollback();
  32. } catch (SQLException e1) {
  33. e1.printStackTrace();
  34. }
  35. }
  36. }
  37. }
  38. //註:如果應用mysql默認的事務隔離級別,則兩次打印出的內容一致;
  39. }

個人覺得多個select時,不用放入一個事務,select查詢本身不需要事務提交。而如果在修改數據時,不提交事務,則會修改失敗。select只是用來進行查詢操作,不需要事務回滾,因為select不會對數據庫的產生持久化的修改,沒有必要在數據發生不一致的時候進行回滾。如果要防止數據的不一致情況,可以通過修改事務的隔離級別實現。

事務:

事務的四大特性 (ACID) 1、原子性(Atomicity) 事務是一個不可分割的工作單位,事務中的操作要麽都發生,要麽都不發生。 2、一致性(Consistency)事務前後數據的完整性必須保持一致。 3、隔離性(Isolation)多個用戶並發訪問數據庫時,一個用戶的事務不能被其它用戶的事務所幹擾,多個並發事務之間的數據要相互隔離。 4、持久性(Durability)一個事務一旦被提交,它對數據庫中的數據改變就是永久性的。
事務的隔離級別: 多個線程開啟各自的事務操作數據庫中數據時,數據庫系統要負責隔離操作,以保證各個線程在獲取數據時的準確性。也就是說,隔離級別就是對對事務並發控制的等級。如果事務不考慮隔離性會引發以下問題: (1)臟讀: 指一個事務讀取了另外一個事務未提交的數據。比如 A 向 B 購買商品,如果 B 的事務隔離級別為最低的 read uncommitted,那麽當 A 執行了 update account set money=money+100 where name=‘B‘;以後並沒有提交數據的時候,B 進行了 select money from account where name=‘B‘;查詢賬戶的操作,由於 B 的事務隔離級別最低,所以導致了臟讀,讀取到了 A 沒有提交的數據,當 A 執行了 rollback 回滾命令以後,B 再查詢賬戶,就發現先前增加的 100 元消失了。為了避免臟讀,我們可以將事務的隔離級別設置為:read committed。 (2)不可重復讀: 在一個事務內讀取到了表中的某一行數據,多次讀取結果不同。不可重復讀和臟讀的區別是:臟讀是讀取前一事務未提交的數據,不可重復讀是重新讀取了前一個事務已提交的數據。比如還是剛才的情景,當 B 將自己的事務隔離級別設置了 read committed 時,可以避免臟讀,也就是別人沒有提交的數據是讀不到的。但是如果 A 將數據提交了,執行了 commit 命令後,B 在這個當前事務內再次查詢賬戶的時候,就發現賬戶多了 100 元,這種情況看似是符合邏輯的,但是我們這裏說到的不可重復讀是指在這個當前事務內,不可以發生兩次讀取操作結果不一致的可能性,我們要保證在一個事務中,我們多次從數據庫獲取的數據應該是一致的,這樣才能保證我們進行數據操作的可靠性。為了避免這個為題,我們可以將數據庫的事務隔離級別設置為:repeatable read,這樣就保證了在一個事務中,每次讀取到數據都是一致的。 (3)虛讀 ( 幻讀 ) 在一個事務內讀取到了別的事務插入的數據,導致前後讀取不一致。和不可重復讀的區別是:不可重復讀是讀取到了別人對表中的某一條記錄進行了修改,導致前後讀取的數據不一致。 虛讀是前後讀取到表中的記錄總數不一樣,讀取到了其它事務插入的數據。比如現在有 A 和 B 兩個應用程序,他們並發訪問了數據庫中的某一張表,假設表中有 3 條記錄,B 執行查詢操作, 第一次查詢表得到了 3 條記錄。此時 A 對表進行了修改,增加了一條記錄,當 B 再次查詢表的時候,發現多了一條數據。這種情況就造成了 B 的虛讀。但是虛讀是不一定每次都發生的,這種情況是不確定的。為了避免虛讀,我們可以將事務隔離級別設置為 serializable 如果設置成了這種級別,那麽數據庫就變成了單線程訪問的數據庫,導致性能降低很多。
四種隔離級別及特點:
隔離級別是否存在臟讀是否存在不可重復讀是否存在幻讀
Read UnCommit(未提交讀)YYY
Read Commit(提交讀)NYY
Repeated Reader(可重復讀)NNY
Serializable Reader(序列化讀)NNN

這裏有個事務隔離級別的例子,寫的很好:http://blog.163.com/mr_liuyong/blog/static/1234243762012511105645731/

mysql 多個select需要放入一個事務嗎?