Search code examples
javaspring-bootdockerredislettuce

Where does client Lettuce from a library lettuce-core store data?


  • pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>redis</groupId>
    <artifactId>spring-data-redis-example</artifactId>
    <version>0.0.1</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>

        <version.mapstruct>1.3.0.Final</version.mapstruct>
        <version.apache.maven.plugins>3.8.1</version.apache.maven.plugins>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

    <!--    <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.3.0</version>
        </dependency>-->


    <!--    <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.8.1</version>
        </dependency>-->


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
            <version>5.3.3.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mapstruct</groupId>
            <artifactId>mapstruct</artifactId>
            <version>${version.mapstruct}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin> 
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${version.apache.maven.plugins}</version>
                <groupId>org.apache.maven.plugins</groupId>

                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.mapstruct</groupId>
                            <artifactId>mapstruct-processor</artifactId>
                            <version>${version.mapstruct}</version>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

This is a configuration file java.

@Configuration
public class RedisConfig {

    @Value("${spring.redis.host}")
    private String hostName;

    @Bean
    LettuceConnectionFactory lettuceConnectionFactory() {

        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();

        redisStandaloneConfiguration.setHostName(this.hostName);

        LettuceConnectionFactory lettuceConnectionFactory =
                new LettuceConnectionFactory(redisStandaloneConfiguration);


        return lettuceConnectionFactory;
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        final RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory());
        template.setValueSerializer(new GenericToStringSerializer<>(Object.class));
        return template;
    }

    /**
     * <b>MessageSubscriber</b> is  a implementation
     * of {@link org.springframework.data.redis.connection.MessageListener}
     * The MessageSubscriber is developed in the app
     * @return
     */
    @Bean
    MessageListenerAdapter messageListener() {
        return new MessageListenerAdapter(new MessageSubscriber());
    }


    @Bean
    RedisMessageListenerContainer redisContainer() {

        final RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(lettuceConnectionFactory());
        container.addMessageListener(messageListener(), topic());
        return container;
    }

    /**
     * <b>MessagePublisherImpl</b> is a implementation of {@link redis.service.message.MessagePublisher}
     * The MessagePublisher is developed in the application
     * @return
     */
    @Bean
    MessagePublisher redisPublisher() {

        return new MessagePublisherImpl(redisTemplate(), topic());
    }

    @Bean
    ChannelTopic topic() {
        return new ChannelTopic("pubsub:queue");
    }
}

This is config file for redis server

bind 0.0.0.0
protected-mode yes
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
pidfile /var/run/redis/redis-server.pid
loglevel notice
logfile /data/log/redis-server.log
databases 16
always-show-logo yes
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data/bases
slave-serve-stale-data yes
slave-read-only yes
repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
slave-priority 100
lazyfree-lazy-eviction no
lazyfree-lazy-expire no
lazyfree-lazy-server-del no
slave-lazy-flush no
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-load-truncated yes
aof-use-rdb-preamble no
lua-time-limit 5000
slowlog-log-slower-than 10000
slowlog-max-len 128
latency-monitor-threshold 0
notify-keyspace-events ""
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
activerehashing yes
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit slave 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60
hz 10
aof-rewrite-incremental-fsync yes
  • repository
@Repository
public class RedisRepositoryImpl implements RedisRepository {
    private static final String KEY = "Movie";
    
    private RedisTemplate<String, Object> redisTemplate;
    private HashOperations hashOperations;
    
    @Autowired
    public RedisRepositoryImpl(RedisTemplate<String, Object> redisTemplate){
        this.redisTemplate = redisTemplate;
    }

    @PostConstruct
    private void init(){
        hashOperations = redisTemplate.opsForHash();
    }
    
    public void add(final Movie movie) {
        hashOperations.put(KEY, movie.getId(), movie.getName());
    }

    public void delete(final String id) {
        hashOperations.delete(KEY, id);
    }
    
    public Movie findMovie(final String id){
        return (Movie) hashOperations.get(KEY, id);
    }
    
    public Map<Object, Object> findAllMovies(){
        return hashOperations.entries(KEY);
    }

  
}
  • rest

  • create:

@RestController
@RequestMapping("api")
public class CreateRestController {

    private RedisCreateService service;

    @Autowired
    public CreateRestController(RedisCreateService service) {
        this.service = service;
    }

    @PostMapping("keys")
    public ResponseEntity<String> add( @RequestParam String key, @RequestParam String value){

        service.add(key, value);

        return new ResponseEntity<>(HttpStatus.OK);
    }
}
  • read:
@RestController
@RequestMapping("api")
public class ReadRestController {

    private RedisReadService service;

    @Autowired
    public ReadRestController(RedisReadService service) {
        this.service = service;
    }

    @GetMapping("values")
    public @ResponseBody Map<String, String> findAll(){

        Map<String, String> all = service.getAll();

        return all;
    }

    @RequestMapping("keys/all")
    public @ResponseBody Map<String, String> keys() {

        Map<String, String> keys = service.getKeys();

        return keys;
    }
}

Data is saved and read fairly well. I assume they are saved to a redis database that has an in-memory implementation, although I didn't configure this specifically. I inferred because when I sent commands through redis-cli, I don't get answers by queried keys.

But, while the application is working , data is saved and to is reading.

After Stop the application and then Start the application, data has lost.

Moreover, I use the plugin - redis simple. there I see data, If I work from redis-cli. When I work from the application , I don't see this data.

Please, anyone explain me this. How I must configure my application.


Solution

  • you didn't set a key serializer, so it uses the JDK serializer as default. So the key was not actually stored as String in Redis server.

    Change your code in the config about redis to this and try again.

        @Bean
    public RedisTemplate<String, Object> redisTemplate() {
        final RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(lettuceConnectionFactory());
        template.setKeySerializer(new GenericToStringSerializer<>(Object.class));
        template.setValueSerializer(new Jackson2JsonRedisSerializer<>(Object.class));
        return template;
    }
    

    Redis should have persistence on by default, you should see the data after a restart. If not, check your redis logs and find the information in it. Previously I've seen redis unable to persist because it doesn't have enough file permissions to save data in the directory.