分布式服务数据一致性-mysql篇

前言:

单台服务器的时候,使用mutex/RWMutex都可以给goroutine加锁,当服务部署到多台服务器时,mutex/RWMutex不能解决并发问题,需要分布式锁解决。

mysql解决方案:

1.悲观锁方案

#向mysql请求一把锁 for update ,使用for update的时候注意:默认每个语句mysql都是自动提交的
SELECT @@autocommit;
#需要关闭autocommit
SET autocommit=0;
#符合条件的数据会被行锁,如果条件字段没有索引则会发生表锁,在没有满足条件的情况下,有索引不锁表,无索引锁全表
SELECT * FROM goods WHERE product_id = 1 FOR UPDATE;
……需要执行的逻辑代码
#释放这把锁
COMMIT;
#如果不加for update关键字是不会被锁的,类似读写锁
SELECT * FROM goods WHERE product_id = 1 FOR UPDATE;
//注意事项:需要开启事务手动提交释放锁
var wg sync.WaitGroup
wg.Add(20)
for i := 0; i < 20; i++ {
   // 开始事务
   go func() {
      var goods Goods
      tx := db.Begin()
      tx.Clauses(clause.Locking{Strength: "UPDATE"}).Where(Goods{ProductId: 1}).First(&goods)
      goods.Inventory -= 1
      tx.Save(&goods)
      fmt.Println("库存数量",goods.Inventory)
      tx.Commit()
      wg.Done()
   }()
}
wg.Wait()

2.乐观锁方案

//通过版本号或者时间戳确认,不符合条件重新执行。没有用到锁,可以避免出现死锁
var wg sync.WaitGroup
wg.Add(20)
for i := 0; i < 20; i++ {
   go func() {
      var goods Goods
      for  {
         db.Where(Goods{ProductId: 1}).First(&goods)
         //最后一个库存扣减会失败,gorm会忽略零值的字段,添加select选择要更新的字段,或者使用Save方法保存
         result := db.Model(&Goods{}).Select("Inventory","Version").
            Where("product_id=? and version=?",1,goods.Version).
            Updates(Goods{Inventory: goods.Inventory - 1, Version: goods.Version + 1})
         if result.RowsAffected == 0 {
            fmt.Println("库存扣减失败")
         }else {
            break
         }
      }
      fmt.Println("库存数量", goods.Inventory)
      wg.Done()
   }()
}
wg.Wait()
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!