Skip to content

事务和锁


注意

使用事务处理,需要数据库引擎支持事务处理。比如 MySQL 的 MyISAM 不支持事务处理,需要使用 InnoDB 引擎。

Lock()

  • @param lockStr 锁类型,默认 FOR UPDATE
  • 排它锁 FOR UPDATE
  • 共享锁 LOCK IN SHARE MODE
  • 注意:锁要在事务中使用,不可单独使用

事务 BeginTransaction()

  • @param tg.Source{} 数据源,参数选填,不传默认会读取 config/config.yaml 里的数据库配置
  • -------@param Link 数据库连接字符串
  • -------@param Debug 是否打印最终执行的SQL语句,默认不打印
  • -------@param CreateTime 创建时间字段名,默认 create_time
  • -------@param UpdateTime 更新时间字段名,默认 update_time
  • -------@param DeleteTime 删除时间字段名,默认 delete_time
  • -------@param MaxOpen 最大打开连接数
  • -------@param MaxIdle 最大空闲连接数
  • -------@param MaxIdleTime 连接在空闲状态下的最大存活时间
  • -------@param MaxLifeTime 连接的最大生命周期,从创建到被关闭的总时间

事务配合锁解决并发超卖的问题

var goods Goods
tx := tg.BeginTransaction()
err := tx.Db("goods").Where("id", "=", 1).Lock().FindOne(&goods)
if err != nil {
    fmt.Println("查询异常")
    return
}
if goods.Stock > 0 {
    err = tx.Db("goods").Where("id", "=", 1).Decr("stock", 1)
    if err != nil {
        tx.Rollback()
    }
} else {
    fmt.Println("库存不足")
}
tx.Commit()
var goods Goods
tx := tg.BeginTransaction()
err := tx.Db("goods").Where("id", "=", 1).Lock().FindOne(&goods)
if err != nil {
    fmt.Println("查询异常")
    return
}
if goods.Stock > 0 {
    err = tx.Db("goods").Where("id", "=", 1).Decr("stock", 1)
    if err != nil {
        tx.Rollback()
    }
} else {
    fmt.Println("库存不足")
}
tx.Commit()

最终的SQL语句为:

START TRANSACTION
SELECT * FROM goods WHERE id = 1 FOR UPDATE
UPDATE goods SET stock = stock - 1 WHERE id = 1
COMMIT
START TRANSACTION
SELECT * FROM goods WHERE id = 1 FOR UPDATE
UPDATE goods SET stock = stock - 1 WHERE id = 1
COMMIT

备案号:冀ICP备20015584号-5