Spring的JDBC事務實現
之前專案中有大量資料提交的需求,考慮了幾個解決方案後還是覺得使用事務提交效率更高、資料插入也更方便。
一、首先,讓我們來看看什麼是事務
事務(Transaction)是併發控制的單元,是使用者定義的一個操作序列。這些操作要麼都做,要麼都不做,是一個不可分割的工作單位。通過事務,sql server能將邏輯邏輯相關的一組操作繫結在一起,以便伺服器保持資料的完整性。事務通常由begin transaction開始,以Commit或者Rollback結束。Commit表示提交,即提交事務的所有操作,具體的說就是將事務中所有對資料的更新寫回到資料庫的物理磁碟上,事務正常結束。Rollback表示回滾,即在事務執行的過程中發生了某種故障,事務不能繼續進行,系統將事務中對資料庫
的所有已完成的操作全部撤銷,滾回到事務開始的狀態。
事務具有以下特性:
1、原子性(Atomicity):事務是資料庫的邏輯工作單元,必須是原子工作單位,事務的原子性確保動作要麼全部執行,要麼全部不執行。
2、一致性(Consistency):事務在完成時,系統必須確保所有的資料處於一致的狀態,而不會是部分完成部分失敗。在現實中的資料不應該被破壞。
3、隔離性(Isolation):一個事務的執行不能被其他事務所影響。
4、永續性(Durability):一個事務一旦提交,事務的操作便永久的儲存在DB中,即使此時再執行回滾操作也不能撤銷所做的更改。無論發生什麼系統錯誤,它的結果都不應該受到影響。
事務可分為以下幾種:
1、自動提交事務
每條單獨的語句都是一個事務。每個語句後都隱含一個commit。
2、顯式事務
以begin transaction開始,以Commit或者Rollback結束。
3、隱式事務
當連線以隱式事務模式進行操作時,sql server資料庫引擎例項將在提交或回滾當前事務後自動啟動新事務,無需描述事務的
開始,只需提交或回滾每個事務,但每個事務仍以Commit或者Rollback顯式結束。連線將隱式事務模式開啟後,為資料庫引擎例項
首次執行以下任何語句時,都會自動啟動一個隱式事務:alter table,insert,create,open,delete,revoke,drop,select,
fetch,truncate table,grant,update。在發出commit或rollback語句之前,該事務將一直保持有效。在第一個事務被提交或回
滾之後,下次當連線執行以上任何語句時,資料庫引擎例項都會自動啟動一個新事務。該引擎將不斷生成隱式事務鏈,直到隱式事
務模式關閉為止。
二、Spring對事務的支援
Spring並不直接管理事務,而是提供了多種事務管理器,他們將事務管理的職責委託給Hibernate或者JTA等持久化機制所提供的相關平臺框架的事務來實現。 Spring事務管理器的介面org.springframework.transaction.PlatformTransactionManager,通過這個介面,Spring為各個平臺如JDBC、Hibernate等都提供了對應的事務管理器,但是具體的實現就是各個平臺自己的事情了。
此介面的內容如下:
Public interface PlatformTransactionManager()...{
// 由TransactionDefinition得到TransactionStatus物件
TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException;
// 提交
Void commit(TransactionStatus status) throws TransactionException;
// 回滾
Void rollback(TransactionStatus status) throws TransactionException;
}
從這裡我們可以看到具體的事務管理機制對Spring來說是透明的,它並不關心那些,那些是對應各個平臺需要關心的,所以Spring事務管理的一個優點就是為不同的事務API提供一致的程式設計模型,如JTA、JDBC、Hibernate、JPA等。
三、事務應用例項
本例項主要解決了提交大量資料的需求,使用JDBC事務實現。
1、那麼如何使用JDBC事務呢?
如果應用程式中直接使用JDBC來進行持久化,DataSourceTransactionManager會來處理事務邊界。為了使用DataSourceTransactionManager,我們需要使用如下的XML將其裝配到應用程式的上下文定義中:
<!-- (事務管理)transaction manager-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
實際上,DataSourceTransactionManager是通過呼叫java.sql.Connection來管理事務,而後者是通過DataSource獲取到的。通過呼叫連線的commit()方法來提交事務,同樣,事務失敗則通過呼叫rollback()方法進行回滾。
2、話不多說,直接上實現程式碼
/**
* 資料提交
* @return
*/
@RequestMapping(value = "/submitTerm.go", method = { RequestMethod.GET, RequestMethod.POST })
@ResponseBody
public void submitTerm(@RequestBody submitInfo submitInfo, HttpServletRequest request) throws Exception {
//獲取資料庫連線
WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
DataSource dataSource = wac.getBean(DataSource.class);
Connection con = dataSource.getConnection();
PreparedStatement ps = null;
try {
//設定事務的提交方式為非自動提交:
con.setAutoCommit(false);
// 建立執行語句
String sql = "insert into dec_company_baseinfo (dwmc,addr,zzjgdm,yyzzzch,reg_time,postcode,"
+ "e_mail,dw_url,jyfs,jyfw,dwzycp,hylb,hwyxjgs,qnydl,szzqjysc,gpdm,dkzhm,dwdjzclx,"
+ "dwgsdjzh,dwdsdjzh,dwdh,dw_fax,zcszbsc,ssgxjsly,hwyfjgs,qnysl,gssssj,gfgsclfs,zczb,"
+ "zczb_zz,zczb_wz,zczb_wzzb,sszb,sszb_zz,sszb_wz,sszb_wzzb,yfbgmj_lhn,yfbgmj_lhw,"
+ "scyfmj_lhn,scyfmj_lhw,yyyfjg_country,yyyfjg_province,yyyfjg_city,yyyfjg_area,dwzz,"
+ "dwzyzz,dwjbkhyh,khhm,yhxydj,yhzh,data_status,xzgl_num,scyx_num,yfsj_numjgzz_num,"
+ "qtgw_num,bs_num,ss_num,bk_num,dz_num,qtxl_num,gjzc_num,zjzc_num,cjzc_num,qtzc_num,"
+ "wjys_num,gdzjjhrc_num,lhxqgccrc_num,gjqrjhrc_num,szskqjhrc_num,gdcxcytd_num,"
+ "szsgcczyrc_num,qtrc_num,snnmcyry_num,mzg_num,wzg_num,cjsb_num,lxgg_num,wjzj_num,"
+ "snxzgxbys_num,sncpxssr,sndjlr,sndnsze,zzsze) values (#{dwmc},#{addr},#{zzjgdm},"
+ "#{yyzzzch},#{reg_time},#{postcode},#{e_mail},#{dw_url},#{jyfs},#{jyfw},#{dwzycp},"
+ "#{hylb},#{hwyxjgs},#{qnydl},#{szzqjysc},#{gpdm},#{dkzhm},#{dwdjzclx},#{dwgsdjzh},"
+ "#{dwdsdjzh},#{dwdh},#{dw_fax},#{zcszbsc},#{ssgxjsly},#{hwyfjgs},#{qnysl},#{gssssj},"
+ "#{gfgsclfs},#{zczb},#{zczb_zz},#{zczb_wz},#{zczb_wzzb},#{sszb},#{sszb_zz},"
+ "#{sszb_wz},#{sszb_wzzb},#{yfbgmj_lhn},#{yfbgmj_lhw},#{scyfmj_lhn},#{scyfmj_lhw},"
+ "#{yyyfjg_country},#{yyyfjg_province},#{yyyfjg_city},#{yyyfjg_area},#{dwzz},"
+ "#{dwzyzz},#{dwjbkhyh},#{khhm},#{yhxydj},#{yhzh},#{data_status},#{xzgl_num},"
+ "#{scyx_num},#{yfsj_numjgzz_num},#{qtgw_num},#{bs_num},#{ss_num},#{bk_num},#{dz_num},"
+ "#{qtxl_num},#{gjzc_num},#{zjzc_num},#{cjzc_num},#{qtzc_num},#{wjys_num},"
+ "#{gdzjjhrc_num},#{lhxqgccrc_num},#{gjqrjhrc_num},#{szskqjhrc_num},#{gdcxcytd_num},"
+ "#{szsgcczyrc_num},#{qtrc_num},#{snnmcyry_num},#{mzg_num},#{wzg_num},#{cjsb_num},"
+ "#{lxgg_num},#{wjzj_num},#{snxzgxbys_num},#{sncpxssr},#{sndjlr},#{sndnsze},#{zzsze})";
String sql1 = "insert into dec_talent_baseinfo (zzjgdm,rc_type,name,xl,mobile,tel,fax,e_mail,"
+ "card_type,card_no,zw,zc) values (#{zzjgdm},#{rc_type},#{name},#{xl},#{mobile},"
+ "#{tel},#{fax},#{e_mail},#{card_type},#{card_no},#{zw},#{zc})";
String sql2 = "insert into dec_finance_baseinfo (zzjgdm,xmlb,sn,qn,dqn,zzl_avg) values "
+ "(#{zzjgdm},#{xmlb},#{sn},#{qn},#{dqn},#{zzl_avg})";
String sql3 = "insert into dec_development_baseinfo (zzjgdm,xmmc,sn,qn,dqn,data_status,zzl_avg)"
+ " values (#{zzjgdm},#{xmmc},#{sn},#{qn},#{dqn},#{data_status},#{zzl_avg})";
String sql4 = "insert into dec_support_baseinfo (zzjgdm,seq,xmmc,zzbm,zzje,zzxs,zzsj,yssj,"
+ "xmysqk,jkchqk,hksj) values (#{zzjgdm},#{seq},#{xmmc},#{zzbm},#{zzje},#{zzxs},"
+ "#{zzsj},#{yssj},#{xmysqk},#{jkchqk},#{hksj})";
String sql5 = "insert into dec_products_baseinfo (zzjgdm,seq,zycpmc,sfjyzscq,cplx,cpxxsrze,"
+ "zqyxssrbl) values (#{zzjgdm},#{seq},#{zycpmc},#{sfjyzscq},#{cplx},#{cpxxsrze},"
+ "#{zqyxssrbl})";
// 分別執行事務
ps = con.prepareStatement(sql);
ps.executeUpdate();
ps = con.prepareStatement(sql1);
ps.executeUpdate();
ps = con.prepareStatement(sql2);
ps.executeUpdate();
ps = con.prepareStatement(sql3);
ps.executeUpdate();
ps = con.prepareStatement(sql4);
ps.executeUpdate();
ps = con.prepareStatement(sql5);
ps.executeUpdate();
// 在try塊內新增事務的提交操作,表示操作無異常,提交事務。
con.commit();
con.setAutoCommit(true);
} catch (Exception ex) {
try {
con.rollback();//操作失敗則事務回滾
} catch (Exception e) {
e.printStackTrace();
}
ex.printStackTrace();
} finally {
//最後一定要關閉
try {
ps.close();
con.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}