Spring Transaction

本文深入解析Spring事务管理机制,涵盖事务的基本概念、特点及其在Spring框架中的应用方式。介绍了多种事务管理方法,包括使用TransactionTemplate、配置事务代理、XML配置及注解驱动的方式。

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

事务回顾

事务的概念:

事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。

事务的特点:
  • A原子性:要么都成功,要么都失败
  • C一致性:使数据库从一个一致状态到另一个一致状态
  • I隔离性:多线程、进程访问数据库的互相影响
  • D持久性:事务一旦提交,则改变是持久的
事务并发访问的问题
  • 脏读:指一个事务读取了另外一个事务未提交的数据。
  • 不可重复读:一个事务重新读取了前一事务已经提交的数据
  • 虚读:实质一个事务内读取到了别的事务插入的数据,导致前后读取不一致
事务的隔离等级

读未提交:Read uncommitted 不能防止脏读
读已经提交的:Read committed 可以防止脏读,但不能防止不可重复读
读可以重复读的:Repeatable read 可防止不可重复读,但不能防止虚读
序列化:Serializable 可避免脏读、不可重复读、虚读情况的发生,但效率低

Spring事务管理

Spring事务管理常用对象
  • PlatformTransactionManager(平台事务管理器)
    • 平台事务管理器,spring要管理事务,必须使用事务管理器;
      进行事务配置时,必须配置事务管理器。
      有多种实现,通过实现此接口,Spring可以管理任何实现了这些接口的事务。开发人员可以使用统一的编程模型来控制管理事务。
    • 常见的事务管理器的实现
      DataSourceTransactionManager :jdbc开发时事务管理器,采用JdbcTemplate
      HibernateTransactionManager:hibernate开发时事务管理器,整合hibernate
  • TransactionDefinition(事务定义)
  • TransactionStatus(事务状态)
PlatformTransactionManager api详解
TransactionStatus getTransaction(TransactionDefinition definition)

事务管理器 通过“事务详情”,获得“事务状态”,从而管理事务。 获取事务状态后,Spring根据传播行为来决定如何开启事务;
- void commit(TransactionStatus status) 根据状态提交
- void rollback(TransactionStatus status) 根据状态回滚

TransactionStatus

这个接口的作用就是获取事务的状态(回滚点、是否完成、是否新事物、是否回滚)属性

TransactionDefinition

这个接口的作用就是定义事务的名称、隔离级别、传播行为、超时时间长短、只读属性等。

  • 常用定义
    PROPAGATION_REQUIRED
    支持现有的事务,如果没有则新建一个事务
    PROPAGATION_REQUIRES_NEW
    总是发起一个新事务。如果当前已存在一个事务,则将其挂起。
使用转账的案例作为 演示案例,去测试spring提供的事物解决方案是否可行。
#方法一

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:context="http://www.springframework.org/schema/context"
        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">

    <context:component-scan base-package="com.bamzhy"></context:component-scan>

    <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbutils"/>
        <property name="user" value="root"/>
        <property name="password" value="12345"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>
    <bean class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="txManager"/>
    </bean>
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
</beans>
  • xml逻辑链:
    datasource里边包含property,将datasource注入transactionManager,将transactionmanager注入transactiontemplate
    (transactiontemplate包含transactionmanager)

service层实现:

@Service("service")
public class AccountService implements AccoutService {
    @Autowired
    AccoutDao dao;
    @Autowired
    TransactionTemplate transactionTemplate;
    @Override
    public void transafer(String from, String to, int money) {
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {

            //保证doInTransactionWithoutResult方法里边的代码在事务里边
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                //查询账户
                Account fromAc = dao.queryAccount(from);
                Account toAc = dao.queryAccount(to);
                //业务计算
                fromAc.setMoney(fromAc.getMoney() - money);
                toAc.setMoney(toAc.getMoney() + money);
                //更新账户
                dao.updateAccount(fromAc);
                //int i=1/0;
                dao.updateAccount(toAc);

            }
        });
    }
}
  • 代码逻辑链:
    在service层定义好dao层对象、transactiontemplate对象以及核心方法。
    在核心方法里调用transactionTemplate.execute(new TransactionCallbackWithoutResult(){})方法并复写doInTransactionWithoutResult(TransactionStatus transactionStatus) ,并且在此方法中填入需要在事务中执行的代码。
    执行时get service层的实例,强转为service类型并调用核心方法,即可完成了Spring下的事务管理。

值得一提的是dao层的class可以继承JdbcSupport并且复写一些方法。

@Repository
public class AccoutDaoImpl extends JdbcDaoSupport implements AccoutDao  {

    //构造方法
    @Autowired
    public AccoutDaoImpl(DataSource ds) {
        this.setDataSource(ds);
    }

    @Override
    public Account queryAccount(String name) {
        //得到数据库中name=?的数据
        List<Account> query = getJdbcTemplate().query("select * from account where name = ?",
                new Object[]{name},
                new BeanPropertyRowMapper<Account>(Account.class)
        );
        return query.get(0);
    }

    @Override
    public boolean updateAccount(Account account) {
        int update = getJdbcTemplate().update("update account set money= ? where name =?",
                new Object[]{account.getMoney(), account.getName()});
        return update==1?true:false;
     }
}
#方法二

使用事务模板配置实现
原理:配置一个Service的代理类(TransactionProxyFactoryBean),去增强service的转账方法

   <bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/dbutils"/>
        <property name="user" value="root"/>
        <property name="password" value="12345"/>
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
    </bean>

    <bean id="serviceproxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!--这里是增强目标-->
        <property name="target" ref="service"/>
        <!--这里是目标实现类-->
        <property name="proxyInterfaces" value="com.bamzhy.bean.service.AccoutService"/>
        <!--这里是事务管理-->
        <property name="transactionManager" ref="txManager"/>
        <!--事务属性-->
        <property name="transactionAttributes">
          <!--具体属性-->
          <props>
              <prop key="transafer">PROPAGATION_REQUIRED,ISOLATION_REPEATABLE_READ</prop>
          </props>
        </property>
    </bean>
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

获取实例时使用getBean(servicepoxy)代理来完成

#方法三

通过Spring tx xml配置实现
xmlns:tx=”http://www.springframework.org/schema/tx”
xsi:schemaLocation=”http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

    <!--构建切面-->
     <aop:config >
         <aop:pointcut id="mypointcut"
                       expression="execution( * com.bamzhy.bean.service.impl.AccountService.*(..))"/>
         <aop:advisor advice-ref="myadvice" pointcut-ref="mypointcut"/>
     </aop:config>

    <!--事物的增强的实现-->
    <tx:advice id="myadvice" transaction-manager="txManager">
      <tx:attributes>
          <tx:method name="transafer" isolation="REPEATABLE_READ" propagation="REQUIRED"  />
      </tx:attributes>
    </tx:advice>
#方法四 通过Spring tx 注解实现
  • xml文件中增加以下注解:
    < tx:annotation-driven transaction-manager=”txManager”/>
    < bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
    < property name=”dataSource” ref=”datasource”>
    < /bean>
    < bean id=”datasource” class=”com.mchange.v2.c3p0.ComboPooledDataSource”>
    < property name=”jdbcUrl” value=”jdbc:mysql://localhost:3306/dbutils”/>
    < property name=”user” value=”root”/>
    < property name=”password” value=”12345”/>
    < property name=”driverClass” value=”com.mysql.jdbc.Driver”/>
    < /bean>
  • 在service中配置事务注解:
    @Transactional(isolation=Ioslation.DEFAULT,propagation=Propagation.REQUIRED)

// isolation隔离 propagation 传播

具体赋值可看之前的TransactionDefinition的两张图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值