update 大家会允许这样写吗?

202 天前
 Niner
User u = userMapper.selectOne(id);
u.setName(myname);
u.setAge(myAge);
userMapper.updateById(u);

我看工作里面很多代码都是这样更新的,虽然方便但是有并发问题,大佬们 cr 遇到会打回去吗?

7739 次点击
所在节点    Java
73 条回复
oracleHe
202 天前
以面向对象的思维来说一般都是这么写的。因为往往在实际业务中你把对象 select 出来除了赋值可能还会做很多业务逻辑和计算,完了就将整个对象 update 。如果在要求比较高的场景下,要解决并发问题就通过分布式锁来处理。

当然假如只是单纯更新数据的场景,这种写法并不好,因为可能只要更新一个字段却执行了两个 sql ,甚至把所有字段都更新了一遍,效率比较低,也存在你说的并发问题。所以简单的更新数据比较建议直接通过一句简单的 update 更新。
oldking24
202 天前
分场景呢,如果真的并发高那就加锁,要么乐观锁 version 字段,要么加分布式锁,按理说,用户不会天天修改自己的用户信息。
xuanbg
202 天前
@dcsuibian 严格来说,不加锁的更新都有可能出你说的问题。加锁带来的问题是性能下降,和用户交互不友好。
但这个问题可以通过业务规则规避,只允许一个用户修改数据就啥问题都没了。
spritecn
202 天前
没啥 大影响 ..很多代码这么写的,虽然新开一个 userForUpdate 类会清淅一点
并不并发的,没区别,就算你只更新你的,并发你不加锁,开不开新类也控制不了
对于阿里/腾讯 这类优化过的 mysql,会自动过滤不需要更新的字段,对性能影响也不大
Vegetable
202 天前
所以,问题出在 mapper 的 updatebyid 并不会像符合认知的 orm 行为那样,只修改自己变更过的字段。而是会 update 整个对象除了 ID 外所有的字段。

对不熟悉的人来说,这个还挺隐蔽的,但是想必已经是 java 生态内的常识了吧。
gerefoxing
202 天前
只更新需要更新的字段,全部更新没意义,重新 new 个对象更新
cornorj6
202 天前
spring data jpa 中可以给实体加个 @Version 就能自动处理乐观缩,这种方式没有毛病,只有更新的一瞬间判断,感觉效率比行锁高。
yor1g
202 天前
那怎么写才正确呢 🤣 每个更新操作都考虑并发么
chobitssp
202 天前
ef 使用 ChangeTracker 跟踪状态变化 只会更新变化的字段
java 的 orm 不清楚是否支持
wei2629
202 天前
除非需要事务, 不然我觉得这就是最好的选择。
cathub86
202 天前
局部变量这样写 没事吧
jnliyan1
202 天前
查询是不是多余了
cenbiq
202 天前
如果你用 C# ef orm ,官方就是推荐这么写的,但是 ef 自带乐观锁支持和 patch 更新,改了什么字段就更新什么字段
carytseng
202 天前
这是 mysql 经典的丢失更新问题,举个相似例子,a 用户读取 user1 时 age=0 并修改 age=age+1=1 ,b 用户读取 user1 时 age=0 并修改 age=age+2=2 ,此时丢失了 a 用户的修改,中间其实更新了+1 ,所以处理时如果要满足场景你在读前就要加锁
YepTen
202 天前
某些场景下,绝对允许;
某些场景下,绝对不允许;
某些场景下,无所屌谓;
所以,你是哪个场景?
wuhunyu
202 天前
使用乐观锁更新的话,如果出现了并发有概率出现部分用户无法更新成功的情况,也就是数据库返回受影响行数为 0 ,这个时候需要提示用户修改失败,并要求重新刷新表单数据之后重新提交修改,并发量大的情况下,用户仍然有可能第二次提交也是失败的

使用锁的话,大概率是可以更新成功的,但可能遇到的问题有,并发量大时可能会等待,表现为用户提交表单等待的时间会长一点或者直接等待超时(这种情况下,有可能修改成功,也可能失败)。此外还有一个问题是,后提交的用户有可能会把之前提前的信息给覆盖掉(比如 #13 提到的问题)

如果按照锁升级策略来看的话,是否可以考虑如下策略
默认使用乐观锁,当出现冲突时,也就是数据库返回受影响行数为 0 时,进入重锁模式,重锁模式释放完毕之后,再做一个判断,如果当前没有使用资源的线程,则切换回乐观锁模式
Pursue9
202 天前
用 MP 的 LambdaUpdateWrapper ,只更新指定字段
MoYi123
202 天前
没并发问题吧, 这里只是用了一个比较蠢的办法去构造了 User u 而已.
pangdundun996
202 天前
为啥不按需更新?
```java
User u= new User();
u.setId(id);
u.setName(myname);
u.setAge(myAge);
userMapper.updateById(u);

```
zzNaLOGIC
202 天前
就算是生成器生成的 mapper ,都有 updateByPrimaryKeySelective 吧
用一下又不麻烦,这样就是纯懒到家了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1107192

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX