当前位置: 首页 > 图灵资讯 > 技术篇> 事务的属性

事务的属性

来源:图灵教育
时间:2023-06-17 13:50:25

代码写在course28中1.事务属性包括哪些123

事务的属性_隔离级别

1.1事务中的关键属性:123

●事务传播行为

●事务隔离等级

●事务超时

●只读事务

●什么异常的回滚事务设置?

●设置什么异常不回滚事务?

2.事务传播行为1232.1是什么?123

a()方法和b()方法在service类中,a()方法上有事务,b()方法上也有事务。当B()方法在a()方法实施过程中被调用时,事务是如何传递的?合并到事务中?还是开始新的事务?这就是事务传播行为。

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

事务的属性_隔离级别_02

2.2共有七种传播行为:

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

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

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

●REQUIRES_NEW:开始一个新的事务,如果一个事务已经存在,就把它挂起来【不管有没有,直接开新事务,开新事务和之前的事务没有嵌套关系,之前的事务都挂了】

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

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

●NESTED:如果目前正在进行事务,则该方法应在嵌套事务中运行。嵌套事务可以独立于外部事务提交或回滚。如果没有外部事务,行为就像REQUIRED。【如果有事务,在此事务中嵌套另一个完全独立的事务,可以独立提交和回滚。没有事情就像REQUIRED。】

2.2.REQUIRED124-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号事务。    }

Accountserviceipl2类

在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 Accountserviceimplell2 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);    }

事务的属性_spring_03

事务的属性_事物的属性_04

总结

不增加act-003和act-004,说明事务得到了控制,正面证明了accountserviceimpl实现类中的save方法和accountserviceimpl2中的save方法,将事务传播行为设置为添加@Transactional(propagation=Propagation.REQUIRED)时间,用的是一个事务,如果方法1中有try-catch,则无法捕捉到异常,因为两种方法是一种事务,但如果出现异常,则回滚

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

2.2.REQUIRES_NEW126

开始一个新的事务,如果一个事务已经存在,就把它挂起来【不管有没有,直接开新事务,开新事务和之前的事务没有嵌套关系,之前的事务都挂了】

我们将之前代码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

这种隔离水平存在脏读问题。所谓脏读(dirtyread)表示可以读取其他事务未提交的数据。

读提交:READ_COMMITTED

只有在提交其他事务后才能解决脏阅读问题,但存在不可重复阅读的问题。

可重复读:REPEATABLE_READ

如果解决了不可重复读取的问题,可以达到可重复读取的效果。只要目前的事务没有结束,读取的数据总是一样的。但是有幻读的问题。

序列化:SERIALIZABLE

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

可以通过表格记忆:

隔离级别

脏读

不可重复读

幻读

读未提交

读提交

可重复读

序列化

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_UNCOMITED

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

3.5测试事务隔离级READ_COMMITTED

读取和提交READ_COMMITED@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

上一篇:

Java集合去重的几种方法

下一篇:

MyBatis