For those of you who have used Redis scripts, this is primarily intended to prevent race conditions. Because the scripts are executed sequentially. (Don't worry about efficiency) For example, I'm working with the highest score for setting up exams.
If you haven't used it before, go to the introduction of Redis scripts, send scripts, cache scripts, send SHA1 execution scripts, and the syntax of basic LUA scripts.
1. Usage Scenarios for Redis scripts
In some cache settings, race conditions are often present, resulting in incorrect data due to concurrency. such as the well-known + + operation. It is easy for us to have errors in concurrency when we implement + + via Redis ourselves. So Redis provides the INCR function. When I set the top score, I get the score 70,a 80, then set 80. Then at the same time, B gets the score 70, but B scores 78,78>70, then sets 78. In this case, the modification of B replaces the modification of a. This is also the first type of update loss in the database isolation level.
To prevent this problem, Redis provides a way to execute commands sequentially, using scripts.
2. Script Class Redisscript
Redistemplate provides a high level of support for scripting, and the execution method is similar to the previous one, all through the connection callback. However, it is important to note that the script does not support transactions, so the script can not be connection.multi () to open the transaction, or use the @transactional annotation to let spring to open the transaction, these will throw an exception, you will be able to test themselves.
See here, we create a new highest score script class, Maxscorescript, inherit from interface Redisscript, need to implement three methods:
Public InterfaceRedisscript<t> { /** * @returnthe SHA1 of the script, used for executing Redis evalsha command*/String getSha1 (); /** * @returnThe script result type. Should be one of Long, Boolean, List, or deserialized value type. Can be NULL if * The script returns a Throw-away status (i.e "OK")*/Class<T>Getresulttype (); /** * @returnThe script contents*/String getscriptasstring ();}
getSha1 (), is the Get script summary. Read the script should know that Redis support cache script, the first time the script is sent, followed by sending the script SHA1 summary information directly to execute, presumably to save the transfer cost it. After all, the digest requires only 32 characters.
Getresulttype (), which is the class that gets the return type, needs to be consistent with the defined generic T. In fact, before hibernate in the Basedao, have used direct through the instance to obtain the generic class. Although I do not understand why add here, but the implementation of this method, there is absolutely no mistake.
getscriptasstring (), no doubt, this is the return script content. As for how to write a script, here is no explanation.
3. Execute the script using Redistemplate
public <T> T Execute (redisscript<t> script, list<k> keys, Object ... args) { return scriptexecutor.execute (script, keys, args); } public <T> T Execute (redisscript<t> script, redisserializer<?> Argsserializer, Redisserializer<t> Resultserializer, List<K> keys, Object ... args) { return scriptexecutor.execute (script, Argsserializer, Resultserializer, keys, args); }
In contrast, the second one is to pass in the serializer itself, the first being the default key and value serializer.
It is strongly recommended to use the second one. Then unified incoming (Stringserializer), the parameters are all converted to string. When I was using it, LUA compared the size to find the comparison wrong. Later debugging only found, is Jdkserializer, Redis put him as a string of \xu. Such a string, the string comparison is obviously inaccurate. However, a string such as "11", "12" can be converted to num type by LUA and then compared.
Of course, there may be other business scenarios that do not need to be done, and it is possible. Self-analysis and discretion.
We see the source code that executes the script
protected<T> T eval (redisconnection connection, redisscript<t> script, ReturnType returntype,intNumkeys,byte[] Keysandargs, redisserializer<t>Resultserializer) {Object result; Try{result=Connection.evalsha (SCRIPT.GETSHA1 (), ReturnType, Numkeys, Keysandargs); } Catch(Exception e) {if(!Exceptioncontainsnoscripterror (E)) { ThrowEinstanceofRuntimeException? (RuntimeException) E:Newredissystemexception (E.getmessage (), E); } result=Connection.eval (scriptbytes (script), ReturnType, Numkeys, Keysandargs); } if(Script.getresulttype () = =NULL) { return NULL; } returnDeserializeresult (Resultserializer, result); }
This piece of code is the final call, and there are some serialization parameters that were not posted.
The default is to submit the SHA1 digest directly, get an exception, if the exception belongs to Exceptioncontainsnoscripterror, and then send the execution script, get the return result after the user-defined result serializer to deserialize.
4. Summary
This article tells Redistemplate how to use a script. May not understand the script in connection or under the Redis console to use the classmate, still do not comprehend. But if you know the console to send scripts, then through the use of redistemplate, will make many problems solved.
All I can bring to you here is finished. The next article I will have encountered problems listed below, the lesson, future. Hope everyone later encounter, will not be in the card too long time.
In-depth understanding of the use of spring Redis (iv), redistemplate performing Redis scripts