WorkNormalRecord

虚心听取建议和意见,多学习,多看看有效的代码以及学习编程和业务理解思想。

命令记录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
composer config --list # 可以查看php composer的配置,里面包含依赖包更新的仓库的用户名密码。

nginx启动

sudo /opt/homebrew/bin/nginx

sudo nginx -s reload

本地nacos启动:

sh startup.sh -m standalone 单机启动


php项目本地配置:

查找nginx.conf的安装位置:nginx -t

cd /opt/homebrew/etc/nginx/servers

创建一个项目对应的conf

重启加载配置

启动不了查看nginx日志,修改日志打印路径为当前文件夹,不然会出错

// php依赖下载
composer install -vvv

composer update -vvv

使用了wire依赖注入框架的项目本地启动:

go run . 同时启动main.go 和 wire_gen.go

Cookie 状态为httponly代表只能服务端通过脚本调用,不能在客户端浏览器获取!!!!!

curl -v # 查看域名端口号

top / lscpu # 查看运行任务使用的资源情况 cpu等等
# 查询端口占用情况
1. lsof -i :端口号 #其中端口号为需要查询的端口号。
2. netstat -tln | grep 端口号 #其中端口号为需要查询的端口号。

# ECS防火墙常用命令
systemctl status firewalld # 查看防火墙状态
firewall-cmd --list-all # 查看防火墙放行端口列表
firewall-cmd --permanent --add-port=8989/tcp # 永久放行8989端口
firewall-cmd --reload # 重载配置
systemctl stop firewalld # 关闭防火墙
systemctl disable firewalld # 关闭防火墙开机自启

Curl各个阶段时间

1
2
3
4
5
6
7
8
9
curl -o /dev/null -s -w time_namelookup:"\t"%{time_namelookup}"\n"time_connect:"\t\t"%{time_connect}"\n"time_appconnect:"\t"%{time_appconnect}"\n"time_pretransfer:"\t"%{time_pretransfer}"\n"time_starttransfer:"\t"%{time_starttransfer}"\n"time_total:"\t\t"%{time_total}"\n"time_redirect:"\t\t"%{time_redirect}"\n"speed_download:"\t\t"%{speed_download}"\n" https://www.baidu.com

time_namelookup: 0.000196 // dns解析时间,从请求开始到DNS解析完毕所用时间
time_connect: 0.005290 // 建立 tcp 链接完成时间,包括 dns 解析时间
time_appconnect: 0.000000 // 建立 tcp 完成时间,包括上层ssl handshake
time_pretransfer: 0.005305 // 从开始到准备传输的时间
time_starttransfer: 0.012730 // 发出请求到server开始返回第一个byte的时间
time_total: 0.012756 // 总耗时
time_redirect: 0.000000 // 重定向时间

img

Timing web requests with cURL and Chrome (cloudflare.com)

K8s 安装网络工具

1
2
3
4
5
apt update
apt install net-tools # ifconfig
apt install iputils-ping # ping
apt install dnsutils # dig
apt install telnet # telnet

img

1
2
3
4
5
6
7
8
# PHP常用函数解析 
empty() //判断一个变量是否被认为是空的。当一个变量并不存在,或者它的值等同于 FALSE,那么它会被认为不存在返回true。

is_array//函数是一种非常常用的函数,它用来判断一个变量是否是数组

is_numeric()//函数是一个用于检测变量或值是否为数字的函数。如果变量或值为数字,则返回true,否则返回false, "123abc"也可以被判断为数字类型。

isset()//函数用于检测变量是否已设置并且非NULL

知识点记录

  1. 线上环境和测试环境访问通过Switchhost切换再访问。

  2. 开发新功能一定要兼容之前的版本,注意字段变更和逻辑判断问题。

  3. 写代码之前先规划一下大体结构,注意代码的优化,注意细节问题的把握。

  4. 注意日志的合理打印,不要都等有问题之后再加日志,注意日志的格式和级别。

  5. 对于代码的安全问题要严格进行效验,前后端都需要,不能嫌麻烦就不处理。

  6. redis设置key时要添加统一前缀,比如UserID_1001:对象内容

  7. 代码中多处出现的相同的代码提取成方法来进行简化,数字进行常量提取优化

  8. 做原来的东西的修改操作时一定要仔细考虑到影响范围,要考虑到是否会影响其他东西

  9. go strcut可以通过 Name int json:"name,string" 来指定该字段使用string类型接收来转换。

    1
    2
    3
    4
    5
    type User struct {
    Name int `json:"name,string"`
    Age bool `json:"age,string"`
    }
    可以将string类型的json转换为对应的类型
  10. go - redis的setnx和hsetnx是同步的,并且同类型键值存在不会报错,虽然是string和hash两种,但是也不能出现key相同。

  11. 先set a 然后再hset/hsetnx a,会报错,先Hset a 然后再set a,会把之前的hash覆盖,如果是setnx则不会报错,也不会修改原hash,不会覆盖。

  12. time.Duration(0) redis过期时间设置0 为永久

  13. Redis 删除不存在的key不会报错,del srem都一样

  14. 状态码5XX表示服务端错误。

状态码 含义
500 Internal Server Error 服务器内部错误,服务器处理请求的过程中出现一个错误(内存地址越界、空指针等),导致服务器无法继续处理请求。
502 Bad Gateway 网关错误,网关请求服务器,在网关设置的超时时间之内服务器中断请求,即没有正常返回数据。 1. 服务不可用,网关找不到对应的upstream。 2. 服务进程被杀掉,php服务设置超时时间主动杀掉进程。 3. 服务进程为长连接,断开过程中被复用。
504 Gateway Timeout 网关超时,网关请求服务器,到了网关设置的超时时间之后服务器仍然没有返回数据。
  1. find . -name “*.go” | xargs cat | wc -l 查询项目代码行数.
  2. ctx.shouldBind既可以接收Get参数也可以接收Post参数,更加灵活.
  3. 新服务部署完后需要配置deployment的yaml配置文件

配置后才能正常的访问内网环境域名的接口

1
2
3
4
5
6
7
8
9
10
hostAliases:
- hostnames:
- x.x.x.com
ip: x.x.x.x
- hostnames:
- x.x.x.com
ip: x.x.x.x
- hostnames:
- x.x.x.com
ip: x.x.x.x
  1. MySQL select…… For update 对于查询的数据加锁,避免其他的事务操作修改数据

https://www.cnblogs.com/moyui/articles/12051588.html

  1. 查看文件大小命令
1
2
ls -lh
du -sh
  1. gorm的In查询的注意点
1
2
3
4
5
6
ids := []int{1,2,3}
db.Find(&users, ids) // SELECT * FROM users WHERE id IN (1,2,3);
使用上述语句进行In查询对应的主键ID数组为空的时候,会查询全部的值。
解决办法:
使用db.Find(&users,"id in (?)", ids)
手动拼接in查询语句,在数组为空的时候就不会查询出数据。
  1. gorm数据库查询排序,优先根据a字段降序,再根据b字段降序
1
2
3
4
错误写法: 下面的a后面不指定排序方式会默认采用升序进行排序
db.Order("a,b desc").Find(&users)这个语句等同于db.Order("a asc,b desc").Find(&users)
正确写法:
db.Order("a desc,b desc").Find(&users)
  1. 系统设计原则

系统设计开发过程中遵循的基本原则,包括架构设计、功能实现、代码编写。

简单适用原则

简单,要求设计简单、理解简单、维护简单,意味着容易学习上手、开发维护成本小、不容易出问题;适用,要求系统应能够通过合适的方式满足业务需求,意味着系统应当面向我们的业务特性量身定制。

简单适用原则,要求设计应当以最简单优雅的方式,满足业务需求。能够用简单的方式解决的问题,就不要用更复杂的方式,不炫技;一些目前预见没有必要的功能,不需要实现,但在设计时应当为后续的实现预留条件,并避免过度设计。

最大共性原则

最大共性原则,要求在设计过程中,跳出具体的业务功能需求,从更高的视角寻找业务的共性,抽象出业务模型,针对业务模型进行开发, 进而通过业务模型实现功能需求。

优秀的业务模型,能够在后续的持续开发迭代中保证系统的逻辑一致性和可扩展性,降低开发成本并延长系统的使用周期, 避免通过不断拷贝代码、增加逻辑分支而陷入开发的绝望循环。

  1. 项目代码开发规范

    【强制】时间相关字段无特别说明MySQL中类型使用 int(11) 无符号 (支持 0-4294967295), golang中类型使用int64;

    【强制】学生ID字段统一用stuId,数据库字段类型 bigint(20)无符号,golang中类型使用int64;

    【强制】和环境(测试、灰度、生产环境)相关配置统一到app的configs中,禁止在代码中硬编码;

    【推荐】数据逻辑处理,特别是涉及到多表的逻辑,尽量在biz层处理, 开启事务除外;

    【强制】api的Response输出字段统一使用驼峰命名;

    【强制】数据库表名、字段全部使用小写,单词间下划线分割;

    【强烈推荐】Redis key 统一使用小写,统一增加前缀growth,功能或库表分割使用英文冒号(:),其他分隔符使用下划线(_), 复杂类型的field命名使用驼峰;

    【强烈推荐】日志打印原则:谁报错谁打日志的原则,即:data内报错, 由data打印错误日志,biz层直接调用data产生的错误可不打印日志; 但biz内调用data后数据处理发生的错误应该有biz层自行打印错误日志;

    【强烈推荐】打印错误日志时,要把关键参数或数据放到日志中, 不要仅打印error信息;

    【强烈推荐】方法或函数要加注释,特殊逻辑要加详细注释甚至文档链接加以说明;

    【强烈推荐】data层入参是结构体时,要对必需属性做校验,防止外层调用漏传,进而写脏数据;

    【强烈推荐】数据库新增操作:使用结构体进行创建的时候,对于有值的字段采用select区分出来,避免数据库默认值设置错误问题。比如is_deleted默认值为-1,不是字段零值;

    【强烈推荐】数据库修改操作:尽量使用map结构映射字段进行更新,使用结构体更新会存在零值更新失败的问题;

    【强烈推荐】数据库查询操作:尽量使用Take、Last、First进行查询,使用Find进行查询的时候查询不到不会报错,前面三个会报错record not found;

    【强烈推荐】MySQL字段都设置为NOT NULL,并设置默认值;

    【强制】ToC接口统一使用POST,不再区分GET和POST,和客户端使用保持统一;

  2. Dockerfile模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM public-env-mirror-service-registry.cn-beijing.cr.aliyuncs.com/dist/golang:1.16

WORKDIR /tmp/source
# 准备工作
#RUN export
COPY go.mod .
COPY go.sum .
COPY . .

#加入git访问权限
#COPY .netrc /root/.netrc

# 编译
RUN go env -w GOPRIVATE=xxx.xxx.com
RUN go env
#WORKDIR /tmp/source/cmd/server
RUN GOPROXY="https://goproxy.cn" GO111MODULE=on go build -o /tmp/source/bin/server .
RUN chmod +x /tmp/source/bin/server

WORKDIR /tmp/source
#ARG envType=test
#COPY configs/config_${envType}.toml conf/env/env.toml
# 执行编译生成的二进制文件
CMD ["/tmp/source/bin/server","-conf","conf/env/env.toml"]
# 暴露端口
EXPOSE 80
  1. 忽略已经加入版本管理的文件

如果某些文件已经被纳入了版本管理中,直接修改.gitignore是无效的。需要先把文件从版本管理的索引中删除,然后修改.gitignore文件,然后提交即可。

1
2
3
4
5
# 第一步:从索引中删除文件
git rm --cached filename
# 第二部:修改 .gitignore文件,添加忽略规则
# 第三步:提交变更
git commit -m 'update .gitignore'
  1. go替换依赖资源包为本地文件
1
replace codeup.aliyun.com/61e54b0e0bb300d827e1ae27/backend/golib v1.0.60-0.20240312093259-7793c839dcce => /Users/xwx/go/src/golib
  1. Gin框架的shouldBind方法针对json格式的参数一次请求只能使用一次,不能多次使用,绑定参数的时候有多次绑定的情况需要额外注意前端传参的格式已经接口的协议是GET还是POST。

https://www.cnblogs.com/davis12/p/16355634.html

1
2
3
4
5
6
// ShouldBind绑定参数时,如果参数类型是form-data/x-www-form-urlencoded时,可以多次使用ShouldBind
// 但是如果参数类型是json时,只能使用一次ShouldBind

// ShouldBindJSON不能使用多次,尽管是针对不同地址空间的结构体,也不能和shouldBind共同使用多次
//1.单次解析,追求性能使用 ShouldBindJson,因为多次绑定解析会出现EOF
//2.多次解析,避免报EOF,使用ShouldBindBodyWith
  1. tree 文件目录 ,这个命令可以获取文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
xwx@xwxdeMacBook-Pro src % tree test   
test
├── algorithm
│ └── algorithm_test.go
├── base
│ ├── base.go
│ └── base_test.go
├── benchmark
│ └── test01
│ ├── map_array.go
│ └── map_array_test.go
├── util
│ ├── time_test.go
│ ├── util.go
│ └── util_test.go
├── websocket
│ └── main.go
└── 完成学习.png

43 directories, 72 files
  1. 设置header头的时候不论大小写,在真正进行http/https请求的时候,不同的web框架会将header头转换为不同的格式。php fend框架会转换为HTTP_原key全大写,go gin框架会转化为全驼峰。
image-20240330092300182

image-20240330092400339

  1. redis缓存多处同时插入缓存值时候容易造成并发问题记录。

以下以redis的List类型举例:

  1. 不加锁
  • 接口A—>查询key是否存在—>不存在插入缓存(叠加的方式)
  • 接口B—>查询key是否存在—>不存在插入缓存(叠加的方式)

这种情况下,当接口AB同时请求的时候,会造成A,B都查询到key不存在的情况,然后就会进行写入,造成数据叠加出错。

  1. 加锁 redis setnx 分布式锁,defer del key expire 3s
  • 接口A—>查询key是否存在—>不存在—>逻辑操作—>获取锁—>获取成功—>插入缓存(叠加的方式)—>释放锁
  • 接口B—>查询key是否存在—>不存在—>逻辑操作—>获取锁—>获取成功—>插入缓存(叠加的方式)—>释放锁

这种情况下,假如接口同时请求都查询到了key不存在进行获取锁的操作,如果接口A获取成功,但是获取成功后进行后续的逻辑操作速度很快,处理完成后就释放锁,这个时候在极端情况下接口B也会出现获取到锁的情况,同样也会出现数据叠加插入的情况。【特别是在判断key是否存在和获取锁之间有其他的逻辑操作的情况下,更容易出现此类问题】

  1. 加锁 redis setnx 分布式锁,defer del key expire 3s,获取锁成功后再判断key是否存在,类似于双重检测锁
  • 接口A—>查询key是否存在—>不存在—>逻辑操作—>获取锁—>获取成功—>查询key是否存在—>不存在—>插入缓存(叠加的方式)—>释放锁
  • 接口B—>查询key是否存在—>不存在—>逻辑操作—>获取锁—>获取成功—>查询key是否存在—>不存在—>插入缓存(叠加的方式)—>释放锁

这种情况下,即时A获取锁之后很快处理完就释放了锁,就算极端情况下接口B也获取成功了锁,但是这个时候再去查询key是否存在就必定存在了(即时A接口缓存写入失败,也不会出问题),就不会进行后续的插入缓存操作了。

如果是string类型,可以使用setnx这些的命令来进行处理,但是List类型没有类似的命令就需要自己加锁来避免并发问题,为了避免缓存多次写入造成数据重复,也可以使用set来处理,对于排序有要求的可以使用zset,总之,办法很多,选择适合当前的项目开发即可。

  1. 阿里云日志库查询日志特殊语句记录,当我们需要匹配output输出字段里面的部分字符串的时候,可以使用如下语句进行查询,#代表后续不进行分词。

1
2
3
4
5
6
7
1. 查询指定日期里面output字段值包含字符串"ranking":0的日志记录。
* and request_uri : "/v1/myHome/info?" and output:#"ranking\"\:0"
1. 查询指定日期里面output字段值包含字符串"ranking":0的日志记录的数量。
* | select count(*) from log where request_uri='/v1/myHome/info?' and output like '%ranking":0%'

查询数据
level:ERROR and not msg: unique_user_medal | select msg where cast(replace(replace(REGEXP_EXTRACT(msg, '\[(\d+)\]'), '[', ''),']', '') as bigint) < 2000000000

  1. 项目代码中要尽量避免出现如下代码的情况,当数据量比较大的时候,接口的耗时就会成倍增加。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 错题代码实例,极其不推荐
func WrongExample() {
result := make([]string, 0)
for i := 0; i < 10; i++ {
res := "通过rpc或者http的方式请求到数据" // 平均一次请求100ms,10次请求就是1s,假如需要循环100次,那就是10s,这样就会导致接口严重超时
result = append(result, res)
}
fmt.Println(result)
/*
解决办法:
1. 通过批量请求的方式来减低每次网络请求造成的耗时问题,一次性把数据全部请求出来进行处理
2. 通过并发的方式来减少每次网络请求造成的耗时问题,一次性把数据全部请求出来进行处理
3. 如果对于列表信息请求接口返回中不是用户这次请求需要展示的数据,而是类似于模块的跳转链接的这类情况,可以不用在列表接口里
提前把数据构造好,除非数据都是很好构造的情况,不需要额外请求数据,其余情况都可以在用户真实点击的时候再去请求接口获取跳转链接,把过程拆分成多个阶段。
*/
}
  1. 在项目代码的数据库设计中,如果某个字段会比较长,比如订单记录或者其他记录的唯一标识的字段[76074586-2001200-221507607-2097321-22205789_23402135_1_744605_0],这种情况下需要特别注意数据库中对应字段设置的长度是否满足。因为某些情况下执行insert操作,超过数据库指定的字段长度也不会报错,会自动截断,这取决于数据库是否设置开启了严格检测模式。

https://blog.csdn.net/u010738038/article/details/137768633

1
2
3
4
5
6
7
SELECT @@SESSION.sql_mode;  # 查询数据库是否开启严格检测模式
STRICT_TRANS_TABLES # 查询结果包含该字段就代表开启严格检测模式,字段长度不符就会报错。

# 可以通过如下SQL语句进行数据库字段长度的修改。
ALTER TABLE 数据库名字.table_name MODIFY COLUMN cloumn_name VARCHAR(255);

# 并且类型推荐VARCHAR,不使用char

MySQL之char、varchar类型简析

  1. 启动脚本文件执行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 批量删除指定key匹配缓存 -match 后面的参数为所需要清除的缓存key的匹配模式

// 本地测试
go run main.go -cmd ClearAssignCache -match 'growth:total_rank:*'

// 测试环境OR线上环境
/tmp/work/bin/script -cmd ClearAssignCache -match 'growth:total_rank:*'

// 后台执行
1. sh -c "/tmp/work/bin/script -cmd ClearAssignCache -match 'growth:total_rank:*' &"
2. /tmp/work/bin/script -cmd ClearAssignCache -match 'growth:total_rank:*' &

// 示例代码
var cmd = flag.String("cmd", "", "用户执行的命令")
var match = flag.String("match", "", "用户想要删除的缓存key匹配")

func main() {
flag.Parse()
execCommand := *cmd
matchKey := *match
}
  1. Ping和Telnet是两种不同的网络工具,它们用于不同的目的。以下是它们的主要区别:

    • Ping:主要用于检测网络连通性和诊断网络问题。
    • Telnet:主要用于远程登录和管理系统,以及测试特定端口的连通性。

    Ping

    1. 功能

      • 用于测试主机之间的连通性。
      • 通过发送ICMP(Internet Control Message Protocol)回显请求包并等待回显应答来确定目标主机是否可达。
    2. 使用场景

      • 检查网络连接状况。
      • 测试网络延迟和数据包丢失率。
    3. 协议

      • 使用ICMP协议。
    4. 命令示例

      bash复制

      ping example.com

    5. 输出信息

      • 显示往返时间、TTL值以及成功与失败的数据包统计信息。

    Telnet

    1. 功能

      • 用于远程登录到另一台计算机,通常用于管理设备或服务器。
      • 提供一个命令行接口,可以执行各种操作。
    2. 使用场景

      • 远程访问和管理服务器。
      • 测试特定端口是否开放。
    3. 协议

      • 使用TCP协议,默认端口为23。
    4. 命令示例

      bash复制

      telnet example.com 80

    5. 输出信息

      • 建立连接后会显示远程系统的提示符,允许用户输入命令进行交互。
  2. Gorm框架Upsert使用,创建或者更新,如果存在记录则进行更新,如下两种方式

1. 通过ON DUPLICATE KEY来实现创建或更新 需要有唯一主键或者唯一索引才能支持,一条sql, 会导致主键不连续,每次执行的时候主键都会递增,不管本次操作是插入还是更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
SQL: INSERT INTO `user_monthly_report` (`stu_id`,`year_month`,`version`,`read_status`,`data`,`create_time`,`update_time`)
VALUES (2100051684,'202401','v0.0.1',1,'{"key":"va1111lue"}',1724744553,1724744553)
ON DUPLICATE KEY UPDATE `data`=VALUES(`data`),`update_time`=VALUES(`update_time`)
*/
func TestUpsert1(t *testing.T) {
report := model.UserMonthlyReport{
StuId: 2100051684,
YearMonth: "202401",
Version: "v0.0.1",
ReadStatus: 1,
Data: []byte("{\"key\":\"va1111lue\"}"),
CreateTime: time.Now().Unix(),
UpdateTime: time.Now().Unix(),
}
err := DB.Table("user_monthly_report").Clauses(clause.OnConflict{
// 这里可以使用数据库唯一键对应的列名或者使用唯一键的名称
// 数据库 UNIQUE KEY `uni_stu_month` (`stu_id`,`year_month`)
// 使用这个 Columns: []clause.Column{{Name: "uni_stu_month"}}, 或者下面这个语句都可以
Columns: []clause.Column{{Name: "stu_id"}, {Name: "year_month"}},
DoUpdates: clause.AssignmentColumns([]string{"data", "update_time"}),
}).Create(&report).Error
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", report)
}

2.通过FirstOrCreate 来实现创建或更新 先查询 然后再根据情况创建或更新,两条sql。这个方法实现的upsert不会导致主键不连续,也不依赖唯一索引,更加灵活。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/*
SQL 1: SELECT * FROM `user_monthly_report` WHERE stu_id = 2100051684 and `year_month` = '202410' ORDER BY `user_monthly_report`.`id` LIMIT 1
查询语句查到数据则进行更新、查不到则进行创建
SQL 2: UPDATE `user_monthly_report` SET `data`='{"key":"value"}',`update_time`=1724746094 WHERE (stu_id = 2100051684 and `year_month` = '202412') AND `id` = 159
SQL 3: INSERT INTO `user_monthly_report` (`stu_id`,`year_month`,`version`,`read_status`,`data`,`create_time`,`update_time`) VALUES (2100051684,'202411','v0.0.1',1,'{"key":"va1111lue"}',1724745450,1724745450)
*/
func TestUpsert2(t *testing.T) {
report := model.UserMonthlyReport{
StuId: 2100051684,
YearMonth: "202412",
Version: "v0.0.1",
ReadStatus: 1,
Data: []byte("{\"key\":\"value\"}"),
CreateTime: time.Now().Unix(),
UpdateTime: time.Now().Unix(),
}
update := model.UserMonthlyReport{
Data: report.Data,
UpdateTime: report.UpdateTime,
}
err := DB.Table("user_monthly_report").Where("stu_id = ? and `year_month` = ?", report.StuId, report.YearMonth).Assign(&update).FirstOrCreate(&report).Error
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("%+v\n", report)
}
  1. Go “github.com/spf13/cast” 包转换字符串为int的时候有坑,cast.ToInt()。
1
2
3
4
5
6
7
8
9
10
11
12
func TestCast(t *testing.T) {
fmt.Println(cast.ToInt("07")) // 7
fmt.Println(cast.ToInt("08")) // 0
fmt.Println(cast.ToInt("012")) // 10
fmt.Println(cast.ToInt("027")) // 23
fmt.Println("--------------") // 推荐使用如下转换
fmt.Println(strconv.Atoi("07")) // 7
fmt.Println(strconv.Atoi("08")) // 8
fmt.Println(strconv.Atoi("012")) // 12
fmt.Println(strconv.Atoi("027")) // 27
}
// 这是因为在许多编程语言中,以零开头的数字被解释为八进制数,而不是十进制数。在八进制系统中,只有0到7是有效数字,所以当你尝试转换"08"或"09"时,会导致错误或者返回0,因为它们不是有效的八进制数字。
  1. 从数据量比较大的MySQL表里面随机取10条数据,怎么实现比较好?

  2. 使用MySQL自带的函数Rand()

1
2
3
SELECT * FROM your_table_name
ORDER BY RAND()
LIMIT 10;

ORDER BY RAND() 的实现原理相对简单,但在大数据集上可能会影响性能。以下是这个过程的基本步骤:

  • 生成随机数:对于每一行,MySQL 会使用 RAND() 函数生成一个介于0和1之间的随机数。

  • 排序 :然后 MySQL 对这些随机数进行排序。这意味着每一行都会被赋予一个随机值,并且整个表的数据将根据这些随机值重新排列。

  • 限制结果:最后,使用 LIMIT 10 来返回前10条记录。

  1. 另一种方法是创建一个包含所有主键的临时表或缓存,然后从中随机选择:

    1. 创建一个包含所有主键的临时表:

      CREATE TEMPORARY TABLE temp_keys AS (SELECT id FROM your_table_name);

    2. 从临时表中随机选择10个主键:

      SELECT * FROM your_table_name WHERE id IN ( SELECT id FROM temp_keys ORDER BY RAND() LIMIT 10 );

    这减少了排序操作的范围,从而提高了效率。

  2. 查询数据库的最大主键id,然后通过工具函数生成0-最大主键值之间的10个随机数,然后根据随机数查询对应的记录。

此方法查询通过主键id查询效率高,把随机数生成放在代码逻辑里面,适用于递增主键。

  1. 查询日志中某个记录出现相同的次数

    1
    2
    3
    语句格式:查询语句 | 分析语句
    实例:
    init roundNo1 success and InitNovActRoundTaskFinishCache | SELECT msg, COUNT(*) as DuplicateCount GROUP BY msg HAVING DuplicateCount > 1

    image-20241205112453525


WorkNormalRecord
https://zty-f.github.io/2024/11/05/work_record/
作者
ZTY
发布于
2024年11月5日
更新于
2025年1月2日
许可协议