1 Star 0 Fork 0

Wsage/go-framework

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
optim_lock.go 4.44 KB
一键复制 编辑 原始数据 按行查看 历史
王少奇 提交于 2021-08-22 21:37 . 新增 乐观锁和版本管理
package handler
import (
"database/sql"
"fmt"
"gitee.com/scottq/go-framework/src/miscs"
"os"
"time"
)
const LOCK_TABLE = "lock_optimistic"
var CREATE_LOCK_TABLE_SQL = fmt.Sprintf(`
CREATE TABLE IF NOT EXISTS %s
(
id bigint unsigned NOT NULL AUTO_INCREMENT,
lock_name varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '锁名',
lock_at datetime DEFAULT NULL COMMENT '锁定时间',
unlock_at datetime DEFAULT NULL COMMENT '解锁时间',
lock_host varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '主机信息',
timeout bigint unsigned default 0 COMMENT '超时时间,单位:秒',
status int unsigned DEFAULT 0 COMMENT '锁状态,0:未锁定,1:已锁',
PRIMARY KEY (id),
UNIQUE KEY idx_lock (lock_name)
) ENGINE = InnoDB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='乐观锁表'
`, LOCK_TABLE)
type IOptimisticLock interface {
Lock(name string) bool
UnLock(name string) bool
}
type OptimisticLock struct {
db *sql.DB
timeout int64 //unit: seconds
}
func NewOptimisticLock(db *sql.DB, timeout int64) (IOptimisticLock, error) {
lock := &OptimisticLock{
db: db,
timeout: timeout,
}
if err := lock.init(); err != nil {
return nil, err
}
return lock, nil
}
type Lock struct {
LockName string
LockAt string
UnLockAt string
LockHost string
Timeout int64
Status int
}
func (l *Lock) IsLock() bool {
lockTime, err := time.Parse(miscs.DateTimeLayout, l.LockAt)
if err != nil {
return false
}
expireTime := lockTime.Add(time.Second * time.Duration(l.Timeout))
if l.Status == STATUS_LOCK && expireTime.UnixNano() > time.Now().UnixNano() {
//锁中
return true
}
//未锁
return false
}
const STATUS_UNLOCK = 0
const STATUS_LOCK = 1
func (this *OptimisticLock) Lock(name string) bool {
findLock, err := this.queryLock(name)
if err != nil {
fmt.Println("query lock fail:", err)
return false
}
if findLock == nil {
err := this.addLock(name)
if err != nil {
fmt.Println("add lock fail:", err)
return false
}
findLock, err = this.queryLock(name)
if err != nil {
fmt.Println("after add query lock fail:", err)
return false
}
} else if findLock.IsLock() {
fmt.Println("query is lock fail:", err)
return false
}
lock, err := this.lockLock(name, findLock.LockAt)
if err != nil {
fmt.Println("lock fail:", err)
return false
}
return lock
}
func (this *OptimisticLock) UnLock(name string) bool {
ok, err := this.unLock(name)
if err != nil {
fmt.Println(err)
return false
}
return ok
}
func (this *OptimisticLock) init() error {
var err error
_, err = this.db.Exec(CREATE_LOCK_TABLE_SQL)
if err != nil {
return err
}
return nil
}
func (this *OptimisticLock) queryLock(name string) (*Lock, error) {
db := this.db
findLock := &Lock{}
selectSql := fmt.Sprintf("SELECT lock_name,ifnull(lock_at,'') as lock_at,lock_host,timeout,status FROM %s WHERE lock_name=? LIMIT 1", LOCK_TABLE)
row := db.QueryRow(selectSql, name)
err := row.Scan(
&findLock.LockName,
&findLock.LockAt, &findLock.LockHost,
&findLock.Timeout, &findLock.Status)
if err == sql.ErrNoRows {
return nil, nil
} else if err != nil {
return nil, err
}
return findLock, nil
}
func (this *OptimisticLock) addLock(name string) error {
db := this.db
t := time.Unix(0, 0).Format(miscs.DateTimeLayout)
insertSql := fmt.Sprintf("INSERT INTO %s SET lock_name=?,status=?,lock_at=?,unlock_at=?", LOCK_TABLE)
_, err := db.Exec(insertSql, name, STATUS_UNLOCK, t, t)
if err != nil {
return err
}
return nil
}
func (this *OptimisticLock) lockLock(name string, lastLockAt string) (bool, error) {
db := this.db
lockAt := time.Now().Format(miscs.DateTimeLayout)
hostname, err := os.Hostname()
updateSql := fmt.Sprintf("UPDATE %s SET lock_at=?,lock_host=?,timeout=?,status=? WHERE lock_name=? AND lock_at=?", LOCK_TABLE)
ret, err := db.Exec(updateSql,
lockAt, hostname, this.timeout, STATUS_LOCK,
name, lastLockAt)
if err != nil {
return false, err
}
a, _ := ret.RowsAffected()
return a == 1, nil
}
func (this *OptimisticLock) unLock(name string) (bool, error) {
db := this.db
unlockAt := time.Now().Format(miscs.DateTimeLayout)
updateSql := fmt.Sprintf("UPDATE %s SET unlock_at=?,status=? WHERE lock_name=? AND status=?", LOCK_TABLE)
ret, err := db.Exec(updateSql, unlockAt, STATUS_UNLOCK, name, STATUS_LOCK)
if err != nil {
return false, err
}
a, _ := ret.RowsAffected()
return a == 1, nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/scottq/go-framework.git
git@gitee.com:scottq/go-framework.git
scottq
go-framework
go-framework
v1.1.25

搜索帮助

0d507c66 1850385 C8b1a773 1850385