当前位置:   article > 正文

【项目】仿牛客网社区开发 第3章 Spring Boot 实践 开发社区核心功能 4 事务管理_仿牛客网的社区论坛是真的吗

仿牛客网的社区论坛是真的吗

【项目】仿牛客网社区开发

在这里插入图片描述

第3章 Spring Boot 实践 开发社区核心功能

4 事务管理
4.1 回顾
  • 什么是事务
    • 事务是由N步数据库操作序列组成的逻辑执行单元,这系列操作要么全执行,要么全放弃执行。
  • 事务的特性(ACID
    • 原子性(Atomicity):事务是应用中不可再分的最小执行体。
    • 一致性(Consistency):事务执行的结果,须使数据从一个一致性状态,变为另一个一致性状态。
    • 隔离性(Isolation):各个事务的执行互不干扰,任何事务的内部操作对其他的事务都是隔离的。
    • 持久性(Durability):事务一旦提交,对数据所做的任何改变都要记录到永久存储器中。
4.2 事务的隔离性
  • 常见的并发异常
    • 第一类丢失更新、第二类丢失更新。
    • 脏读、不可重复读、幻读。
  • 常见的隔离级别
    • Read Uncommitted:读取未提交的数据。
    • Read Committed:读取已提交的数据。
    • Repeatable Read:可重复读。
    • Serializable:串行化。
4.3 第一类丢失更新

某一个事务的回滚, 导致另外一个事务已更新的数据丢失了。【$T1 到 T6 $ 可能只有1ms 甚至更短】

在这里插入图片描述

4.4 第二类丢失更新

某一个事务的提交, 导致另外一个事务已更新的数据丢失了。

在这里插入图片描述

4.5 脏读

某一个事务, 读取了另外一个事务未提交的数据。

在这里插入图片描述

4.6 不可重复读

某一个事务, 对同一个数据前后读取的结果不一致。

在这里插入图片描述

4.7 幻读

某一个事务, 对同一个表前后查询到的行数不一致。

在这里插入图片描述

4.8 事务隔离级别

在这里插入图片描述

从上到下,隔离级别由低到高。Y 表示会出现该类问题。N 表示不会【当然这也对应着性能的下降】

通常中间两个是在应用中使用较多的

4.9 实现机制
  • 悲观锁(数据库)

    • 共享锁(S锁)

      事务A对某数据加了共享锁后,其他事务只能对该数据加共享锁,但不能加排他锁。

    • 排他锁(X锁)

      事务A对某数据加了排他锁后,其他事务对该数据既不能加共享锁,也不能加排他锁。

  • 乐观锁(自定义)

    • 版本号、时间戳等

      在更新数据前,检查版本号是否发生变化。若变化则取消本次更新,否则就更新数据(版本号+1)。

4.10 Spring事务管理
  • 声明式事务
    • 通过XML配置,声明某方法的事务特征。
    • 通过注解,声明某方法的事务特征。
  • 编程式事务
    • 通过 TransactionTemplate 管理事务, 并通过它执行数据库的操作。

在这里插入图片描述

Spring 使用一套API 即可面向所有种类的数据库

代码演示:

【需求,在一个用户完成注册时,自动发布一条“新人报道” 的帖子】

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private DiscussPostMapper discussPostMapper;

    // REQUIRED: 支持当前事务(外部事务),如果不存在则创建新事务.【一定需要事务】
    // REQUIRES_NEW: 创建一个新事务,并且暂停当前事务(外部事务).
    // NESTED: 如果当前存在事务(外部事务),则嵌套在该事务中执行(独立的提交和回滚),否则就会REQUIRED一样.
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public Object save1() {
        // 新增用户
        User user = new User();
        user.setUsername("alpha");
        user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
        user.setPassword(CommunityUtil.md5("123" + user.getSalt()));
        user.setEmail("alpha@qq.com");
        user.setHeaderUrl("http://images.nowcoder.com/head/972t.png");
        user.setCreateTime(new Date());
        userMapper.insertUser(user);

        // 新增帖子
        DiscussPost post = new DiscussPost();
        post.setUserId(user.getId());
        post.setTitle("Hello");
        post.setContent("新人报道!");
        post.setCreateTime(new Date());
        discussPostMapper.insertDiscussPost(post);

        Integer.valueOf("abc"); // 故意报个错误出来

        return "ok";
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

测试一下

package com.nowcoder.community;

import com.nowcoder.community.service.AlphaService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

/**
 * @Projectname: community
 * @Classname: TransactionTests
 * @Author: Ding Jiaxiong
 * @Date:2023/4/19 10:53
 */

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class TransactionTests {

    @Autowired
    private AlphaService alphaService;

    @Test
    public void testSave1() {
        Object obj = alphaService.save1();
        System.out.println(obj);
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

现在的save1方法中是有一个错误的,理想运行结果是 事务回滚,不执行插入操作,

运行结果

在这里插入图片描述

OK,报错了,但是我更关心的是 数据有没有插入成功

在这里插入图片描述

验证了,没有,事务回滚了

这是注解式,接下来演示编程式事务:

    @Autowired
    private TransactionTemplate transactionTemplate;

    public Object save2() {
        transactionTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        return transactionTemplate.execute(new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus status) {
                // 新增用户
                User user = new User();
                user.setUsername("beta");
                user.setSalt(CommunityUtil.generateUUID().substring(0, 5));
                user.setPassword(CommunityUtil.md5("123" + user.getSalt()));
                user.setEmail("beta@qq.com");
                user.setHeaderUrl("http://image.nowcoder.com/head/999t.png");
                user.setCreateTime(new Date());
                userMapper.insertUser(user);

                // 新增帖子
                DiscussPost post = new DiscussPost();
                post.setUserId(user.getId());
                post.setTitle("你好");
                post.setContent("我是新人!");
                post.setCreateTime(new Date());
                discussPostMapper.insertDiscussPost(post);

                Integer.valueOf("abc");

                return "ok";
            }
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

在这里插入图片描述

同样测试一下

    @Test
    public void testSave2() {
        Object obj = alphaService.save2();
        System.out.println(obj);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果

在这里插入图片描述

OK,和注解式事务运行效果一样,看看数据库

在这里插入图片描述

在这里插入图片描述

肯定都是没有插入成功的,出现错误,回滚了

后面就是真正的运用到我们的项目了,注意优先使用注解式事务,如果运行过程中需要对一些东西进行控制,再使用编程式事务。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/573013
推荐阅读
相关标签
  

闽ICP备14008679号