Spring学习之事务 *** 作

Spring学习之事务 *** 作,第1张

Spring学习之事务 *** 作

目录

事务的概念

事务引入

Spring事务管理

介绍

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

声明式事务管理参数配置

基于XML方式实现声明式事务管理

基于完全注解方式实现声明式事务管理


事务的概念

什么是事务

①:事务是数据库 *** 作最基本单元,逻辑上一组 *** 作,要么都成功要么都失败,如果有一个失败,那么所有 *** 作都失败。

②:典型场景:银行转账

事务的四大特性(ACID)

①:原子性

②:一致性

③:隔离性

④:持久性

事务引入

我们使用常见的银行转账案例来引入事务的 *** 作。

思路:将数据库中一个人的账户金额减去转账金额,另一个人的加上转账金额。

步骤

①:创建数据库,创建对应表,添加相应的记录

CREATE TABLE t_account(
id VARCHAr(20),
username VARCHAr(50),
money INT
)

                                        

②:创建 service ,搭建 dao,完成对象创建和对象注入关系。

service ---> dao, dao ---> JdbcTemplate,JdbcTemplate ---> DataSource

③:在 dao 中创建两个方法:多钱与少钱,在 service 中创建转账的方法

        UserDao接口

public interface UserDao {
    //少钱
    public void reduceMoney();
    //多钱
    public void addMoney();
}

        UserDaoImp

@Repository
public class UserDaoImp implements UserDao{
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public void reduceMoney() {
        String sql = "update t_account set money=money-? where username=?";
        jdbcTemplate.update(sql,100,"张三");
    }

    @Override
    public void addMoney() {
        String sql = "update t_account set money=money+? where username=?";
        jdbcTemplate.update(sql,100,"李四");
    }
}

        UserService

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    //转账方法
    public void moveMoney(){
        userDao.reduceMoney();
        userDao.addMoney();
    }
}

④:测试

public class UserTest {
    @Test
    public void test1(){
        ApplicationContext context = new FileSystemXmlApplicationContext("G:\SpringStudy\Spring-TranOperation\bean1.xml");
        UserService userService = context.getBean("userService", UserService.class);
        userService.moveMoney();
    }
}

                ​​​​​​​        ​​​​​​​        ​​​​​​​        

注意点:

如果上面代码正常执行,那么不会出现问题;但是如果在执行过程中出现了异常,那么可能就会导致一些问题。

根据上面案例我们来模拟银行转账过程中断电的情况

        ​​​​​​​​​​​​​​表初始状态 ​​​​​​​

                                        

        手动添加异常:在张三执行少钱 *** 作后,添加一个除 0 *** 作,其余不变

//转账方法
    public void moveMoney(){
        userDao.reduceMoney();
        //使用除 0  *** 作来模拟转账过程中断电
        int num = 1 / 0;
        userDao.addMoney();
    }

         ​​​​​​​执行后表结果:

我们可以发现张三账户的钱已经转出了,但李四的账户却没有收到,导致总钱数发生了变化。这种情况我们就可以使用事务来进行解决。

        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​        ​​​​​​​

Spring事务管理 介绍

1、事务一般是添加到 JavaEE 三层结构里面的 Service 层(业务逻辑层)

2、在 Spring 进行事务管理 *** 作,有两种方式

​        编程式事务管理和声明式事务管理(常用)

3、声明式事务管理(底层使用了 AOP 原理)

​        ① 基于注解方式(常用)

​        ② 基于 XML 配置方式

4、Spring 事务管理常用 API (提供了一个事务管理器接口 PlatformTransactionManager ,针对  不同的框架提供不同的实现类)

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

1、在 spring 配置文件中配置事务管理

      JdbcTemplate 使用的是DataSourceTransactionManager 实现类

    
    
        
        
    

2、在 spring 配置文件中开启事务注解

        ①:在 spring 配置文件中引入名称空间 tx ,和之前配置名称空间方法一样

        ②:开启事务注解

    

3、在 service 类上面(或者 service 类里面的方法上面)添加事务注解

        ①:@Transactional,该注解可以添加在类上面,也可以添加到方法上面

        ②:如果把这个注解添加到类上面,表明这个类里面的所有方法都被添加了事务

               如果添加到方法上面,表明该方法被添加了事务

4、基于上面的小例子进行测试

        修改后的 UserService 类 ​​​​​​​

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    //转账方法
    @Transactional
    public void moveMoney(){
        userDao.reduceMoney();
        //使用除 0  *** 作来模拟转账过程中断电
        int num = 1 / 0;
        userDao.addMoney();
    }
}

        异常 ​​​​​​​

​​​​​​​

        结果:可以发现当出现异常后,执行了回滚 *** 作,恢复已经被修改的数据

 

声明式事务管理参数配置

 在 @Transactional 注解里面配置事务相关参数,主要参数如下

        ①:propagation:事务传播行为

                事务传播行为:多事务方法直接进行调用,这个过程中事务是如何进行管理的

                事务方法:使数据库表数据进行变化的 *** 作

                事务的传播行为可以有由传播属性指定。Spring指定了 7 种传播行为

 常用的是 REQUIRED(默认) 和 REQUIRES_NEW, 配置如下

        ②:isolation:事务隔离级别

                <1> 事务有隔离性的特性,多事务 *** 作之间不会产生影响

                <2> 如果不考虑隔离性会产生脏读不可重复读虚(幻)读 等问题。

                        脏读:一个未提交的事务读取到另一个未提交事务的数据,若后者执行了回滚 *** 作,就导致前者读到了脏数据

                        不可重复读:一个未提交事务读取到了一个已提交事务修改后的数据,导致几次读取到的数据不一致

                        虚读:一个未提交事务读取到另一提交事务修改数据的记录,导致几次读取到的数据记录不一致

通俗理解可查看该博客【数据库】快速理解脏读、不可重复读、幻读阳阳的博客-CSDN博客脏读

                <3> 解决:通过设置事务隔离性,解决读问题,MySql 中默认是可重复读级别

        ③:timeout:超时时间

                事务需要在一定时间内提交,如果不提交就会进行事务回滚

                默认是 -1,也就是不回滚;但可以自己设置,单位是秒

        ④:readOnly:是否只读

                读:查询 *** 作;写:增、删、改

                默认值是 false,可以执行增、删、改、查 *** 作

                可以设置为 true,只可以执行查 *** 作

        ⑤:rollbackFor:回滚

                设置查询哪些异常进行事务回滚

        ⑥:noRollbackFor:不回滚

                设置出现哪些异常不进行回滚

基于XML方式实现声明式事务管理

在 spring 配置文件中进行配置

        1、配置事务管理器

    
    
        
        
    

        2、配置通知

    
    
        
        
            
                
            
                
            
        
    

        3、配置切入点和切面

    
    
        
        
        
        
    
基于完全注解方式实现声明式事务管理

        创建配置类,使用配置类来替代 xml 配置文件

@Configuration  //配置类
@ComponentScan(basePackages = "com.zhouyue")
@EnableTransactionManagement //开启事务
public class TxConfig {
    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/user_db");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    //创建 JdbcTemplate 对象
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        //到 IOC 容器中根据类型找到 dataSource
        //注入dataSource
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

    //创建事务管理器
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
}

        测试方法

    @Test
    public void test2(){
        ApplicationContext context = new AnnotationConfigApplicationContext(TxConfig.class);
        UserService userService = context.getBean("userService", UserService.class);
        userService.moveMoney();
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5692358.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存