基於註解的事務管理
- 配置數據源:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<context:property-placeholder location="classpath:jdbc.properties" />
// 佔位符的設置
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="${driverClassName}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
<!-- 連接池啓動時的初始值 -->
<property name="initialSize" value="${initialSize}" />
<!-- 連接池的最大值 -->
<property name="maxActive" value="${maxActive}" />
<!-- 最大空閒值.當經過一個高峯時間後,連接池可以慢慢將已經用不到的連接慢慢釋放一部分,一直減少到maxIdle爲止 -->
<property name="maxIdle" value="${maxIdle}" />
<!-- 最小空閒值.當空閒的連接數少於閥值時,連接池就會預申請去一些連接,以免洪峯來時來不及申請 -->
<property name="minIdle" value="${minIdle}" />
</bean>
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<tx:annotation-driven transaction-manager="txManager" />
<bean id="personService" class="com.spring.test.manager.impl.PersonManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
url=jdbc/:mysql/://localhost/:3306/myproj?useUnicode/=true& characterEncoding/=UTF-8
username=root
password=123456
initialSize=1
maxActive=500
maxIdle=2
minIdle=1
- 配置事務,需要在xml配置文件中引入聲明事務的tx命名空間,支持註解的方式和XML配置方式。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
- 註解方式用法
<bean id="txManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 指定採用@Transactional 註解的方式使用事務 -->
注意:@Transactional只能用於public方法上。如果用在private、protected,系統不會抱錯,但是配置的事務設置將失效。如果一定要在非public方法上用這個註解,需要引入AspectJ.
- 基本用法
@Service @Transactional
public class PersonDao implements IPersonDao {
//.......
}
- Spring事務管理的傳播屬性
REQUESTED:如果方法運行時,已經處在一個事務中,那麼加入到該事務中來,否則爲自己創建一個新事務。
NOT_SUPPORTED:聲明方法不需要事務。如果方法沒有關聯到一個事務,容器不會爲它開啓事務。如果方法在一個事務中被調用,該事物會被掛起,在方法調用結束後,原先的事務恢復運行。
REQUEST_NEW:不管是否存在事務,業務方法總會爲自己發起一個新的事務。如果方法運行在一個事務中,則原有事務掛起,新的事務創建,直到方法執行結束,新事務纔算結束,原先的事務纔會恢復執行。
MANDATORY:指定業務方法只能在一個已經存在的事務中執行,業務方法不能發起自己的事務。如果業務方法在沒有事務的環境下調用,容器就會拋出異常。
SUPPORTS:如果業務方法在某個事務範圍內被調用,則方法稱爲該事物的一部分。如果業務方法在事務範圍外被調用,則方法在沒有事務的環境下執行。
NEVER:指定業務方法不能再事務範圍內執行。如果業務方法在某個事務中執行,容器會拋出例外,如果業務方法沒有關聯到任何事務,才能正常執行。
NESTED:如果一個活動的事務存在,則運行在一個嵌套的事務中,如果沒有活動事務,則按REQUESTED屬性執行。它使用了一個獨立的事務,這個事務擁有多個可以回滾的保存點。內部事務的回滾不會影響到外部事務。
- Spring容器在默認狀態下,碰到unchecked-exception會回滾,checked-exception則不會 。
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
throw new RuntimeException("This is unchecked-exception.");
}
運行此方法,默認狀態下,數據庫中的數據不會刪除,spring容器會回滾事務。
public void delete(Integer personid) throws Exception {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
throw new Exception("This is checked-exception.");
}
運行此方法,默認狀態下,數據庫中的數據會被刪除,spring容器不會回滾事務。
修改默認情況,指定事務中碰到某個checked-exception,spring容器會回滾事務。
public void delete(Integer personid) throws Exception {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
throw new Exception("This is checked-exception.");
}運行此方法,spring容器會回滾事務。
同理,也可修改屬性,使得事務中碰到unchecked-exception不回滾事務。
public void delete(Integer personid) {
jdbcTemplate.update("delete from person where id=?", new Object[]{personid},
new int[]{java.sql.Types.INTEGER});
throw new RuntimeException("This is unchecked-exception.");
}
- 註解中指定傳播屬性
默認狀態下,數據庫事務的傳播屬性爲REQUIRED。
可以按如下方法明確指定傳播屬性。
@Transactional(propagation=Propagation.NOT_SUPPORTED)
public List<Person> getPersons() {
return (List<Person>)jdbcTemplate.query("select * from person", new PersonRowMapper());
}
- 隔離級別
數據庫系統提供了四種隔離級別,不同的隔離級別採用不同的鎖類型來實現。大多數據庫系統默認的隔離級別爲Read Committed。
Read Uncommitted:讀未提交的數據,會出現髒讀,不可重複讀和幻讀
Read Committed:讀已提交的數據,會出現不可重複讀和幻讀
Repeatable Read:可重複讀,會出現幻讀
Serializable:最高隔離級別,效率也最低,不會出現以上的髒讀,不可重複讀和幻讀。
髒讀:一個事務讀到另一個未提交事務的更新數據。
不可重複讀:在同一個事物中,多次讀取同一數據返回的結果不同。即後續讀取可以讀到另一個事務已提交的更新事務。
幻讀:一個事務讀到另一個事務已提交的insert數據。