事务管理

发布时间 2023-08-25 11:25:21作者: 奔跑的阿彤

事务管理

什么是事务

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

事务的特性ACID

  • 原子性:事务是应用中不可再分的最小执行体。

  • 一致性:事务执行的结果,须使数据从一个一致性状态,变为另一个一致性状态。

  • 隔离性:各个事务的执行互不干扰,任何事务的内部操作对其他的事务都是隔离的。

  • 持久性:事务一旦提交,对数据所做的任何改变都要记录到永久储存器中。

事务的隔离性 面试重点

常见的并发异常

第一类丢失更新,第二类丢失更新。

脏读,不可重复读,幻读。

常见的隔离级别

  • Read Uncommitted:读取未提交的数据。(最低的级别)

  • Read Committed:读取已提交的数据。(可选)

  • Repeatable Read:可重复读。 (可选)

  • Serializable:串行化。(级别最高 能解决所有问题)产生枷锁:降低数据库性能

第一类丢失更新

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

第二类丢失更新

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

脏读

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

不可重复读

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

幻读

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

实现机制

悲观锁(数据库)

  • 共享锁(s锁)

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

  • 排他锁(X锁)

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

乐观锁(自定义)

  • 版本号,时间戳等

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

Spring事务管理

  • 声明式事务 优先选择

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

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

  • 编程式事务

    通过TransactionTemplate 管理事务。

    并通过它执行数据库的操作。

测试代码:

//注册用户,系统自动发帖
@Autowired
private UserMapper userMapper;

//事务回滚,当程序执行,发生异常,保证业务完整性
@Autowired
private DiscussPostMapper discussPostMapper;

@Autowired
private TransactionTemplate transactionTemplate;
   
    // 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";
  }

   //事务2,编程式事务
   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";
          }
      });
  }
//测试事务
@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);
  }

}

事务回滚,当程序执行,发生异常,保证业务完整性