SpringBoot开发十七-事务管理

需求介绍

熟悉事务管理。

什么是事务 

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

事务的特性(ACID)

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

 

事务的隔离性

常见的并发异常 

  • 第一类丢失更新、第二类丢失更新。
  •  脏读、不可重复读、幻读。

常见的隔离级别 

  • Read Uncommitted:读取未提交的数据。
  • Read Committed:读取已提交的数据。
  • Repeatable Read:可重复读。
  • Serializable:串行化。

 

 

 

 

 

 

 

 

 

 

 实现机制

悲观锁(数据库)

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

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

乐观锁(自定义)

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

 Spring事务管理

声明式事务

  • 通过XML配置,声明某方法的事务特征。
  • 通过注解,声明某方法的事务特征。

编程式事务

  • 通过 TransactionTemplate 管理事务, 并通过它执行数据库的操作。

 

代码实现

   首先模拟某一个业务,利用事务实现,首先我们要确定我们的业务要写在 Service 业务层,所以在 AlphaService 文件里面编写,我们先考虑一个事务,比方说我们注册一个用户增加一个 user,并且自动的用这个 user 的账号发个帖。那么这一个业务包含两个增加操作。

@Autowired
    private UserMapper userMapper;

    @Autowired
    private DiscussPostMapper discussPostMapper;

 /**
     * 通过注解声名某方法的事务特征, 管理事务
     */

    /**
     * isolation : 隔离级别
     * propagation : 传播机制
     * @return
     */
    // 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";
    }

    /**
     * 通过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";
            }
        });
    }

  

然后新建一个测试类,测试我们的方法。

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;

@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);
    }

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

  

结果会报错,查数据库我们也会看到这个数据是没有插到数据库里面。

  

posted @ 2021-07-06 15:26  宋同学shl  阅读(162)  评论(0)    收藏  举报