• Spring Boot之事务管理


    1. 事务的定义

    事务是由 N 步数据库操作序列组成的逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行。

    2. 事务的特性

    事务的 ACID 特性:

    • 原子性:事务是应用中不可分割的最小执行体
    • 一致性:事务执行的结果必须使得数据从一个一致性状态转变为另一个一致性状态
    • 隔离性:各个事务的执行互不干扰,任何事务的内部操作对其他事务都是隔离的
    • 持久性:事务一旦提交,对数据所做的任何修改都要记录到永久存储器中

    3. 事务的隔离性

    • 常见的并发异常
      • 第一类丢失更新、第二类丢失更新
      • 脏读、不可重复读、幻读
    • 常见的隔离级别
      • Read Uncommitted:读取未提交的数据
      • Read Commited:读取已提交的数据
      • Repeatable Read:可重复读
      • Serializable:串行化

    第一类更新丢失:某一个事务的回滚,导致另一个事务已更新的数据丢失了。

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

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

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

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

    隔离级别第一类丢失更新脏读第二类丢失更新不可重复读幻读
    Read Uncommitted
    Read Commited
    Repeatable Read
    Repeatable Read

    4. 事务管理

    实现机制

    • 悲观锁(数据库)
      • 共享锁(S锁):事务A对某数据加了共享锁以后,其他事务只能对该数据加共享锁,但不能加排他锁
      • 排他锁(X锁):事务A对某数据加了排他锁以后,其他事务对该数据既不能加共享锁,也不能加排他锁。
    • 乐观锁(自定义)
      • 版本号、时间戳等
      • 在更新数据前,检查版本号是否发生变化。若发生变化则取消本次更新,否则就更新数据(版本号+1).

    Spring 事务管理

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

    5. 示例

    package com.nowcoder.community.service;
    
    import com.nowcoder.community.dao.AlphaDao;
    import com.nowcoder.community.dao.DiscussPostMapper;
    import com.nowcoder.community.dao.UserMapper;
    import com.nowcoder.community.entity.DiscussPost;
    import com.nowcoder.community.entity.User;
    import com.nowcoder.community.util.CommunityUtil;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Scope;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.TransactionDefinition;
    import org.springframework.transaction.TransactionStatus;
    import org.springframework.transaction.annotation.Isolation;
    import org.springframework.transaction.annotation.Propagation;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.support.TransactionCallback;
    import org.springframework.transaction.support.TransactionTemplate;
    
    import javax.annotation.PostConstruct;
    import javax.annotation.PreDestroy;
    import java.util.Date;
    
    @Service
    //@Scope("prototype")
    public class AlphaService {
    
        @Autowired
        private AlphaDao alphaDao;
    
        @Autowired
        private UserMapper userMapper;
    
        @Autowired
        private DiscussPostMapper discussPostMapper;
    
        @Autowired
        private TransactionTemplate transactionTemplate;
    
    
    
        public AlphaService() {
    //        System.out.println("实例化AlphaService");
        }
    
        @PostConstruct
        public void init() {
    //        System.out.println("初始化AlphaService");
        }
    
        @PreDestroy
        public void destroy() {
    //        System.out.println("销毁AlphaService");
        }
    
        public String find() {
            return alphaDao.select();
        }
    
        // 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://image.nowcoder.com/head/99t.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";
        }
    
        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
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
  • 相关阅读:
    Linux打包和使用动静态库
    excel高级绘图技巧100讲(六)-甘特图在项目进度上的实战应用案例
    河道采砂执法监管信息化平台:科技赋能,智慧监管
    解决vscode终端不显示conda环境变量名称问题【详细步骤!实测可行!!】
    SpringMVC获取请求参数
    单商户社区团购系统小程序源码
    前端:下载文件(多种方法)
    制造业SRM管理系统供应商全方位闭环管理,实现采购寻源与流程高效协同
    Web前端-元素显示和js引入
    高考志愿系统-信息管理模块:院校信息分析
  • 原文地址:https://blog.csdn.net/hutianle/article/details/126470360