Spring 学习笔记(五)

本文详细介绍了Spring中的事务管理,包括事务的四大特性(原子性、一致性、隔离性、持久性)以及如何搭建转账环境。在转账场景中,由于缺少事务管理,导致可能出现数据不一致的问题。接着,文章深入探讨了Spring声明式事务管理,包括基于注解和XML配置的方式,并讲解了如何通过@Transactional注解配置事务的属性如传播行为、隔离级别、超时时间和只读标志。最后,展示了全注解配置实现声明式事务管理的例子。

学习内容来自 B站尚硅谷视频

事务概念

事务就是一组数据库操作,要么都成功,要么都失败,从一个一致性状态到另一个一致性状态

四大特性

  1. 原子性:不可分割
  2. 一致性:要么都成功,要么都失败,从一个一致性状态到另一个一致性状态
  3. 隔离性:一个事务的执行不能被其它事务干扰
  4. 持久性:事务一旦提交,它对数据库的改变就是永久性的

事务操作环境搭建

转账环境:
在这里插入图片描述

  1. 创建数据库表,添加记录
    在这里插入图片描述
    在这里插入图片描述

  2. 创建对应实体类和 service、dao 类

service 中注入 dao 类,dao 中注入 jdbcTemplate 对象,在 jdbcTemplate 中注入 DataSource

public interface UserDao {


}
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;
}
@Service
public class UserService {


    // 注入 dao
    @Autowired
    private UserDao userDao;
}
  1. 在 dao 中创建两个方法:多钱、少钱的方法,在 service 中创建转账方法
public interface UserDao {

    // 多钱
    void addMoney();

    // 少钱
    void reduceMoney();
}
@Repository
public class UserDaoImpl implements UserDao {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    // jack 给 jerry 转账 100
    @Override
    public void reduceMoney() {
        String sql = "update t_account set money = money - ? where username = ?";
        jdbcTemplate.update(sql, 100, "jack");
    }

    @Override
    public void addMoney() {
        String sql = "update t_account set money = money + ? where username = ?";
        jdbcTemplate.update(sql, 100, "jerry");
    }
}
@Service
public class UserService {
    
    // 注入 dao
    @Autowired
    private UserDao userDao;

    // 转账
    public void accountMoney() {
        userDao.reduceMoney();
        userDao.addMoney();
    }
}

此时转账环境构建完毕

但是,如果在转账时,执行 reduceMoney 方法后,系统出错,没有正确执行 addMoney 方法。此时,数据库中 jack 账户会少 100,但是 jerry 并不会多 100

所以需要事务来保证转账行为的一致性

事务操作

事务应该添加到 Service 层(业务逻辑层)

Spring 有两种方式实现事务管理操作

  • 编程式事务管理(在需要加事务操作的方法处挨个加上事务相关逻辑)
  • 声明式事务管理,常用

声明式事务管理

两种实现方式

  • 基于注解方式,常用
  • 基于 xml 配置文件

Spring 底层使用 AOP 实现声明式事务管理

事务管理 API

  • Spring 提供了一个接口 PlatfomTransactionManager,代表事务管理器,这个接口针对不同的框架提供不同的实现类
    在这里插入图片描述

注解方式实现声明式事务管理

  1. 在 Spring 配置文件中配置事务管理器

本例子使用 JdbcTemplate 操作数据库,需要使用 DataSourceTransactionManager

<!--    创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        注入 DataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
  1. 开启事务注解

(1)引入名称空间 tx

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

(2) 开启事务注解

<!--    开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
  1. 在 service 类上添加事务注解


@Transactional 注解可以加在方法上(该方法加上事务),也可以加在类上(类所有方法都会加上事务)

参数配置

@Transactional 注解可以针对事务配置相关参数

@Transactional 参数如下

在这里插入图片描述

  • propagation:事务传播行为

多事务方法之间进行调用,这个过程事务是如何管理的
事务方法是修改数据库表数据的方法
在这里插入图片描述
在这里插入图片描述

  • isolation:事务隔离级别

隔离级别用来解决事务并发操作时的问题

有三个读问题:

脏读:一个未提交事务读取另一个未提交事务的数据。比如事务 A 读取了 事务 B 未提交的数据,然后事务 B 回滚操作,事务 A 就是读到了脏数据

不可重复读:一个未提交事务读取另一个提交事务修改的数据。一个事务 A 多次读取同一数据,事务 B 在事务 A 多次读取数据的过程中,对数据进行了修改并提交,那么事务 A 多次读取的数据会不一致

幻读:一个未提交事务读取另一个提交事务添加/删除的数据。比如事务 A 把学生数据库中成绩中的分数换成 ABCD 等级,但是这个时候事务 B 添加了一条分数数据,那么事务 A 操作结束后,会发现有一条数据没改过来

通过设置隔离性就可以解决读问题

脏读不可重复读幻读
READ UNCOMMITTED(读未提交)
READ COMMITTED(读已提交)
REPEATABLE READ(可重复读)
SERIALIZABLE(串行化)

设置隔离级别
在这里插入图片描述

  • timeout:超时时间

如果事务在超时时间内没有提交则自动回滚
默认值为 -1,即不设置超时时间
单位为 s

设置
在这里插入图片描述

  • readOnly:是否只读

默认值 false,表示不限制写(修改、删除)操作
设置为 true 时,事务只能对数据进行查询操作

  • rollbackFor:回滚

设置出现指定异常时事务进行回滚

  • noRollbackFor:不回滚

设置出现指定异常是不进行事务回滚

XML 声明式事务管理

  1. 在 Spring 配置文件中配置

(1)配置事务管理器

<!--    创建事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!--        注入 DataSource-->
        <property name="dataSource" ref="dataSource"/>
    </bean>

(2)配置通知

<!--    配置通知-->
    <tx:advice id="txadvice">
<!--        配置事务参数-->
        <tx:attributes>
<!--            指定添加事务的方法-->
            <tx:method name="accountMoney" propagation="REQUIRED"/>
<!--            指定名称可以使用通配符等-->
<!--            <tx:method name="account*"/>-->
        </tx:attributes>
    </tx:advice>

(3)配置切入点和切面

<!--    配置切入点和切面-->
    <aop:config>
<!--        配置切入点-->
        <aop:pointcut id="pt" expression="execution(* com.sict.spring5.service.UserService.*(..))"/>

<!--        配置切面-->
        <aop:advisor advice-ref="txadvice" pointcut-ref="pt"/>
    </aop:config>

全注解实现声明式事务管理

创建配置类代替配置文件即可

@Configuration
@ComponentScan(basePackages = "com.sict.spring5")   // 开启组件扫描
@EnableTransactionManagement    // 开启事务
public class TxConfig {

    // 创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource() {
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql:///user_db");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("woqu0000");
        return druidDataSource;
    }

    // 创建 JdbcTemplate 对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        // 注入 DataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    // 创建事务管理器对象
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource) {
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值