一篇彻底搞明白MySQL锁机制--乐观锁 & 悲观锁

最近工作太忙了,抽点时间赶紧写一下,最近公司进行抽奖活动,涉及到预扣库存,秒杀等高并发的情况,所以总结写一下心得。大神请忽略哈哈哈,欢迎大家一起分享交流。

一、前言

       在分布式系统中,我们经常会需要进行加锁的操作,而在分布式中加锁的中间件又有很多中方式,譬如常用的Redis,Zoookper,Memcached,Chubby等,或者我们也可以使用MySQL上的锁机制( Mysql 并发事务会引起更新丢失问题),所以在分布式系统中,我们会进行加锁处理。下面简单介绍一下上面几种锁的基本原理(详细的大家可以百度哈哈哈哈)

  1.       Memcached:利用 Memcached 的 add 命令。此命令是原子性操作,只有在 key 不存在的情况下,才能 add 成功,也就                                意味着线程得到了锁。
  2.       Redis:          和 Memcached 的方式类似,利用 Redis 的 setnx 命令。此命令同样是原子性操作,只有在 key 不存在的                                情况下,才能 set 成功。
  3.       Zookeeper:  利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分                                布式锁服务的。
  4.       Chubby:     Google 公司实现的粗粒度分布式锁服务,底层利用了 Paxos 一致性算法。

具体的技术点大家都可以问度娘,我们这次主要是总结一下MySQL中的锁机制(悲观锁&乐观锁)

二、悲观锁

      悲观锁,正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)(以上内容来自百度百科)。不过我们简单的来讲就是类似我们Java中的(1.7前重量级锁)Synchronized(关键字),只要我们需要同步执行我们的代码块,就加上Synchronized,JVM底层就能保证其线程安全性(只限制在单体架构上,SOA架构下Synchronized是不能做到这一点的,需要用到我们上面总结的分布式锁机制)。那再MySql中如何实现一把悲观锁呢?我们直接上代码:

准备表数据:       

DROP DATABASE IF EXISTS cyhTest;
CREATE DATABASE cyhTest;

USE cyhTest;

DROP TABLE IF EXISTS employee;

CREATE TABLE IF NOT EXISTS employee (
  id      INTEGER NOT NULL,
  money   INTEGER,
  version INTEGER,
  PRIMARY KEY (id)
)
  ENGINE = INNODB;

INSERT INTO employee VALUE (1, 0, 1);

SELECT * FROM employee;

  上面描述查询员工信息    目前数据库中只有一条记录,且初始Money=0。

测试一下(条件):

  • 还是两个会话(终端),左边会话是白色背景、右边会话是黑色背景
  • 关闭自动提交:set autocommit = 0; 

第一步:两个终端均关闭自动提交

左边:

右边:

第二步:左边利用 select .... for update 的悲观锁语法锁住记录

select * from employee where id = 1 for update; 

  一篇彻底搞明白MySQL锁机制--乐观锁 & 悲观锁_第1张图片

第三步:右边也尝试利用 select .... for update 的悲观锁语法锁住记录

  锁表查询

可以看到,Sql语句被挂起(被阻塞)!提示:如果被阻塞的时间太长,会提示如下:

第四步:左边执行更新操作并提交事务

update employee set money = 0 + 1 where id = 1;
commit; 

执行结果:

  一篇彻底搞明白MySQL锁机制--乐观锁 & 悲观锁_第2张图片

执行结果分析:

  •   Money 的旧值为0,所以更新时 Money=0+1
  •   一执行 commit 后,注意查看右边Sql语句的变化

第五步:查看右边Sql语句的变化

执行分析:

  • 被左边悲观锁阻塞了 11.33 秒
  • Money=1,这是左边更新后的结果

结论:

可以看到,当左边(事务A)使用了 select ... for update 的悲观锁后,右边(事务B)再想使用将被阻塞,同时,阻塞被解除后事务B能看到事务A对数据的修改,所以,这就可以很好地解决并发事务的更新丢失问题啦(诚然,这也是人家悲观锁的分内事)

Java代码演示

Mapper层(XML文件):

  提示:这里是 SELCT ... FOR UPDATE

Service 层:

@Transactional(rollbackFor = RuntimeException.class)
public void increaseMoneyWithPessimisticLock(Integer id) {
    Employee employee = employeeMapper.findByIdWithPessimisticLock(id);
    final Integer oldMoney = employee.getMoney();
    LOGGER.info("oldMoney: {}", oldMoney);
    employee.setMoney(oldMoney + 1);
    employeeMapper.updateEmployee(employee);
}

   提示:第3行中的 findByIdWithPessimisticLock() 方法就对应上面XML文件中的Mapper,有悲观锁

应用层(测试代码):

private void increaseMoneyWithPessimisticLock() {
   int threadCount = 100;
   while (threadCount-- > 0) {
        new Thread(() -> employeeService.increaseMoneyWithPessimisticLock(1)).start();
   }
}

提示:100根线程,每个线程将Money值加1,预期结果是100

查询数据库&查看结果

SELECT * FROM employee;

   Money=100,是预期结果。

查看输出日志: 

2019-11-26 15:12:14,335  INFO [Thread-5] (EmployeeService.java:36) - oldMoney: 0
2019-11-26 15:12:14,343  INFO [Thread-25] (EmployeeService.java:36) - oldMoney: 1
2019-11-26 15:12:14,345  INFO [Thread-27] (EmployeeService.java:36) - oldMoney: 2
2019-11-26 15:12:14,347  INFO [Thread-23] (EmployeeService.java:36) - oldMoney: 3
2019-11-26 15:12:14,349  INFO [Thread-13] (EmployeeService.java:36) - oldMoney: 4
2019-11-26 15:12:14,350  INFO [Thread-38] (EmployeeService.java:36) - oldMoney: 5
2019-11-26 15:12:14,351  INFO [Thread-24] (EmployeeService.java:36) - oldMoney: 6
2019-11-26 15:12:14,353  INFO [Thread-4] (EmployeeService.java:36) - oldMoney: 7
2019-11-26 15:12:14,355  INFO [Thread-26] (EmployeeService.java:36) - oldMoney: 8
2019-11-26 15:12:14,357  INFO [Thread-8] (EmployeeService.java:36) - oldMoney: 9
2019-11-26 15:12:14,360  INFO [Thread-3] (EmployeeService.java:36) - oldMoney: 10
2019-11-26 15:12:14,361  INFO [Thread-81] (EmployeeService.java:36) - oldMoney: 11
2019-11-26 15:12:14,363  INFO [Thread-20] (EmployeeService.java:36) - oldMoney: 12
2019-11-26 15:12:14,365  INFO [Thread-40] (EmployeeService.java:36) - oldMoney: 13
2019-11-26 15:12:14,366  INFO [Thread-29] (EmployeeService.java:36) - oldMoney: 14
2019-11-26 15:12:14,453  INFO [Thread-14] (EmployeeService.java:36) - oldMoney: 15
2019-11-26 15:12:14,475  INFO [Thread-7] (EmployeeService.java:36) - oldMoney: 16
2019-11-26 15:12:14,485  INFO [Thread-11] (EmployeeService.java:36) - oldMoney: 17
2019-11-26 15:12:14,488  INFO [Thread-48] (EmployeeService.java:36) - oldMoney: 18
2019-11-26 15:12:14,491  INFO [Thread-47] (EmployeeService.java:36) - oldMoney: 19
2019-11-26 15:12:14,494  INFO [Thread-12] (EmployeeService.java:36) - oldMoney: 20
2019-11-26 15:12:14,497  INFO [Thread-72] (EmployeeService.java:36) - oldMoney: 21
2019-11-26 15:12:14,500  INFO [Thread-46] (EmployeeService.java:36) - oldMoney: 22
2019-11-26 15:12:14,501  INFO [Thread-44] (EmployeeService.java:36) - oldMoney: 23
2019-11-26 15:12:14,503  INFO [Thread-45] (EmployeeService.java:36) - oldMoney: 24
2019-11-26 15:12:14,504  INFO [Thread-41] (EmployeeService.java:36) - oldMoney: 25
2019-11-26 15:12:14,505  INFO [Thread-9] (EmployeeService.java:36) - oldMoney: 26
2019-11-26 15:12:14,507  INFO [Thread-19] (EmployeeService.java:36) - oldMoney: 27
2019-11-26 15:12:14,508  INFO [Thread-55] (EmployeeService.java:36) - oldMoney: 28
2019-11-26 15:12:14,509  INFO [Thread-36] (EmployeeService.java:36) - oldMoney: 29
2019-11-26 15:12:14,518  INFO [Thread-43] (EmployeeService.java:36) - oldMoney: 30
2019-11-26 15:12:14,547  INFO [Thread-53] (EmployeeService.java:36) - oldMoney: 31
2019-11-26 15:12:14,556  INFO [Thread-52] (EmployeeService.java:36) - oldMoney: 32
2019-11-26 15:12:14,558  INFO [Thread-51] (EmployeeService.java:36) - oldMoney: 33
2019-11-26 15:12:14,560  INFO [Thread-50] (EmployeeService.java:36) - oldMoney: 34
2019-11-26 15:12:14,562  INFO [Thread-32] (EmployeeService.java:36) - oldMoney: 35
2019-11-26 15:12:14,563  INFO [Thread-85] (EmployeeService.java:36) - oldMoney: 36
2019-11-26 15:12:14,565  INFO [Thread-84] (EmployeeService.java:36) - oldMoney: 37
2019-11-26 15:12:14,567  INFO [Thread-33] (EmployeeService.java:36) - oldMoney: 38
2019-11-26 15:12:14,568  INFO [Thread-82] (EmployeeService.java:36) - oldMoney: 39
2019-11-26 15:12:14,570  INFO [Thread-34] (EmployeeService.java:36) - oldMoney: 40
2019-11-26 15:12:14,571  INFO [Thread-35] (EmployeeService.java:36) - oldMoney: 41
2019-11-26 15:12:14,573  INFO [Thread-83] (EmployeeService.java:36) - oldMoney: 42
2019-11-26 15:12:14,574  INFO [Thread-42] (EmployeeService.java:36) - oldMoney: 43
2019-11-26 15:12:14,575  INFO [Thread-22] (EmployeeService.java:36) - oldMoney: 44
2019-11-26 15:12:14,585  INFO [Thread-30] (EmployeeService.java:36) - oldMoney: 45
2019-11-26 15:12:14,586  INFO [Thread-28] (EmployeeService.java:36) - oldMoney: 46
2019-11-26 15:12:14,613  INFO [Thread-16] (EmployeeService.java:36) - oldMoney: 47
2019-11-26 15:12:14,615  INFO [Thread-17] (EmployeeService.java:36) - oldMoney: 48
2019-11-26 15:12:14,616  INFO [Thread-21] (EmployeeService.java:36) - oldMoney: 49
2019-11-26 15:12:14,618  INFO [Thread-18] (EmployeeService.java:36) - oldMoney: 50
2019-11-26 15:12:14,619  INFO [Thread-37] (EmployeeService.java:36) - oldMoney: 51
2019-11-26 15:12:14,621  INFO [Thread-39] (EmployeeService.java:36) - oldMoney: 52
2019-11-26 15:12:14,623  INFO [Thread-2] (EmployeeService.java:36) - oldMoney: 53
2019-11-26 15:12:14,624  INFO [Thread-1] (EmployeeService.java:36) - oldMoney: 54
2019-11-26 15:12:14,626  INFO [Thread-10] (EmployeeService.java:36) - oldMoney: 55
2019-11-26 15:12:14,627  INFO [Thread-15] (EmployeeService.java:36) - oldMoney: 56
2019-11-26 15:12:14,628  INFO [Thread-56] (EmployeeService.java:36) - oldMoney: 57
2019-11-26 15:12:14,630  INFO [Thread-54] (EmployeeService.java:36) - oldMoney: 58
2019-11-26 15:12:14,632  INFO [Thread-31] (EmployeeService.java:36) - oldMoney: 59
2019-11-26 15:12:14,642  INFO [Thread-57] (EmployeeService.java:36) - oldMoney: 60
2019-11-26 15:12:14,645  INFO [Thread-6] (EmployeeService.java:36) - oldMoney: 61
2019-11-26 15:12:14,672  INFO [Thread-62] (EmployeeService.java:36) - oldMoney: 62
2019-11-26 15:12:14,677  INFO [Thread-59] (EmployeeService.java:36) - oldMoney: 63
2019-11-26 15:12:14,679  INFO [Thread-61] (EmployeeService.java:36) - oldMoney: 64
2019-11-26 15:12:14,680  INFO [Thread-58] (EmployeeService.java:36) - oldMoney: 65
2019-11-26 15:12:14,681  INFO [Thread-80] (EmployeeService.java:36) - oldMoney: 66
2019-11-26 15:12:14,682  INFO [Thread-76] (EmployeeService.java:36) - oldMoney: 67
2019-11-26 15:12:14,684  INFO [Thread-78] (EmployeeService.java:36) - oldMoney: 68
2019-11-26 15:12:14,685  INFO [Thread-100] (EmployeeService.java:36) - oldMoney: 69
2019-11-26 15:12:14,686  INFO [Thread-99] (EmployeeService.java:36) - oldMoney: 70
2019-11-26 15:12:14,688  INFO [Thread-79] (EmployeeService.java:36) - oldMoney: 71
2019-11-26 15:12:14,689  INFO [Thread-94] (EmployeeService.java:36) - oldMoney: 72
2019-11-26 15:12:14,690  INFO [Thread-60] (EmployeeService.java:36) - oldMoney: 73
2019-11-26 15:12:14,691  INFO [Thread-77] (EmployeeService.java:36) - oldMoney: 74
2019-11-26 15:12:14,709  INFO [Thread-95] (EmployeeService.java:36) - oldMoney: 75
2019-11-26 15:12:14,711  INFO [Thread-96] (EmployeeService.java:36) - oldMoney: 76
2019-11-26 15:12:14,712  INFO [Thread-98] (EmployeeService.java:36) - oldMoney: 77
2019-11-26 15:12:14,738  INFO [Thread-75] (EmployeeService.java:36) - oldMoney: 78
2019-11-26 15:12:14,740  INFO [Thread-74] (EmployeeService.java:36) - oldMoney: 79
2019-11-26 15:12:14,741  INFO [Thread-73] (EmployeeService.java:36) - oldMoney: 80
2019-11-26 15:12:14,742  INFO [Thread-71] (EmployeeService.java:36) - oldMoney: 81
2019-11-26 15:12:14,743  INFO [Thread-69] (EmployeeService.java:36) - oldMoney: 82
2019-11-26 15:12:14,745  INFO [Thread-70] (EmployeeService.java:36) - oldMoney: 83
2019-11-26 15:12:14,746  INFO [Thread-68] (EmployeeService.java:36) - oldMoney: 84
2019-11-26 15:12:14,748  INFO [Thread-66] (EmployeeService.java:36) - oldMoney: 85
2019-11-26 15:12:14,749  INFO [Thread-67] (EmployeeService.java:36) - oldMoney: 86
2019-11-26 15:12:14,751  INFO [Thread-64] (EmployeeService.java:36) - oldMoney: 87
2019-11-26 15:12:14,754  INFO [Thread-65] (EmployeeService.java:36) - oldMoney: 88
2019-11-26 15:12:14,755  INFO [Thread-63] (EmployeeService.java:36) - oldMoney: 89
2019-11-26 15:12:14,767  INFO [Thread-97] (EmployeeService.java:36) - oldMoney: 90
2019-11-26 15:12:14,769  INFO [Thread-93] (EmployeeService.java:36) - oldMoney: 91
2019-11-26 15:12:14,770  INFO [Thread-49] (EmployeeService.java:36) - oldMoney: 92
2019-11-26 15:12:14,796  INFO [Thread-92] (EmployeeService.java:36) - oldMoney: 93
2019-11-26 15:12:14,801  INFO [Thread-91] (EmployeeService.java:36) - oldMoney: 94
2019-11-26 15:12:14,803  INFO [Thread-89] (EmployeeService.java:36) - oldMoney: 95
2019-11-26 15:12:14,803  INFO [Thread-90] (EmployeeService.java:36) - oldMoney: 96
2019-11-26 15:12:14,804  INFO [Thread-88] (EmployeeService.java:36) - oldMoney: 97
2019-11-26 15:12:14,806  INFO [Thread-87] (EmployeeService.java:36) - oldMoney: 98
2019-11-26 15:12:14,807  INFO [Thread-86] (EmployeeService.java:36) - oldMoney: 99

可以看到,oldMoney 值由0到99依次严格递增且不重复(这就是想要的效果)。

三、乐观锁

         乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。相对悲观锁而言,乐观锁更倾向于开发运用。乐观锁的特点是先进行业务操作,不到万不得已不会去拿锁。乐观地认为拿锁多半会是成功的,因此在完成业务操作需要实际更新数据的最后一步再去拿一下锁。个人理解乐观锁更加相似于CAS操作,或者更加贴切来说有点类似于我们在版本控制工具中得SVN与Git得原理,当修改了某个文件需要提交的时候,它会检查文件的当前版本是否与服务器上的一致,如果一致那就可以直接提交,如果不一致,那就必须先更新服务器上的最新代码然后再提交(也就是先将这个文件的版本更新成和服务器一样的版本)。

  3.1 如何实现乐观锁

乐观锁在数据库中的实现完全是要靠逻辑支撑的,数据库本身并不提供支持,而是需要开发者自己来实现。常用的两种做法:版本号控制或者时间戳控制。

版本号控制原理:

  • 为表中加一个 version 字段;(常用)
  • 当读取数据时,连同这个 version 字段一起读出;
  • 数据每更新一次就将此值加一;
  • 当提交更新时,判断数据库表中对应记录的当前版本号是否与之前取出来的版本号一致,如果一致则可以直接更新,如果不一致则表示是过期数据需要重试或者做其它操作(PS:这完完全全就是 CAS 的实现逻辑呀~)
  • 至于时间戳控制,其原理和版本号控制差不多,也是在表中添加一个 timestamp 的时间戳字段,然后提交更新时判断数据库中对应记录的当前时间戳是否与之前取出来的时间戳一致,一致就更新,不一致就重试。

Java代码演示

我们以最为常用的version版本号控制,进行乐观锁

Mapper层(XML文件):


        UPDATE employee SET money = #{e.money}, version = #{e.version} + 1 WHERE id = #{e.id} AND #{e.version} = version
    

  提示:

  • SET 中有 version = #{e.version} + 1 的操作
  • WHERE 条件中有 #{e.version} = version 的判断

Service 层:

1     /**
 2      * 失败尝试
 3      * @param id
 4      */
 5     public void increaseMoneyWithOptimisticLock(Integer id) {
 6         int tryTimes = 0;
 7         while (true) {
 8             tryTimes++;
 9             if (internalIncreaseMoneyWithOptimisticLock(id) != 0) {
10                 // 说明更新成功,直接退出
11                 break;
12             }
13             if (tryTimes == 200) {
14                 // 达到最大重试次数,退出
15                 break;
16             }
17             try {
18                 // 休息一段时间后再重试
19                 TimeUnit.MILLISECONDS.sleep(new Random().nextInt(1000));
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22                 Thread.currentThread().interrupt();
23             }
24         }
25         LOGGER.info("tryTimes: {}", tryTimes);
26     }
27 
28     /**
29      * 查找Employee对象,并进行更新
30      * @param id
31      * @return
32      */
33     @Transactional(rollbackFor = RuntimeException.class)
34     public Integer internalIncreaseMoneyWithOptimisticLock(Integer id) {
35         Employee employee = employeeMapper.findById(id);
36         final Integer oldMoney = employee.getMoney();
37         LOGGER.info("oldMoney: {}", oldMoney);
38         employee.setMoney(oldMoney + 1);
39         return employeeMapper.updateEmployeeWithOptimisticLock(employee);
40     }

  提示:  

  • 乐观锁,其实是开发者自己实现的逻辑
  • 更新失败后,休息一段时间后再进行重试

应用层(测试代码):

private void increaseMoneyWithOptimisticLock() {
     int threadCount = 100;
     while (threadCount-- > 0) {
        new Thread(() -> employeeService.increaseMoneyWithOptimisticLock(1)).start();
     }
}

提示:100根线程,每个线程将Money值加1,预期结果是Money的值在之前的基础上增加100

查询数据库&查看结果:

之前Money=100,现在预期增加100,所以现在Money=200符合预期。同时,version 字段的值也由最初的1更新为101(也被更新了100次,每次加一)。

查看输出日志: 

2019-11-26 16:24:07,851  INFO [Thread-36] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,853  INFO [Thread-54] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,856  INFO [Thread-55] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,856  INFO [Thread-45] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,858  INFO [Thread-56] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,858  INFO [Thread-53] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,858  INFO [Thread-33] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,859  INFO [Thread-57] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,859  INFO [Thread-31] (EmployeeService.java:77) - oldMoney: 100
2019-11-26 16:24:07,863  INFO [Thread-30] (EmployeeService.java:77) - oldMoney: 101
2019-11-26 16:24:07,868  INFO [Thread-29] (EmployeeService.java:77) - oldMoney: 101
2019-11-26 16:24:07,880  INFO [Thread-75] (EmployeeService.java:77) - oldMoney: 101
2019-11-26 16:24:07,881  INFO [Thread-76] (EmployeeService.java:77) - oldMoney: 102
2019-11-26 16:24:07,882  INFO [Thread-78] (EmployeeService.java:77) - oldMoney: 102
2019-11-26 16:24:07,883  INFO [Thread-77] (EmployeeService.java:77) - oldMoney: 102
2019-11-26 16:24:07,885  INFO [Thread-79] (EmployeeService.java:77) - oldMoney: 103
2019-11-26 16:24:07,887  INFO [Thread-80] (EmployeeService.java:77) - oldMoney: 103
2019-11-26 16:24:07,888  INFO [Thread-28] (EmployeeService.java:77) - oldMoney: 104
2019-11-26 16:24:07,890  INFO [Thread-27] (EmployeeService.java:77) - oldMoney: 104
2019-11-26 16:24:07,892  INFO [Thread-26] (EmployeeService.java:77) - oldMoney: 105
2019-11-26 16:24:07,894  INFO [Thread-25] (EmployeeService.java:77) - oldMoney: 105
2019-11-26 16:24:07,895  INFO [Thread-24] (EmployeeService.java:77) - oldMoney: 106
2019-11-26 16:24:07,897  INFO [Thread-83] (EmployeeService.java:77) - oldMoney: 106
2019-11-26 16:24:07,898  INFO [Thread-82] (EmployeeService.java:77) - oldMoney: 106
2019-11-26 16:24:07,900  INFO [Thread-84] (EmployeeService.java:77) - oldMoney: 107
2019-11-26 16:24:07,904  INFO [Thread-21] (EmployeeService.java:77) - oldMoney: 108
2019-11-26 16:24:07,906  INFO [Thread-20] (EmployeeService.java:77) - oldMoney: 109
2019-11-26 16:24:07,907  INFO [Thread-6] (EmployeeService.java:77) - oldMoney: 109
2019-11-26 16:24:07,908  INFO [Thread-9] (EmployeeService.java:77) - oldMoney: 110
2019-11-26 16:24:07,909  INFO [Thread-85] (EmployeeService.java:77) - oldMoney: 110
2019-11-26 16:24:07,909  INFO [Thread-86] (EmployeeService.java:77) - oldMoney: 111
2019-11-26 16:24:07,911  INFO [Thread-91] (EmployeeService.java:77) - oldMoney: 111
2019-11-26 16:24:07,912  INFO [Thread-81] (EmployeeService.java:77) - oldMoney: 112
2019-11-26 16:24:07,913  INFO [Thread-90] (EmployeeService.java:77) - oldMoney: 112
2019-11-26 16:24:07,915  INFO [Thread-96] (EmployeeService.java:77) - oldMoney: 112
2019-11-26 16:24:07,924  INFO [Thread-97] (EmployeeService.java:77) - oldMoney: 113
2019-11-26 16:24:07,926  INFO [Thread-36] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,928  INFO [Thread-18] (EmployeeService.java:77) - oldMoney: 113
2019-11-26 16:24:07,929  INFO [Thread-4] (EmployeeService.java:77) - oldMoney: 113
2019-11-26 16:24:07,932  INFO [Thread-94] (EmployeeService.java:77) - oldMoney: 114
2019-11-26 16:24:07,934  INFO [Thread-12] (EmployeeService.java:77) - oldMoney: 114
2019-11-26 16:24:07,935  INFO [Thread-93] (EmployeeService.java:77) - oldMoney: 114
2019-11-26 16:24:07,939  INFO [Thread-92] (EmployeeService.java:77) - oldMoney: 115
2019-11-26 16:24:07,940  INFO [Thread-69] (EmployeeService.java:77) - oldMoney: 115
2019-11-26 16:24:07,960  INFO [Thread-86] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,961  INFO [Thread-9] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,960  INFO [Thread-75] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,962  INFO [Thread-33] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,963  INFO [Thread-87] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,963  INFO [Thread-6] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,964  INFO [Thread-20] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,964  INFO [Thread-21] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,964  INFO [Thread-90] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,965  INFO [Thread-26] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,965  INFO [Thread-28] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,965  INFO [Thread-83] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,966  INFO [Thread-76] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,966  INFO [Thread-79] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,967  INFO [Thread-84] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:07,974  INFO [Thread-16] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,974  INFO [Thread-17] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,974  INFO [Thread-89] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,975  INFO [Thread-13] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,976  INFO [Thread-7] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,976  INFO [Thread-100] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,976  INFO [Thread-95] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,978  INFO [Thread-88] (EmployeeService.java:77) - oldMoney: 116
2019-11-26 16:24:07,978  INFO [Thread-8] (EmployeeService.java:77) - oldMoney: 117
2019-11-26 16:24:07,979  INFO [Thread-11] (EmployeeService.java:77) - oldMoney: 117
2019-11-26 16:24:07,980  INFO [Thread-5] (EmployeeService.java:77) - oldMoney: 118
2019-11-26 16:24:07,980  INFO [Thread-19] (EmployeeService.java:77) - oldMoney: 118
2019-11-26 16:24:07,980  INFO [Thread-22] (EmployeeService.java:77) - oldMoney: 118
2019-11-26 16:24:07,981  INFO [Thread-2] (EmployeeService.java:77) - oldMoney: 119
2019-11-26 16:24:07,981  INFO [Thread-23] (EmployeeService.java:77) - oldMoney: 119
2019-11-26 16:24:07,982  INFO [Thread-35] (EmployeeService.java:77) - oldMoney: 119
2019-11-26 16:24:07,982  INFO [Thread-32] (EmployeeService.java:77) - oldMoney: 119
2019-11-26 16:24:07,983  INFO [Thread-34] (EmployeeService.java:77) - oldMoney: 120
2019-11-26 16:24:07,983  INFO [Thread-37] (EmployeeService.java:77) - oldMoney: 120
2019-11-26 16:24:07,984  INFO [Thread-38] (EmployeeService.java:77) - oldMoney: 120
2019-11-26 16:24:07,985  INFO [Thread-39] (EmployeeService.java:77) - oldMoney: 121
2019-11-26 16:24:07,985  INFO [Thread-40] (EmployeeService.java:77) - oldMoney: 121
2019-11-26 16:24:07,986  INFO [Thread-41] (EmployeeService.java:77) - oldMoney: 121
2019-11-26 16:24:07,986  INFO [Thread-43] (EmployeeService.java:77) - oldMoney: 121
2019-11-26 16:24:07,987  INFO [Thread-44] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,988  INFO [Thread-48] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,988  INFO [Thread-49] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,989  INFO [Thread-50] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,986  INFO [Thread-42] (EmployeeService.java:77) - oldMoney: 121
2019-11-26 16:24:07,990  INFO [Thread-52] (EmployeeService.java:77) - oldMoney: 123
2019-11-26 16:24:07,989  INFO [Thread-51] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,988  INFO [Thread-47] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,987  INFO [Thread-46] (EmployeeService.java:77) - oldMoney: 122
2019-11-26 16:24:07,991  INFO [Thread-60] (EmployeeService.java:77) - oldMoney: 123
2019-11-26 16:24:07,990  INFO [Thread-58] (EmployeeService.java:77) - oldMoney: 123
2019-11-26 16:24:07,992  INFO [Thread-64] (EmployeeService.java:77) - oldMoney: 124
2019-11-26 16:24:07,992  INFO [Thread-65] (EmployeeService.java:77) - oldMoney: 124
2019-11-26 16:24:07,992  INFO [Thread-61] (EmployeeService.java:77) - oldMoney: 124
2019-11-26 16:24:07,993  INFO [Thread-63] (EmployeeService.java:77) - oldMoney: 125
2019-11-26 16:24:07,995  INFO [Thread-68] (EmployeeService.java:77) - oldMoney: 125
2019-11-26 16:24:07,995  INFO [Thread-67] (EmployeeService.java:77) - oldMoney: 125
2019-11-26 16:24:07,995  INFO [Thread-15] (EmployeeService.java:77) - oldMoney: 125
2019-11-26 16:24:07,996  INFO [Thread-66] (EmployeeService.java:77) - oldMoney: 125
2019-11-26 16:24:07,997  INFO [Thread-99] (EmployeeService.java:77) - oldMoney: 126
2019-11-26 16:24:07,998  INFO [Thread-98] (EmployeeService.java:77) - oldMoney: 126
2019-11-26 16:24:07,998  INFO [Thread-74] (EmployeeService.java:77) - oldMoney: 126
2019-11-26 16:24:08,002  INFO [Thread-92] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,002  INFO [Thread-73] (EmployeeService.java:77) - oldMoney: 127
2019-11-26 16:24:08,002  INFO [Thread-18] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,004  INFO [Thread-62] (EmployeeService.java:77) - oldMoney: 127
2019-11-26 16:24:08,004  INFO [Thread-27] (EmployeeService.java:77) - oldMoney: 127
2019-11-26 16:24:08,005  INFO [Thread-46] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,006  INFO [Thread-59] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,006  INFO [Thread-71] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,006  INFO [Thread-3] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,007  INFO [Thread-56] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,008  INFO [Thread-72] (EmployeeService.java:77) - oldMoney: 128
2019-11-26 16:24:08,008  INFO [Thread-93] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,010  INFO [Thread-70] (EmployeeService.java:77) - oldMoney: 129
2019-11-26 16:24:08,010  INFO [Thread-10] (EmployeeService.java:77) - oldMoney: 129
2019-11-26 16:24:08,010  INFO [Thread-17] (EmployeeService.java:77) - oldMoney: 129
2019-11-26 16:24:08,011  INFO [Thread-14] (EmployeeService.java:77) - oldMoney: 129
2019-11-26 16:24:08,012  INFO [Thread-1] (EmployeeService.java:77) - oldMoney: 130
2019-11-26 16:24:08,032  INFO [Thread-5] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,032  INFO [Thread-49] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,032  INFO [Thread-87] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,032  INFO [Thread-64] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,032  INFO [Thread-8] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,033  INFO [Thread-41] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,033  INFO [Thread-52] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,034  INFO [Thread-2] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,034  INFO [Thread-72] (EmployeeService.java:77) - oldMoney: 131
2019-11-26 16:24:08,035  INFO [Thread-99] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,035  INFO [Thread-34] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,035  INFO [Thread-68] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,037  INFO [Thread-30] (EmployeeService.java:77) - oldMoney: 131
2019-11-26 16:24:08,049  INFO [Thread-30] (EmployeeService.java:77) - oldMoney: 132
2019-11-26 16:24:08,068  INFO [Thread-3] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,068  INFO [Thread-10] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,068  INFO [Thread-73] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,068  INFO [Thread-1] (EmployeeService.java:65) - tryTimes: 1
2019-11-26 16:24:08,070  INFO [Thread-24] (EmployeeService.java:77) - oldMoney: 133
2019-11-26 16:24:08,082  INFO [Thread-69] (EmployeeService.java:77) - oldMoney: 134
2019-11-26 16:24:08,087  INFO [Thread-60] (EmployeeService.java:77) - oldMoney: 135
2019-11-26 16:24:08,117  INFO [Thread-38] (EmployeeService.java:77) - oldMoney: 136
2019-11-26 16:24:08,125  INFO [Thread-46] (EmployeeService.java:77) - oldMoney: 137
2019-11-26 16:24:08,131  INFO [Thread-30] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,132  INFO [Thread-72] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,149  INFO [Thread-11] (EmployeeService.java:77) - oldMoney: 138
2019-11-26 16:24:08,170  INFO [Thread-98] (EmployeeService.java:77) - oldMoney: 139
2019-11-26 16:24:08,180  INFO [Thread-60] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,181  INFO [Thread-46] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,180  INFO [Thread-69] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,180  INFO [Thread-38] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,180  INFO [Thread-24] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,188  INFO [Thread-71] (EmployeeService.java:77) - oldMoney: 140
2019-11-26 16:24:08,204  INFO [Thread-96] (EmployeeService.java:77) - oldMoney: 141
2019-11-26 16:24:08,210  INFO [Thread-11] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,210  INFO [Thread-98] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,230  INFO [Thread-91] (EmployeeService.java:77) - oldMoney: 142
2019-11-26 16:24:08,239  INFO [Thread-71] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,239  INFO [Thread-96] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,254  INFO [Thread-25] (EmployeeService.java:77) - oldMoney: 143
2019-11-26 16:24:08,254  INFO [Thread-58] (EmployeeService.java:77) - oldMoney: 143
2019-11-26 16:24:08,263  INFO [Thread-17] (EmployeeService.java:77) - oldMoney: 144
2019-11-26 16:24:08,268  INFO [Thread-91] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,275  INFO [Thread-63] (EmployeeService.java:77) - oldMoney: 145
2019-11-26 16:24:08,275  INFO [Thread-89] (EmployeeService.java:77) - oldMoney: 145
2019-11-26 16:24:08,277  INFO [Thread-51] (EmployeeService.java:77) - oldMoney: 146
2019-11-26 16:24:08,279  INFO [Thread-56] (EmployeeService.java:77) - oldMoney: 147
2019-11-26 16:24:08,280  INFO [Thread-40] (EmployeeService.java:77) - oldMoney: 147
2019-11-26 16:24:08,280  INFO [Thread-65] (EmployeeService.java:77) - oldMoney: 147
2019-11-26 16:24:08,287  INFO [Thread-100] (EmployeeService.java:77) - oldMoney: 148
2019-11-26 16:24:08,298  INFO [Thread-25] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,299  INFO [Thread-17] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,310  INFO [Thread-47] (EmployeeService.java:77) - oldMoney: 149
2019-11-26 16:24:08,319  INFO [Thread-6] (EmployeeService.java:77) - oldMoney: 150
2019-11-26 16:24:08,327  INFO [Thread-100] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,327  INFO [Thread-56] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,327  INFO [Thread-63] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,328  INFO [Thread-51] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,364  INFO [Thread-6] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,365  INFO [Thread-47] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,388  INFO [Thread-33] (EmployeeService.java:77) - oldMoney: 151
2019-11-26 16:24:08,400  INFO [Thread-58] (EmployeeService.java:77) - oldMoney: 152
2019-11-26 16:24:08,404  INFO [Thread-35] (EmployeeService.java:77) - oldMoney: 153
2019-11-26 16:24:08,424  INFO [Thread-89] (EmployeeService.java:77) - oldMoney: 154
2019-11-26 16:24:08,427  INFO [Thread-33] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,431  INFO [Thread-88] (EmployeeService.java:77) - oldMoney: 155
2019-11-26 16:24:08,453  INFO [Thread-12] (EmployeeService.java:77) - oldMoney: 156
2019-11-26 16:24:08,454  INFO [Thread-70] (EmployeeService.java:77) - oldMoney: 157
2019-11-26 16:24:08,457  INFO [Thread-89] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,457  INFO [Thread-58] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,458  INFO [Thread-35] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,459  INFO [Thread-54] (EmployeeService.java:77) - oldMoney: 158
2019-11-26 16:24:08,461  INFO [Thread-67] (EmployeeService.java:77) - oldMoney: 159
2019-11-26 16:24:08,470  INFO [Thread-31] (EmployeeService.java:77) - oldMoney: 160
2019-11-26 16:24:08,485  INFO [Thread-12] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,485  INFO [Thread-70] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,486  INFO [Thread-88] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,488  INFO [Thread-81] (EmployeeService.java:77) - oldMoney: 161
2019-11-26 16:24:08,497  INFO [Thread-23] (EmployeeService.java:77) - oldMoney: 162
2019-11-26 16:24:08,504  INFO [Thread-82] (EmployeeService.java:77) - oldMoney: 163
2019-11-26 16:24:08,507  INFO [Thread-50] (EmployeeService.java:77) - oldMoney: 164
2019-11-26 16:24:08,510  INFO [Thread-78] (EmployeeService.java:77) - oldMoney: 165
2019-11-26 16:24:08,514  INFO [Thread-67] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,514  INFO [Thread-54] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,516  INFO [Thread-97] (EmployeeService.java:77) - oldMoney: 166
2019-11-26 16:24:08,517  INFO [Thread-31] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,534  INFO [Thread-61] (EmployeeService.java:77) - oldMoney: 167
2019-11-26 16:24:08,538  INFO [Thread-29] (EmployeeService.java:77) - oldMoney: 168
2019-11-26 16:24:08,543  INFO [Thread-23] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,544  INFO [Thread-81] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,544  INFO [Thread-50] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,543  INFO [Thread-82] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,544  INFO [Thread-78] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,556  INFO [Thread-74] (EmployeeService.java:77) - oldMoney: 169
2019-11-26 16:24:08,572  INFO [Thread-61] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,573  INFO [Thread-29] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,572  INFO [Thread-97] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,582  INFO [Thread-80] (EmployeeService.java:77) - oldMoney: 170
2019-11-26 16:24:08,583  INFO [Thread-48] (EmployeeService.java:77) - oldMoney: 171
2019-11-26 16:24:08,584  INFO [Thread-27] (EmployeeService.java:77) - oldMoney: 172
2019-11-26 16:24:08,589  INFO [Thread-32] (EmployeeService.java:77) - oldMoney: 173
2019-11-26 16:24:08,602  INFO [Thread-74] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,608  INFO [Thread-85] (EmployeeService.java:77) - oldMoney: 174
2019-11-26 16:24:08,631  INFO [Thread-32] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,631  INFO [Thread-27] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:08,631  INFO [Thread-80] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,632  INFO [Thread-48] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,634  INFO [Thread-22] (EmployeeService.java:77) - oldMoney: 175
2019-11-26 16:24:08,660  INFO [Thread-85] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,689  INFO [Thread-22] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,696  INFO [Thread-44] (EmployeeService.java:77) - oldMoney: 176
2019-11-26 16:24:08,696  INFO [Thread-43] (EmployeeService.java:77) - oldMoney: 176
2019-11-26 16:24:08,704  INFO [Thread-13] (EmployeeService.java:77) - oldMoney: 177
2019-11-26 16:24:08,712  INFO [Thread-4] (EmployeeService.java:77) - oldMoney: 178
2019-11-26 16:24:08,722  INFO [Thread-45] (EmployeeService.java:77) - oldMoney: 179
2019-11-26 16:24:08,723  INFO [Thread-7] (EmployeeService.java:77) - oldMoney: 179
2019-11-26 16:24:08,727  INFO [Thread-44] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,743  INFO [Thread-77] (EmployeeService.java:77) - oldMoney: 180
2019-11-26 16:24:08,748  INFO [Thread-59] (EmployeeService.java:77) - oldMoney: 181
2019-11-26 16:24:08,754  INFO [Thread-57] (EmployeeService.java:77) - oldMoney: 182
2019-11-26 16:24:08,756  INFO [Thread-45] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,756  INFO [Thread-13] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,757  INFO [Thread-4] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,765  INFO [Thread-39] (EmployeeService.java:77) - oldMoney: 183
2019-11-26 16:24:08,779  INFO [Thread-66] (EmployeeService.java:77) - oldMoney: 184
2019-11-26 16:24:08,785  INFO [Thread-59] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,785  INFO [Thread-77] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,796  INFO [Thread-55] (EmployeeService.java:77) - oldMoney: 185
2019-11-26 16:24:08,811  INFO [Thread-62] (EmployeeService.java:77) - oldMoney: 186
2019-11-26 16:24:08,814  INFO [Thread-39] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,814  INFO [Thread-57] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,814  INFO [Thread-66] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,827  INFO [Thread-94] (EmployeeService.java:77) - oldMoney: 187
2019-11-26 16:24:08,840  INFO [Thread-53] (EmployeeService.java:77) - oldMoney: 188
2019-11-26 16:24:08,840  INFO [Thread-95] (EmployeeService.java:77) - oldMoney: 188
2019-11-26 16:24:08,843  INFO [Thread-62] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,843  INFO [Thread-55] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,857  INFO [Thread-37] (EmployeeService.java:77) - oldMoney: 189
2019-11-26 16:24:08,872  INFO [Thread-94] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,872  INFO [Thread-53] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,887  INFO [Thread-15] (EmployeeService.java:77) - oldMoney: 190
2019-11-26 16:24:08,891  INFO [Thread-16] (EmployeeService.java:77) - oldMoney: 191
2019-11-26 16:24:08,902  INFO [Thread-37] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,909  INFO [Thread-14] (EmployeeService.java:77) - oldMoney: 192
2019-11-26 16:24:08,931  INFO [Thread-16] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,931  INFO [Thread-15] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,960  INFO [Thread-14] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:08,964  INFO [Thread-65] (EmployeeService.java:77) - oldMoney: 193
2019-11-26 16:24:08,965  INFO [Thread-42] (EmployeeService.java:77) - oldMoney: 194
2019-11-26 16:24:08,970  INFO [Thread-19] (EmployeeService.java:77) - oldMoney: 195
2019-11-26 16:24:08,989  INFO [Thread-65] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:09,018  INFO [Thread-42] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:09,018  INFO [Thread-19] (EmployeeService.java:65) - tryTimes: 2
2019-11-26 16:24:09,025  INFO [Thread-40] (EmployeeService.java:77) - oldMoney: 196
2019-11-26 16:24:09,056  INFO [Thread-40] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:09,318  INFO [Thread-43] (EmployeeService.java:77) - oldMoney: 197
2019-11-26 16:24:09,352  INFO [Thread-43] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:09,433  INFO [Thread-7] (EmployeeService.java:77) - oldMoney: 198
2019-11-26 16:24:09,473  INFO [Thread-7] (EmployeeService.java:65) - tryTimes: 3
2019-11-26 16:24:09,578  INFO [Thread-95] (EmployeeService.java:77) - oldMoney: 199
2019-11-26 16:24:09,627  INFO [Thread-95] (EmployeeService.java:65) - tryTimes: 3

可以看到,还是有一些线程会拿到相同的值,但是由于版本控制使得最终只有一根线程能够更新成功,其它更新失败的线程会继续尝试,最终能更新成功。

 

四、总结&对比

悲观锁与乐观锁总结
  悲观锁 乐观锁
概念 查询时直接锁住记录使得其它事务不能查询,更不能更新 提交更新时检查版本或者时间戳是否符合
语法 select ... for update 使用 version 或者 timestamp 进行比较
实现者 数据库本身 开发者
适用场景 并发量大 并发量小
类比Java Synchronized关键字 CAS 算法

 

 

 

 

 

 

 

你可能感兴趣的:(微服务,MySQL,springcloud)