Do redis transactions satisfy atomicity?

Code nongshen Shang 2021-09-15 10:01:07
redis transactions satisfy atomicity


Talking about database transactions , It is estimated that the first reaction of many students is ACID, Platoon ACID First in A Atomicity , Require all operations in a transaction , Or it's all done , Or not at all . be familiar with redis My classmates must know , stay redis There are also transactions in , So does its transaction satisfy atomicity ? Let's take a look at .

What is? Redis Business ?

Similar to database transactions ,redis Transactions are also used to execute multiple commands at once . It's easy to use , It can be used MULTI Start a transaction , Then queue multiple commands into the transaction queue , Finally by EXEC Command triggers transaction , Execute all commands in the transaction . Look at a simple example of transaction execution :

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name Hydra
QUEUED
127.0.0.1:6379> set age 18
QUEUED
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) (integer) 19

You can see , When the data types of instructions and operands are normal , Input EXEC After that, all commands were executed successfully .

Redis Do transactions satisfy atomicity ?

If you want to verify redis Does the transaction satisfy atomicity , So you need to redis When the transaction execution is abnormal , Let's test for two different types of errors .

Grammar mistakes

First, test the syntax error in the command , In this case, the number of parameters of the command is incorrect or there is an error in the input command itself . Let's enter a malformed command in the transaction , Start the transaction and enter the following commands in turn :

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name Hydra
QUEUED
127.0.0.1:6379> incr
(error) ERR wrong number of arguments for 'incr' command
127.0.0.1:6379> set age 18
QUEUED

The command entered incr No parameters are added later , Syntax error due to incorrect command format , At this time, when you command to join the team, you will immediately detect the error and prompt error. Use exec Perform transactions , View result output :

127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.

under these circumstances , As long as a command in the transaction has a syntax error , In execution exec An error will be returned directly after , All commands, including those with correct syntax, will not be executed . Verify this , Take a look at the execution of other instructions in the transaction , see set Command execution results , All empty , Indicates that the instruction was not executed .

127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
(nil)

Besides , If there is a spelling error in the command itself 、 Or enter a command that does not exist , It also belongs to grammatical errors , An error will be reported directly when executing a transaction .

Running error

Run error means that the input instruction format is correct , But an error occurred during the execution of the command , A typical scenario is when the data type of the input parameter does not meet the parameter requirements of the command , A running error will occur . For example, in the following example , To a string The value of type performs the operation of the list , An error is as follows :

127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> lpush key1 value2
(error) WRONGTYPE Operation against a key holding the wrong kind of value

This kind of mistake lies in redis It cannot be found until the instruction is actually executed , Only when it is actually executed can it be found , Therefore, such commands can be received by the transaction queue , It will not immediately report an error like the syntax error above .

Let's take a look at the situation when there is a running error in the transaction , In the following transaction , Try to be on string Type data to carry out incr Self increment operation :

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set name Hydra
QUEUED
127.0.0.1:6379> set age eighteen
QUEUED
127.0.0.1:6379> incr age
QUEUED
127.0.0.1:6379> del name
QUEUED

redis Up to now, there is no indication of an error , perform exec Look at the output :

127.0.0.1:6379> exec
1) OK
2) OK
3) (error) ERR value is not an integer or out of range
4) (integer) 1

You can see the result of running , although incr age An error occurred with this command , But the commands before and after it are executed normally , Look at these again key Corresponding value , It does prove that the other instructions are executed successfully :

127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
"eighteen"

Phased conclusion

Analyze the running results of the above transactions :

  • There is Grammar mistakes Under the circumstances , All commands will not be executed
  • There is Running error Under the circumstances , Except for commands with errors in execution , Other commands can be executed normally

Through analysis, we know redis Transactions in are not atomic , In case of running error , There is no rollback function similar to that in the database . So why redis Rollback is not supported , The official documentation gives instructions , The main idea is as follows :

  • redis Command failure will only occur in the case of syntax error or data type error , This result is caused by errors in the programming process , This should be detected in the development environment , Not the production environment
  • Do not use rollback , Can make redis Simpler interior design , Faster
  • Rollback cannot avoid errors in programming logic , If you want to increase the value of a key 2 But only increased 1, In this case, even rollback cannot help

For the above reasons ,redis The official choice is simpler 、 Faster way , Error rollback is not supported . In this case , If we need to ensure atomicity in our business scenario , Then the developer is required to ensure the success or failure of all commands by other means , For example, check the parameter type before executing the command , Or make transaction compensation in time when there are errors in transaction execution .

Mention other ways , I believe many friends have heard Use Lua Script to ensure the atomicity of the operation , For example, in distributed locks, we usually use Lua Script , that , magical Lua Can scripts really guarantee atomicity ?

ordinary Lua Script entry

In the verification of lua Before the atomicity of the script , We need a simple understanding of it .redis from 2.6 The version starts to support execution lua Script , Its functions are very similar to transactions , a section lua The script is executed as a command , This will multiple redis Command write lua, You can achieve the execution results of similar transactions . Let's take a look at the following common commands .

EVAL command

Most commonly used EVAL Used to execute a script , Its command format is as follows :

EVAL script numkeys key [key ...] arg [arg ...]

Briefly explain the parameters :

  • script Is a lua Script program
  • numkeys There are several parameters for specifying subsequent parameters key, If not key Then for 0
  • key [key …] Represents the used in the script redis The key , stay lua The script passes KEYS[i] In the form of
  • arg [arg …] Represents additional parameters , stay lua The script passes ARGV[i] obtain

Take a simple example :

127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 value1 vauel2
1) "key1"
2) "key2"
3) "value1"
4) "vauel2"

In the above order , In double quotation marks lua Script program , hinder 2 Indicates that there are two key, Namely key1 and key2, The following parameters are additional parameters value1 and value2.

If you want to use it lua Script execution set command , It can be written like this :

127.0.0.1:6379> EVAL "redis.call('SET', KEYS[1], ARGV[1]);" 1 name Hydra
(nil)

It's used here redis Built in lua function redis.call To complete set command , The execution results are printed here nil Because there is no return value , If you're not used to it , In fact, we can add return 0; Return statement .

SCRIPT LOAD and EVALSHA command

These two commands are put together because they are usually used in pairs . First look at SCRIPT LOAD, It is used to load scripts into the cache , return SHA1 The checksum , At this time, only the command is cached , But the order was not executed immediately , Take an example :

127.0.0.1:6379> SCRIPT LOAD "return redis.call('GET', KEYS[1]);"
"228d85f44a89b14a5cdb768a29c4c4d907133f56"

Here comes back a SHA1 Checksum , You can use EVALSHA To execute the script :

127.0.0.1:6379> EVALSHA "228d85f44a89b14a5cdb768a29c4c4d907133f56" 1 name
"Hydra"

Use this here SHA1 The value is equivalent to importing the command cached above , Splice later numkeyskeyarg Equal parameter , The command can be executed normally .

Other commands

Use SCRIPT EXISTS Command to determine whether the script is cached :

127.0.0.1:6379> SCRIPT EXISTS 228d85f44a89b14a5cdb768a29c4c4d907133f56
1) (integer) 1

Use SCRIPT FLUSH Order clear redis Medium lua Script cache :

127.0.0.1:6379> SCRIPT FLUSH
OK
127.0.0.1:6379> SCRIPT EXISTS 228d85f44a89b14a5cdb768a29c4c4d907133f56
1) (integer) 0

You can see , Yes SCRIPT FLUSH after , Through again SHA1 The value no longer exists when viewing the script . Last , You can also use SCRIPT KILL The command kills the currently running lua Script , But it will only take effect if the script does not perform a write operation .

From these operations ,lua Scripts have the following advantages :

  • Multiple network requests can be completed in one request , Reduce network overhead , Reduced network latency
  • The script sent by the client will exist redis in , Other clients can reuse this script , Without repeated coding to complete the same logic

Java The code uses lua Script

stay Java You can use Jedis It's packaged in API To execute lua Script , Here is a use Jedis perform lua An example of a script :

public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
String script="redis.call('SET', KEYS[1], ARGV[1]);"
+"return redis.call('GET', KEYS[1]);";
List<String> keys= Arrays.asList("age");
List<String> values= Arrays.asList("eighteen");
Object result = jedis.eval(script, keys, values);
System.out.println(result);
}

Execute the above code , The console prints get Results returned by command :

eighteen

After the simple bedding is completed , Let's take a look lua Whether the script can achieve rollback level atomicity . Modify the above code , Insert a command that runs incorrectly :

public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
String script="redis.call('SET', KEYS[1], ARGV[1]);"
+"redis.call('INCR', KEYS[1]);"
+"return redis.call('GET', KEYS[1]);";
List<String> keys= Arrays.asList("age");
List<String> values= Arrays.asList("eighteen");
Object result = jedis.eval(script, keys, values);
System.out.println(result);
}

View the execution results :

Go to the client again get command :

127.0.0.1:6379> get age
"eighteen"

in other words , Although the program threw an exception , However, the command before the exception is executed normally and is not rolled back . Try again, directly in redis Run this command in the client :

127.0.0.1:6379> flushall
OK
127.0.0.1:6379> eval "redis.call('SET', KEYS[1], ARGV[1]);redis.call('INCR', KEYS[1]);return redis.call('GET', KEYS[1])" 1 age eight
(error) ERR Error running script (call to f_c2ea9d5c8f60735ecbedb47efd42c834554b9b3b): @user_script:1: ERR value is not an integer or out of range
127.0.0.1:6379> get age
"eight"

Again , The instruction before the error is still not rolled back , So what we often heard before Lua What is it about scripts that guarantee atomic operations ?

Actually , stay redis Is the same one used in lua Interpreter to execute all commands , It ensures that when a period of time lua When the script executes , There won't be any other scripts or redis The order is executed at the same time , It ensures that the operation will not be inserted or disturbed by other instructions , What is achieved is only this degree of atomicity .

But unfortunately , If the script runs with an error and ends halfway , Subsequent operations will not be performed , However, previous writes will not be undone , So even if you use lua Script , Nor can it achieve atomicity similar to database rollback .

This article is based on redis 5.0.3 To test

Official document related instructions :https://redis.io/topics/transactions

Author's brief introduction , Manongshen (CODER_SANJYOU), An official account of sharing love , Interesting 、 thorough 、 direct , Talk to you about technology . Personal wechat DrHydra9, Welcome to add friends , Further communication .

版权声明
本文为[Code nongshen Shang]所创,转载请带上原文链接,感谢
https://javamana.com/2021/09/20210909145631886l.html

  1. L'arrivée de marchandises sèches, l'entretien d'emploi Java 12 grandes usines ont réussi à changer d'emploi,
  2. Multiple postures for handling container time in k8s environment
  3. Echarts remove left Gap, Blank
  4. Hotspot Weekly | zoom $100 million, docker fees, $38 billion Data bricks
  5. JsonMappingException: No serializer found for class org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory...
  6. Java. Security. Securerandom source code analysis Java. Security. EGD = file: / dev /. / urandom
  7. When using IntelliJ idea, jump directly and quickly from the mapper interface to mapper.xml
  8. When idea writes SQL in mybatis XML, the solution to the problems of table name, field and red reporting
  9. Spring cloud integrates Nacos
  10. 应届毕业生Java笔试题目,2021大厂Java社招最全面试题,
  11. Liver explosion! Take you to understand Hadoop serialization
  12. linux系列之:告诉他,他根本不懂kill
  13. java版gRPC实战之三:服务端流
  14. RabbitMQ核心知识总结!
  15. linux系列之:告诉他,他根本不懂kill
  16. java版gRPC实战之三:服务端流
  17. RabbitMQ核心知识总结!
  18. 10天拿到字节跳动Java岗位offer,学习Java开发的步骤
  19. 10天拿到字节跳动Java岗位offer,Java知识点思维导图
  20. Résumé des connaissances de base de rabbitmq!
  21. 10天拿到字節跳動Java崗比特offer,Java知識點思維導圖
  22. 10 jours pour obtenir un Byte Jump Java post offer, Java Knowledge point Mind Map
  23. 10 jours pour obtenir l'octet Jump Java post offer, apprendre les étapes du développement Java
  24. Java version of gppc Reality Three: server side stream
  25. Linux Series: Dites - lui qu'il ne connaît pas kill du tout
  26. "Data structure and algorithm" of front end -- binary search
  27. 2020-2021京东Java面试真题解析,如何才能通过一线互联网公司面试
  28. 13 SpringBoot整合RocketMQ实现过滤消息-根据SQL表达式过滤消息
  29. 12 SpringBoot整合RocketMQ实现过滤消息-根据TAG方式过滤消息
  30. 11 SpringBoot整合RocketMQ实现事务消息
  31. 11 springboot Consolidated rocketmq Implementation transaction message
  32. 12 springboot Consolidated rocketmq Implements Filtering messages - Filtering messages according to tag method
  33. 13 springboot Consolidated rocketmq Implementation Filtering messages - Filtering messages according to SQL expressions
  34. linux系列之:告诉他,他根本不懂kill
  35. (1)java Spring Cloud+Spring boot企业快速开发架构之微服务是什么?它的优缺点有哪些?
  36. Oracle 检查 DATE 列 RANGE 分区表已有分区的最大日期时间
  37. ConcurrentHashMap--原理
  38. 2020 - 2021 JD Java interview Real question Analysis, How can interview through First - Line Internet Company
  39. Concurrenthashmap - - Principes
  40. Oracle vérifie l'heure de date maximale d'une partition existante dans la colonne date
  41. Docker Compose 实践及梳理
  42. Qu'est - ce qu'un microservice pour Java Spring Cloud + Spring Boot Enterprise Quick Development architecture?Quels sont ses avantages et ses inconvénients?
  43. Plus sign interview knowledge points in Java
  44. Pratique et organisation de la composition des dockers
  45. Linux Series: Dites - lui qu'il ne connaît pas kill du tout
  46. Convenient CSS and jQuery drop-down menu solution
  47. Linux analog packet loss rate
  48. Redis:我是如何与客户端进行通信的
  49. 15 useful cron work examples commonly used by Senior Linux system administrators
  50. 24个 JavaScript 循环遍历方法,你都知道吗?
  51. Reading notes of JavaScript advanced programming (3rd Edition) 4
  52. 30分钟学会Docker里面开启k8s(Kubernetes)登录仪表盘(图文讲解)
  53. 24 méthodes de traversée de boucle Javascript, vous savez?
  54. 30 minutes pour apprendre à ouvrir le tableau de bord k8s (kubernets) dans le docker (explication graphique)
  55. Redis: comment je communique avec les clients
  56. Wsl2: Windows native Linux subsystem
  57. 30分钟学会Docker里面开启k8s(Kubernetes)登录仪表盘(图文讲解)
  58. Python高级用法总结(8)-函数式编程
  59. 261页前端面试题宝典,JavaScript变量声明提升
  60. The performance of JVM and Java applications of the same version differs by 30% on X86 and aarch64 platforms. Why?