Spring中的事务管理
Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。
编程式事务管理
- 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
- 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码
声明式事务管理:
- 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
- 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。
事务管理器:
- 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
- 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法。
编写基本代码来测试事务:
1.实体类和接口
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String address; }
public interface UserMapper { List<User> select(); int add(User user); int delete(int id); }
2.mapper文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mapper.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.lili.dao.UserMapper"> <select id="select" resultType="com.lili.entity.User"> select * from user; </select> <insert id="add" parameterType="com.lili.entity.User"> insert into user values (#{id},#{username},#{address}) </insert> <delete id="delete" parameterType="int"> deletes from user where id = #{id} </delete> </mapper>
注意,这里我故意把delete写为deletes
3.接口的实现类
public class UserMapperImpl extends SqlSessionDaoSupport implements UserMapper { @Override public List<User> select() { User user = new User(12,"测试","beijing"); UserMapper mapper = getSqlSession().getMapper(UserMapper.class); mapper.add(user); mapper.delete(12); return mapper.select(); } @Override public int add(User user) { return getSqlSession().getMapper(UserMapper.class).add(user); } @Override public int delete(int id) { return getSqlSession().getMapper(UserMapper.class).delete(id); } }
在查询方法中,进行了添加和删除。
进行测试:
@Test public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); UserMapper userMapper = context.getBean("userMapper", UserMapper.class); userMapper.select().forEach(System.out::println); }
正常报错,但是插入成功!显然不满足实际业务需求,要么都成功。要么都不成功,故我们接下来就要加入事务
使用Spring管理事务,注意头文件约束
xmlns:tx="http://www.springframework.org/schema/tx" http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
JDBC事务:
<bean id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean>
配置事务的通知:
<tx:advice id="txAdvice" transaction-manager="transactionManager"> <!--给那些方法配置事务--> <tx:attributes> <tx:method name="add" propagation="REQUIRED"/> <tx:method name="delete" propagation="REQUIRED"/> <tx:method name="*" propagation="REQUIRED"/> </tx:attributes> </tx:advice>
spring的事务传播特性:
事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。spring支持7种事务传播行为:
- propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,这是最常见的选择。
- propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
- propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
- propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
- propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
- propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
- propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与propagation_required类似的操作
配置AOP
导入aop的头文件约束
<aop:config> <aop:pointcut id="txPointCut" expression="execution(* com.lili.dao.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/> </aop:config>
删掉刚才的数据,再次进行测试!结果和预期一样,都不成功,则spring的声明式事务配置就ok了