1 数据库的 update 在修改这条数据的的过程中(这个过程指的是 数据库执行update 到 事务提交的过程中 )为这条数据加上 写锁,阻止 别的事务 对锁定数据的修改,请求后一个修改事务的线程阻塞,直到前一个事务的完成,所以针对这条数据的 2 个修改 是一个一个来的。所以 数据库的 update t1 set a = a+1; 这样的操作 不会导致 a数据的 丢失,因为前一个事务 执行的时候回阻塞后一个事务提交数据。 但是 如果先查询出a=1, 然后 a = 1(这个1 是查询到的 a)+1 ;这样的操作会 丢失 a ,因为 a 两个事务查询的a 可能 会被修改了。
2, es 的 全部修改,如果没有带上 version的 时候,直接替换原来的 文档,没有查询的过程。多线程操作,不区分执行的先后顺序。 但是带上version的时候 version 表示先后顺序。先执行成功的为主,后来的不合法被舍弃(抛出异常)。
3, es 部分修改的时候,修改请求到达 es 的 时候,es会在内部查询 一下原理的文档,然后执行 ,部分更新,注意一下,这时候 是 es 并不阻止 别的线程修改 这条数据,可能这个es 内部的查询 同是有多个( 这个阶段叫做 retrieve ),检索完成 记录一下 这是的 version, 和传过来的新的数据一起生成新的文档,然后把旧的文档改成假删除(这个过程叫做 reindex),这时候会修改 set version=version and version = version,如果另一个 线程做着同样的操作并且慢了 一点点,重建 索引这步 就会出异常。这时候 es会 重 复检索和 重构索引的过程 知道 正常完成 或者 重试次数大于 retry_on_conflict 抛出异常。
es 会吧 原理的就文档
总结:数据库 拒绝 第二个事务来修改 已经被修改但是未被提交的数据(事务未提交)。 es 的全更新 不会有自动检索 的过程,直接替换,可以通过version 控制并发。部分更新有自动检索的过程 ,并发修改冲突会重新检索,带上version然后重新新构建索引
重试 retry_on_conflict 次后会抛出异常,并且 也可以通过 version 控制(retry_on_conflict 默认0 次 相当于 自动带上了version,但是不完成等价 , 因为 version 读的 时机 不同,有些情况可能 不同的结果,主要肯写法 和 业务 情景 比如 a = a+1 就没影响,但是 a = 1+1 就有影响,可以细细体会 一下,挺有意思的 )。