spring 梳理13--声明式事务

1、事务特性

1. 事务特性分为四个:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持续性 (Durability)简称ACID。

  • 1. 原子性(Atomicity):事务是数据库逻辑工作单元,事务中包含的操作要么都执行成功,要么都执行失败。
  • 2. 一致性(Consistency):事务执行的结果必须是使数据库数据从一个一致性状态变到另外一种一致性 状态。当事务执行成功后就说数据库处于一致性状态。如果在执行过程中发生错误,这些未完成事务对 数据库所做的修改有一部分已写入物理数据库,这是数据库就处于不一致状态。
  • 3. 隔离性(Isolation):一个事务的执行过程中不能影响到其他事务的执行,即一个事务内部的操作及使 用的数据对其他事务是隔离的,并发执行各个事务之间无不干扰。
  • 4. 持续性(Durability):即一个事务执一旦提交,它对数据库数据的改变是永久性的。之后的其它操作 不应该对其执行结果有任何影响。

 

2、测试事务存在否

将上面的代码拷贝到一个新项目中 在之前的案例中,我们给userDao接口新增两个方法,删除和增加用户;

@Mapper
public interface UserMapper {
/**
* 修改用户
* @param user
* @return
*/
int updateUser(User user);
/**
* 新增user
* @param user
* @return
*/
int addUser(User user);
/**
* 获取所有的用户
* @return
*/
List<User> getAllUsers();
...
}

 

mapper文件,我们故意把 deletes 写错,测试!

<insert id="addUser" parameterType="com.xinzhi.entity.User">
insert into user (id,username,password) values (#{id},#{username},#{password})
</insert>
<update id="updateUser" parameterType="com.xinzhi.entity.User">
update user set username=#{username},password=#{password} where id = #{id}
</update>
<select id="getAllUsers" resultType="com.xinzhi.entity.User">
select id,username,password from user
</select>

 

 

编写接口的实现类,在实现类中,我们去操作一波

@Mapper
public interface UserMapper {
/**
* 修改用户
* @param user
* @return
*/
int updateUser(User user);
/**
* 新增user
* @param user
* @return
*/
int addUser(User user);
/**
* 获取所有的用户
* @return
*/
List<User> getAllUsers();
}

 

 

public interface IUserService {
/**
* 测试事务使用,工作中我们的事务一般是定义在service层中
*/
void transaction();
}

 

 

@Service
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
public void transaction() {
userMapper.addUser(new User(100,"IT楠老师","123"));
int i = 1/0;
userMapper.updateUser(new User(100,"IT楠老师","234"));
}
}

 

 

测试

@Test
public void testNoTransaction(){
IUserService userService = context.getBean(IUserService.class);
userService.transaction();
}

 

结果 :插入成功了。

 

显然不是我们想要的,接下来的时间我们需要看看事务在spring中怎么处理。

 

 

 

3、Spring中的事务管理

Spring在不同的事务管理API之上定义了一个抽象层,使得开发人员不必了解底层的事务管理API就可以使用Spring 的事务管理机制。Spring支持编程式事务管理和声明式的事务管理。

 

编程式事务管理

  • 将事务管理代码嵌到业务方法中来控制事务的提交和回滚
  • 缺点:必须在每个事务操作业务逻辑中包含额外的事务管理代码

 

声明式事务管理

  • 一般情况下比编程式事务好用。
  • 将事务管理代码从业务方法中分离出来,以声明的方式来实现事务管理。
  • 将事务管理作为横切关注点,通过aop方法模块化。Spring中通过Spring AOP框架支持声明式事务管理。

 

 

使用Spring管理事务,注意头文件的约束导入 : tx

xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">

 

 

事务管理器

  • 无论使用Spring的哪种事务管理策略(编程式或者声明式)事务管理器都是必须的。
  • 就是 Spring的核心事务管理抽象,管理封装了一组独立于技术的方法

 

 

JDBC事务

<bean
id="transactionManager"class="org.springframework.jdbc.datasource.DataSourceTransaction
Manager">
<property name="dataSource" ref="dataSource" />
</bean>

 

这次我们先看看注解形式的事务

<!-- 开启事务注解,并配置一个事务管理器 -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>

 

加注解

@Service
@Transactional
public class UserServiceImpl implements IUserService{
@Autowired
private UserMapper userMapper;
public void transaction() {
userMapper.addUser(new User(100,"IT楠老师","123"));
int i = 1/0;
userMapper.updateUser(new User(100,"IT楠老师","234"));
}
}

 

测试:

@Test
public void testNoTransaction(){
IUserService userService = context.getBean(IUserService.class);
userService.transaction();
}

 

 

 

 

 

并不意外,除了注解的形式,我们还可以使用配置文件进行声名式事务的配置

声明式事务,其实是AOP的典型应用。都是在业务方法中将事务的开启关闭织入。

 

 

<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="update*" propagation="REQUIRED"/>
<tx:method name="search*" propagation="REQUIRED"/>
<tx:method name="get*" read-only="true"/>
<tx:method name="find*" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置aop织入事务-->
<aop:config>
<aop:pointcut id="txPointcut" expression="execution(* com.xinzhi.service.impl.*.*
(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>
</aop:config>

 

删掉刚才插入的数据,再次测试!

 

@Test
public void test2(){
ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
UserMapper mapper = (UserMapper) context.getBean("userDao");
List<User> user = mapper.selectUser();
System.out.println(user);
}

 

 

 

 

 

 

 

4、spring事务传播特性

事务传播行为就是多个事务方法相互调用时,事务如何在这些方法间传播。

 

spring支持7种事务传播行为:

  • propagation_requierd:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务 中,这是最常见的选择。
  • propagation_supports:支持当前事务,如果没有当前事务,就以非事务方法执行。
  • propagation_mandatory:使用当前事务,如果没有当前事务,就抛出异常。
  • propagation_required_new:新建事务,如果当前存在事务,把当前事务挂起。
  • propagation_not_supported:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • propagation_never:以非事务方式执行操作,如果当前事务存在则抛出异常。
  • propagation_nested:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与 propagation_required类似的操作

 

Spring 默认的事务传播行为是 PROPAGATION_REQUIRED,它适合于绝大多数的情况

posted @ 2021-01-24 15:47  Master_Sun  阅读(99)  评论(0编辑  收藏  举报