既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上C C++开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
sqlstr := &strings.Builder{}
sqlstr.WriteString("insert into resource_lock(resource_lock_key,resource_lock_val)value(?,?)")
sqlargs := make([]interface{}, 0)
sqlargs = append(sqlargs, "lock", "method_lock")
_, err := SqlDB.Exec(sqlstr.String(), sqlargs...)
if err != nil {
fmt.Println("client second add lock failed", err.Error())
time.Sleep(time.Millisecond * 3)
continue //
}
fmt.Println("client second process things")
// 解锁
sqlstr.Reset()
sqlstr.WriteString("delete from resource_lock where resource_lock_key = 'lock'")
_, err = SqlDB.Exec(sqlstr.String())
if err != nil {
fmt.Println("client second failed to delete lock", err.Error())
} else {
fmt.Println("client second delete lock...")
}
time.Sleep(time.Millisecond * 5)
}
}
func mointer() {
defer wg.Done()
curtime := ""
tmp := "2006-01-02 15:04:05"
for {
sqlstr := "select update_time from resource_lock where resource_lock_key = 'lock'"
var time_str string
rows := SqlDB.QueryRow(sqlstr)
err := rows.Scan(&time_str)
if err != nil || err == sql.ErrNoRows {
time.Sleep(time.Second * 1)
continue
}
if len(curtime) == 0 {
curtime = time_str
}
res, _ := time.ParseInLocation(tmp, time_str, time.Local)
cur_res, _ := time.ParseInLocation(tmp, curtime, time.Local)
tm := res.Unix() - cur_res.Unix()
if tm >= 10 {
strstr := "delete from resource_lock where resource_lock = 'lock'"
fmt.Println("mointer delete unexpired lock")
SqlDB.Exec(strstr)
curtime = "" // 置空
}
time.Sleep(time.Millisecond * 5)
}
}
func main() {
var err error
wg.Add(4)
SqlDB, err = sql.Open("mysql", "root:passwd@tcp(localhost:port)/sql_db?charset=utf8")
if err != nil {
fmt.Println("connect failed", err.Error())
}
fmt.Println("success to connect mysql db !")
go clientFirst()
go clientSecond()
go mointer()
go func() {
defer wg.Done()
wg.Wait()
}()
// 主进程阻塞
select {}
}
b.基于缓存模型的分布式锁
在缓存中redis当中,使用的是setnx命令进行实现的分布式锁,都是原子操作处理的,实现思想跟数据库一样,需要加锁的时候,在缓存中添加一条数据,释放锁的时候,删除掉该数据即可。如下所示:
加锁:如下代码利用uuid作为value值。
func redis_lock(lock_name string, acquire_time int, time_out time.Duration) (string, error) {
// """获取一个分布式锁"""
identifier := uuid.NewV1().String()
end := time.Now().Second() + acquire_time
lock := "string:lock:" + lock_name
for {
if t := time.Now().Second(); t <= end {
if client.SetNX(lock, identifier, time_out).Val() {
return identifier, nil
} else {
// 获取生命周期时间,并设置过期时间
client.Expire(lock, client.TTL(lock).Val())
}
} else {
break
}
time.Sleep(time.Second)
}
return "", nil
}
如上代码,获取锁时,尝试获取锁,并且给予时间内尝试获取锁,超时就表示获取失败。并在失败时,检查之前的,并设置该锁的有效时间长,避免该锁一直存在,导致其他客户端无法获取锁。
解锁:
func redis_unlock(lock_name string, identify string) {
lock := “string🔒” + lock_name
for {
val, err := client.Get(lock).Result()
fmt.Println(“unlock key-var”, lock, “-”, val)
if err == nil {
if val == identify {
client.Del(lock)
return
}
} else {
break
}
}
}
如上代码中,表示的是解锁。
但是如上也是有缺陷的:
a.A获取了锁,但是A的业务逻辑进入睡眠了,但是锁的有效期到了,redis中自动清理了该锁,B需要来加锁,也成功了获取了锁,但是,此刻A从业务中睡眠中醒来,在释放锁的时候,将该锁匙放掉了,这样导致了问题的产生。如下图:
![](https://img-blog.csdnimg.cn/a8e2cbe91be343cc960860f9497cb3fb.png)
所以使用时,避免业务休眠时间大于锁的有效期。从而避免出现如上图问题。
b.redis中使用get和del也要进行原子操作,使用lua脚本实现原子操作处理,如上代码修改如下:
const (
script = if redis.call("get",KEYS[1]) == ARGV[1] then return redis.call("del",KEYS[1]) else return 0 end
)
func redis_unlock(lock_name string, identify string) {
lock := “string🔒” + lock_name
var count int = 0
for {
// 利用lua脚本来保证redis的get和del操作的原子性
if val, err := client.Eval(script, []string{lock}, identify).Result(); err != nil {
if !strings.Contains(err.Error(), “Noscript”) {
fmt.Println(“no script !!!”)
}
// 尝试五次,放弃,所周期时间到了,也会释放该锁
if count < 5 {
break
}
count++
} else {
fmt.Println("unlock key-var", lock, "-", val)
client.ScriptLoad(script)
break
}
}
}
如上代码,保证了原子操作,get&del,用于释放锁。
c.redis中实现了如下方式实现分布式锁:
RedLock算法
这个算法基于N个完全独立的Redis节点(通常情况下N可以设置成5),客户端可以分成以下5个步骤来完成获取锁的操作
![img](https://img-blog.csdnimg.cn/img_convert/258ae9b35b2fe7422a89c054c2f6f94a.png)
![img](https://img-blog.csdnimg.cn/img_convert/64e5060f810e17de038d47d2ae3e69dd.png)
**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**
**[需要这份系统化的资料的朋友,可以添加戳这里获取](https://bbs.csdn.net/topics/618668825)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**