MySQL使用JDBC高级操作和事务
JDBC批處理和事務
回顧
1 jdbc介紹 :Java Database Connectity java數據庫連接技術定義一套連接數據的規范和標準。2 jdbc包含兩個部分JDBC APIJDBC 驅動程序3 JDBC的使用步驟1 導入jar包2 注冊驅動3 獲取連接 33064 創建命令5 執行命令,處理結果6 釋放資源4 JDBC的api Driver 驅動DriverManager 驅動管理類Connection 負責連接數據庫Statement 負責執行命令ResultSet 封裝結果集PreparedStatment 預編譯命令 5 數據庫工具類DbUtils.java1 注冊驅動2 獲取連接3 釋放資源4 執行命令 (增刪改 DDL)今日內容
1、JDBC的批處理 2、JDBC操作二進制 3、數據庫事務 4、JDBC實現事務教學目標
1、掌握JDBC的批處理 2、熟悉JDBC操作二進制 3、掌握數據庫事務和ACID和隔離級別 4、掌握數據庫事務的使用 5、掌握JDBC的事務操作第一節 JDBC批處理
批量處理允許您將相關的SQL語句分組到批處理中,并通過對數據庫的一次調用提交它們。
當需要一次向數據庫發送多個SQL語句時,可以減少連接數據庫的開銷,從而提高性能。
1.1 Statement批處理
以下是使用語句對象的批處理的典型步驟序列
- 使用*createStatement()*方法創建Statement對象。
- 使用*setAutoCommit()*將auto-commit設置為false 。(可選)
- 使用*addBatch()*方法在創建的語句對象上添加您喜歡的SQL語句到批處理中。
- 在創建的語句對象上使用*executeBatch()*方法執行所有SQL語句。
- 最后,使用*commit()*方法提交所有更改。(可選)
1.2 PrepareStatement批處理
第二節 JDBC操作二進制
PreparedStatement對象可以使用輸入和輸出流來提供參數數據。這使您可以將整個文件放入可以保存大值的數據庫列,例如Text和BLOB數據類型。
有以下方法可用于流式傳輸數據 -
- **setAsciiStream():**此方法用于提供大的ASCII值。
- **setCharacterStream():**此方法用于提供大型UNICODE值。
- **setBinaryStream():**此方法用于提供較大的二進制值。
setXXXStream()方法除了參數占位符之外還需要額外的參數,文件大小。
考慮我們要將XML文件XML_Data.xml上傳到數據庫表中。這是XML文件的內容 -
<?xml version="1.0" encoding="UTF-8"?> <Employee><id>100</id><first>Zara</first><last>Ali</last><Salary>10000</Salary><Dob>18-08-1978</Dob> </Employee> // Import required packages import java.sql.*; import java.io.*; import java.util.*;public class JDBCExample {// JDBC driver name and database URLstatic final String JDBC_DRIVER = "com.mysql.jdbc.Driver"; static final String DB_URL = "jdbc:mysql://localhost:3306/EMP";// Database credentialsstatic final String USER = "username";static final String PASS = "password";public static void main(String[] args) {Connection conn = null;PreparedStatement pstmt = null;Statement stmt = null;ResultSet rs = null;try{// Register JDBC driverClass.forName("com.mysql.jdbc.Driver");// Open a connectionSystem.out.println("Connecting to database...");conn = DriverManager.getConnection(DB_URL,USER,PASS);//Create a Statement object and build tablestmt = conn.createStatement();createXMLTable(stmt);//Open a FileInputStreamFile f = new File("XML_Data.xml");long fileLength = f.length();FileInputStream fis = new FileInputStream(f);//Create PreparedStatement and stream dataString SQL = "INSERT INTO XML_Data VALUES (?,?)";pstmt = conn.prepareStatement(SQL);pstmt.setInt(1,100);pstmt.setAsciiStream(2,fis,(int)fileLength);pstmt.execute();//Close input streamfis.close();// Do a query to get the rowSQL = "SELECT Data FROM XML_Data WHERE id=100";rs = stmt.executeQuery (SQL);// Get the first rowif (rs.next ()){//Retrieve data from input streamInputStream xmlInputStream = rs.getAsciiStream (1);int c;ByteArrayOutputStream bos = new ByteArrayOutputStream();while (( c = xmlInputStream.read ()) != -1)bos.write(c);//Print resultsSystem.out.println(bos.toString());}// Clean-up environmentrs.close();stmt.close();pstmt.close();conn.close();}catch(SQLException se){//Handle errors for JDBCse.printStackTrace();}catch(Exception e){//Handle errors for Class.forNamee.printStackTrace();}finally{//finally block used to close resourcestry{if(stmt!=null)stmt.close();}catch(SQLException se2){}// nothing we can dotry{if(pstmt!=null)pstmt.close();}catch(SQLException se2){}// nothing we can dotry{if(conn!=null)conn.close();}catch(SQLException se){se.printStackTrace();}//end finally try}//end trySystem.out.println("Goodbye!"); }//end mainpublic static void createXMLTable(Statement stmt) throws SQLException{System.out.println("Creating XML_Data table..." );//Create SQL StatementString streamingDataSql = "CREATE TABLE XML_Data " +"(id INTEGER, Data TEXT)";//Drop table first if it exists.try{stmt.executeUpdate("DROP TABLE IF EXISTS XML_Data");//Build table.stmt.executeUpdate(streamingDataSql);}catch(SQLException se){}// do nothing}//end createXMLTable }//end JDBCExample案例:把圖片放入數據庫
package com.qf.day04;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.ProcessBuilder.Redirect; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet;/*** 把圖片放入數據庫* @author wgy**/ public class Demo4 {public static void main(String[] args) throws Exception{//write();read();}public static void write() throws Exception{Class.forName("com.mysql.jdbc.Driver");String url="jdbc:mysql://localhost:3306/school";Connection conn=DriverManager.getConnection(url, "root", "root");PreparedStatement pstat=conn.prepareStatement("insert into bigdata2(id,img) values(?,?)");FileInputStream fis=new FileInputStream("d:\\圖片\\003.jpg");pstat.setInt(1, 1);pstat.setBinaryStream(2, fis);int count=pstat.executeUpdate();System.out.println(count);pstat.close();conn.close();}public static void read() throws Exception{Class.forName("com.mysql.jdbc.Driver");String url="jdbc:mysql://localhost:3306/school";Connection conn=DriverManager.getConnection(url, "root", "root");PreparedStatement pstat=conn.prepareStatement("select * from bigdata2 where id=1");ResultSet rs=pstat.executeQuery();if(rs.next()) {int id=rs.getInt("id");System.out.println(id);//處理圖片InputStream is=rs.getBinaryStream("img");FileOutputStream fos=new FileOutputStream("d:\\haha.jpg");byte[] buf=new byte[1024];int len=0;while((len=is.read(buf))!=-1) {fos.write(buf,0,len);}fos.close();is.close();}rs.close();pstat.close();conn.close();System.out.println("讀取完成");} }第三節 數據庫事務
一組要么同時執行成功,要么同時失敗的SQL語句。是數據庫操作的一個執行單元。
3.1 事務概述
? 數據庫事務(Database Transaction) ,是指作為單個邏輯工作單元執行的一系列操作,要么完全地執行,要么完全地不執行。 事務處理可以確保除非事務性單元內的所有操作都成功完成,否則不會永久更新面向數據的資源。通過將一組相關操作組合為一個要么全部成功要么全部失敗的單元,可以簡化錯誤恢復并使應用程序更加可靠。一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性。事務是數據庫運行中的邏輯工作單位,由DBMS中的事務管理子系統負責事務的處理。
事務開始于
- 連接到數據庫上,并執行一條DML語句insert、update或delete
- 前一個事務結束后,又輸入了另一條DML語句
事務結束于
- 執行commit或rollback語句。
- 執行一條DDL語句,例如create table語句,在這種情況下,會自動執行commit語句。
- 執行一條DDL語句,例如grant語句,在這種情況下,會自動執行commit。
- 斷開與數據庫的連接
- 執行了一條DML語句,該語句卻失敗了,在這種情況中,會為這個無效的DML語句執行rollback語句。
3.2 事務的四大特點
(ACID)
- Actomicity(原子性)
表示一個事務內的所有操作是一個整體,要么全部成功,要么全部失敗
- Consistency(一致性)
表示一個事務內有一個操作失敗時,所有的更改過的數據都必須回滾到修改前狀態
- Isolation(隔離性)
事務查看數據時數據所處的狀態,要么是另一并發事務修改它之前的狀態,要么是另一事務修改它之后的狀態,事務不會查看中間狀態的數據。
- Durability(持久性)
持久性事務完成之后,它對于系統的影響是永久性的。
案例演示
CREATE TABLE account(id INT PRIMARY KEY,NAME VARCHAR(20) NOT NULL,money DOUBLE(10,2) )public static void main(String[] args) {Connection connection=null;PreparedStatement pstat1=null;PreparedStatement pstat2=null;//1注冊驅動try {Class.forName("com.mysql.jdbc.Driver");//2獲取連接connection=DriverManager.getConnection("jdbc:mysql://localhost:3306/school", "root", "root");//3創建命令//3.1開啟事務 ,設置事務自動提交為falseconnection.setAutoCommit(false);pstat1=connection.prepareStatement("update account set money=money-1000 where name='張莎強'");pstat1.executeUpdate();//int c=10/0;pstat2=connection.prepareStatement("update account set money=money+1000 where name='小蒼'");pstat2.executeUpdate();System.out.println("轉賬成功...");//3.2提交事務connection.commit();} catch (Exception e) {System.out.println("出現異常");try {connection.rollback();//出現問題,要回滾(撤銷事務做過的修改)connection.commit();//可加也不不加} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}finally {if(pstat1!=null){try {pstat1.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(pstat2!=null){try {pstat2.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}if(connection!=null){try {connection.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}}Mysql支持的事務語句
#開啟事務 START TRANSACTION; # connection.setAutoCommit(false); UPDATE account SET money=money-1000 WHERE id=1; UPDATE account SET money=money+1000 WHERE id=2; #提交事務 COMMIT;#connection.commit(); #回滾 ROLLBACK; #connection.rollback();3.3 事務隔離級別
SQL標準定義了4類隔離級別,包括了一些具體規則,用來限定事務內外的哪些改變是可見的,哪些是不可見的。低級別的隔離級一般支持更高的并發處理,并擁有更低的系統開銷。
Read Uncommitted(讀取未提交內容)
? 在該隔離級別,所有事務都可以看到其他未提交事務的執行結果。本隔離級別很少用于實際應用,因為它的性能也不比其他級別好多少。讀取未提交的數據,也被稱之為臟讀(Dirty Read)。
Read Committed(讀取提交內容)
? 這是大多數數據庫系統的默認隔離級別(但不是MySQL默認的)。它滿足了隔離的簡單定義:一個事務只能看見已經提交事務所做的改變。這種隔離級別
也支持所謂的不可重復讀(Nonrepeatable Read),因為同一事務的其他實例在該實例處理其間可能會有新的commit,所以同一select可能返回不同結果。
Repeatable Read可重讀
只要這個事務還沒結束,沒有提交,就算是其他事務提交了,當前事務也不會讀到
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-IQAEk7IY-1576317161188)(file:///C:\Users\Administrator.C1CWIYTPJWAKWQO\AppData\Roaming\Tencent\Users\1158068596\TIM\WinTemp\RichOle`77(`8~7C{4XZX60@3U}K@1.png)][外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hdDIcxGM-1576317161189)(file:///C:\Users\Administrator.C1CWIYTPJWAKWQO\AppData\Roaming\Tencent\Users\1158068596\TIM\WinTemp\RichOle\GB0{LC7Y_6YO%ZSQ[BUDYYJ.png)]
? 這是MySQL的默認事務隔離級別,它確保同一事務的多個實例在并發讀取數據時,會看到同樣的數據行。不過理論上,這會導致另一個棘手的問題:幻讀(Phantom Read)。簡單的說,幻讀指當用戶讀取某一范圍的數據行時,另一個事務又在該范圍內插入了新行,當用戶再讀取該范圍的數據行時,會發現有新的“幻讀” 行。InnoDB和Falcon存儲引擎通過多版本并發控制(MVCC,Multiversion Concurrency Control)機制解決了該問題。
Serializable 可串行化
? 這是最高的隔離級別,它通過強制事務排序,使之不可能相互沖突,從而解決幻讀問題。簡言之,它是在每個讀的數據行上加上共享鎖。在這個級別,可能導致大量的超時現象和鎖競爭。效率最低的。
? 這四種隔離級別采取不同的鎖類型來實現,若讀取的是同一個數據的話,就容易發生問題。
例如:
? 臟讀(Drity Read):某個事務已更新一份數據,另一個事務在此時讀取了同一份數據,由于某些原因,前一個RollBack了操作,則后一個事務所讀取的數據就會是不正確的。
? 演示案例:
#修改事務的隔離級別: SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] #查看事務隔離級別 SELECT @@tx_isolation;? 不可重復讀(Non-repeatable read):在一個事務的兩次查詢之中數據不一致,這可能是兩次查詢過程中間插入了一個事務更新的原有的數據。
? 演示案例:
# 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;START TRANSACTION; UPDATE account SET money=money+1000 WHERE id=2; COMMIT;# B方 賣 鄭帥 #(修改隔離級別) SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; #查看隔離級別 SELECT @@tx_isolation; SELECT *FROM account; #發貨 #修改隔離級別 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; SELECT *FROM account;#不可重復讀START TRANSACTION;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account; COMMIT; #再次修改隔離級別SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;START TRANSACTION;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account;SELECT SUM(money) FROM account; COMMIT;? 幻讀(Phantom Read):在一個事務的兩次查詢中數據筆數不一致,例如有一個事務查詢了幾列(Row)數據,而另一個事務卻在此時插入了新的幾列數據,先前的事務在接下來的查詢中,就會發現有幾列數據是它先前所沒有的。但是InnoDB存儲引擎通過多版本并發控制機制解決了該問題。
3.4 JDBC中事務應用
如果JDBC連接處于自動提交模式,默認情況下,則每個SQL語句在完成后都會提交到數據庫。
事務使您能夠控制是否和何時更改應用于數據庫。它將單個SQL語句或一組SQL語句視為一個邏輯單元,如果任何語句失敗,則整個事務將失敗。
要啟用手動事務支持,而不是JDBC驅動程序默認使用的自動提交模式,請使用Connection對象的**setAutoCommit()**方法。如果將boolean false傳遞給setAutoCommit(),則關閉自動提交。我們可以傳遞一個布爾值true來重新打開它。
3.4.1 事務的提交和回滾
完成更改后,我們要提交更改,然后在連接對象上調用**commit()**方法,如下所示:
conn.commit( );否則,要使用連接名為conn的數據庫回滾更新,請使用以下代碼 -
conn.rollback( ); try{//Assume a valid connection object connconn.setAutoCommit(false);Statement stmt = conn.createStatement();String SQL = "INSERT INTO Employees " +"VALUES (106, 20, 'Rita', 'Tez')";stmt.executeUpdate(SQL); //Submit a malformed SQL statement that breaksString SQL = "INSERTED IN Employees " +"VALUES (107, 22, 'Sita', 'Singh')";stmt.executeUpdate(SQL);// If there is no error.conn.commit(); }catch(SQLException se){// If there is any error.conn.rollback(); }3.4.2 Savepoint
新的JDBC 3.0 Savepoint接口為您提供了額外的事務控制。
設置保存點時,可以在事務中定義邏輯回滾點。如果通過保存點發生錯誤,則可以使用回滾方法來撤消所有更改或僅保存在保存點之后所做的更改。
Connection對象有兩種新的方法來幫助您管理保存點 -
- **setSavepoint(String savepointName):**定義新的保存點。它還返回一個Savepoint對象。
- **releaseSavepoint(Savepoint savepointName):**刪除保存點。請注意,它需要一個Savepoint對象作為參數。此對象通常是由setSavepoint()方法生成的保存點。
1、要取消掉JDBC的自動提交:void setAutoCommit(boolean autoCommit)
2、執行各個SQL語句,加入到批處理之中
3、如果所有語句執行成功,則提交事務 commit();如果出現了錯誤,則回滾:rollback()
try {connection.setAutoCommit(false);add(connection); // int i = 1/0;sub(connection);System.out.println("===============");connection.commit();} catch (Exception e) {// TODO Auto-generated catch blockSystem.out.println("---------------");try {connection.rollback();} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}以上就是java代碼利用jdbc操作數據庫的最簡單版本,數據庫事務通常要借助補捉異常語句
總結
1 批處理
? Statement實現批處理
? stat.addBatch(sql);// insert update delete
? stat.executeBatch();
? PreparetedStatement
? pstat.addBatch();
? pstat.executeBatch();
? pstat.clearBatch();
2 jdbc操作大數據
? 大文本 text mediumtext longtext
? setAsciiStream();
? setCharacterStream();
? setBinaryStream();
? 二進制 blob
? setBinaryStream();
3 事務
? 原子性 A:不能分割
? 一致性 C:事務執行前后保持一致
? 隔離型 I: 事務與事務之間對數據的讀取控制
? 持久性 D:事務提交或回滾之后,永久保存數據庫。
4 修改隔離級別
#修改事務的隔離級別: SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL [READ UNCOMMITTED|READ COMMITTED|REPEATABLE READ|SERIALIZABLE] #查看事務隔離級別 SELECT @@tx_isolation;java代碼更改隔離級別
conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);5 保存點
SavePoint
作業題
1、實現一個學生管理系統,要求實現正刪改查,基于控制臺實現即可 要求可以對學生信息進行添加、修改、刪除、查詢的功能面試題
1、什么是JDBC,在什么時候會用到它? 2、execute,executeQuery,executeUpdate的區別是什么? 3、JDBC的PreparedStatement是什么? 4、相對于Statement,PreparedStatement的優點是什么?總結
以上是生活随笔為你收集整理的MySQL使用JDBC高级操作和事务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 增量式光照模型
- 下一篇: API是什么?API的基础知识你知道多少