1 概述
是指作為單個邏輯工作單元執(zhí)行的一系列操作,要么完全地執(zhí)行园担,要么完全地不執(zhí)行旨椒。事務可以分為編程式事務和聲明式事務。
編程式事務控制又叫細粒度事務的控制魔吐,可以針對指定的方法以及方法中具體的某一行代碼添加事務控制扎筒。需要自己每次手動的去添加莱找,開發(fā)比較繁瑣,每次都要開啟嗜桌、提交奥溺、回滾。
- jdbc 代碼:conn.setAutoCommite(false) //設置手動控制事務
- hibernate 代碼:session.beginTransaction() //開啟一個事務
聲明式事務又叫粗粒度事務的控制骨宠,只能給方法添加事務控制浮定。Spring 提供了對事務的管理,我們需要使用事務時只需要在配置文件中配置即可层亿,不使用時直接移除桦卒,這樣便大大的降低了事務控制的耦合。Spring 事務控制的實現(xiàn)是依賴與 Aop匿又。
2 事務控制的幾種方式
2.1 xml 實現(xiàn)
【1】步驟
- 引入 Spring-aop 相關的4個 jar
- 引入 aop 名稱空間
- 引入 tx 名稱空間
- 引入 Spring-jdbc 相關 jar(使用到spring jabcTemplate)
【2】實現(xiàn)
模擬: 在service中調用2次dao方灾, 希望其中一個dao執(zhí)行失敗,整個操作回滾
bean.xml (核心配置文件)
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 數(shù)據源對象: C3P0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>
<!-- 2. 創(chuàng)建JdbcTemplate對象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3.創(chuàng)建 Dao碌更、Service -->
<bean id="userDao" class="com.acey.tx.a_xml_tx.UserDao">
<property name="jdbcTemplate" ref="jdbcTemplate"/>
</bean>
<bean id="userService" class="com.acey.tx.a_xml_tx.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 4. 聲明式事務管理配置-->
<!-- 4.1 配置事務管理器類-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 4.2 配置事務增強(如何管理)-->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!--(1)方法名中包含 find 的方法只讀-->
<tx:method name="*find*" read-only="true"/>
<!--(2)方法名中以 get 開頭的方法只讀-->
<tx:method name="get*" read-only="true"/>
<!--除了(1)和(2)其它的方法進行讀寫-->
<tx:method name="*" read-only="false"/>
</tx:attributes>
</tx:advice>
<!-- 4.3 aop 配置裕偿,攔截哪些方法應用事務管理-->
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.acey.tx.a_xml_tx.*Service.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
</beans>
由于我們使用的是 jdbc 技術,所以我們在配置事務管理器類時使用的是
DataSourceTransactionManager
痛单,如果我們使用的是 hibernate 技術嘿棘,我們需要使用
HibernateTransactionManager
2.2 注解實現(xiàn)
【1】步驟
- 引入 Aop 相關 jar
- bean.xml 中配置事務管理器類以及指定 注解方式實現(xiàn)聲明式事務
- 在需要添加事務控制的地方加上 @Transactional
@Transactional注解
- 定義到方法上,當前方法使用 Spring 的聲明式事務
- 定義在類上桦他,當前類的所有方法使用 Spring 的聲明式事務
- 定義到父類上蔫巩,當執(zhí)行父類的方法時應用事務
【2】實現(xiàn)(核心代碼)
bean.xml
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 1. 數(shù)據源對象: C3P0連接池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver"></property>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
<property name="user" value="root"></property>
<property name="password" value="root"></property>
<property name="initialPoolSize" value="3"></property>
<property name="maxPoolSize" value="10"></property>
<property name="maxStatements" value="100"></property>
<property name="acquireIncrement" value="2"></property>
</bean>
<!-- 2. 創(chuàng)建JdbcTemplate對象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3. 開啟注解掃描-->
<context:component-scan base-package="com.acey.tx.b_anno_tx"/>
<!-- 4.創(chuàng)建事務管理器-->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 5.開啟事務注解-->
<tx:annotation-driven transaction-manager="txManager"></tx:annotation-driven>
</beans>
UserDao.class
@Repository
public class UserDao {
@Resource
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
// @Transactional(
// readOnly = false, //讀寫事務
// timeout = -1, //事務的超時時間(-1(默認值)表示不限制)
// noRollbackFor = ArithmeticException.class, //遇到數(shù)學類異常不回滾
// propagation = Propagation.REQUIRED //事務的傳播行為
// )
@Transactional
public void save(String name) {
String sql = "insert into t_user (name) values(?)";
jdbcTemplate.update(sql, name);
int i = 1 / 0;//異常
jdbcTemplate.update(sql, name);
}
}
3 事務屬性
@Transactional(
readOnly = false, //讀寫事務
timeout = -1, //事務的超時時間(-1(默認值)表示不限制)
noRollbackFor = ArithmeticException.class, //遇到數(shù)學類異常不回滾
propagation = Propagation.REQUIRED //事務的傳播行為
)
其中事務傳播行分為:
- Propagation.REQUIRED
指定當前的方法必須在事務的環(huán)境下執(zhí)行;
如果當前運行的方法快压,已經存在事務圆仔, 就會加入當前的事務; - Propagation.REQUIRED_NEW
指定當前的方法必須在事務的環(huán)境下執(zhí)行蔫劣;
如果當前運行的方法坪郭,已經存在事務: 事務會掛起; 會始終開啟一個新的事務脉幢,執(zhí)行完后歪沃;
剛才掛起的事務才繼續(xù)運行。
所有實例代碼地址 https://github.com/Aceysx/SpringDemo