首页 > 其他分享 >事务的属性

事务的属性

时间:2023-06-14 13:31:52浏览次数:32  
标签:事务 READ Account act import save 属性

代码写在course28中

1. 事务属性包括哪些  123

事务的属性_隔离级别

1.1 事务中的重点属性: 123

● 事务传播行为

● 事务隔离级别

● 事务超时

● 只读事务

● 设置出现哪些异常回滚事务

● 设置出现哪些异常不回滚事务

2. 事务传播行为  123

2.1 什么是事务的传播行为?  123

在service类中有a()方法和b()方法,a()方法上有事务,b()方法上也有事务,当a()方法执行过程中调用了b()方法,事务是如何传递的?合并到一个事务里?还是开启一个新的事务?这就是事务传播行为。

事务传播行为在spring框架中被定义为枚举类型:

事务的属性_事务隔离级别_02

2.2 一共有七种传播行为:

● REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】

● SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行【有就加入,没有就不管了】

● MANDATORY:必须运行在一个事务中,如果当前没有事务正在发生,将抛出一个异常【有就加入,没有就抛异常】

● REQUIRES_NEW:开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】

● NOT_SUPPORTED:以非事务方式运行,如果有事务存在,挂起当前事务【不支持事务,存在就挂起】

● NEVER:以非事务方式运行,如果有事务存在,抛出异常【不支持事务,存在就抛异常】

● NESTED:如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于外层事务进行提交或回滚。如果外层事务不存在,行为就像REQUIRED一样。【有事务的话,就在这个事务里再嵌套一个完全独立的事务,嵌套的事务可以独立的提交和回滚。没有事务就和REQUIRED一样。】

2.2.1 事务传播行为REQUIRED   124-125

在代码中设置事务的传播行为:

AccountServiceImpl实现类中的save方法,去调用AccountServiceImpl2中的save方法

将AccountServiceImpl2中的save方法的事务传播行为设置为@Transactional(propagation = Propagation.REQUIRED)   (这里解释AccountServiceImpl实现类中的save方法为社么也要添加事务传播行为REQUIRED,目的就是开启这个方法的事务,就算是我们不指定,我们的AccountServiceImpl上面有@Transactional注解 //针对这个类开启事务 ,也就是说这个类里的所有方法都会开启事务 )

AccountServiceImpl类
@Resource(name = "accountService2")
    private AccountService accountService;

    //研究事务传播行为  124
    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void save(Account act) {

        // 这里调用dao的insert方法。
        accountDao.insert(act); // 保存act-003账户

        // 创建账户对象
        Account act2 = new Account("act-004", 1000.0);
        try {
            //这里调用AccountServiceImpl2中的save方法
            accountService.save(act2); // 保存act-004账户
        } catch (Exception e) {

        }
        // 继续往后进行我当前1号事务自己的事儿。
    }
AccountServiceImpl2类

AccountServiceImpl2中的save方法中模拟异常

package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import com.powernode.bank.service.AccountService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * AccountService接口第二个实现类  124
 **/
@Service("accountService2")
public class AccountServiceImpl2 implements AccountService {

    @Resource(name = "accountDao")
    private AccountDao accountDao;

    @Override
    public void transfer(String fromActno, String toActno, double money) {

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void save(Account act) {
        accountDao.insert(act);
        // 模拟异常  125
        String s = null;
        s.toString();

        // 事儿没有处理完,这个大括号当中的后续也许还有其他的DML语句。
    }
}
可以编写程序测试一下传播行为:
//研究事务传播行为  124-125
    @Test
    public void testPropagation() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        // 获取1号service对象
        AccountService accountService = applicationContext.getBean("accountService", AccountService.class);
        Account act = new Account("act-003", 1000.0);
        accountService.save(act);
    }

事务的属性_事物的属性_03

事务的属性_spring_04

总结

没有增加act-003和act-004,说明事务控制住了,正面证明了AccountServiceImpl实现类中的save方法和AccountServiceImpl2中的save方法,在添加事务传播行为设置为@Transactional(propagation = Propagation.REQUIRED)时,用的是一个事务,方法1中如果有try—catch也捕捉不到异常,因为两个方式是一个事务,但凡遇到异常就回滚

再次强调REQUIRED:支持当前事务,如果不存在就新建一个(默认)【没有就新建,有就加入】

2.2.2 事务传播行为REQUIRES_NEW   126

开启一个新的事务,如果一个事务已经存在,则将这个存在的事务挂起【不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起】

我们将之前的代码AccountServiceImpl2中的save方法事务传播行为设置为 @Transactional(propagation = Propagation.REQUIRES_NEW)并且模拟异常

@Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void save(Account act) {
        accountDao.insert(act);
        // 模拟异常  125
        String s = null;
        s.toString();

        // 事儿没有处理完,这个大括号当中的后续也许还有其他的DML语句。
    }

事务的属性_隔离级别_05

总结

可以和明显的看出act-003添加成功,但是act-004没有添加成功,说明AccountServiceImpl中的save方法事务和AccountServiceImpl2中的save方法事务时不同的是两个事务,也就是说当方法2发生异常,方法1中如果有try—catch的话会捕捉到异常进而不会影响自己的代码执行提交,方法1中的事务不会管方法2,但是如果我们的方法1中没有设置try—catch,就不会捕捉方法2的异常,一样会报错回滚,进而二者都不成功

REQUIRES_NEW不管有没有,直接开启一个新事务,开启的新事务和之前的事务不存在嵌套关系,之前事务被挂起

3. 事务的隔离级别  127

事务的属性_事务隔离级别_06

事务隔离级别类似于教室A和教室B之间的那道墙,隔离级别越高表示墙体越厚。隔音效果越好。

3.1 数据库中读取数据存在的三大问题:(三大读问题)127

脏读:读取到没有提交到数据库的数据,叫做脏读。

不可重复读:在同一个事务当中,第一次和第二次读取的数据不一样。

幻读:读到的数据是假的。

3.2 事务隔离级别包括四个级别:  127

读未提交:READ_UNCOMMITTED

这种隔离级别,存在脏读问题,所谓的脏读(dirty read)表示能够读取到其它事务未提交的数据。

读提交:READ_COMMITTED

解决了脏读问题,其它事务提交之后才能读到,但存在不可重复读问题。

可重复读:REPEATABLE_READ

解决了不可重复读,可以达到可重复读效果,只要当前事务不结束,读取到的数据一直都是一样的。但存在幻读问题。

序列化:SERIALIZABLE 

解决了幻读问题,事务排队执行。不支持并发。

大家可以通过一个表格来记忆:

隔离级别

脏读

不可重复读

幻读

读未提交

读提交

可重复读

序列化

3.3 在Spring代码中如何设置隔离级别?  128

隔离级别在spring中以枚举类型存在:

事务的属性_事物的属性_07

@Transactional(isolation = Isolation.READ_COMMITTED)

3.4 测试事务隔离级别:READ_UNCOMMITTED   129

怎么测试:一个service负责插入,一个service负责查询。负责插入的service要模拟延迟。

IsolationService1负责查询

package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

/**
 * 事务的隔离级别   129
 * 测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
 **/
@Service("i1") //添加进spring管理
public class IsolationService1 {

    @Resource(name = "accountDao") //注入
    private AccountDao accountDao;

    // 1号
    // 负责查询
    // 当前事务可以读取到别的事务没有提交的数据。
    @Transactional(isolation = Isolation.READ_UNCOMMITTED)
    // 对方事务提交之后的数据我才能读取到。
    //@Transactional(isolation = Isolation.READ_COMMITTED)
    public void getByActno(String actno) {
        Account account = accountDao.selectByActno(actno);
        System.out.println("查询到的账户信息:" + account);
    }

}

IsolationService2负责插入

package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;

/**
 * 事务的隔离级别   129
 * 测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
 **/
@Service("i2")
public class IsolationService2 {

    @Resource(name = "accountDao")
    private AccountDao accountDao;

    // 2号
    // 负责insert
    @Transactional
    public void save(Account act) throws IOException {

       accountDao.insert(act);

        // 睡眠一会
        try {
            Thread.sleep(1000 * 20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

测试

//事务的隔离级别   129
    //测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
    @Test
    public void testIsolation1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        IsolationService1 i1 = applicationContext.getBean("i1", IsolationService1.class);
        i1.getByActno("act-004");
    }

    //事务的隔离级别   129
    //测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
    @Test
    public void testIsolation2() throws IOException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        IsolationService2 i2 = applicationContext.getBean("i2", IsolationService2.class);
        Account act = new Account("act-004", 1000.0);
        i2.save(act);
    }

很明显在IsolationService2还没提交时,我们的IsolationService1就查到了数据

强调READ_UNCOMMITTED时读未提交

事务的属性_隔离级别_08

3.5 测试事务隔离级别READ_COMMITTED

将设置为读提交READ_COMMITTED   即@Transactional(isolation = Isolation.READ_COMMITTED)

对方事务提交之后的数据我才能读取到。

@Transactional(isolation = Isolation.READ_COMMITTED)
    public void getByActno(String actno) {
        Account account = accountDao.selectByActno(actno);
        System.out.println("查询到的账户信息:" + account);
    }
package com.powernode.bank.service.impl;

import com.powernode.bank.dao.AccountDao;
import com.powernode.bank.pojo.Account;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;

/**
 * 事务的隔离级别   129
 * 测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
 **/
@Service("i2")
public class IsolationService2 {

    @Resource(name = "accountDao")
    private AccountDao accountDao;

    // 2号
    // 负责insert
    @Transactional
    public void save(Account act) throws IOException {

       accountDao.insert(act);

        // 睡眠一会
        try {
            Thread.sleep(1000 * 20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}

测试

//事务的隔离级别   129
    //测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
    @Test
    public void testIsolation1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        IsolationService1 i1 = applicationContext.getBean("i1", IsolationService1.class);
        i1.getByActno("act-004");
    }

    //事务的隔离级别   129
    //测试事务隔离级别:READ_UNCOMMITTED 和 READ_COMMITTED
    @Test
    public void testIsolation2() throws IOException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        IsolationService2 i2 = applicationContext.getBean("i2", IsolationService2.class);
        Account act = new Account("act-004", 1000.0);
        i2.save(act);
    }

结果显示报错,因为IsolationService2还没提交,IsolationService1根本查不到数据,就会报错

事务的属性_事物的属性_09

标签:事务,READ,Account,act,import,save,属性
From: https://blog.51cto.com/u_15784725/6476779

相关文章

  • python对接事务性MSMQ队列
    研究了很久,逐步了解到原理后,发现python发送消息到事务性msmq肯定可行。现在能搜到的资源没有任何一篇文章说明了这个,包括gpt都一样。废话不多说,直接上代码 importwin32com.client#关键代码必须使用gencache导入"MSMQ.MSMQQueueInfo"win32com.client.gencache.Ensure......
  • 在上一操作期间遇到问题:Debug|AnyCPU 配置中 TargetFrameworkMoniker和NugetTargetMon
    在上一操作期间遇到问题:Debug|AnyCPU配置中TargetFrameworkMoniker和NugetTargetMoniker属性的值均为空场景使用VS打开之前的项目,报错:在上一操作期间遇到问题:Debug|AnyCPU配置中TargetFrameworkMoniker和NugetTargetMoniker属性的值均为空新建项目后,选择该项目未项......
  • Spring如何实现事务
    参考:spring事务管理(详解和实例):https://www.cnblogs.com/yixianyixian/p/8372832.htmlSpring事物四种实现方式:基于编程式事务管理实现基于TransactionProxyFactoryBean的声明式事务管理基于AspectJ的XML声明式事务管理基于注解的声明式事务管理参考:https://blog.csdn.net/zhux......
  • android Button组件的属性和方法
    androidButton组件的属性和方法   一、相关属性     二、相关方法 setClickable(booleanclickable)设置按钮是否允许点击。clickable=true:允许点击clickable=false:禁止点击setBackgroundResource(intresid)通过资源文件设置背景色。resid:资源xml文件ID。按钮默认背......
  • UISlider滑动条的属性介绍以及于标签联合使用实时显示变动值
     UISlider滑动条的属性介绍以及于标签联合使用实时显示变动值 (1)滑动条的左右端背景可以设置上一页下一页的图片; (2)滑动条的轨道图片可以设置为渐变等等图片。 (3)滑动条因为值可以互动,所以addTarget:方法很重要,其中事件值变动UIControlEventValueChanged比较特殊,其实和按钮的按下......
  • CSS常用属性
    颜色RGB(红,绿,蓝)三种颜色的集合,最低值是0(十六进制00)到最高值255(十六进制FF)HSLH色相(0-360),S饱和度(百分比),L亮度(百分比)(不)透明度rgba、hsla(新版浏览器可不写a,直接写4个值)line-height行间距(letter-spacing字母间间距,word-spacing单词间距)值描述normal默认。......
  • 84 局部变量 在get set等方法中 ;成员变量在属性中
    packagecom.fqs.demo061302;publicclassGirl{//属性//成员变量Stringname;privateintage;publicvoidsetAge(intage){//【局部变量】名称可以和上面的【成员变量】一样//赋值if(age<50&&age>18){this......
  • Spring 配置 事务的几种方式
    评:Spring配置文件中关于事务配置总是由三个组成部分,DataSource、TransactionManager和代理机制这三部分,无论是那种配置方法,一般变化的只是代理机制这块! 首先我创建了两个类,一个接口一个实现:1.package2.publicinterface3.publicvoid4.} 实现:1.package2.import3.im......
  • Java8 Stream List Map:Stream 流对象汇总 求和 某个属性 BigDecimal MDouble
    测试实体(数字对象使用MDouble):importcom.mchweb.common.lang.MDouble;importlombok.*;@Getter@Setter@Builder(toBuilder=true)@NoArgsConstructor@AllArgsConstructorpublicclassUser{privateMDoublemoney;}importcom.mchweb.common.lang.MDouble;imp......
  • 一文解读.NET 数据库事务
    事务是数据库系统中的重要概念,本文讲解作者从业CRUD十余载的事务多种使用方式总结。以下所有内容都是针对单机事务而言,不涉及分布式事务相关的东西!关于事务原理的讲解不针对具体的某个数据库实现,所以某些地方可能和你的实践经验不符。1|0认识事务为什么需要数据库事务?转账是生......