Spring学习日记——DAY06(事务管理)

今天针对Spring框架的事务管理功能展开了学习,学习内容如下:

我们在使用jdbc技术来实现事务管理:设置自动提交为false,当没有异常,手动提交commit,如果有异常调用rollback

使用mybatis来实现事务管理:设置自动提交为false,sqlSession来调用commit,rollback;

使用spring框架,屏蔽掉不同数据库操作方式带来的差异,提供同一的事务管理机制

Spring框架内部采用事务管理器的接口PlatformTransactionManager,来完成commit和rollback针对不同的框架,来提供不同的实现类:

mybatis:DataSourceTransactionManager

hibernate:HibernateTransactionManager

1.事务相关属性介绍

1.1事务隔离级别:

|---------------------------|-------------------------------------------------------------------------------------|
| 级别 | 描述 |
| ISOLATION_DEFAULT | 默认级别,mysql数据库默认隔离级别是ISOLATION_REPEATABLE_READ,Oracle数据库默认级别ISOLATION_READ_COMMITTED |
| ISOLATION_READ_UNCOMMITED | 读未提交,没有解决并发问题 |
| ISOLATION_READ_COMMITED | 读已提交,解决脏读 |
| ISOLATION_REPEATABLE_READ | 可重复读,解决脏读,不可重复读 |
| ISOLATION_SERIALIZABLE | 串行化,不会发生并发问题 |

1.2事务超时时间

表示当前事务的最长执行时间,如果在指定时间内结束,则事务正常提交。如果超过指定时间,则事务回滚。以秒为单位时,默认-1,不限时;

1.3事务传播行为

分析REQUIRED、REQUIRED_NEW、NESTED的差别

1.4Spring默认的事务提交和回滚的时机

如果业务方法可以正常执行结束,没有异常,事务执行提交

如果方法中出现运行时异常或者是Error,则回滚事务

如果方法中出现检查型异常,则提交事务

2.实战

我们模拟一个用户,银行帐户,执行一笔支付操作,将用户余额减少,并在交易记录中记录一条数据。

2.1创建实体类

java 复制代码
package com.xzit.entity;
import lombok.Data;
import lombok.experimental .Accessors ;
@Data
@Accessors(chain = true)
public class Acc {
    private int id ;
    private String accno ;
    private String name ;
    private int money;
}
java 复制代码
package com.xzit.entity;
import lombok.Data;
import lombok.experimental .Accessors ;
@Data
@Accessors(chain = true)
 public class Records {
    private int id ;
    private String accno ;
    private String category;
    private int money;
}

2.2Mapper的编写

java 复制代码
package com.xzit.mapper ;
import com.xzit.entity .Acc ;
import org.apache.ibatis.annotations.Update ;
import org.springframework.stereotype.Repository;
@Repository
public interface AccMapper {
@Update("update acc set money=money-#{money} where accno=#{accno}")
 void update(Acc acc);
}
java 复制代码
package com.xzit.mapper ;
import com.xzit.entity.Records ;
import org.apache.ibatis.annotations.Insert ;
import org.springframework.stereotype.Repository;
@Repository
public interface RecordsMapper {
@Insert("insert into records values(null ,#{accno},#{category},#
{money})")
void insert(Records records);
}

2.3Service的编写

javascript 复制代码
package com .xzit .service ;
import java.io.FileNotFoundException ;
public interface AccService {
void doPay(int money) throws FileNotFoundException ;
}
java 复制代码
package com.xzit.service ;
import com.xzit.entity.Acc ;
import com.xzit.entity.Records ;
import com.xzit.mapper.AccMapper ;
import com.xzit.mapper.RecordsMapper ;
import org.springframework.stereotype.Service ;
import org.springframework.transaction.annotation.Isolation ;
import org.springframework.transaction.annotation.Propagation ;
import org.springframework.transaction.annotation.Transactional ;
import javax.annotation.Resource ;
import java.io.FileNotFoundException ;
import java.util.concurrent.TimeUnit ;
@Service
public class AccServiceImpl implements AccService {
@Resource
private AccMapper accMapper ;
@Resource
    private RecordsMapper recordsMapper;

    @Transactional(
            propagation = Propagation.REQUIRED,
            isolation = Isolation.REPEATABLE_READ,
            timeout = 3
            /* rollbackFor = {
                     FileNotFoundException.class,
                     NullPointerException.class
             },
             noRollbackFor = {}*/
    )
    @Override
    public void doPay(int money) throws FileNotFoundException {
        //存一条交易记录
        Records records = new Records();
        records.setAccno("123456").setCategory("支出").setMoney(money);
        recordsMapper.insert(records);
        System.out.println("执行交易记录处理");
        //模拟超时处理
        try {
            TimeUnit.SECONDS.sleep(4);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //运行时异常
        /* try {
             int i = 10 / 0;//算术异常(运行时异常)
         }catch(ArithmeticException e){}*/
        //检查型异常
        /* if (money > 2000)
             throw new FileNotFoundException("文件找不到异常");*/
        //修改用户原帐户下的余额
        Acc acc = new Acc();
        acc.setAccno("123456");
        acc.setMoney(money);
        accMapper.update(acc);
        System.out.println("执行用户余额修改处理");

    }
}

可以看到我这里的doPay方法将两个DAO层的方法组装起来以实现功能,并且通过@Transactional对方法事务的超时时间、事务隔离级别、事务传播行为、以及回滚时机进行了配置;

2.4spring配置文件

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"
       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/tx 
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- 对应db.properties文件 -->
    <context:property-placeholder location="classpath:db.properties"/>

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.xzit"/>

    <!-- 数据源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 配置SqlSessionFactory -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:SqlMapConfig.xml"/>
    </bean>

    <!-- 对Mapper的扫描 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        <!-- 配置Mapper文件的基准包 -->
        <property name="basePackage" value="com.xzit.mapper"/>
    </bean>

    <!-- 配置事务管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

</beans>

我们在实际进行事务管理时需要配置事务管理器

2.5通过XML配置事务

对于pom.xml文件

需要加入pom.xml文件

XML 复制代码
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.30</version>
</dependency>

在ApplicationContext.xml文件中进行编写

XML 复制代码
<!-- 配置事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

<!--<tx:annotation-driven transaction-manager="transactionManager">
</tx:annotation-driven>-->

<tx:advice id="myTransaction" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="doPay" propagation="REQUIRED" timeout="3"/>
        <tx:method name="select*" propagation="SUPPORTS"/>
        <tx:method name="*" propagation="REQUIRED"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="myPointcut" expression="execution(* *..service..*.*(..))"/>
    <aop:advisor advice-ref="myTransaction" pointcut-ref="myPointcut"></aop:advisor>
</aop:config>

我们先配置好TransactionManager再使用tx:advice进行作用方法的配置,最后再通过aop配置切点注入事务管理;

3.Transactional的属性

相关推荐
兰令水1 小时前
topcode【随机算法题】【2026.5.14打卡-java版本】
java·算法·leetcode
雪度娃娃1 小时前
结构型设计模式——代理模式
java·c++·设计模式·系统安全·代理模式
万邦科技Lafite1 小时前
京东商品详情 API 接口全面讲解
java·数据库·redis·api·电商开放平台
折哥的程序人生 · 物流技术专研1 小时前
Java面试85题图解版 · 全系列总目录
java·开发语言·后端·面试·职场和发展
武子康1 小时前
Java-01 深入浅出 MyBatis 入门与核心原理:半自动 ORM 框架详解
java·后端·mybatis
木易 士心1 小时前
Java 跳出多层循环
java·开发语言·后端
数电发票API1 小时前
数电发票接口对接流程详解:从认证到冲红的完整指南
java
咸甜适中1 小时前
rust语言学习笔记Trait之 From 和 Into (类型转换)
笔记·学习·rust
float_com1 小时前
【java进阶】------ 多线程【上】
java