Java-JDBC調用批處理、存儲過程、事務


一、使用Batch批量處理數據庫 

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

1、實現批處理有兩種方式,第一種方式:

           Statement.addBatch(sql)  list

執行批處理SQL語句

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

            clearBatch()方法:清除批處理命令

例:

Connection conn = null;

Statement st = null;

ResultSet rs = null;

try {

conn = JDBCManager.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{

JDBCManager.DBclose(con,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’);

 

 

 

2、實現批處理的第二種方式:

         PreparedStatement.addBatch();

例:

conn = JDBCManager.getConnection();//獲取工具;

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

st = conn.prepareStatement(sql);//預處理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();//將一組參數添加到此 PreparedStatement 對象的批處理命令中。

if(i%1000==0){

st.executeBatch();

st.clearBatch();清空此 Statement 對象的當前 SQL 命令列表。 

}

}

st.executeBatch();將一批命令提交給數據庫來執行,如果全部命令執行成功,則返回更新計數組成的數組。返回數組的 int 元素的排序對應於批中的命令,批中的命令根據被添加到批中的順序排序

 

 

采用PreparedStatement.addBatch()實現批處理

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

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

 

 

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

Connection con=null;

PreparedStatement ps=null;

con = JDBCManager.getConnection();

String sql="insert into users(name,password) values(?,?)";

try {

ps = con.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);//獲取返回的主鍵;

ps.setString(1, "qq");

ps.setString(2, "123");

ps.executeUpdate();

ResultSet rs=ps.getGeneratedKeys();//返回一個結果集,保存着產生的key的結果集,

while(rs.next()){

 System.out.println(rs.getObject(1));//結果集只有一個值;

}

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

JDBCManager.DBclose(con, ps, null);

}

 

三、JDBC調用存儲過程

 

存儲過程的創建

create procedure 存儲過程名(參數)

存儲過程體

 

編寫一個存儲過程,查詢學生表中的所有信息。

delimiter $$

create procedure myproc1()

 begin

       select * form xs;

   end $$

delimiter ;

 

執行:call myproc1();

 

參數

in :輸入參數

out: 輸出參數

inout:輸入輸出參數

 

要求:編寫一個存儲過程,通過學號查詢某學生的信息。

delimiter $$

create procedure select_student(in xh char(6))

begin

         select * from xs where 學號=xh;

end $$

delimiter ;

執行:call  select_student('081101');

 

要求:編寫一個存儲過程,統計學生的總人數

delimiter $$

create procedure count_xs(out number int)

begin

         select count(*) into number from xs;

end $$

delimiter ;

 

執行:call count_xs(@rs);

            查詢: select @rs;

 

create procedure 存儲過程名(in|out|inout 參數名 類型。。。。);

 

JDBC調用存數過程(創建好存儲過程體):

當值是輸入函數時:

例:

Connection con=null;

       CallableStatement cs=null;

       con=JDBCManager.getConnection();

       try {

cs=con.prepareCall("{call pd(?,?)}");//存儲過程語句;

cs.setString(1, "yy");

cs.setString(2, "msn");

cs.execute();//執行

System.out.println("執行成功");

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

JDBCManager.DBclose(con, cs, null);

}

當輸入和輸出同時:

Connection con=null;

      CallableStatement cs=null;

      con=JDBCManager.getConnection();

      try {

cs=con.prepareCall("{call pcall(?,?)}");

cs.setInt(1, 10);

cs.registerOutParameter(2,Types.CHAR);//獲取一下注冊類型;

cs.execute();//執行

System.out.println(cs.getString(2));//獲取第二個String類型的參數值;

cs.execute();

System.out.println("執行成功");

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}finally{

JDBCManager.DBclose(con, cs, null);

}

 

 

四、事務的使用

        事務指邏輯上的一組操作,組成這組操作的各個單元,要不全部成功,要不全部不成功。

        例如: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的事務主要分以下步驟

1.設置事務的提交方式為非自動提交:

   conn.setAutoCommit(false);

2.將需要添加事務的代碼放入try,catch塊中。

3.在try塊內添加事務的提交操作,表示操作無異常,提交事務。 

    conn.commit();

4.在catch塊內添加回滾事務,表示操作出現異常,撤銷事務:

    conn.rollback();

5.設置事務提交方式為自動提交:

     conn.setAutoCommit(true);

 

事務的特性(ACID)

 

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

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

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

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

 

事務的隔離性:

 

臟讀:

指一個事務讀取了另外一個事務未提交的數據。

這是非常危險的,假設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元。

 

不可重復讀:

在一個事務內讀取表中的某一行數據,多次讀取結果不同。

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

 

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

 

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

 

虛讀(幻讀)

是指在一個事務內讀取到了別的事務插入的數據,導致前后讀取不一致。

如丙存款100元未提交,這時銀行做報表統計account表中所有用戶的總額為500元,然后丙提交了,這時銀行再統計發現帳戶為600元了,造成虛讀同樣會使銀行不知所措,到底以哪個為准。

 

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

Serializable:可避免臟讀、不可重復讀、虛讀情況的發生。(串行化)(序列化)

Repeatable read:可避免臟讀、不可重復讀情況的發生。(可重復讀)

Read committed:可避免臟讀情況發生(讀已提交)。

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

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

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

 

例:

Connection con=null;

PreparedStatement st=null;

String sql1="insert into users(name,password) values('bbbbb','bbbb')";

String sql2="delete from users where id=9";

try {

con=DBManager.getConnection();

con.setAutoCommit(false);//把自動提交方式變為人工

 

st=con.prepareStatement(sql1);

st.executeUpdate();

System.out.println("第一個語句成功了");

 

 

st=con.prepareStatement(sql2);

st.executeUpdate();

System.out.println("第二個語句成功了");

 

con.commit();

 

} catch (Exception e) {

try {

con.rollback();//出現異常進行回滾;

} catch (SQLException e1) {

// TODO Auto-generated catch block

e1.printStackTrace();

}

e.printStackTrace();

}finally{

try {

con.setAutoCommit(true);

} catch (SQLException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

DBManager.closeDB(con, st, null);

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM