- Created by 郭强, last modified on Sep 01, 2021
为安全性保证、防止误操作,Update
及Delete
方法必须带有Where
条件才能提交执行,否则将会错误返回,错误信息如:there should be WHERE condition statement for XXX operation
。goframe
是一款用于企业生产级别的框架,各个模块设计严谨,工程实践的细节处理得比较好。
Update
更新方法
Update
用于数据的更新,往往需要结合Data
及Where
方法共同使用。Data
方法用于指定需要更新的数据,Where
方法用于指定更新的条件范围。同时,Update
方法也支持直接给定数据和条件参数。
使用示例:
// UPDATE `user` SET `name`='john guo' WHERE name='john' g.Model("user").Data(g.Map{"name" : "john guo"}).Where("name", "john").Update() g.Model("user").Data("name='john guo'").Where("name", "john").Update() // UPDATE `user` SET `status`=1 ORDER BY `login_time` asc LIMIT 10 g.Model("user").Data("status", 1).Order("login_time asc").Limit(10).Update() // UPDATE `user` SET `status`=1 WHERE 1 g.Model("user").Data("status=1").Where(1).Update() g.Model("user").Data("status", 1).Where(1).Update() g.Model("user").Data(g.Map{"status" : 1}).Where(1).Update()
也可以直接给Update
方法传递data
及where
参数:
// UPDATE `user` SET `name`='john guo' WHERE name='john' g.Model("user").Update(g.Map{"name" : "john guo"}, "name", "john") g.Model("user").Update("name='john guo'", "name", "john") // UPDATE `user` SET `status`=1 WHERE 1 g.Model("user").Update("status=1", 1) g.Model("user").Update(g.Map{"status" : 1}, 1)
Counter
更新特性
可以使用Counter
类型参数对特定的字段进行数值操作,例如:增加、减少操作。
Counter
数据结构定义:
// Counter is the type for update count. type Counter struct { Field string Value float64 }
Counter
使用示例,字段自增:
updateData := g.Map{ "views": &gdb.Counter{ Field: "views", Value: 1, }, } // UPDATE `article` SET `views`=`views`+1 WHERE `id`=1 result, err := db.Update("article", updateData, "id", 1)
Counter
也可以实现非自身字段的自增,例如:
updateData := g.Map{ "views": &gdb.Counter{ Field: "clicks", Value: 1, }, } // UPDATE `article` SET `views`=`clicks`+1 WHERE `id`=1 result, err := db.Update("article", updateData, "id", 1)
Increment/Decrement
自增/减
我们可以通过Increment
和Decrement
方法实现对指定字段的自增/自减常用操作。两个方法的定义如下:
// Increment increments a column's value by a given amount. func (m *Model) Increment(column string, amount float64) (sql.Result, error) // Decrement decrements a column's value by a given amount. func (m *Model) Decrement(column string, amount float64) (sql.Result, error)
使用示例:
// UPDATE `article` SET `views`=`views`+10000 WHERE `id`=1 g.Model("article").Where("id", 1).Increment("views", 10000) // UPDATE `article` SET `views`=`views`-10000 WHERE `id`=1 g.Model("article").Where("id", 1).Decrement("views", 10000)
RawSQL
语句嵌入
gdb.Raw
是字符串类型,该类型的参数将会直接作为SQL
片段嵌入到提交到底层的SQL
语句中,不会被自动转换为字符串参数类型、也不会被当做预处理参数。例如:
// UPDATE `user` SET login_count='login_count+1',update_time='now()' WHERE id=1 g.Model("user").Data(g.Map{ "login_count": "login_count+1", "update_time": "now()", }).Where("id", 1).Update() // 执行报错:Error Code: 1136. Column count doesn't match value count at row 1
使用gdb.Raw
改造后:
// UPDATE `user` SET login_count=login_count+1,update_time=now() WHERE id=1 g.Model("user").Data(g.Map{ "login_count": gdb.Raw("login_count+1"), "update_time": gdb.Raw("now()"), }).Where("id", 1).Update()
Delete
删除方法
Delete
方法用于数据的删除。
使用示例:
// DELETE FROM `user` WHERE uid=10 g.Model("user").Where("uid", 10).Delete() // DELETE FROM `user` ORDER BY `login_time` asc LIMIT 10 g.Model("user").Order("login_time asc").Limit(10).Delete()
也可以直接给Delete
方法传递where
参数:
// DELETE FROM `user` WHERE `uid`=10 g.Model("user").Delete("uid", 10) // DELETE FROM `user` WHERE `score`<60 g.Model("user").Delete("score < ", 60)
软删除特性
软删除特性请查看章节:ORM链式操作-时间维护
Content Menu
- No labels
24 Comments
marc
是不可以理解为
views
字段加1
, 如果想要-1
则写成:糖水不加糖
个人感觉挺麻烦的..做自减都要做一次负数转化.还是常规链式的Inc/Dec机制比较区分.
郭强
负数转化?
糖水不加糖
例如会员消费余额,前端传回来是个正数(消费多少),扣除余额的时候在Value之前就要对这个金额做一次转换使之变为负数(在前面加个减号).
sanrentai
Counter
使用示例能否加个
sql
语句 这样容易理解郭强
感谢建议,已更新。
harry
能否实现类似
Laravel
的UpdateOrCreate
?https://laravel.com/docs/8.x/eloquent#upserts
如果存在就更新,否则插入数据
每次都要重复写这些逻辑,或者是要在每个
dao
里面去拷贝代码,感觉不太优雅郭强
哥,就是
Save
方法。😓harry
感觉不对,这个差异很大,比如表结构
id, name, date, score, created_at, updated_at
name
和date
是唯一索引此时会
Insert
一条新记录但是实际意图是:
如果存在
name="test" and date="2021-01-18"
的记录,则更新其score
为80
否则插入
name="test", date="2021-01-18", score=80
郭强
现在
Save
的逻辑就是这样啊,你把debug
打开看看sql
对不对:ORM链式操作-写入保存harry
谢谢💕,由于
debug
显示的SQL
较长,没注意看后面的ON DUPLICATE KEY UPDATE
,只看到前面的INSERT INTO
了xx
有没有mysql更新json类型字段的例子?
Tian Gilbert
请问一下,删除了以后怎样检查删除操作是否执行成功呢?谢谢了!
郭强
判断返回的
Result
结果,里面有RowsAffected
方法。Tian Gilbert
明白了,感谢!
echoyang
我在测试这条语句时,没有生效,请问是我的数据表有问题吗?
我的数据表如下
趴哥 KingFly
echoyang
我在测试以下示例时,用debug看到的sql对不上
我的例子如下
郭强
嗯,试试最新的
master
分支。echoyang
好。
糖水不加糖
好像Delete没有对Batch做支持.mysql下占位符只能到65535个,假设批量删除超过这个数直接就报错了,这里应该让Batch方法生效.
郭强
可以把代码提个
issue
我看看呢。糖水不加糖
all,_:=g.Model("table").Array("filed")或者手动生成一个长度大于65535的数组做为删除的where参数.
只要len(all)大于65535时直接执行g.Model("table").Where("filed", all).Delete()则返回mysql的错误信息Prepared statement contains too many placeholders.需要将all手动切割成两部分在执行delete.
假设删除10240条记录执行g.Model("table").Where("filed", all).Batch(1024).Delete() 每次批量删除1024条记录,执行10次.(当前版本对delete执行Batch链式方法也不会再执行删除时做数组切割,即不论是否显式调用Batch都对delete无影响)
糖水不加糖
感觉在ORM执行前应该对参数(占位符)长度做下与判断,如果超长了可以转为默认批处理模式(触发场景不多,基本都发生在batch insert与where in delete)以提升ORM的健壮性.实际用户逻辑并没有错,但会直接返回占位符过长错误.