自增id 在insert 操作时报错自增id约束冲突
原因分析:当前最大id与记录的最大id不一致,且最大id>自增id记录值
比如现在数据库 表中现在的id是100,而id自增才增长到95,在添加一条数据的时候,id是96,id为96的这条数据已经有了,所以id就违反了唯一性约束
解决方案:
1.查询这张表中已经存在的id的最大值是多少
Select max(id) from t_device;
2.查询这张表的id的自增序列是多少.
Select nextval(‘t_device_id_seq’);
3 . 如果这张表的id的最大值大于 id的自增序列的值.那就证明添加的时候会出现id被占用,而导致id违反唯一性约束的问题. 我们只需要重新给id的自增序列赋值,赋一个大于现在表中id的最大值就可以了.
SELECT setval('t_device_id_seq', xxx);
4.在重新查询一下,id的自增序列的值是多少,如果和上一步我们设置的值一样的话,就没有问题了.
Select nextval(‘t_device_id_seq’);
nilTime := time.Time{}
fmt.Println(nilTime.IsZero()) //true
fmt.Println(nilTime) //0001-01-01 00:00:00 +0000 UTC
在update语句中不应该通过join来进行多表关联,而是要通过from来多表关联,如下:
update a
set value = 'test'
from b,c
where
a.b_id = b.id
and b.c_id = c.id
and a.key = 'test'
and c.value = 'test';
通过from来多表关联,而关联条件则是放到了where中,这样就可以达到我们想要的效果了。另外补充一句,对于set xxx = 'xxx'
这个update的部分,是不可以在column字段前加上表前缀的,比如下边的写法就是有语法错误的:
update a
set a.value = 'test';
通过date命令查看时间
# 查看主机时间
[root@localhost ~]# date2016年 07月 27日 星期三 22:42:44 CST
# 查看容器时间
root@b43340ecf5ef:/# date Wed Jul 27 14:43:31 UTC 2016
可以发现,他们相隔了8小时。
CST应该是指(China Shanghai Time,东八区时间)
UTC应该是指(Coordinated Universal Time,标准时间)
解决方案,参考文档:https://segmentfault.com/a/1190000023624052
计算状态为5的个数
select sum(case when t.status = 5 then 1 else 0 end) as pass_count,
需求:筛选出姓名中包含:王、赵、孙任意姓氏的数据
select * from zhong_ods.t_ods_exam_student where u_name like any (array['%王%', '%张%', '%孙%']);
需求:筛选出姓名中不包含:王、赵、孙任意姓氏的数据。
select * from zhong_ods.t_ods_exam_student where u_name not like all (array['%王%', '%张%', '%孙%']);
利用case when 去进行不同状态的计数
耗时60ms
select sum(case when status = 1 then 1 else 0 end) as count,
对比关联多表,耗时1.5s
select * from t
left join (select id, count(distinct id) as count
from t_test
where status = 1
group by id) as a on t.test_id = a.id
使用func (*xorm.Session).SQL(query interface{}, args ...interface{}) *xorm.Session
或者func (*xorm.Engine).SQL(query interface{}, args ...interface{}) *xorm.Session
都仅会执行.SQL()里面的statement
若再对session执行func (session *Session) And(query interface{}, args ...interface{}) *Session
或者func (session *Session) Where(query interface{}, args ...interface{}) *Session
等其他条件都不会产生作用
func TestSQL(t *testing.T) {
session.SQL("select * from host").Where("id=?", 1).Find(&hosts)
fmt.Println(hosts) // 会把id不是1的也查出来,说明Where无效
}
两个同时插入,导致主键冲突,从而报错,在频繁的批量插入时容易出现这种情况,两次插入冲突了
1、定义全局锁,不能放在方法里面
2、
//插入时频繁调用,同时转化可能耗时,定义一个全局锁
var mutex sync.Mutex
func test(){
mutex.Lock()
defer mutex.Unlock()
do something()
}
new()
,除非你需要一个指针变量type Person struct {
name string
age int
}
func main() {
var p1 Person
fmt.Println(p.age) //0,Person初始化了
var p2 *Person //声明一个*Person类型的指针p,说明p初始化的内容就是指针的默认值,就是nil 了。
fmt.Println(p2) //
fmt.Println(p2.age) //panic: runtime error: invalid memory address or nil pointer dereference
p3 := new(Person) //返回类型指针,初始化一个变量为零的值,生成一个指向类型变量的地址。
fmt.Println(p3.age) //0
fmt.Println(p3==nil)//false
p4 := &Person{} //返回类型变量的地址,初始化一个变量的值,第二步:生成类型变量的地址并返回。
fmt.Println(p4.age) //0
fmt.Println(p4==nil)//false
}
所以在查询数据库的时候,如果要查是否存在
//GetOriginAssetByOriginId 查询原始资产瓦片信息
func GetOriginById(id string) (*entity.Origin, error) {
origin := entity.Origin{}
has, err := db.Engine.Where("origin_id = ?", id).Get(&origin)
if err != nil {
return nil, err
}
return &origin, nil
}
// 判断返回的是否存在
test = GetOriginById("123")
if test!=nil{
...
}
实际上test返回的永远都不会是nil,正确的应该如此处理
//GetOriginAssetByOriginId 查询原始资产瓦片信息
func GetOriginById(id string) (*entity.Origin, error) {
origin := entity.Origin{}
has, err := db.Engine.Where("origin_id = ?", id).Get(&origin)
if err != nil {
return nil, err
}
if !has {
return nil, nil
}
return &origin, nil
}
s := ""
split := strings.Split(s, ",")
fmt.Println(split[0]=="") //true
fmt.Println(len(split)) //1
fmt.Println(split)//[]
函数运行时间和进程的运行时间, 因为go语句是开启一个新的, 刚创建的goroutine去运行这个函数, 但是本身的主进程还会继续运行, 所以, 如果你只写一个go语句, 后面没有可以运行程序的话就会出现一个尴尬的问题, 主进程直接关闭, 对应goroutine也直接关闭,导致函数没有运行
func main() {
go hello("小飞")
go hello("飞啊飞")
// time.Sleep(100 * time.Second) 不加这行代码的话就会出现这种情况
}
1、数据量比较大时,用异步去跑,因为可能运行实行太长,导致接口超时,返回失败,出问题。直接return,异步执行刷数据
2、刷数据的接口,尽量考虑灵活度,比如指定任务、指定时间范围,因为每一次都是全量的话,太不智能了。
在进行数据库的查询的时候出现了 A、B、A+B三列求和不一致的情况,数据库字段的运算中,null与任何值运算的结果都是null,
https://www.modb.pro/db/131794
通过 on 过滤的原理如下:
通过 where 过滤的原理如下:
详情:https://www.modb.pro/db/131794
参考文档:https://blog.walkbc.com/2019/11/25/gin-lesson-queryParameters/
1、路径规则
path
和path/
是不同的,如果path/
不存在,则会重定向到path
。2、路径示例
#合法定义
/d1
/d2/:param1
/d3/:param1/:param2
/d4/:param1/:param2/
/d5/:param1/*param2
/d6/:param1/:param2/*param3
参数识别
URL:https://mhost.com/article/:id?tenantId=1
/article/id 是路由(请求PATH),其中由“/”分割的每一部分都可以当作请求参数
* searchBy := c.Param("id")获取
* c.Params获取所有的key-value数组,按照自已意愿处理
tenantId=1 是请求的query,不是路由部分。
//如果参数不存在,或者为空,则返回空字符串
* pSize := c.Query("pageSize")
//如果参数不存在,设置参数的默认值
* pNum := c.DefaultQuery("pageNum","1")
转化接口返回的信息类型
total====> float64
list ====> []interface {}
"data": {
"total": 11,
"list": [
"NViaS5cM1m",
"CaTx2kLcsN",
"rPQkBsTZTf",
"C7cYOx9fuz",
"oenUAfDeA5",
"GmH0VKqByA",
"6ob3fyv77M",
"I2HY1yaVs4",
"EpIm9aWzTn",
"p6mpcC0cnE",
"sfJsmmfyb2"
]
}
func main() {
foo := []interface{}{"a", "b", "c"}
out := []string{}
for _, v := range foo {
out = append(out, v.(string))
}
fmt.Println(out)//[a b c]
fmt.Println(reflect.TypeOf(out))//[]string
}
reflect: reflect.Value.Set using unaddressable value
情景:某个字段设置了唯一索引,判断当这个索引的数据存在则更新,不存在则新增。
使用Update这个新的结构体,报错,因为
"pq: duplicate key value violates unique constraint \"uidxnk_t_toa_aoi\"",
UPDATE "public"."t_origin_asset"
SET "asset_origin_id" = 'zRoizuT8GU',#唯一索引也被set,就会冲突
0的初始类型默认是int,如果用0强制类型转换
func test()(int64,err){
return 0.(int64), err
}
sql := `
select *
from t
inner join a on a.id = t.aid
where b.deleted = 0
and c.deleted = 0
and t.info= %s ====> and t.info='%s' `
db.Engine.SQL(exeSql).Find()
怎么接收多个表的字段,对应的结构体
type Detail struct {
Id int64
UserId int64 `xorm:"index"`
}
// 查询的内容在两个表里面,创建一个新的结构体用于接收值,里面直接加不同的表对应的结构体
type UserDetail struct {
UserInfo User `xorm:"extends"`
UserDetailInfo Detail `xorm:"extends"`
}
// 联表查询,写别名区分不同的表
var users []UserDetail
err := engine.Table("user").Select("user.*, detail.*").
Join("INNER", "detail", "detail.user_id = user.id").
Where("user.name = ?", name).Limit(10, 0).
Find(&users)
// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0
此时如果表中有重复的字段的话,会出现xorm值对应错误,此时必须按照联表的顺序接收值
比如 A,B ,C三个表都有id字段,查询的时候为 A inner join B,C,接收的时候 必须 A.Id,B.Id,C.Id,这样进行接收,也不能只接收部分表的Id,还是会出现映射错误
当我使用 order by create_time进行分页查询排序时,发现不同页码会反复出现一些内容,但是有些内容却找不到
原因分析:
order by的字段重复(创建时间一样),这个时候排序不稳定
优化器在遇到order by x limit m,n语句的时使用priority queue进行了优化,优先队列排序priority queue使用了堆排序的排序方法,而堆排序是一个不稳定的排序方法,也就是相同的值可能排序出来的结果和读出来的数据顺序不一致。
参考:https://juejin.cn/post/6943089541200740360
分页重复数据是否出现与排序字段数据唯一性有关,与排序字段是否有序无关,换句话说,只要排序字段的数据能够保证唯一性(如主键、唯一索引、不重复的普通字段),那么分页就不会存在重复数据,否则会有可能出现重复数据在不同分页中
解决方案:
结合使用数据唯一的字段,将原本不唯一的排序条件变成组合唯一的排序条件,因此可以解决分页数据重复的问题
SELECT * FROM account_info order by id LIMIT 0,5
SELECT * FROM account_info order by amount,id LIMIT 0,5 # 多个字段组合保证唯一性
因为xorm在执行OR 等各种条件相当于加()
,而我们习惯使用时认为关系型运算符优先级高到低为:NOT >AND >OR
,如果where 后面有OR条件的话,则OR自动会把左右的查询条件分开,而导致了不一致
xorm执行顺序:
select * from student
(where id=1)
(and grade=1)
(or class=2)
(and subject='math')
我们以为的顺序:
select * from student where id=1 and grade=1 or (class=2 and subject='math')
此时可以先用查询该字段的语句结果作为一个新表,进行内联查询,这样层层嵌套,直至满足条件
select t1.id from t_tile_basic t1
inner join (select tile_code, max(version) as ver
from t_tile_basic
where t_tile_basic.task_manage_id = 0
group by tile_code) t2 on t1.tile_code = t2.tile_code and t1.version = t2.ver
Where task_manage_id = 0);
1、前后端参数名称是否一致,有没有未关联上
2、注意POST和GET的方法对应Option是否有对应格式的注释,否则无法绑定
// gin 框架的绑定前端传参方法
func (c *Context) ShouldBind(obj any) error {
b := binding.Default(c.Request.Method, c.ContentType())
return c.ShouldBindWith(obj, b)
}
// 如果是GET方法,默认使用form表单进行绑定参数
func Default(method, contentType string) Binding {
if method == http.MethodGet {
return Form
}
...
}
// 对于这个option,siza只有json格式的映射,此时前端GET传参json就无法绑定
type PageOptions struct {
Page int `form:"page" json:"page"`
Size int `json:"size"`
}
1、确认是否配置iam接口权限
2、是否正式环境、测试环境token搞错
3、是否get、post请求有误
4、是否url错误,多斜杠、路径错误
//string转成int:
int, err := strconv.Atoi(string)
//string转成int64:
int64, err := strconv.ParseInt(string, 10, 64)
//int转成string:
string := strconv.Itoa(int)
//int64转成string:
string := strconv.FormatInt(int64,10)
func main() {
intSlice := []int32{1, 2, 3}
strSlice := intSliceToString(intSlice, ",")
fmt.Println("strSlice:", strSlice)
}
// 下述方法里边的3行代码,任意一行都可以实现将int类型切片转化成指定格式的字符串
func intSliceToString(a []int32, delim string) string {
//return strings.Trim(strings.Join(strings.Fields(fmt.Sprint(a)), delim), "[]")
//return strings.Trim(strings.Join(strings.Split(fmt.Sprint(a), " "), delim), "[]")
return strings.Trim(strings.Replace(fmt.Sprint(a), " ", delim, -1), "[]")
}
表的内联join条件在这里并没有意义,因为这种写法本身就是不对的!正确写法
update t_task_statics
set tile_code=t_task.tile_code
from t_task
where t_task_statics.task_id = t_task.id;
遇到的问题:
1、一起修复bug,新建了两个bug修复分支,并行开发,一直往test-for-merge分支合并
2、同时开发了新功能分支,也往test-for-merge合并测试
3、因为修复的两个bug分支有交集,所以单独开发很麻烦,于是合并了三个分支的内容作为开发分支
4、新功能没办法及时上,修复功能需要尽快上,但是开发分支又耦合了三个分支
review:
1、修复代码可以单独建分支,但是如果有交集,最好用同一个分支
2、修复分支不要与新功能分支耦合在一起
3、一定要保持分支各自的独立性,千万不要耦合到test分支的代码!!!
> git log # 得到你需要回退一次提交的commit id
> git reset --hard XXXXX #回退到某个指定的版本commit id
HEAD is now at XXXXX (commit的描述信息)
> git push origin HEAD --force ## 强制提交一次,之前错误的提交就从远程仓库删除
var a *[]int64 // a为指针型,此时指针为空
var b []int64 //切片
t.Log(a == nil) //true,指针型此时没有初始化为空
t.Log(a) // nil
t.Log(b) // []
t.Log(&b == nil) //false,切片数组虽然内容为空,但是有地址
t.Log(b == nil) //true
Golang 中可以使用 pprof 库来检测循环引用。pprof 是 Go 语言内置的性能分析工具,可以帮助您诊断程序的性能问题,包括内存泄漏和循环引用。
您可以通过以下步骤使用 pprof 检测循环引用:
使用 go tool pprof 命令来获取更多有关程序性能的信息。
panic: runtime error: invalid memory address or nil pointer dereference, 也就是空指针异常
当声明一个指针变量时,指针在内存中的值是 nil,表示这个指针是没有指向一个特定的变量。
通过 i = 10 赋值时,这种方式会报错,因为 i 表示指针实际指向的值,空指针是没有指向的。
所以我们可以得出结论: 当指针变量没有指向时,也就是为 nil 时,不能对 *point 就行赋值操作,否则会报空指针异常
先修bug,再观察,再补数据
要先修bug,再补数据,补数据前也不能盲目补,而是先观察下有什么共性,先观察、思考
go的GC机制:https://juejin.cn/post/6882206650875248654
// 把局部变量当做参数传递进去赋值,不会产生变量被清理的情况
a := Test{}
b := Test{}
err = MetricString2Object(ctx, options.A, options.B, &a, &b)
// 原先的用法
a, b, err := entity.MetricString2Object(ctx, options.A, options.B)
// MetricString2Object 将字符串转化成对应option数据
func MetricString2Object(ctx context.Context, a string, b string) (*Test, *Test, error) {
// 局部变量在内部,被GC清理,导致返回的不是默认全0的而是null的空指针
a := Test{}
b := Test{}
...
return &a,&b
}
在 Go 语言中,如果你在执行网络连接时收到一条 “dial tcp: connect: connection refused” 的错误消息,这通常表示无法连接到目标服务器。这可能是由于目标服务器拒绝了你的连接,或者因为目标服务器尚未启动而无法响应连接请求。
如果你正在尝试连接到一台远程服务器,则可以尝试使用其他工具(如 ping 或 traceroute)来检查服务器是否可以到达,并查看是否存在防火墙规则或其他网络配置问题。
如果你正在尝试在本地主机上运行一个服务器,则可能是因为该服务器尚未启动,或者因为该服务器监听的端口已被占用。此时,你可以尝试检查服务器是否已启动,并查看是否存在其他程序正在使用该端口。
session一层一层透传
如果手动打开了session.begin(),那么后续的操作如果没有session.commit(),后面的操作直接close的话就会被回滚,导致数据消失。
if len(options.WorkMetricChangeOption)>0 && json.Valid([]byte(options.WorkMetricChangeOption)) {
}
// 前端输入结构体的string,后端bind后,如果前端没有传入值,全部都会解析为初始零值
json.unmarshal(byteStr,&school)
test := &School{}
// 输出
school == test //说明输入为空
参考链接:https://blog.csdn.net/weixin_45559862/article/details/114630936
方法一:连表查询
SELECT * from user t1
INNER JOIN ( SELECT max ( create_time ) create_time FROM user ) t2 ON t1.create_time = t2.create_time
方法二limit:
SELECT * from user ORDER BY create_time desc limit 1
# xorm的方法
Get()方法只能返回单条记录,其生成的 SQL 语句想当于总是有 LIMIT 1
api/v1/audit/log/config/bizType [不支持]
api/v1/audit/log/config/biztype [支持]
func f() (map[int]string,error){
// 一个方法
}
func test(){
// 最好先对res进行初始化 res := make(map[int]string,0),下面再进行调用
res,err := f() // 如果返回的是空的map[int]string
for range res..... //此时没有初始化就会报空指针异常!!
}
// 最好对Map使用的地方做一下容错处理
if entity.IfExistCaseMap != nil {
if value, ok := entity.IfExistCaseMap.Get(tileCodeIn14); ok {
has = value
}
}
json.Unmarshal
并不接受空指针(nil pointer)。在定义前端传参Req时,尽量避免定义指针类型,或者重写这个结构体的unmarsahl方法
var a *School //nil
a := &School{} //初始值全为0值的结构体
a := new(School) //初始值全为0值的结构体
import (
"encoding/json"
"fmt"
)
type Result struct {
Foo string
}
func main() {
content := `{"foo": "bar"}`
res := &Result{}
err := json.Unmarshal([]byte(content), &res)
if err != nil {
panic(err)
}
fmt.Printf("res = %+v\n", res) // 正常返回
res2 := &Result{}
err = json.Unmarshal([]byte(content), res2)
if err != nil {
panic(err)
}
fmt.Printf("res2 = %+v\n", res2) // 正常返回
var res3 *Result
err = json.Unmarshal([]byte(content), &res3)
if err != nil {
panic(err)
}
fmt.Printf("res3 = %+v\n", res3) // 正常返回
var res4 *Result
err = json.Unmarshal([]byte(content), res4)
if err != nil {
panic(err)
}
fmt.Printf("res4 = %+v\n", res4) // panic!!! json: Unmarshal(nil *main.Result)
}