JDBC 學習筆記(二)—— 大數據+存儲過程+批處理+事務管理

 

 

本文查閱方法:
    一、查閱目錄 —— 查閱本文目錄,肯定想要查閱的目錄標題
    二、快捷「查找」 —— 在當前瀏覽器頁面,按鍵 「Ctrl+F」 按鍵組合,開啓瀏覽器的查找功能,
             在查找搜索框中 輸入須要查閱的 目錄標題,即可以直接到達 標題內容 的位置。
    三、學習小結 —— 文中的學習小結內容,是筆者在學習以後總結出的,開發時可直接參考其進行應用開發的內容, 進一步加快了本文的查閱 速度。(水平有限,僅供參考。)
 java

 


 

  

 

本文目錄mysql

 

      學習小結sql

 

      一、使用JDBC處理大數據數據庫

 

      二、使用JDBC處理大文本瀏覽器

 

      三、使用JDBC處理二進制數據併發

 

      四、Oracle中大數據處理oracle

 

      五、使用JDBC進行批處理框架

 

      六、採用Statement.addBatch(sql)方式實現批處理的優缺點函數

 

      七、實現批處理的第二種方式:PreparedStatement.addBatch() 學習

 

      八、採用PreparedStatement.addBatch()實現批處理的優缺點

 

      九、得到MySQL數據庫自動生成的主鍵

 

      十、JDBC調用存儲過程

 

      十一、事務的概念

 

      十二、JDBC控制事務語句

 

      1三、事務的四大特性(ACID)

 

      1四、事務的隔離級別

 

      1五、事務的隔離性可避免問題—— 髒讀:

 

      1六、事務的隔離性可避免問題—— 不可重複讀

 

      1七、事務的隔離性可避免問題—— 虛讀(幻讀)

 

      1八、事務隔離性的設置語句

 

      1九、在MySQL客戶端窗口界面演示事務的四種隔離級別。 

 

 

 

相關學習

 

JDBC 學習筆記(一)—— 基礎知識 + 分頁技術

      連接地址:http://even2012.iteye.com/blog/1886946

 

JDBC 學習筆記(二)—— 大數據+存儲過程+批處理+事務

      連接地址:http://even2012.iteye.com/blog/1886950

 

JDBC 學習筆記(三)—— 數據源(數據庫鏈接池):DBCP數據源、C3P0 數據源以及自定義數據源技術

      連接地址:http://even2012.iteye.com/blog/1886953

 

JDBC 學習筆記(四)—— 自定義JDBC框架+Apache—DBUtils框架+事務管理+操做多表  

      連接地址:http://even2012.iteye.com/blog/1886956

 

 

 

 


 

 

 

 

 

 學習小結

 

 

 

 

 

 

 


 

 

 

一、使用JDBC處理大數據

 

    在實際開發中,程序須要把大文本或二進制數據保存到數據庫。

 

     

 

    基本概念:大數據也稱之爲LOB(Large Objects),LOB又分爲:clob和blob

 

        (a)clob用於存儲大文本。(mysql 中採用Text)

 

        (b)blob用於存儲二進制數據,例如圖像、聲音、二進制文等。

 

     

 

    對MySQL而言只有blob,而沒有clob,mysql存儲大文本採用的是Text,其體系中的Text和blob分別又分爲:

 

           (a)Text ——TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT

 

           (b)blob ——TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB

 

 

 


 

 

 

二、使用JDBC處理大文本

 

    (1) 保存數據—— 對於MySQL中的Text類型,可調用以下方法設置:

 

            PreparedStatement.setCharacterStream(i, reader, length);

 

            //注意length長度須設置,而且設置爲int型

 

     

 

    (2) 獲取數據—— 對於MySQL中的Text類型,可調用以下方法獲取:

 

            (a) reader = resultSet. getCharacterStream(i);

 

            (b) reader = resultSet.getClob(i).getCharacterStream();

 

            (c) string s = resultSet.getString(i);

 

        

 

Demo樣例:

 

public class Demo1 { 

 

  /**讀寫大文本 

 

   create table testclob

 

   (

 

         id varchar(40) primary key,

 

         resume text

 

   ); 

 

   */ 

 

  @Test

 

  public void insert() throws SQLException, FileNotFoundException{ 

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null;

 

     

 

        try{

 

                  conn = JdbcUtils.getConnection();

 

                  String sql = "insert into testclob(id,resume) values(?,?)";

 

                  st = conn.prepareStatement(sql);

 

                  st.setString(1, "1");

 

             

 

                  File file = new File("src/1.txt");

 

                  FileReader reader = new FileReader(file);

 

                  st.setCharacterStream(2, reader, (int) file.length());

 

                  int num = st.executeUpdate();

 

                  if(num>0){

 

                            System.out.println("插入成功!!");

 

                  }

 

        }finally{

 

                  JdbcUtils.release(conn, st, rs);

 

        }

 

  }

 

 

 

  @Test

 

  public void read() throws SQLException, IOException{

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null; 

 

        try{

 

              conn = JdbcUtils.getConnection();

 

              String sql = "select id,resume from testclob where id='1'";

 

              st = conn.prepareStatement(sql);

 

              rs = st.executeQuery();

 

              if(rs.next()){

 

                    //String resume = rs.getString("resume");

 

                    Reader reader = rs.getCharacterStream("resume");

 

                    FileWriter writer = new FileWriter("c:\\1.txt");

 

                    try {

 

                          int len = 0;

 

                          char buffer[] = new char[1024];

 

                          while ((len = reader.read(buffer)) > 0) {

 

                            writer.write(buffer, 0, len);

 

                          }

 

                    } finally {

 

                          if (reader != null) {

 

                                reader.close();

 

                          }

 

                          writer.close();

 

                    }

 

              }

 

        }finally{

 

              JdbcUtils.release(conn, st, rs);

 

        }

 

  }

 

}

 

 

 

 

 


 

 

 

三、使用JDBC處理二進制數據

 

    (1) 保存數據—— 對於MySQL中的BLOB類型,可調用以下方法設置:

 

            PreparedStatement. setBinaryStream(i , inputStream, length);

 

     

 

    (2) 獲取數據—— 對MySQL中的BLOB類型,可調用以下方法獲取:

 

           (a)  InputStream in  = resultSet.getBinaryStream(i);

 

           (b) InputStream in  = resultSet.getBlob(i).getBinaryStream();

 

         

 

Demo樣例:

 

public class Demo2 {

 

  /*

 

   create table testblob

 

   (

 

     id varchar(40) primary key,

 

     image blob

 

   ); 

 

   */  

 

  @Test

 

  public void insert() throws SQLException, FileNotFoundException{

 

    Connection conn = null;

 

    PreparedStatement st = null;

 

    ResultSet rs = null;

 

    try{

 

      conn = JdbcUtils.getConnection();

 

      String sql = "insert into testblob(id,image) values(?,?)";

 

      st = conn.prepareStatement(sql);

 

      st.setString(1, "1");

 

      File file = new File("src/1.jpg");

 

      FileInputStream in = new FileInputStream(file);

 

      st.setBinaryStream(2, in, (int) file.length());

 

      st.executeUpdate();

 

    }finally{

 

      JdbcUtils.release(conn, st, rs);

 

    }

 

  }

 

 

 

  @Test

 

  public void read() throws SQLException, IOException{

 

    Connection conn = null;

 

    PreparedStatement st = null;

 

    ResultSet rs = null;

 

    try{

 

      conn = JdbcUtils.getConnection();

 

      String sql = "select id,image from testblob where id='1'";

 

      rs = conn.prepareStatement(sql).executeQuery();

 

      if(rs.next()){

 

        InputStream in = rs.getBinaryStream("image");

 

        OutputStream out = new FileOutputStream("c:\\1.jpg");;

 

        try {

 

          int len = 0;

 

          byte buffer[] = new byte[1024];

 

          while ((len = in.read(buffer)) > 0) {

 

            out.write(buffer, 0, len);

 

          }

 

        } finally {

 

          if (in != null)

 

            in.close();

 

          if (out != null)

 

            out.close();

 

        }

 

      }

 

    }finally{

 

      JdbcUtils.release(conn, st, rs);

 

    }

 

  }

 

}

 

 

 


 

 

 

四、Oracle中大數據處理

 

        Oracle定義了一個BLOB字段用於保存二進制數據,但這個字段並不能存放真正的二進制數據,只能向這個字段存一個指針,而後把數據放到指針所指向的Oracle的LOB段中, LOB段是在數據庫內部表的一部分。

 

        於是在操做Oracle的Blob以前,必須得到指針(定位器)才能進行Blob數據的讀取和寫入。

 

        如何得到表中的Blob指針呢? 能夠先使用insert語句向表中插入一個空的blob(調用oracle的函數empty_blob()  ),這將建立一個blob的指針,而後再把這個empty的blob的指針查詢出來,這樣就可獲得BLOB對象,從而讀寫blob數據了。

 

 

 

    Oracle中LOB類型的處理步驟

 

    (1)  插入空blob ——  insert into test(id,image) values(?,empty_blob());

 

    (2)  得到blob的cursor ——  select image from test where id= ? for update;  

 

                                                      Blob b = rs.getBlob(「image」);

 

        注意:  須加for update,鎖定該行,直至該行被修改完畢,保證不產生併發衝突。

 

    (3)  利用 io,和獲取到的cursor往數據庫讀寫數據

 

        注意:以上操做需開啓事務。

 

    備註:本文關於Oracle中LOB類型數據處理的操做僅供參考,詳細內容參見 有關Oracle的博文。

 

 

 


 

 

 

五、使用JDBC進行批處理

 

    業務場景:當須要向數據庫發送一批SQL語句執行時,應避免向數據庫一條條的發送執行,而應採用JDBC的批處理機制,以提高執行效率。

 

    實現批處理有兩種方式,

 

            第一種方式: Statement.addBatch(sql) (實際上是將sql語句 放在了一個 list 集合中。)

 

            第二種方式:  PreparedStatement.addBatch() (實際上是將sql語句 放在了一個 list 集合中。)

 

    執行批處理SQL語句

 

            executeBatch()方法:執行批處理命令

 

            clearBatch()方法:清除批處理命令(其實是清除 List集合中的SQL語句,不然會形成內存溢出。)

 

 

 

    Demo樣例:第一種方式:Statement.addBatch(sql)

 

 @Test
 public void test1() throws SQLException{

 

            Connection conn = null;

 

            Statement st = null;

 

            ResultSet rs = null;

 

            try {

 

                    conn = JdbcUtil.getConnection();

 

                    String sql1 = "insert into user(name,password,email,birthday)  values('kkk','123','abc@sina.com','1978-08-08')";

 

                    String sql2 = "update user set password='123456' where id=3";

 

                    st = conn.createStatement();

 

                    st.addBatch(sql1);  //把SQL語句加入到批命令中

 

                    st.addBatch(sql2);  //把SQL語句加入到批命令中

 

                    st.executeBatch();

 

                    st.clearBatch();

 

            } finally{

 

                 JdbcUtil.free(conn, st, rs);

 

            }

 

 }

 

 

 


 

 

 

六、採用Statement.addBatch(sql)方式實現批處理的優缺點

 

        優勢:能夠向數據庫發送多條不一樣的SQL語句。

 

        缺點:SQL語句沒有預編譯。當向數據庫發送多條語句相同,但僅參數不一樣的SQL語句時,需重複寫上不少條SQL語句。

 

            例如:

 

               Insert into user(name,password) values(‘aa’,’111’);

 

               Insert into user(name,password) values(‘bb’,’222’);

 

               Insert into user(name,password) values(‘cc’,’333’);

 

               Insert into user(name,password) values(‘dd’,’444’);

 

         

 


 

 

 

七、實現批處理的第二種方式:PreparedStatement.addBatch() 

 

    Demo樣例:第二種 方式

 

 @Test
 public void test2() throws SQLException{

 

        conn = JdbcUtil.getConnection();

 

        String sql = "insert into user(name,password,email,birthday) values(?,?,?,?)";

 

        st = conn.prepareStatement(sql);

 

        for(int i=0;i<50000;i++){

 

                st.setString(1, "aaa" + i);

 

                st.setString(2, "123" + i);

 

                st.setString(3, "aaa" + i + "@sina.com");

 

                st.setDate(4,new Date(1980, 10, 10));

 

                 

 

                st.addBatch();

 

                if(i%1000==0){      //爲防止(list集合) 內存溢出:設定每累加1000條數據就向數據庫發送一次

 

                        st.executeBatch();

 

                        st.clearBatch();

 

                }

 

        }

 

        st.executeBatch(); //當剩餘的條數小於1000條時就不會被髮送到數據庫,因此此處要在發送一次。

 

 

 

 


 

 

 

八、採用PreparedStatement.addBatch()實現批處理的優缺點

 

    優勢:發送的是預編譯後的SQL語句,執行效率高。

 

    缺點:只能應用在SQL語句相同,但參數不一樣的批處理中。所以此種形式的批處理常常用於在同一個表中批量插入數據,或批量更新表的數據。

 

 

 


 

 

 

九、得到MySQL數據庫自動生成的主鍵

 

    示例:

 

        Connection conn = JdbcUtil.getConnection(); 

 

        String sql = "insert into user(name,password,email,birthday)  values('abc','123','abc@sina.com','1978-08-08')";

 

                                                              //重載函數:返回生成的自動主鍵

 

        PreparedStatement st = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS );         

 

        st.executeUpdate();

 

 

 

        ResultSet rs = st.getGeneratedKeys();  //獲得插入行的主鍵

 

        if(rs.next())

 

             System.out.println(rs.getObject(1));

 

    注:此參數僅對insert操做有效。

 

 

 

 Demo樣例: 

 

public class Demo4 { 

 

  /**

 

   獲取自動生成的主鍵

 

   create table test

 

   (

 

         id int primary key auto_increment,

 

         name varchar(40)

 

   ); 

 

   */

 

  public static void main(String[] args) throws SQLException { 

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null; 

 

        try{

 

              conn = JdbcUtils.getConnection();

 

              String sql = "insert into test(name) values('aaa')";

 

              st = conn.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);

 

              st.executeUpdate();

 

         

 

              rs = st.getGeneratedKeys();

 

              if(rs.next()){

 

                    System.out.println(rs.getInt(1));

 

              } 

 

        }finally{

 

              JdbcUtils.release(conn, st, rs);

 

        }

 

  } 

 

}

 

 

 

 


 

 

 

 

 

十、JDBC調用存儲過程

 

編寫存儲過程(參看mysql文檔)

 

本文重在JDBC對存儲過程的調用,關於其知識內容,將在《Oracle數據庫 知識》博文中詳細介紹

 

 存儲過程Demo樣例:

 

 CREATE PROCEDURE demoSp (IN inputParam VARCHAR(255) ,INOUT  inOutParam varchar(255) )

 

     BEGIN

 

             SELECT CONCAT ( 'ZYXW---- ', inputParam ) into  inOutParam ;

 

     END

 

 

 

在Java中,JDBC對存儲過程的調用 (這纔是本文重點):

 

    (1) 獲得CallableStatement,並調用存儲過程:

 

            CallableStatement cStmt = conn.prepareCall("{call demoSp(?, ?)}");     

 

    (2) 設置參數,註冊返回值,獲得輸出

 

            cStmt.setString(1, "abcdefg");

 

            cStmt.registerOutParameter(2, Types.VARCHAR);    //類型參數值參見JDK中:java.sql.Types

 

            cStmt.execute();

 

            System.out.println(cStmt.getString(2));

 

小常識:「存儲過程」在金融證券 行業中應用的很是普遍,而且將會保密其表結構和字段,徹底使用公開的存儲過程來實現表數據的調用。

 

Demo樣例:

 

    public class Demo5 { 

 

              /**

 

               調用存儲過程

 

               * @throws SQLException 

 

               */

 

              public static void main(String[] args) throws SQLException {

 

             

 

                    Connection conn = null;

 

                    CallableStatement  st = null;

 

                    ResultSet rs = null;

 

                 

 

                    try{

 

                          conn = JdbcUtils.getConnection();

 

                          st = conn.prepareCall("{call demoSp(?,?)}");

 

                          st.setString(1, "aaaaa");

 

                          st.registerOutParameter(2, Types.VARCHAR);

 

                          st.execute();

 

                     

 

                          System.out.println(st.getString(2)); 

 

                    }finally{

 

                          JdbcUtils.release(conn, st, rs);

 

                    }

 

              } 

 

    }

 

 

 

 


 

  

 

十一、事務的概念

 

        事務指邏輯上的一組操做,組成這組操做的各個單元,要麼所有都成功,要麼所有不成功。

 

        例如:A——B轉賬,對應於以下兩條sql語句

 

                 update from account set money=money+100 where name=‘b’;

 

                 update from account set money=money-100 where name=‘a’;

 

        數據庫默認事務是自動提交的,也就是發一條sql它就執行一條。若是想多條sql放在一個事務中執行,則須要使用以下語句。

 

        數據庫開啓事務命令

 

        start transaction  開啓事務

 

        Rollback  回滾事務

 

        Commit   提交事務

 

         

 

        Demo:

 

            Start transaction
                …
                …
            commit

 

 

 

Demo樣例:

 

public static void main(String[] args) throws SQLException { 

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null;

 

        try{

 

              conn = JdbcUtils.getConnection();

 

              conn.setAutoCommit(false);    //start transaction;  開啓事務

 

         

 

              String sql1 = "update account set money=money-100 where name='aaa'";

 

              String sql2 = "update account set money=money+100 where name='bbb'";

 

         

 

              st = conn.prepareStatement(sql1);

 

              st.executeUpdate();

 

         

 

              int x = 1/0;    // 人爲製造異常,驗證事務

 

         

 

              st = conn.prepareStatement(sql2);

 

              st.executeUpdate();

 

         

 

              conn.commit();    // Commit   提交事務

 

        }finally{

 

              JdbcUtils.release(conn, st, rs);

 

        } 

 

  }

 

 

 


 

 

 

十二、JDBC控制事務語句

 

    當Jdbc程序向數據庫得到一個Connection對象時,默認狀況下這個Connection對象會自動向數據庫提交在它上面發送的SQL語句。若想關閉這種默認提交方式,讓多條SQL在一個事務中執行,可以使用下列語句:

 

    (1) JDBC控制事務語句

 

        Connection.setAutoCommit(false);     //至關於 start transaction

 

        Connection.rollback();     //至關於  rollback

 

        Connection.commit();     //至關於   commit

 

 

 

    (2) 設置事務回滾點

 

        Savepoint sp = conn.setSavepoint();

 

        Conn.rollback(sp);    // 會滾到指定的位置,該位置以前的操做任然有效執行,由於須要被提交

 

        Conn.commit();   //回滾後必需要提交

 

 

 

Demo樣例:事務回滾點——演示銀行轉賬案例

 

  public static void main(String[] args) throws SQLException { 

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null;

 

        Savepoint sp = null;

 

        try{

 

              conn = JdbcUtils.getConnection();   //mysql repeatable read

 

              conn.setAutoCommit(false);    //start transaction;

 

         

 

              String sql1 = "update account set money=money-100 where name='aaa'";

 

              String sql2 = "update account set money=money+100 where name='bbb'";

 

              String sql3 = "update account set money=money+100 where name='ccc'";

 

         

 

              st = conn.prepareStatement(sql1);

 

              st.executeUpdate();

 

         

 

              sp = conn.setSavepoint();

 

         

 

              st = conn.prepareStatement(sql2);

 

              st.executeUpdate();

 

         

 

              int x = 1/0;

 

         

 

              st = conn.prepareStatement(sql3);

 

              st.executeUpdate();

 

         

 

              conn.commit();

 

        }catch (Exception e) {

 

              e.printStackTrace();

 

              conn.rollback(sp);

 

              conn.commit();  //手動回滾後,必定要記得提交事務

 

        }finally{

 

              JdbcUtils.release(conn, st, rs);

 

        }

 

  }

 

 

 


 

 

 

1三、事務的四大特性(ACID)

 

    (1) 原子性(Atomicity) 原子性是指事務是一個不可分割的工做單位,事務中的操做要麼都發生,要麼都不發生。

 

    (2) 一致性(Consistency) 事務先後,數據的完整性必須保持一致。

 

    (3) 隔離性(Isolation) 事務的隔離性是多個用戶併發訪問數據庫時,數據庫爲每個用戶開啓的事務,不能被其餘事務的操做數據所幹擾,多個併發事務之間要相互隔離。

 

    (4) 持久性(Durability) 持久性是指一個事務一旦被提交,它對數據庫中數據的改變就是永久性的,接下來即便數據庫發生故障也不該該對其有任何影響。

 

 

 


 

 

 

1四、事務的隔離級別

 

        多個線程開啓各自事務操做數據庫中數據時,數據庫系統要負責隔離操做,以保證各個線程在獲取數據時的準確性。

 

        若是不考慮隔離性,可能會引起問題:髒讀、不可重複讀、虛讀(幻讀) 。

 

         

 


 

 

 

1五、事務的隔離性可避免問題—— 髒讀:

 

    髒讀: 指一個事務讀取了另一個事務未提交的數據。【針對同一個業務操做】

 

     這是很是危險的,假設A向B轉賬貨款100元,對應sql語句以下所示

 

     (1) update account set money=money+100 while name=‘b’;  

 

     (2) update account set money=money-100 while name=‘a’;

 

     

 

     當第1條sql執行完,第2條還沒執行(A未提交時),若是此時B查詢本身的賬戶,就會發現本身多了100元錢。若是A等B走後再回滾,B就會損失100元。

 

 

 


 

 

 

1六、事務的隔離性可避免問題—— 不可重複讀

 

不可重複讀:在一個事務內讀取表中的某一行數據,屢次讀取結果不一樣。【針對同一行數據】

 

不可重複讀和髒讀的區別:髒讀是讀取前一事務未提交的髒數據,不可重複讀是從新讀取了前一事務已提交的數據。

 

         例如銀行想查詢A賬戶餘額,第一次查詢A賬戶爲200元,此時A向賬戶存了100元並提交了,銀行接着又進行了一次查詢,此時A賬戶爲300元了。銀行兩次查詢不一致,可能就會很困惑,不知道哪次查詢是準的。

 

         

 

        不少人認爲這種狀況就對了,無須困惑,固然是後面的爲準。咱們能夠考慮這樣一種狀況,好比銀行程序須要將查詢結果分別輸出到電腦屏幕和寫到文件中,結果在一個事務中針對輸出的目的地,進行的兩次查詢不一致,致使文件和屏幕中的結果不一致,銀行工做人員就不知道以哪一個爲準了。

 

 

 


 

 

 

1七、事務的隔離性可避免問題—— 虛讀(幻讀)

 

虛讀(幻讀) :是指在一個事務內讀取到了別的事務插入的數據,致使先後讀取不一致。【針對整張表】

 

如丙存款100元未提交,這時銀行作報表統計account表中全部用戶的總額爲500元,而後丙提交了,這時銀行再統計發現賬戶爲600元了,形成虛讀一樣會使銀行不知所措,到底以哪一個爲準。

 

 

 


 

 

 

1八、事務隔離性的設置語句

 

    數據庫共定義了四種隔離級別:

 

            (1) Serializable:可避免髒讀、不可重複讀、虛讀狀況的發生。(串行化,近似於單線程操做。)

 

            (2) Repeatable read:可避免髒讀、不可重複讀狀況的發生。(可重複讀)

 

            (3) Read committed:可避免髒讀狀況發生(讀已提交)。

 

            (4) Read uncommitted:最低級別,以上狀況均沒法保證。(讀未提交)

 

         set   transaction isolation level 設置事務隔離級別

 

         select @@tx_isolation  查詢當前事務隔離級別

 

 

 

Demo樣例:Java中設定事務的隔離級別。

 

public static void main(String[] args) throws SQLException, InterruptedException {

 

        Connection conn = null;

 

        PreparedStatement st = null;

 

        ResultSet rs = null;

 

        Savepoint sp = null;

 

        try{

 

              conn = JdbcUtils.getConnection();   //mysql repeatable read

 

              conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);

 

              conn.setAutoCommit(false);    //start transaction;

 

         

 

              String sql = "select * from account";

 

              conn.prepareStatement(sql).executeQuery();

 

         

 

              Thread.sleep(1000*20);     // 等待另外一個程序運行一樣的代碼以校驗事務

 

         

 

              conn.commit();

 

        }finally{

 

              JdbcUtils.release(conn, st, rs);

 

        }

 

  }

 

 

 


 

 

 

 1九、在MySQL客戶端窗口界面掩飾事務的四種隔離級別。

 

(1) 演示髒讀發生 

 

a窗口

 

set transaction isolation level read uncommitted;

 

start transaction;

 

select * from account;

 

-------------發現a賬戶是1000元,轉到b窗口

 

select * from account;

 

-------------發現a賬戶是1100元,發生了髒讀(這個事務讀取到了別的事務未提交的數據) 

 

b窗口

 

start transaction;

 

update account set money=money+100 where name='aaa';

 

-------------事務在不提交的狀況下,轉到a窗口進行查詢 

 

 

 

(2) 避免髒讀,並演示不可重複讀問題的發生 

 

a窗口

 

set transaction isolation level read committed;

 

start transaction;

 

select * from account;

 

-------------發現a賬戶是1000元,轉到b窗口

 

select * from account;

 

-------------發現a賬戶是1000元,這時咱們發現read committed這種級別能夠避免髒讀

 

-------------轉到b窗口

 

select * from account;

 

-------------發現a賬戶是1100元,這時就發生不可重複讀(指這個事務讀取到了別的事務提交的數據)

 

 

 

b窗口

 

start transaction;

 

update account set money=money+100 where name='aaa';

 

-------------事務在不提交的狀況下,轉到a窗口進行查詢

 

commit;

 

-------------轉到a窗口

 

 

 

(3)避免髒讀、不可重複讀,並演示虛讀問題的發生 

 

a窗口

 

set transaction isolation level repeatable read;

 

start transaction;

 

select * from account;

 

--------------------發現a賬戶是1000元,而且表的總紀錄數是3條,這時轉到b窗口

 

select * from account

 

--------------------發現a賬戶是1000元,這說明repeatable read這種級別可避免髒讀

 

-------------------轉到b窗口

 

select * from account

 

---------------------發現a賬戶是1000元,這說明repeatable read這種級別還能夠避免不可重複讀

 

---------------------轉到b窗口

 

select * from account

 

---------------------發現表中可能會多出一條ddd的記錄,這就發生了虛讀,也就是在這個事務內讀取了別的事務插入的數據(幻影數據)

 

  

 

b窗口

 

start transaction;

 

update account set money=money+100 where name='aaa';

 

---------------------轉到a窗口

 

commit;

 

---------------------轉到a窗口

 

start transaction;

 

insert into account(name,money) values('ddd','1000');

 

commit;

 

--------------------轉到a窗口 

 

  

 

 

 


 

 

敬請評論(1)若您以爲本文 有用處  —— 請留言評論,以堅決其餘 IT童鞋 閱讀本文的信心。(2)若您以爲本文 沒用處  —— 請留言評論,筆者將會改進不足,以便爲你們整理更加好用的筆記。 

相關文章
相關標籤/搜索