17-Spring5 开启事务管理

17-Spring5 开启事务管理,第1张

17-Spring5 开启事务管理 1.事务概念

1、什么是事务
(1)事务是数据库 *** 作最基本单元,逻辑上一组 *** 作,要么都成功,如果有一个失败所有 ***
作都失败
(2)典型场景:银行转账

  • lucy 转账 100 元 给 mary
  • lucy 少 100,mary 多 100

2、事务四个特性(ACID)
(1)原子性
每个事务都是一个整体,不可分隔。事务的原子性确保动作要么全部都成功,要么全部都失败。事务执行过程中出错,会回滚到事务开始前的状态,所有的 *** 作就像没有发生一样。

(2)一致性
事务在执行前数据库的数据与执行后数据库的数据要保持一致。也就是说一个事务执行之前和执行之后数据必须处于一致性状态。比如A向B转账,不可能A扣了钱,B却没收到。

(3)隔离性
一个用户的事务 *** 作不能被其它的用户事务所干扰,也就是多个并发事务之间 *** 作是隔离的。
比如A正在从一张yhk中取钱,在A取钱的过程结束前,B不能向这张卡转账。

(4)持久性
是指一个事务一旦提交成功,那么对数据库的数据的修改是永久性的。就算数据库出现故障或关机,数据也是永久保存下来的。

3、为啥需要用到事务
举个转账的例子:
执行转账前

1号账户给2号账户转账200

    public void change(){
        //模拟1号账户给2号账户转账200
        accountDao.updateMoneyById(1, -200.00);
        //模拟出故障
        int a = 10/0;
        accountDao.updateMoneyById(2, 200.00);
    }
  @Test
    public void test1(){
        //1.加载bean的xml文件, 以src为根目录
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        //2.获取配置的对象, 参数1:bean的id值, 参数2: 类名.class
        AccountService accountService = context.getBean("accountService", AccountService.class);

        //3.使用对象
        accountService.change();

    }

执行结果:

由于没有开启事务, 这里出现了故障, 导致1号账户的钱被扣除了, 但是2号账户却没有收到钱.

所以事务这个时候就派上了用场, 下面介绍如何开启事务管理

2.开启事务管理

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

2、在 Spring 进行事务管理 *** 作
(1)有两种方式:编程式事务管理和声明式事务管理
编程式事务管理就是自己写代码逻辑, 用try catch 来实现出故障时回滚的 *** 作, 如下:

3、声明式事务管理
使用Spring框架提供的方式
(1)基于注解方式
(2)基于 xml 配置文件方式

4、在 Spring 进行声明式事务管理,底层使用 AOP 原理

5、Spring 事务管理 API

3.项目代码

下面展示Spring框架提供的基于注解方式开启事务管理

配置文件bean1.xml



    
    

    
    
    
        
        
        
        
    

    
    
    
        
        
    

    
    
        
        
    

    
    


Account

package com.limi.entity;

public class Account {
    private Integer id;

    private String userName;

    private Double price;

    public Account(){}

    public Account(Integer id, String userName, Double price) {
        this.id = id;
        this.userName = userName;
        this.price = price;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}

AccountDao

package com.limi.dao;

public interface AccountDao {

    //修改账户余额
    int updateMoneyById(Integer id, Double money);
}

AccountDaoImpl

package com.limi.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class AccountDaoImpl implements  AccountDao{

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public int updateMoneyById(Integer id, Double money) {

        String sql;
        if(money>0)
            sql = "update t_account set money = money+? where id = ?";//加法
        else
        {
            money = -money;
            sql = "update t_account set money = money-? where id = ?";//减法
        }
        int res = jdbcTemplate.update(sql, money, id);
        return res;
    }
}


AccountService

package com.limi.service;

import com.limi.dao.AccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Transactional
@Service
public class AccountService {

    @Autowired
    private AccountDao accountDao;

    public void change(){
        //模拟1号账户给2号账户转账200
        accountDao.updateMoneyById(1, -200.00);
        //模拟出故障
        int a = 10/0;
        accountDao.updateMoneyById(2, 200.00);
    }
}

测试类MyTest

package com.limi.test;
import com.limi.dao.AccountDao;
import com.limi.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {

    @Test
    public void test1(){
        //1.加载bean的xml文件, 以src为根目录
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");

        //2.获取配置的对象, 参数1:bean的id值, 参数2: 类名.class
        AccountService accountService = context.getBean("accountService", AccountService.class);

        //3.使用对象
        accountService.change();

    }
}


执行转账前

执行结果


可以看到, 出现故障执行了回滚, 保障了数据的正确性

4.细节知识







例如

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

原文地址: http://outofmemory.cn/zaji/5482243.html

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

发表评论

登录后才能评论

评论列表(0条)

保存