select * from tableA where a=1;a有索引但是走了全表扫描为什么,什么情况下会发生?
(b,a)联合索引,不满足最左匹配原则
defer panic recover
package main
import (
"fmt"
)
func main() {
defer func() {
if r := recover(); r != nil {
fmt.Println("Recovered from panic:", r)
}
}()
fmt.Println("Before panic")
panic("Something went wrong!") // 触发 panic
fmt.Println("This line will not be executed") // 不会执行
}
map,range两次为什么会不同,怎么实现并发安全
map 的特性:
无序:Go 的 map 是无序的,使用 range 遍历 map 时,每次遍历的顺序可能不同。
不安全:在多个 goroutine 同时读写同一个 map 时,会引发竞态条件,导致程序崩溃或返回不一致的结果。
package main
import (
"fmt"
)
func main() {
book := map[int]string{}
book[1] = "why"
book[2] = "yyy"
book[3] = "xza"
for i,v := range book{
fmt.Println(i,v)
}
for i,v := range book{
fmt.Println(i,v)
}
}
输出:
3 xza
1 why
2 yyy
1 why
2 yyy
3 xza
当你两次使用 range 遍历同一个 map 时,可能会得到不同的结果。这是因为:
map 的顺序在每次迭代时都是随机的。
如果在遍历过程中对 map 进行了修改(如增加或删除元素),这会导致遍历过程中的行为未定义。
package main
import (
"fmt"
"sync"
)
func main() {
// 创建一个非线程安全的 map
data := make(map[string]int)
// 使用 WaitGroup 来等待所有 goroutine 完成
var wg sync.WaitGroup
// 启动多个写入 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
data[fmt.Sprintf("key%d", i)] = i
}(i)
}
// 启动多个读取 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println(data[fmt.Sprintf("key%d", i)])
}(i)
}
// 等待所有 goroutine 完成
wg.Wait()
}
go run -race main.go
0
==================
WARNING: DATA RACE
Read at 0x00c00008c150 by goroutine 12:
runtime.mapaccess1_faststr()
D:/Golang/src/runtime/map_faststr.go:13 +0x0
main.main.func2()
D:/VsCode/MycCodeGo/code/main.go:29 +0x114
main.main.gowrap2()
D:/VsCode/MycCodeGo/code/main.go:30 +0x41
Previous write at 0x00c00008c150 by goroutine 8:
runtime.mapassign_faststr()
D:/Golang/src/runtime/map_faststr.go:223 +0x0
main.main.func1()
D:/VsCode/MycCodeGo/code/main.go:20 +0x109
main.main.gowrap1()
D:/VsCode/MycCodeGo/code/main.go:21 +0x41
Goroutine 12 (running) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:27 +0x1d7
Goroutine 8 (finished) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:18 +0x7e
==================
==================
WARNING: DATA RACE
Read at 0x00c000024228 by goroutine 13:
main.main.func2()
D:/VsCode/MycCodeGo/code/main.go:29 +0x11e
main.main.gowrap2()
D:/VsCode/MycCodeGo/code/main.go:30 +0x41
0
Previous write at 0x00c000024228 by goroutine 8:
main.main.func1()
D:/VsCode/MycCodeGo/code/main.go:20 +0x115
main.main.gowrap1()
D:/VsCode/MycCodeGo/code/main.go:21 +0x41
0
Goroutine 13 (running) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:27 +0x1d7
Goroutine 8 (finished) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:18 +0x7e
==================
1
==================
WARNING: DATA RACE
Write at 0x00c00008c150 by goroutine 10:
runtime.mapassign_faststr()
D:/Golang/src/runtime/map_faststr.go:223 +0x0
0
main.main.func1()
D:/VsCode/MycCodeGo/code/main.go:20 +0x109
main.main.gowrap1()
D:/VsCode/MycCodeGo/code/main.go:21 +0x41
Previous write at 0x00c00008c150 by goroutine 11:
runtime.mapassign_faststr()
D:/Golang/src/runtime/map_faststr.go:223 +0x0
main.main.func1()
D:/VsCode/MycCodeGo/code/main.go:20 +0x109
main.main.gowrap1()
D:/VsCode/MycCodeGo/code/main.go:21 +0x41
Goroutine 10 (running) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:18 +0x7e
Goroutine 11 (finished) created at:
main.main()
D:/VsCode/MycCodeGo/code/main.go:18 +0x7e
==================
Found 3 data race(s)
exit status 66
实现并发安全
package main
import (
"fmt"
"sync"
)
type SafeMap struct {
mu sync.Mutex
data map[string]int
}
func NewSafeMap() *SafeMap {
return &SafeMap{data: make(map[string]int)}
}
func (sm *SafeMap) Set(key string, value int) {
sm.mu.Lock()
defer sm.mu.Unlock()
sm.data[key] = value
}
func (sm *SafeMap) Get(key string) int {
sm.mu.Lock()
defer sm.mu.Unlock()
return sm.data[key]
}
func main() {
safeMap := NewSafeMap()
var wg sync.WaitGroup
// 启动多个写入 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
safeMap.Set(fmt.Sprintf("key%d", i), i)
}(i)
}
// 启动多个读取 goroutine
for i := 0; i < 5; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
value := safeMap.Get(fmt.Sprintf("key%d", i))
fmt.Println(value)
}(i)
}
// 等待所有 goroutine 完成
wg.Wait()
}
git 如何进行版本管理
参考:https://blog.csdn.net/sereasuesue/article/details/117080435
git init
git clone
http2特性
参考:https://xiaolincoding.com/network/2_http/http2.html#http-1-1-%E5%8D%8F%E8%AE%AE%E7%9A%84%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98
IO多路复用
鉴权除了session还有哪些?
参考:https://developer.aliyun.com/article/1358589
使用短期的 access token 和 refresh token 的组合有几个重要的安全和设计考虑:
降低风险:如果 access token 被泄露,攻击者可以在其有效期内访问受保护的资源。短期有效的 access token 限制了潜在的损害。
过期机制:短期 token 会定期到期,限制了攻击者能够利用被盗 token 的时间窗口。
refresh token 通常在后台使用,允许用户在不干扰其体验的情况下获取新的 access token,从而避免频繁的登录。
你了解哪些限流算法?
参考:https://zhuanlan.zhihu.com/p/376564740
简单翻译一下:在计算机网络中,限流就是控制网络接口发送或接收请求的速率,它可防止DoS攻击和限制Web爬虫。
限流,也称流量控制。是指系统在面临高并发,或者大流量请求的情况下,限制新的请求对系统的访问,从而保证系统的稳定性。限流会导致部分用户请求处理不及时或者被拒,这就影响了用户体验。所以一般需要在系统稳定和用户体验之间平衡一下。
固定窗口限流法
但是,这种算法有一个很明显的临界问题:假设限流阀值为5个请求,单位时间窗口是1s,如果我们在单位时间内的前0.8-1s和1-1.2s,分别并发5个请求。虽然都没有超过阀值,但是如果算0.8-1.2s,则并发数高达10,已经超过单位时间1s不超过5阀值的定义啦。
滑动窗口限流法
漏桶算法
令牌桶算法
zset常用命令
添加元素
ZADD key score member
向有序集合添加一个元素。如果元素已经存在,则更新其分数。
ZADD myzset 1 “one”获取元素
ZRANGE key start stop [WITHSCORES]
返回指定范围内的元素,按分数升序排列。
ZRANGE myzset 0 -1 WITHSCORES # 获取所有元素及其分数
ZRANK key member
获取指定元素的索引(排名),按分数升序排列。
ZRANK myzset “one”删除元素
ZREM key member [member …]
从有序集合中删除一个或多个元素。
ZREM myzset “one”获取集合的大小
ZCARD key
返回有序集合中元素的数量。
ZCARD myzset获取分数
ZSCORE key member
返回指定元素的分数。
ZSCORE myzset “one”范围查询
ZREVRANGE key start stop [WITHSCORES]
返回指定范围内的元素,按分数降序排列。
ZREVRANGE myzset 0 -1 WITHSCORES # 获取所有元素按分数降序按分数范围获取元素
ZRANGEBYSCORE key min max [WITHSCORES]
返回在指定分数范围内的元素。
ZRANGEBYSCORE myzset 0 5 WITHSCORES按排名范围获取元素
ZREVRANGEBYLEX key min max [LIMIT offset count]
返回按字典序排序的元素,支持范围查询。
ZREVRANGEBYLEX myzset “[a” “[z” # 获取字典序在 a 到 z 之间的元素获取排名范围内的元素数量
ZCOUNT key min max
返回在指定分数范围内的元素数量。
ZCOUNT myzset 0 5合并两个有序集合
ZUNIONSTORE destination numkeys key1 [key2 …]
计算给定的一个或多个有序集合的并集,并将结果存储在目标集合中。
ZUNIONSTORE myzset2 2 myzset1 myzset3
redis两种持久化方式
AOF日志
RDB快照