目录说明
1 概述
是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。事务可以分为编程式事务和声明式事务。
编程式事务控制又叫细粒度事务的控制,可以针对指定的方法以及方法中具体的某一行代码添加事务控制。需要自己每次手动的去添加,开发比较繁琐,每次都要开启、提交、回滚。
- jdbc 代码:conn.setAutoCommite(false) //设置手动控制事务
- hibernate 代码:session.beginTransaction() //开启一个事务
声明式事务又叫粗粒度事务的控制,只能给方法添加事务控制。Spring 提供了对事务的管理,我们需要使用事务时只需要在配置文件中配置即可,不使用时直接移除,这样便大大的降低了事务控制的耦合。Spring 事务控制的实现是依赖与 Aop。
2 事务控制的几种方式
2.1 xml 实现
【1】步骤
- 引入 Spring-aop 相关的4个 jar
- 引入 aop 名称空间
- 引入 tx 名称空间
- 引入 Spring-jdbc 相关 jar(使用到spring jabcTemplate)
【2】实现
模拟: 在service中调用2次dao, 希望其中一个dao执行失败,整个操作回滚
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. 数据源对象: 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. 创建JdbcTemplate对象 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3.创建 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 注解实现
【1】步骤
- 引入 Aop 相关 jar
- bean.xml 中配置事务管理器类以及指定 注解方式实现声明式事务
- 在需要添加事务控制的地方加上 @Transactional
@Transactional注解
- 定义到方法上,当前方法使用 Spring 的声明式事务
- 定义在类上,当前类的所有方法使用 Spring 的声明式事务
- 定义到父类上,当执行父类的方法时应用事务
【2】实现(核心代码)
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. 数据源对象: 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. 创建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.创建事务管理器-->
<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, //遇到数学类异常不回滚
// 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, //遇到数学类异常不回滚
propagation = Propagation.REQUIRED //事务的传播行为
)
其中事务传播行分为:
- Propagation.REQUIRED
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务, 就会加入当前的事务; - Propagation.REQUIRED_NEW
指定当前的方法必须在事务的环境下执行;
如果当前运行的方法,已经存在事务: 事务会挂起; 会始终开启一个新的事务,执行完后;
刚才挂起的事务才继续运行。
所有实例代码地址 https://github.com/Aceysx/SpringDemo