elasticsearch实现乐观锁

elasticsearch的写操作是原子性的,可以通过如下两种方式实现es写操作的乐观锁。

基于_version

version_type在elasticsearch6.x被移除,故该方法不适用于6.x版本,详见https://www.elastic.co/guide/en/elasticsearch/reference/6.7/docs-update.html

PUT /user/user_type/1
{
  "name": "tom",
  "age": 18,
  "doc_version": 1 // 自定义的文档版本号,用于乐观锁
}

只更新低版本的记录

PUT /user/user_type/1?version=2&version_type=external_gt
{
  "name": "tom",
  "age": 18,
  "doc_version": 2
}

忽略版本号强制更新

PUT /user/user_type/1?version=3&version_type=force
{
  "name": "tom",
  "age": 18,
  "doc_version": 3
}

基于script

PUT /user/user_type/1
{
  "name": "tom",
  "age": 18,
  "doc_version": 1 
}

只更新es中doc_version版本低的记录

POST /user/user_type/1/_update
{
  "script": {
    "source": "if(params.doc_force == true || ctx._source.doc_version < params.doc_version){for(entry in params.entrySet()){if (entry.getKey() != 'ctx') ctx._source[entry.getKey()] = entry.getValue();}}else{ctx.op = 'none'}",
    "lang": "painless",
    "params": {
      "name": "tom",
      "age": 19,
      "doc_version": 19
    }
  }
}

忽略自定义版本号doc_version强制更新记录

POST /user/user_type/1/_update
{
  "script": {
    "source": "if(params.doc_force == true || ctx._source.doc_version < params.doc_version){for(entry in params.entrySet()){if (entry.getKey() != 'ctx') ctx._source[entry.getKey()] = entry.getValue();}}else{ctx.op = 'none'}",
    "lang": "painless",
    "params": {
      "name": "tom",
      "age": 19,
      "doc_version": 19,
      "doc_force": true
    }
  }
}

注:读取script中的params的值时,需要过滤掉params.ctx,原因是es的painless脚本会自动向params中添加ctx,如果不过滤,则上述的更新语法会报如下错误:

{
  "error": {
    "root_cause": [
      {
        "type": "remote_transport_exception",
        "reason": "[0l2AYvx][127.0.0.1:9300][indices:data/write/update[s]]"
      }
    ],
    "type": "illegal_argument_exception",
    "reason": "Iterable object is self-referencing itself"
  },
  "status": 400
}

详见https://github.com/elastic/elasticsearch/pull/32096

发布了185 篇原创文章 · 获赞 38 · 访问量 21万+

猜你喜欢

转载自blog.csdn.net/sz85850597/article/details/89736640