Spring声明式事务

本文以转账为例介绍事务概念,阐述Spring中处理事务的方法。使用Spring+MyBatis集成代码,展示了Spring声明式事务AOP的两种实现方式,即使用注解@Transactional和配置xml文件,还说明了相关属性如propagation、read-only的含义及作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在接触事务之前,先看一个例子。
在我们的生活中,会有转账的行为,转账可以大致分为如下几个步骤

  1. 修改自己的账户信息
  2. 在自己的账户上添加一条转账信息
  3. 修改对方的账户信息
  4. 在对方的账户上添加一条转账信息
    如果在第二步执行完后,出现了异常,那么自己的钱就没了,这就会导致一些纠纷了,银行肯定不会允许这种事情发生;
    为了避免这种事情的发生,我们把这所有的操作放在一个事务中,如果在执行这个事务时,发生异常,导致事务无法正常完成,此时就会触发事务的回滚机制,所有执行了的操作都不能生效,即没有提交数据;只有当所有的操作都执行了,事务正常结束,数据才会提交。
    那在Spring中如何处理事务的呢?

Spring声明式事务AOP

在这里使用Spring+MyBatis集成的代码,在这个代码的基础上进行修改
代码的结构如下:
在这里插入图片描述

1.创建UserMapper接口

public interface UserMapper {
     public void addUser(User user);
     public void deleteUser(Integer id);
}

2.创建UserDao接口

public interface UserDao {
     public void addUser(User user);
     public void deleteUser(Integer id);
}

3.创建UserDao的实现类UserDaoImpl

@Repository
public class UserDaoImpl implements UserDao{
     @Autowired
     private UserMapper userMapper;

     @Override
     public void addUser(User user) {
         userMapper.addUser(user);
     }

     @Override
     public void deleteUser(Integer id) {
          userMapper.deleteUser(id);
     }
}

4.创建UserService接口

public interface UserService {
     public void addUser(User user);
     public void deleteUser(Integer id);
}

5.创建UseService的实现类UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
     @Autowired
     private UserDao userDao;
     @Override
     public void addUser(User user) {
          userDao.addUser(user);
     }
     @Override
     public void deleteUser(Integer id) {
          userDao.deleteUser(id);
     }
}

6.创建UserAction类
在这个类中设置一个方法saveAndDel();在这个方法中执行两个操作,一个是插入用户的操作,一个是删除用户的操作。并在两个操作之间设置一个会出现异常的代码;

@Controller
public class UserAction {
     @Autowired
     private UserService userService;
     public void saveAndDel(User user, Integer id) {
          userService.addUser(user);
          int a = 1 / 0;
          userService.deleteUser(id);
     }
}

7.测试

public class Test {

     public static void main(String[] args) {
          ApplicationContext app = new 
ClassPathXmlApplicationContext("classpath:applicationContext.xml");
          UserAction bean = app.getBean(UserAction.class);
          User user = new User(0,"富贵",12);
          bean.saveAndDel(user, 33);
     }
}

测试后发现,只执行了插入用户的操作,发生异常后,删除用户操作并没有执行;也就是说这个事务执行未完成,就进行了提交修改了数据库;作为一个事务当然是不行的,那如何能够设置一个事务呢;?


Spring声明式事务有两种方法,一个是使用注解,一个是配置文件
使用事务需要设置xml文件的Namespace的选项;勾选了后,在它的右侧的Namespace Versions中全部选择第一个没有版本号的版本
在这里插入图片描述

使用注解声明事务

这里可以用到一个注解@Transactional,这个注解可以注释类,也可以注释方法,注释在方法时,表示这个方法是一个事务,作用在类上,表示每一个方法都是一个事务,
具体步骤如下:
1.修改UserAction,添加注解

@Controller 
@Transactional(propagation=Propagation.REQUIRED) // == @Transactional
public class UserAction {
     @Autowired
     private UserService userService;

     public void saveAndDel(User user, Integer id) {
          userService.addUser(user);
          int a = 1 / 0;
         userService.deleteUser(id);
     }
}

2. 修改application-action.xml文件

<context:component-scan base-package="com.young.action"></context:component-scan>
     <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
          <property name="dataSource" ref="dataSource"></property>
     </bean>
<!-- 启动注解事务 -->
     <tx:annotation-driven/>

3.测试

public class Test {

     public static void main(String[] args) {
          ApplicationContext app = new 
ClassPathXmlApplicationContext("classpath:applicationContext.xml");
          UserAction bean = app.getBean(UserAction.class);
          User user = new User(0,"富贵",12);
          bean.saveAndDel(user, 33);
     }
}

此次测试,遇到异常后,事务发生了回滚,数据库没有被修改
在这里插入图片描述

配置xml文件声明事务

1.修改UserAction,删除注解

@Controller 
public class UserAction {
     @Autowired
     private UserService userService;

     public void saveAndDel(User user, Integer id) {
          userService.addUser(user);
          int a = 1 / 0;
         userService.deleteUser(id);
     }
}

2. 修改application-action.xml文件

     <context:component-scan base-package="com.young.action"></context:component-scan>
          <!-- 1,声明事务管理器 -->
          <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
              <property name="dataSource" ref="dataSource"></property>
          </bean>
          <!-- 2,声明事务的传播特性 也就是通知 -->
          <tx:advice id="advice" transaction-manager="transactionManager">
              <tx:attributes>
                   <tx:method name="delete*" propagation="REQUIRED"/>
                  <tx:method name="update*" propagation="REQUIRED"/>
                   <tx:method name="save*" propagation="REQUIRED"/>
                   <tx:method name="add*" propagation="REQUIRED"/>
              </tx:attributes>
          </tx:advice>
              <!-- 3进行AOP织入 -->
          <aop:config>
                   <!-- 声明切面 -->
              <aop:pointcut expression="execution(* com.young.action.*.*(..))" id="pc"/> 
                   <!-- 织入 -->
              <aop:advisor advice-ref="advice" pointcut-ref="pc"/>
          </aop:config>   

相关属性说明
声明事务切面 告诉spring框架,将哪些方法放入到事务中,以及事务特征

  1. propagation:
  • REQUIRED:如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
  • SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。
  • MANDATORY:使用当前的事务,如果当前没有事务,就抛出异常。
  • REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。
  • NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
  • NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
  • NESTED: 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类 似的操作
  1. read-only=“true”,只读事务
    如果把ready—only属性的值设置为true,则数据–只能读。
    ready—only属性设置为true的事务,如果有更新数据的操作,则会报如下异常
    < Connection is read-only. Queries leading to data modification are not allowed>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值