[TOC]
# 事務其他屬性
事務還有一些其他的特點,如在業務bean——PersonServiceBean中,有些業務方法是不需要進行事務管理的,比方說獲取數據的方法,那么這個時候我們就需要用到事物的propagation屬性了,該屬性指定了事務的傳播行為。所以,我們應將getPerson()方法的代碼修改為:
~~~
/**
* 使用JdbcTemplate獲取一條記錄
*/
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public Person getPerson(Integer personid) {
return jdbcTemplate.queryForObject("select * from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER}, new PeronRowMapper());
}
~~~
還要將getPersons()方法的代碼修改為:
~~~
/**
* 使用JdbcTemplate獲取多條記錄
*/
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public List<Person> getPersons() {
return jdbcTemplate.query("select * from person", new PeronRowMapper());
}
~~~
這樣,當這2個業務方法執行的時候,它都不會開啟事務,能節約資源,提供效率。
下面,我們就來對事務傳播屬性做一個總結:
* REQUIRED:業務方法需要在一個事務中運行。如果方法運行時,已經處在一個事務中,那么這個時候就會加入到該事務中,如果當前沒有事務環境的話,就會為自己創建一個新的事務。默認情況下,業務方法的事務傳播屬性就是REQUIRED。在應用開發中,80%的情況下都會使用這種事務傳播屬性。
* NOT_SUPPORTED:聲明方法不需要事務。如果方法沒有關聯到一個事務,容器不會為它開啟事務。如果方法在一個事務中被調用(在其他業務bean的方法中被調用了,而其他業務bean的方法是開啟了事務的),該事務會被掛起,在方法調用結束后,原先的事務便會恢復執行。
* REQUIRESNEW:該屬性表明不管當前是否存在事務,業務方法總會為自己發起一個新的事務。如果方法已經運行在一個事務中,則原有事務會被掛起,新的事務會被創建,直到方法執行結束,新事務才算結束,原先的事務才會恢復執行。
* MANDATORY:該屬性指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起自己的事務。如果業務方法在沒有事務的環境下調用,容器就會拋出異常。
* SUPPORTS:這一事務屬性表明,如果業務方法在某個事務范圍內被調用,則方法成為該事務的一部分。如果業務方法在事務范圍外被調用,則方法在沒有事務的環境下執行。即當標注了事務傳播屬性——SUPPORTS的業務方法在另一個bean的業務方法中執行時,如果另一個bean的業務方法開啟了事務,那么執行到標注了事務傳播屬性——SUPPORTS的業務方法時,它就會處在事務中執行,如果另一個bean的業務方法也沒開啟事務,那么標注了事務傳播屬性——SUPPORTS的業務方法也在沒有事務的環境中進行。
* Never:指定業務方法絕對不能在事務范圍內執行。如果業務方法在某個事務中執行,容器會拋出異常,只有業務方法沒有關聯到任何事務,才能正常執行。
* NESTED:如果一個活動的事務存在,則當前方法運行在一個嵌套的事務中。 如果沒有活動事務,則按REQUIRED屬性執行。它使用了一個單獨的事務,這個事務擁有多個可以回滾的保存點。內部事務的回滾不會對外部事務造成影響。它只對DataSourceTransactionManager事務管理器起效果。
接下來,我們著重介紹事務傳播屬性——NESTED。如有下面一段代碼:
~~~
@Resource OtherService otherService;
public void xxx() {
stmt.executeUpdate("update person set name='888' where id=1");
otherService.update(); // OtherService的update()方法的事務傳播屬性為NESTED
stmt.executeUpdate("delete from person where id=9");
}
~~~
將以上代碼展開,可能就變成了如下這樣一段代碼:
~~~
Connection conn = null;
try {
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.executeUpdate("update person set name='888' where id=1");
Savepoint savepoint = conn.setSavepoint(); // 保存點
try{
conn.createStatement().executeUpdate("update person set name='222' where sid=2");
}catch(Exception ex){
conn.rollback(savepoint);
}
stmt.executeUpdate("delete from person where id=9");
conn.commit();
stmt.close();
} catch (Exception e) {
conn.rollback();
}finally{
try {
if(null!=conn && !conn.isClosed()) conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
~~~
其中,OtherService中標注事務傳播屬性為NESTED的update()方法,就相當于這樣一段代碼:
~~~
Savepoint savepoint = conn.setSavepoint(); // 保存點
try{
conn.createStatement().executeUpdate("update person set name='222' where sid=2");
}catch(Exception ex){
conn.rollback(savepoint);
}
~~~
我們也就明白了內部事務的回滾不會對外部事務造成影響。
# 事務的其他屬性
除了事務傳播屬性外,事務還有一些其他的屬性:
* readOnly屬性:設置為只讀事務,對于只讀事務,它就不能進行更新操作,一般只存在數據讀取的時候,可以將readOnly屬性設置為true,可提供效率。
* timeout屬性:代表事務的超時時間,默認為30s,一般情況下都不需要設置超時時間。
# 事務的isolation屬性
事務的isolation屬性指定了事務的隔離級別,實際上事務的隔離級別并不是由Spring容器決定的,而是由底層數據庫決定的。
# 數據庫系統提供了四種事務隔離級
數據庫系統提供了四種事務隔離級別供用戶選擇。不同的隔離級別采用不同的鎖類型來實現,在四種隔離級別中,Serializable的隔離級別最高,但對并發訪問數據庫的性能影響最大。Read Uncommited的隔離級別最低。大多數據庫默認的隔離級別為Read Commited,如SqlServer,當然也有少部分數據庫默認的隔離級別為Repeatable Read,如Mysql。
* Read Uncommited:讀未提交數據(會出現臟讀,不可重復讀和幻讀)
* Read Commited:讀已提交數據(會出現不可重復讀和幻讀)
* Repeatable Read:可重復讀(會出現幻讀)
* Serializable:串行化
臟讀:一個事務讀取到另一事務未提交的更新新據。前提是并發的兩個或多個事務。
不可重復讀:在同一事務中,多次讀取同一數據返回的結果有所不同。換句話說就是,后續讀取可以讀到另一事務已提交的更新數據。
可重復讀:在同一事務中多次讀取數據時,能夠保證所讀數據一樣,也就是,后續讀取不能讀到另一事務已提交的更新數據。目前要實現可重復讀的話,一般數據庫采用快照技術,在某一時刻(點),當你訪問數據的時候,它把這個數據作為一個鏡像,以后在同一個事務中再去讀取相同記錄的數據時,它都可以從快照里面返回這個數據,不管外部怎么樣對它操作,在多次讀取的時候都不會受到影響。
幻讀:一個事務讀取到另一事務已提交的insert數據。
- 基礎
- 編譯和安裝
- scanner類(鍵盤錄入)
- Random類(隨機數)
- 數組
- 方法
- 類
- ArrayList集合
- char與int
- eclipse
- IDEA
- 變量與常量
- 常用API
- String,StringBuffer,StringBuilder
- 正則,Date,DateFormat,Calendar
- 包裝類,System,Math,Arrays,BigInteger,BigDecimal
- 集合,迭代器,增強for,泛型
- List,set,判斷集合唯一
- map,Entry,HashMap,Collections
- 異常
- IO
- File
- 遞歸
- 字節流
- 字符流
- IO流分類
- 轉換流
- 緩沖流
- 流的操作規律
- properties
- 序列化流與反序列化流
- 打印流
- commons-IO
- IO流總結
- 多線程
- 線程池
- 線程安全
- 線程同步
- 死鎖
- lock接口
- ThreadLoad
- 等待喚醒機制
- 線程狀態
- jdbc
- DBUtils
- 連接池DBCP
- c3p0連接池
- 網絡編程
- 多線程socket上傳圖片
- 反射
- xml
- 設計模式
- 裝飾器模式
- web service
- tomcat
- Servlet
- response
- request
- session和cookie
- JSP
- EL
- JSTL
- 事務
- 監聽器Listener
- 過濾器Filter
- json
- linux安裝軟件
- 反射詳解
- 類加載器和注解
- 動態代理
- jedis
- Hibernate
- 簡介
- 創建映射文件
- Hibernate核心配置文件
- 事務和增刪改查
- HibernateUtils
- 持久化對象的三種狀態
- 檢索方式
- query
- Criteria
- SQLQuery
- 持久化類
- 主鍵生成策略
- 緩存
- 事務管理
- 關系映射
- 注解
- 優化
- struts2
- 搭建
- 配置詳解
- Action
- 結果跳轉方式
- 訪問ServletAPI方式
- 如何獲得參數
- OGNL表達式
- valueStack 值棧
- Interceptor攔截器
- spring
- 導包
- IOC和DI
- Bean獲取與實例化
- Bean屬性注入
- spring注解
- 注解分層
- junit整合
- aop
- 動態代理實現
- cglib代理實現
- aop名詞
- spring的aop
- aop-xml詳解
- aop-注解詳解
- 代理方式選擇
- jdbcTemplate
- spring事務管理
- 回滾注意
- 事務傳播屬性
- MyBatis
- MyBatis簡介
- 入門程序
- 與jdbc hibernate不同
- 原始Dao開發
- Mapper動態代理方式
- SqlMapConfig.xml配置文件
- 輸入參數pojo包裝類
- resultMap
- 動態sql
- 一對一關聯
- 一對多
- 整合spring
- 逆向工程
- maven
- maven簡介
- 倉庫
- maven目錄結構
- maven常用命令
- 生命周期
- eclipse中maven插件
- 入門程序
- 整合struct
- 依賴范圍
- 添加插件
- idea配置
- jar包沖突
- 分模塊開發
- 構建可執行的jar包(包含依賴jar包)
- springMVC
- 處理流程
- java面試
- java版本升級
- java1-8版本變更
- java9新特性
- 鎖
- java資料
- idea
- jdk版本切換
- log4j
- 入門實例
- 基本使用方法
- Web中使用Log4j
- spring中使用log4j
- java代碼優化