日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

方立勋_30天掌握JavaWeb_JDBC、存储过程、事务(二)

發布時間:2023/12/20 java 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 方立勋_30天掌握JavaWeb_JDBC、存储过程、事务(二) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

使用JDBC處理大數據

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

基本概念:大數據也稱之為LOB(Large Objects),LOB又分為:
clob和blob
1. clob用于存儲大文本。
2. blob用于存儲二進制數據,例如圖像、聲音、二進制文等。

對MySQL而言只有blob,而沒有clob,mysql存儲大文本采用的是Text,Text和blob分別又分為:

  • TINYTEXT、TEXT、MEDIUMTEXT和LONGTEXT
  • TINYBLOB、BLOB、MEDIUMBLOB和LONGBLOB

使用JDBC處理大文本

  • 對于MySQL中的Text類型,可調用如下方法設置:
    PreparedStatement.setCharacterStream(index, reader, length);
    //注意length長度須設置,并且設置為int型

  • 對MySQL中的Text類型,可調用如下方法獲取:
    reader = resultSet. getCharacterStream(i);
    reader = resultSet.getClob(i).getCharacterStream();
    string s = resultSet.getString(i);

  • 使用JDBC處理二進制數據

  • 對于MySQL中的BLOB類型,可調用如下方法設置:
    PreparedStatement. setBinaryStream(i, inputStream, length);

  • 對MySQL中的BLOB類型,可調用如下方法獲取:
    InputStream in = resultSet.getBinaryStream(i);
    InputStream in = resultSet.getBlob(i).getBinaryStream();

  • 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往數據庫讀寫數據
    注意:以上操作需開啟事務。

    使用JDBC進行批處理

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

    • 實現批處理有兩種方式,第一種方式:
      Statement.addBatch(sql) list
    • 執行批處理SQL語句
      executeBatch()方法:執行批處理命令
      clearBatch()方法:清除批處理命令
    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(); } 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()

    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){st.executeBatch();st.clearBatch();} } st.executeBatch();

    采用PreparedStatement.addBatch()實現批處理
    優點:發送的是預編譯后的SQL語句,執行效率高。
    缺點:只能應用在SQL語句相同,但參數不同的批處理中。因此此種形式的批處理經常用于在同一個表中批量插入數據,或批量更新表的數據。

    獲得數據庫自動生成的主鍵

    示例:

    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操作有效。

    JDBC調用存儲過程

    什么是存儲過程?
    A:未完待寫。

    編寫存儲過程(參看mysql文檔)
    得到CallableStatement,并調用存儲過程:
    CallableStatement cStmt = conn.prepareCall(“{call demoSp(?, ?)}”);

    設置參數,注冊返回值,得到輸出
    cStmt.registerOutParameter(2, Types.VARCHAR);
    cStmt.setString(1, “abcdefg”);
    cStmt.execute();
    System.out.println(cStmt.getString(2));


    事務

    事務的概念

    • 事務指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。
      例如:A——B轉帳,對應于如下兩條sql語句
      update from account set money=money+100 where name=‘b’;
      update from account set money=money-100 where name=‘a’;

    • 數據庫開啟事務命令
      start transaction 開啟事務
      Rollback 回滾事務
      Commit 提交事務

    使用事務

    • 當Jdbc程序向數據庫獲得一個Connection對象時,默認情況下這個Connection對象會自動向數據庫提交在它上面發送的SQL語句。若想關閉這種默認提交方式,讓多條SQL在一個事務中執行,可使用下列語句:
    • JDBC控制事務語句
      Connection.setAutoCommit(false); start transaction
      Connection.rollback(); rollback
      Connection.commit(); commit

    案例

    在JDBC代碼中使如下轉帳操作在同一事務中執行。
    update from account set money=money-100 where name=‘a’;
    update from account set money=money+100 where name=‘b’;
    設置事務回滾點
    Savepoint sp = conn.setSavepoint();
    Conn.rollback(sp);
    Conn.commit(); //回滾后必須要提交

    事務的特性(ACID)

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

    • 一致性(Consistency)事務必須使數據庫從一個一致性狀態變換到另外一個一致性狀態。

    • 隔離性(Isolation)事務的隔離性是多個用戶并發訪問數據庫時,數據庫為每一個用戶開啟的事務,不能被其他事務的操作數據所干擾,多個并發事務之間要相互隔離。

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

    著重講下:事務的隔離級別

    多個線程開啟各自事務操作數據庫中數據時,數據庫系統要負責隔離操作,以保證各個線程在獲取數據時的準確性。
    如果不考慮隔離性,可能會引發如下問題:

    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元。

    2. 不可重復讀:

    • 在一個事務內讀取表中的某一行數據,多次讀取結果不同。
      例如銀行想查詢A帳戶余額,第一次查詢A帳戶為200元,此時A向帳戶內存了100元并提交了,銀行接著又進行了一次查詢,此時A帳戶為300元了。銀行兩次查詢不一致,可能就會很困惑,不知道哪次查詢是準的。

    • 和臟讀的區別是,臟讀是讀取前一事務未提交的臟數據,不可重復讀是重新讀取了前一事務已提交的數據。

    • 很多人認為這種情況就對了,無須困惑,當然是后面的為準。我們可以考慮這樣一種情況,比如銀行程序需要將查詢結果分別輸出到電腦屏幕和寫到文件中,結果在一個事務中針對輸出的目的地,進行的兩次查詢不一致,導致文件和屏幕中的結果不一致,銀行工作人員就不知道以哪個為準了。

    3. 虛讀(幻讀)

    • 是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致。
    • 如丙存款100元未提交,這時銀行做報表統計account表中所有用戶的總額為500元,然后丙提交了,這時銀行再統計發現帳戶為600元了,造成虛讀同樣會使銀行不知所措,到底以哪個為準。

    事務隔離性的設置語句

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

    • Serializable:可避免臟讀、不可重復讀、虛讀情況的發生。(串行化)
    • Repeatable read:可避免臟讀、不可重復讀情況的發生。(可重復讀)
    • Read committed:可避免臟讀情況發生(讀已提交)。
    • Read uncommitted:最低級別,以上情況均無法保證。(讀未提交)

    set transaction isolation level 設置事務隔離級別
    select @@tx_isolation 查詢當前事務隔離級別

    事務隔離級別不是每個數據庫都有,如mysql有以上四種隔離級別,但oracle只有Serializable和Read committed級別。

    演示不同隔離級別下的并發問題

    1.當把事務的隔離級別設置為read uncommitted時,會引發臟讀、不可重復讀和虛讀

    A窗口
    set transaction isolation level read uncommitted;
    start transaction;
    select * from account;
    —–發現a帳戶是1000元,轉到b窗口
    select * from account
    —–發現a多了100元,這時候a讀到了b未提交的數據(臟讀)

    B窗口
    start transaction;
    update account set money=money+100 where name=’aaa’;
    —–不要提交,轉到a窗口查詢

    2.當把事務的隔離級別設置為read committed時,會引發不可重復讀和虛讀,但避免了臟讀

    A窗口
    set transaction isolation level read committed;
    start transaction;
    select * from account;
    —–發現a帳戶是1000元,轉到b窗口
    select * from account;
    —–發現a帳戶多了100,這時候,a讀到了別的事務提交的數據,兩次讀取a帳戶讀到的是不同的結果(不可重復讀)

    B窗口
    start transaction;
    update account set money=money+100 where name=’aaa’;
    commit;
    —–轉到a窗口

    3.當把事務的隔離級別設置為repeatable read(mysql默認級別)時,會引發虛讀,但避免了臟讀、不可重復讀

    A窗口
    set transaction isolation level repeatable read;
    start transaction;
    select * from account;
    —-發現表有4個記錄,轉到b窗口
    select * from account;
    —-可能發現表有5條記如,這時候發生了a讀取到另外一個事務插入的數據(虛讀)

    B窗口
    start transaction;
    insert into account(name,money) values(‘ggg’,1000);
    commit;
    —–轉到 a窗口

    4.當把事務的隔離級別設置為Serializable時,會避免所有問題

    A窗口
    set transaction isolation level Serializable;
    start transaction;
    select * from account;
    —–轉到b窗口

    B窗口
    start transaction;
    insert into account(name,money) values(‘ggg’,1000);
    —–發現不能插入,只能等待a結束事務才能插入

    總結

    以上是生活随笔為你收集整理的方立勋_30天掌握JavaWeb_JDBC、存储过程、事务(二)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。