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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JDBC的批处理和事务

發布時間:2023/12/16 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JDBC的批处理和事务 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一.JDBC批處理

批量處理允許將相關的SQL語句分組到批處理中,并通過對數據庫的一次調用提交它們。

當需要一次向數據庫發送多個SQL語句時,可以減少連接數據庫的開銷,從而提高性能。

1.1 Statement批處理

步驟:

  • 1 注冊驅動獲取連接
  • 2 使用createStatement()方法創建Statement對象。
  • 3 使用setAutoCommit()將auto-commit設置為false 。(可選)
  • 4 使用addBatch()方法在創建的語句對象上添加您喜歡的SQL語句到批處理中。
  • 5 在創建的語句對象上使用*executeBatch()*方法執行所有SQL語句。
  • 6 使用*ommit()*方法提交所有更改。(可選)
  • 7 釋放資源

傳統方式的statement批處理

public class BatchTest2 {public static void main(String[] args) throws SQLException {Connection connection = DButil.getConnection(); //獲取連接Statement sta = connection.createStatement(); //創建創建Statement對象for (int i = 101; i <=1000 ; i++) {//j將sql添加到批處理中sta.addBatch( "insert into user values ("+i+",'李四','123456','鄭州','666666')");if(i%100==0){//每100條數據執行一次 數組返回的是執行數據的數量int[] ints = sta.executeBatch();sta.clearBatch(); //清空批處理的隊列System.out.println("長度為:"+ints.length);}}int[] res=sta.executeBatch();System.out.println(res.length);sta.clearBatch();//4添加更新語句sta.addBatch("update user set password='999999' where userid=1;");sta.addBatch("update user set password='888888' where userid=2;");//5執行int[] results = sta.executeBatch();System.out.println("數組的長度:"+results.length);for (int result : results) {System.out.println(result);}//6關閉sta.close();connection.close();} }

事務方式的批處理

public class BatchTest2 {public static void main(String[] args) throws SQLException {Connection connection = DbUtils.getConnection();Statement sta = connection.createStatement();//開啟事務connection.setAutoCommit(false);long start = System.currentTimeMillis();for (int i = 1; i <=10000 ; i++) {sta.addBatch( "insert into person values ("+i+",'張三','6666')");if(i%1000==0){int[] ints = sta.executeBatch();sta.clearBatch();System.out.println("長度為:"+ints.length);}}int[] res=sta.executeBatch();System.out.println(res.length);sta.clearBatch();connection.commit();long end = System.currentTimeMillis();System.out.println("消耗時間:"+(end-start));//6關閉sta.close();connection.close();} }

在屬性文件中的url中添加rewriteBatchedStatements=true 會是處理更快

url=jdbc:mysql://localhost:3306/mydb1?useSSL=true&characterEncoding=utf8&rewriteBatchedStatements=true
1.1.2 PrepareStatement批處理
  • 使用占位符創建SQL語句。
  • 使用prepareStatement() 方法創建PrepareStatement對象。
  • 使用*setAutoCommit()*將auto-commit設置為false 。(可選)
  • 使用*addBatch()*方法在創建的語句對象上添加您喜歡的SQL語句到批處理中。
  • 在創建的語句對象上使用*executeBatch()*方法執行所有SQL語句。
  • 最后,使用*commit()*方法提交所有更改。(可選)
  • 傳統添加 耗時間 效率不高

    public class BatchTest {public static void main(String[] args) throws SQLException {Connection connection = DbUtils.getConnection();PreparedStatement psta = connection.prepareStatement("insert into user(userid,username,password,address,phone) values(?,?,?,?,?)");for (int i = 1; i <=10000 ; i++) {psta.setInt(1,i);psta.setString(2,"張三");psta.setString(3,"123456");psta.setString(4,"上海");psta.setString(5,"12423423545");psta.addBatch();if(i%1000==0){int[] ints = psta.executeBatch();System.out.println("長度為:"+ints.length);psta.clearBatch();}}DbUtils.closeAll(connection,psta,null);} }

    事務方式 最快速度 1w數據插入 0.2s

    public class BatchTest {public static void main(String[] args) throws SQLException {Connection connection = DbUtils.getConnection();PreparedStatement psta = connection.prepareStatement("insert into person values(?,?,?)");connection.setAutoCommit(false);long start = System.currentTimeMillis();for (int i = 1; i <=10000 ; i++) {psta.setInt(1,i);psta.setString(2,"張三");psta.setString(3,"123456");psta.addBatch();if(i%1000==0){int[] ints = psta.executeBatch();System.out.println("長度為:"+ints.length);psta.clearBatch();}}connection.commit();long end = System.currentTimeMillis();System.out.println("所耗時間: "+(end-start));DbUtils.closeAll(connection,psta,null);} }

    Statement批處理和PrepareStatement批處理的區別:
    (1)Statment批處理可以添加不同Sql語句,而PrepareStatment只能添加一種sql語句,因為是 預編譯 sql早設定好的 要想插入多種數據 需要另外創PrepareStatement對象。
    (2)PrepareStatment效率比Statment高,而且更安全。

    二.數據庫事務
    2.1事務的概述
    3.1 事務概述

    ? 一組要么同時執行成功,要么同時失敗的SQL語句。是數據庫操作的一個不能分割執行單元。
    ? 數據庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要么完全地執行,要么完全地不執行。 事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。通過將一組相關操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復并使應用程序更加可靠。一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性。事務是數據庫運行中的邏輯工作單位,由DBMS中的事務管理子系統負責事務的處理。

    事務開始于

    • 連接到數據庫上,并執行一條DML語句insert、update或delete
    • 前一個事務結束后,又輸入了另一條DML語句

    事務結束于

    • 執行commit或rollback語句。
    • 執行一條DDL語句,例如create table語句,在這種情況下,會自動執行commit語句。
    • 執行一條DDL語句,例如grant語句,在這種情況下,會自動執行commit。
    • 斷開與數據庫的連接
    • 執行了一條DML語句,該語句卻失敗了,在這種情況中,會為這個無效的DML語句執行rollback語句。

    事務的四大特點(ACID)

    • Atomicity(原子性)
       表示一個事務內的所有操作是一個整體,要么全部成功,要么全部失敗- Consistency(一致性)
       表示一個事務內有一個操作失敗時,所有的更改過的數據都必須回滾到修改前狀態-
      Isolation(隔離性)
      事務查看數據時數據所處的狀態,要么是另一并發事務修改它之前的狀態,要么是另一事務修改它之后的狀態,事務不會查看中間狀態的數據。
    • Durability(持久性)
       持久性事務完成之后,它對于系統的影響是永久性的。

    事務的隔離級別
      SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的并發處理,并擁有更低的系統開銷。

    Read Uncommitted(讀取未提交內容)

    注意 這里的讀取未提交的數據 實際上未提交的數據修然執行了但是未提交 數據庫中的數據是不發生改變的,讀取到的是虛表中的內容,這也就是臟讀
    ? 在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用于實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為臟讀(Dirty Read)。
    案例:
    這里因為賣方的級別是最低的,可以讀沒有提交的數據 當a仿制型時候 沒有提交 表中數據實際沒有變化 但是 b查詢能在虛擬表中查詢到 以為a已經付過錢了 發貨之后 a執行回滾 數據又恢復以前 這就是 臟讀。(需要將b的級別提高一下為Read Committed)

    # A方 買 本偉 SELECT @@tx_isolation; START TRANSACTION; UPDATE account SET money=money-2000 WHERE id=1; UPDATE account SET money=money+2000 WHERE id=2; COMMIT; ROLLBACK;# B方 賣 鄭帥 #(修改隔離級別) SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; #查看隔離級別 SELECT @@tx_isolation; SELECT *FROM account; #發貨

    Read Committed(讀取提交內容)

    這個級別也是會出現問題的,在數據庫進行統計時候,通常是進行多次查詢,當多次查詢結果相同時才會認為數據無誤,提交過去,但是 再查詢過程中用戶如果進行數據修改操作就會使查詢結果不一致,從而造成影響 這就需要設置更高隔離級別
    ? 這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別出現不可重復讀(Nonrepeatable Read)問題,因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。

    案例:

    //在查詢時 (模擬銀行存錢)下方代碼 表示用戶進行存錢操作 回對查詢造成影響 START TRANSACTION;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account; COMMIT; START TRANSACTION; UPDATE account SET money=money+1000 WHERE id=2; COMMIT;

    **Repeatable Read **可重讀

    這個設置可重讀的級別 在進行統計時候 用戶進行修改操作時候 系統會進行屏蔽 等統計結束之后 提交完 在進行操作 將用戶存的錢加進來

    ? 這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀(Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻讀” 行。InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。

    Serializable 可串行化
    ? 這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。效率最低的。

    ? 這四種隔離級別采取不同的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。

    事物的提交和回滾
    開啟事務在完成表的修改止之后 需要進行提交
    回滾代碼案例

    public class TransactionTest {public static void main(String[] args) {Connection connection = DbUtils.getConnection();PreparedStatement psta1=null;PreparedStatement psta2=null;try {//設置自動提交為falseconnection.setAutoCommit(false);psta1 = connection.prepareStatement("update person set money=money-1000 where id=1");psta1.executeUpdate();int a=8/0; //在這里會報錯 到catch中 執行回滾 確保數據不會出現錯誤psta2 = connection.prepareStatement("update person set money=money+1000 where id=2");psta2.executeUpdate();connection.commit();System.out.println("轉賬成功!");} catch (Exception e) {e.printStackTrace();try {connection.rollback();//回滾 當程序運行中出現問題之后 就會回滾 回到執行之前的樣子} catch (SQLException e1) {e1.printStackTrace();}System.out.println("轉賬失敗!");}finally {try {if(connection!=null)connection.close();if(psta1!=null)psta1.close();if(psta2!=null)psta2.close();} catch (SQLException e) {e.printStackTrace();}}} }

    回滾點的操作案例

    什么是回滾點?
    回滾點即是在代碼中設置的一個位置,在程序執行過程中出現錯誤時候,執行回滾操作時候指定位置,就會回滾到指定的位置。
    回滾操作之后還需不需要提交?
    回滾之后如果是回滾到指定的回滾點的話,前面有已經執行的代碼時候 需要提交,如果是默認的回滾到事務開始位置,則不需要提交 因為之前執行的都回到原始狀態了,在提交也沒什么意義。

    設置保存點時,可以在事務中定義邏輯回滾點。如果通過保存點發生錯誤,則可以使用回滾方法來撤消所有更改或僅保存在保存點之后所做的更改。
    Connection對象有兩種新的方法來幫助您管理保存點 -

    • **setSavepoint(String savepointName):**定義新的保存點。它還返回一個Savepoint對象。
    • **releaseSavepoint(Savepoint savepointName):**刪除保存點。請注意,它需要一個Savepoint對象作為參數。此對象通常是由setSavepoint()方法生成的保存點。
    public class RollpointTest {public static void main(String[] args) {Connection connection=null;Savepoint sp1=null;Savepoint sp2=null;Statement stat=null;try {//1獲取連接connection= DbUtils.getConnection();//2開啟事務connection.setAutoCommit(false);//3創建命令對象stat = connection.createStatement();//4執行stat.executeUpdate("insert into person(id,name,money) values(3,'aaa',1000)");sp1=connection.setSavepoint("savepoint1");stat.executeUpdate("insert into person(id,name,money) values(4,'bbb',1000)");sp2=connection.setSavepoint("savepoint2");stat.executeUpdate("insert into person(id,name,money) values(5,'ccc',1000)");connection.releaseSavepoint(sp1);int i=10/0;//成功提交connection.commit();System.out.println("添加成功");} catch (Exception e) {e.printStackTrace();try {connection.rollback(sp1);connection.commit();//回滾沒有回滾到事務開始的位置,需要提交System.out.println("添加失敗");} catch (SQLException e1) {e1.printStackTrace();}}finally {try {stat.close();connection.close();} catch (SQLException e) {e.printStackTrace();}}} }

    總結

    以上是生活随笔為你收集整理的JDBC的批处理和事务的全部內容,希望文章能夠幫你解決所遇到的問題。

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