JDBC的批处理和事务
一.JDBC批處理
批量處理允許將相關(guān)的SQL語(yǔ)句分組到批處理中,并通過(guò)對(duì)數(shù)據(jù)庫(kù)的一次調(diào)用提交它們。
當(dāng)需要一次向數(shù)據(jù)庫(kù)發(fā)送多個(gè)SQL語(yǔ)句時(shí),可以減少連接數(shù)據(jù)庫(kù)的開(kāi)銷(xiāo),從而提高性能。
1.1 Statement批處理
步驟:
- 1 注冊(cè)驅(qū)動(dòng)獲取連接
- 2 使用createStatement()方法創(chuàng)建Statement對(duì)象。
- 3 使用setAutoCommit()將auto-commit設(shè)置為false 。(可選)
- 4 使用addBatch()方法在創(chuàng)建的語(yǔ)句對(duì)象上添加您喜歡的SQL語(yǔ)句到批處理中。
- 5 在創(chuàng)建的語(yǔ)句對(duì)象上使用*executeBatch()*方法執(zhí)行所有SQL語(yǔ)句。
- 6 使用*ommit()*方法提交所有更改。(可選)
- 7 釋放資源
傳統(tǒng)方式的statement批處理
public class BatchTest2 {public static void main(String[] args) throws SQLException {Connection connection = DButil.getConnection(); //獲取連接Statement sta = connection.createStatement(); //創(chuàng)建創(chuàng)建Statement對(duì)象for (int i = 101; i <=1000 ; i++) {//j將sql添加到批處理中sta.addBatch( "insert into user values ("+i+",'李四','123456','鄭州','666666')");if(i%100==0){//每100條數(shù)據(jù)執(zhí)行一次 數(shù)組返回的是執(zhí)行數(shù)據(jù)的數(shù)量int[] ints = sta.executeBatch();sta.clearBatch(); //清空批處理的隊(duì)列System.out.println("長(zhǎng)度為:"+ints.length);}}int[] res=sta.executeBatch();System.out.println(res.length);sta.clearBatch();//4添加更新語(yǔ)句sta.addBatch("update user set password='999999' where userid=1;");sta.addBatch("update user set password='888888' where userid=2;");//5執(zhí)行int[] results = sta.executeBatch();System.out.println("數(shù)組的長(zhǎng)度:"+results.length);for (int result : results) {System.out.println(result);}//6關(guān)閉sta.close();connection.close();} }事務(wù)方式的批處理
public class BatchTest2 {public static void main(String[] args) throws SQLException {Connection connection = DbUtils.getConnection();Statement sta = connection.createStatement();//開(kāi)啟事務(wù)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("長(zhǎng)度為:"+ints.length);}}int[] res=sta.executeBatch();System.out.println(res.length);sta.clearBatch();connection.commit();long end = System.currentTimeMillis();System.out.println("消耗時(shí)間:"+(end-start));//6關(guān)閉sta.close();connection.close();} }在屬性文件中的url中添加rewriteBatchedStatements=true 會(huì)是處理更快
url=jdbc:mysql://localhost:3306/mydb1?useSSL=true&characterEncoding=utf8&rewriteBatchedStatements=true1.1.2 PrepareStatement批處理
傳統(tǒng)添加 耗時(shí)間 效率不高
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("長(zhǎng)度為:"+ints.length);psta.clearBatch();}}DbUtils.closeAll(connection,psta,null);} }事務(wù)方式 最快速度 1w數(shù)據(jù)插入 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("長(zhǎng)度為:"+ints.length);psta.clearBatch();}}connection.commit();long end = System.currentTimeMillis();System.out.println("所耗時(shí)間: "+(end-start));DbUtils.closeAll(connection,psta,null);} }Statement批處理和PrepareStatement批處理的區(qū)別:
(1)Statment批處理可以添加不同Sql語(yǔ)句,而PrepareStatment只能添加一種sql語(yǔ)句,因?yàn)槭?預(yù)編譯 sql早設(shè)定好的 要想插入多種數(shù)據(jù) 需要另外創(chuàng)PrepareStatement對(duì)象。
(2)PrepareStatment效率比Statment高,而且更安全。
二.數(shù)據(jù)庫(kù)事務(wù)
2.1事務(wù)的概述
3.1 事務(wù)概述
? 一組要么同時(shí)執(zhí)行成功,要么同時(shí)失敗的SQL語(yǔ)句。是數(shù)據(jù)庫(kù)操作的一個(gè)不能分割執(zhí)行單元。
? 數(shù)據(jù)庫(kù)事務(wù)(Database Transaction) ,是指作為單個(gè)邏輯工作單元執(zhí)行的一系列操作,要么完全地執(zhí)行,要么完全地不執(zhí)行。 事務(wù)處理可以確保除非事務(wù)性單元內(nèi)的所有操作都成功完成,否則不會(huì)永久更新面向數(shù)據(jù)的資源。通過(guò)將一組相關(guān)操作組合為一個(gè)要么全部成功要么全部失敗的單元,可以簡(jiǎn)化錯(cuò)誤恢復(fù)并使應(yīng)用程序更加可靠。一個(gè)邏輯工作單元要成為事務(wù),必須滿(mǎn)足所謂的ACID(原子性、一致性、隔離性和持久性)屬性。事務(wù)是數(shù)據(jù)庫(kù)運(yùn)行中的邏輯工作單位,由DBMS中的事務(wù)管理子系統(tǒng)負(fù)責(zé)事務(wù)的處理。
事務(wù)開(kāi)始于
- 連接到數(shù)據(jù)庫(kù)上,并執(zhí)行一條DML語(yǔ)句insert、update或delete
- 前一個(gè)事務(wù)結(jié)束后,又輸入了另一條DML語(yǔ)句
事務(wù)結(jié)束于
- 執(zhí)行commit或rollback語(yǔ)句。
- 執(zhí)行一條DDL語(yǔ)句,例如create table語(yǔ)句,在這種情況下,會(huì)自動(dòng)執(zhí)行commit語(yǔ)句。
- 執(zhí)行一條DDL語(yǔ)句,例如grant語(yǔ)句,在這種情況下,會(huì)自動(dòng)執(zhí)行commit。
- 斷開(kāi)與數(shù)據(jù)庫(kù)的連接
- 執(zhí)行了一條DML語(yǔ)句,該語(yǔ)句卻失敗了,在這種情況中,會(huì)為這個(gè)無(wú)效的DML語(yǔ)句執(zhí)行rollback語(yǔ)句。
事務(wù)的四大特點(diǎn)(ACID)
- Atomicity(原子性)
表示一個(gè)事務(wù)內(nèi)的所有操作是一個(gè)整體,要么全部成功,要么全部失敗- Consistency(一致性)
表示一個(gè)事務(wù)內(nèi)有一個(gè)操作失敗時(shí),所有的更改過(guò)的數(shù)據(jù)都必須回滾到修改前狀態(tài)-
Isolation(隔離性)
事務(wù)查看數(shù)據(jù)時(shí)數(shù)據(jù)所處的狀態(tài),要么是另一并發(fā)事務(wù)修改它之前的狀態(tài),要么是另一事務(wù)修改它之后的狀態(tài),事務(wù)不會(huì)查看中間狀態(tài)的數(shù)據(jù)。 - Durability(持久性)
持久性事務(wù)完成之后,它對(duì)于系統(tǒng)的影響是永久性的。
事務(wù)的隔離級(jí)別
SQL標(biāo)準(zhǔn)定義了4類(lèi)隔離級(jí)別,包括了一些具體規(guī)則,用來(lái)限定事務(wù)內(nèi)外的哪些改變是可見(jiàn)的,哪些是不可見(jiàn)的。低級(jí)別的隔離級(jí)一般支持更高的并發(fā)處理,并擁有更低的系統(tǒng)開(kāi)銷(xiāo)。
Read Uncommitted(讀取未提交內(nèi)容)
注意 這里的讀取未提交的數(shù)據(jù) 實(shí)際上未提交的數(shù)據(jù)修然執(zhí)行了但是未提交 數(shù)據(jù)庫(kù)中的數(shù)據(jù)是不發(fā)生改變的,讀取到的是虛表中的內(nèi)容,這也就是臟讀
? 在該隔離級(jí)別,所有事務(wù)都可以看到其他未提交事務(wù)的執(zhí)行結(jié)果。本隔離級(jí)別很少用于實(shí)際應(yīng)用,因?yàn)樗男阅芤膊槐绕渌?jí)別好多少。讀取未提交的數(shù)據(jù),也被稱(chēng)之為臟讀(Dirty Read)。
案例:
這里因?yàn)橘u(mài)方的級(jí)別是最低的,可以讀沒(méi)有提交的數(shù)據(jù) 當(dāng)a仿制型時(shí)候 沒(méi)有提交 表中數(shù)據(jù)實(shí)際沒(méi)有變化 但是 b查詢(xún)能在虛擬表中查詢(xún)到 以為a已經(jīng)付過(guò)錢(qián)了 發(fā)貨之后 a執(zhí)行回滾 數(shù)據(jù)又恢復(fù)以前 這就是 臟讀。(需要將b的級(jí)別提高一下為Read Committed)
Read Committed(讀取提交內(nèi)容)
這個(gè)級(jí)別也是會(huì)出現(xiàn)問(wèn)題的,在數(shù)據(jù)庫(kù)進(jìn)行統(tǒng)計(jì)時(shí)候,通常是進(jìn)行多次查詢(xún),當(dāng)多次查詢(xún)結(jié)果相同時(shí)才會(huì)認(rèn)為數(shù)據(jù)無(wú)誤,提交過(guò)去,但是 再查詢(xún)過(guò)程中用戶(hù)如果進(jìn)行數(shù)據(jù)修改操作就會(huì)使查詢(xún)結(jié)果不一致,從而造成影響 這就需要設(shè)置更高隔離級(jí)別
? 這是大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)的默認(rèn)隔離級(jí)別(但不是MySQL默認(rèn)的)。它滿(mǎn)足了隔離的簡(jiǎn)單定義:一個(gè)事務(wù)只能看見(jiàn)已經(jīng)提交事務(wù)所做的改變。這種隔離級(jí)別出現(xiàn)不可重復(fù)讀(Nonrepeatable Read)問(wèn)題,因?yàn)橥皇聞?wù)的其他實(shí)例在該實(shí)例處理其間可能會(huì)有新的commit,所以同一select可能返回不同結(jié)果。
案例:
//在查詢(xún)時(shí) (模擬銀行存錢(qián))下方代碼 表示用戶(hù)進(jìn)行存錢(qián)操作 回對(duì)查詢(xún)?cè)斐捎绊?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 **可重讀
這個(gè)設(shè)置可重讀的級(jí)別 在進(jìn)行統(tǒng)計(jì)時(shí)候 用戶(hù)進(jìn)行修改操作時(shí)候 系統(tǒng)會(huì)進(jìn)行屏蔽 等統(tǒng)計(jì)結(jié)束之后 提交完 在進(jìn)行操作 將用戶(hù)存的錢(qián)加進(jìn)來(lái)
? 這是MySQL的默認(rèn)事務(wù)隔離級(jí)別,它確保同一事務(wù)的多個(gè)實(shí)例在并發(fā)讀取數(shù)據(jù)時(shí),會(huì)看到同樣的數(shù)據(jù)行。不過(guò)理論上,這會(huì)導(dǎo)致另一個(gè)棘手的問(wèn)題:幻讀(Phantom Read)。簡(jiǎn)單的說(shuō),幻讀指當(dāng)用戶(hù)讀取某一范圍的數(shù)據(jù)行時(shí),另一個(gè)事務(wù)又在該范圍內(nèi)插入了新行,當(dāng)用戶(hù)再讀取該范圍的數(shù)據(jù)行時(shí),會(huì)發(fā)現(xiàn)有新的“幻讀” 行。InnoDB和Falcon存儲(chǔ)引擎通過(guò)多版本并發(fā)控制(MVCC,Multiversion Concurrency Control)機(jī)制解決了該問(wèn)題。
Serializable 可串行化
? 這是最高的隔離級(jí)別,它通過(guò)強(qiáng)制事務(wù)排序,使之不可能相互沖突,從而解決幻讀問(wèn)題。簡(jiǎn)言之,它是在每個(gè)讀的數(shù)據(jù)行上加上共享鎖。在這個(gè)級(jí)別,可能導(dǎo)致大量的超時(shí)現(xiàn)象和鎖競(jìng)爭(zhēng)。效率最低的。
? 這四種隔離級(jí)別采取不同的鎖類(lèi)型來(lái)實(shí)現(xiàn),若讀取的是同一個(gè)數(shù)據(jù)的話(huà),就容易發(fā)生問(wèn)題。
事物的提交和回滾
開(kāi)啟事務(wù)在完成表的修改止之后 需要進(jìn)行提交
回滾代碼案例
回滾點(diǎn)的操作案例
什么是回滾點(diǎn)?
回滾點(diǎn)即是在代碼中設(shè)置的一個(gè)位置,在程序執(zhí)行過(guò)程中出現(xiàn)錯(cuò)誤時(shí)候,執(zhí)行回滾操作時(shí)候指定位置,就會(huì)回滾到指定的位置。
回滾操作之后還需不需要提交?
回滾之后如果是回滾到指定的回滾點(diǎn)的話(huà),前面有已經(jīng)執(zhí)行的代碼時(shí)候 需要提交,如果是默認(rèn)的回滾到事務(wù)開(kāi)始位置,則不需要提交 因?yàn)橹皥?zhí)行的都回到原始狀態(tài)了,在提交也沒(méi)什么意義。
設(shè)置保存點(diǎn)時(shí),可以在事務(wù)中定義邏輯回滾點(diǎn)。如果通過(guò)保存點(diǎn)發(fā)生錯(cuò)誤,則可以使用回滾方法來(lái)撤消所有更改或僅保存在保存點(diǎn)之后所做的更改。
Connection對(duì)象有兩種新的方法來(lái)幫助您管理保存點(diǎn) -
- **setSavepoint(String savepointName):**定義新的保存點(diǎn)。它還返回一個(gè)Savepoint對(duì)象。
- **releaseSavepoint(Savepoint savepointName):**刪除保存點(diǎn)。請(qǐng)注意,它需要一個(gè)Savepoint對(duì)象作為參數(shù)。此對(duì)象通常是由setSavepoint()方法生成的保存點(diǎn)。
總結(jié)
以上是生活随笔為你收集整理的JDBC的批处理和事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: YAML 入门教程
- 下一篇: c语言ifi=1 2,2017年计算机二