affair
Redis's single command guarantees atomicity, but the redis transaction does not guarantee atomicity
Redis Transaction nature: A collection of commands. ----------------- queue set set set implement ------------------- Each command in a transaction is serialized and executed sequentially. No interference from other commands is allowed. Disposable Sequential Exclusiveness Redis Transactions do not have the concept of isolation level Redis A single command guarantees atomicity, but a transaction does not guarantee atomicity!
Redis Transaction Operation Procedure
- Open Transaction (multi)
- Command Entry
- Execute Transaction (exec)
Therefore, commands in a transaction are not executed when joined, and execution (Exec) is not started until a commit is made.
Normal execution
127.0.0.1:6379> multi # Open Transaction OK 127.0.0.1:6379> set k1 v1 # Command Entry QUEUED 127.0.0.1:6379> set k2 v2 # .. QUEUED 127.0.0.1:6379> get k1 QUEUED 127.0.0.1:6379> set k3 v3 QUEUED 127.0.0.1:6379> keys * QUEUED 127.0.0.1:6379> exec # Transaction Execution 1) OK 2) OK 3) "v1" 4) OK 5) 1) "k3" 2) "k2" 3) "k1"
discurd transaction
127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> DISCARD # Abandon Transaction OK 127.0.0.1:6379> EXEC (error) ERR EXEC without MULTI # Transaction not currently open 127.0.0.1:6379> get k1 # Command not executed in abandoned transaction (nil)
Transaction error
Code syntax error (compile-time exception) All commands are not executed
127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> error k1 # This is a grammar error command (error) ERR unknown command `error`, with args beginning with: `k1`, # Errors will be reported but will not affect subsequent command enlistment 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> EXEC (error) EXECABORT Transaction discarded because of previous errors. # Execution error 127.0.0.1:6379> get k1 (nil) # Other commands were not executed
Code logic errors (runtime exceptions) ** Other commands can execute ** > > > > > so transaction atomicity is not guaranteed
127.0.0.1:6379> multi OK 127.0.0.1:6379> set k1 v1 QUEUED 127.0.0.1:6379> set k2 v2 QUEUED 127.0.0.1:6379> INCR k1 # This command has a logical error (incrementing strings) QUEUED 127.0.0.1:6379> get k2 QUEUED 127.0.0.1:6379> exec 1) OK 2) OK 3) (error) ERR value is not an integer or out of range # Runtime error 4) "v2" # Other commands execute normally Although one of the commands reported an error, the following commands still executed successfully. So Redis A single instruction guarantees atomicity, but Redis Transactions do not guarantee atomicity.
Monitor
Pessimistic lock:
- Pessimistic, think there's always a problem, lock everything
Optimistic lock:
- Very optimistic, think there will be no problem at any time, so there will be no lock! When updating data, check to see if anyone has modified the data during this period
- Get version
- Compare version s when updating
Monitoring specified data with watch key is equivalent to optimistic lock locking.
Normal execution
127.0.0.1:6379> set money 100 # Set balance: 100 OK 127.0.0.1:6379> set use 0 # Expense usage: 0 OK 127.0.0.1:6379> watch money # Monitor money (lock up) OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> DECRBY money 20 QUEUED 127.0.0.1:6379> INCRBY use 20 QUEUED 127.0.0.1:6379> exec # The monitor value was not modified in the middle, and the transaction executed normally 1) (integer) 80 2) (integer) 20
Testing multithreaded modification values, using watch es can act as optimistic lock operations for redis (equivalent to getversion)
Let's start another client to simulate queuing threads.
Thread 1:
127.0.0.1:6379> watch money # money Lock OK 127.0.0.1:6379> multi OK 127.0.0.1:6379> DECRBY money 20 QUEUED 127.0.0.1:6379> INCRBY use 20 QUEUED 127.0.0.1:6379> # The transaction was not executed at this time
Simulate thread queuing, thread 2:
127.0.0.1:6379> INCRBY money 500 # Modified money monitored in thread one (integer) 600
Back to thread 1, execute the transaction:
127.0.0.1:6379> EXEC # Another thread modified our value before execution, which will cause the transaction to fail (nil) # No result, transaction execution failed 127.0.0.1:6379> get money # Thread 2 modification takes effect "600" 127.0.0.1:6379> get use # Thread 1 transaction failed, value not modified "0"
Unlock to get the latest value and then lock the transaction.
unwatch to unlock.
Note: Locks are automatically released after each exec submission, whether successful or not
Jedis
Using Java to operate Redis, Jedis is the officially recommended Java connection redis client for Redis.
1. Import Dependency
<!--Import jredis Package for--> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>3.2.0</version> </dependency> <!--fastjson--> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.70</version> </dependency>
2. Coding Test
Connect to database
Operational commands
Disconnect
Code Samples
public class TestPing { public static void main(String[] args) { Jedis jedis = new Jedis("192.168.xx.xxx", 6379); String response = jedis.ping(); System.out.println(response); // PONG } }
Output PONG
Common API s
string,list,set,hash,zset
All the api commands, the ones we learned above, have not changed!
public class TestTX { public static void main(String[] args) { Jedis jedis = new Jedis("127.0.0.1", 6379); jedis.flushDB(); JSONObject jsonObject = new JSONObject(); jsonObject.put("hello","world"); jsonObject.put("name","xiaoli"); // Open Transaction Transaction multi = jedis.multi(); String result = jsonObject.toJSONString(); // jedis.watch(result) try { multi.set("user1",result); multi.set("user2",result); int i = 1/0 ; // Code throws an exception transaction, execution failed! multi.exec(); // Perform business! } catch (Exception e) { multi.discard(); // Abandon Transaction e.printStackTrace(); } finally { System.out.println(jedis.get("user1")); System.out.println(jedis.get("user2")); jedis.close(); // Close Connection } } }
SpringBoot Integration
SpringBoot operational data: spring-data jpa jdbc mongodb redis!
SpringData is also a project with the same name as SpringBoot!
Description: In SpringBoot2. After x, the original jedis was replaced with lettuce?
Jedis: Direct connection, multi-threaded operation, is not safe, if you want to avoid unsafe, use jedis pool connection pool! More like BIO mode
Letuce: With netty, instances can be shared among multiple threads without thread insecurity! Reduced thread data, more like NIO mode
Source analysis:
@Bean @ConditionalOnMissingBean(name = "redisTemplate") // We can define a redisTemplate to replace this default! public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { // The default ReedisTemplate does not have too many settings, redis objects all need to be serialized! // Both generics are Object, Object's type, so we need to cast <String, Object> RedisTemplate<Object, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); return template; } @Bean @ConditionalOnMissingBean // Since String is the most commonly used type in redis, a bean has been proposed separately! public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { StringRedisTemplate template = new StringRedisTemplate(); template.setConnectionFactory(redisConnectionFactory); return template; }
Integration Testing
1. Import Dependency
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
Springboot 2. After x, the original Jedis was replaced by lettuce.
Jedis: Direct connections, multi-threaded operations, are not safe. If you want to avoid insecurity, use jedis pool to connect to the pool! More like BIO mode
Letuce: With netty, instances can be shared across multiple threads without thread insecurity! Reduced thread data, more like NIO mode
When learning the principles of SpringBoot auto-configuration, integrating and configuring a component must have an auto-configuration class, xxxAutoConfiguration, and in spring. The fully qualified name of this class must also be found in factories. Redis is no exception.
So there must also be a RedisProperties class
There are two classes in the @ConditionalOnClass annotation that do not exist by default, so Jedis is not valid
Then look at Lettuce:
Perfect effect.
Now let's go back to RedisAutoConfiguratio
There are only two simple Bean s
- RedisTemplate
- StringRedisTemplate
When you see xxTemplate, you can compare RestTemplat with SqlSessionTemplate to indirectly manipulate components using these Templates. Neither of them is exceptional. Used to manipulate String data types in Redis and Redis, respectively.
There is also a conditional note on RedisTemplate that says we can customize it
Having said that, we need to know how to write a configuration file and connect to Redis, so we need to read RedisProperties
These are some basic configuration properties.
There are also connection pool-related configurations. Be aware that the connection pool for Lettuce is always used.
2. Write a configuration file
# Configure redis spring.redis.host=XXXX spring.redis.port=6379
3. Use RedisTemplate
@SpringBootTest class Redis02SpringbootApplicationTests { @Autowired private RedisTemplate redisTemplate; @Test void contextLoads() { // redisTemplate operates on different data types, the api is the same as our instructions // opsForValue operation string similar to String // opsForList acts like List // opsForSet // opsForHash // opsForZSet // opsForGeo // opsForHyperLog // In addition to basic operations, common methods we use can operate directly through redisTemplate, such as transactions and basic CRUD s // Get Connection Object //RedisConnection connection = redisTemplate.getConnectionFactory().getConnection(); //connection.flushDb(); //connection.flushAll(); redisTemplate.opsForValue().set("mykey","zhangsan"); System.out.println(redisTemplate.opsForValue().get("mykey"); } }
4. Test results
When we returned to Redis to look at the data, we were surprised to find that it was all garbled, but the program could output normally. At this time, it is related to the serialization of storage objects. The objects transmitted in the network also need serialization. Otherwise, they are all garbled.
The serialization configuration inside RedisTemplate is like this
The default serializer is to use JDK serializer
We can then customize RedisTemplate to modify it.
RedisSerializer provides a variety of serialization schemes:
Let's write our own RedisTemplete
package com.li.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; @Configuration public class RedisConfig { // This is a fixed template that I have written for you. Everyone in the enterprise can use it directly! // I defined a RedisTemplate myself @Bean @SuppressWarnings("all") public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { // We have developed for ourselves the convenience of using <String, Object> RedisTemplate<String, Object> template = new RedisTemplate<String, Object>(); template.setConnectionFactory(factory); // Json Serialization Configuration Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); // Serialization of String s StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key uses String serialization template.setKeySerializer(stringRedisSerializer); // hash's key also uses String's serialization template.setHashKeySerializer(stringRedisSerializer); // value serialization using jackson template.setValueSerializer(jackson2JsonRedisSerializer); // hash's value serialization uses jackson template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
All redis operations, in fact, are very simple for java developers, but it is more important to understand the idea of redis and the use and use of each data structure scenario!