Support of Redis for Spring Data

CAST supports Redis via its com.castsoftware.nosqljava  extension. Details about how this support is provided for Java with Spring Data source code is discussed below.

Supported Libraries

Library Version Supported
RedisConnectionFactory Up to: 2.7.7 Alt text
RedisTemplate Up to: 2.7.7 Alt text
StringRedisTemplate Up to: 2.7.7 Alt text
LettuceConnectionFactory Up to: 2.7.7 Alt text
JedisConnectionFactory Up to: 2.7.7 Alt text
CrudRepository * Up to: 2.7.7 Alt text
JpaRepository * Up to: 2.7.7 Alt text

CrudRepository and JpaRepository are supported only if the repository is created using @RedisHash domain.

Supported Operations

Operation

Methods Supported

Insert

org.springframework.data.redis.core.ValueOperations.set

org.springframework.data.redis.core.ValueOperations.multiSet

org.springframework.data.redis.core.ValueOperations.multiSetIfAbsent

org.springframework.data.redis.core.ValueOperations.setIfAbsent

org.springframework.data.redis.core.ValueOperations.append

org.springframework.data.redis.core.ListOperations.leftPush

org.springframework.data.redis.core.ListOperations.leftPushAll

org.springframework.data.redis.core.ListOperations.rightPush 

org.springframework.data.redis.core.ListOperations.rightPushAll

org.springframework.data.redis.core.ListOperations.set

org.springframework.data.redis.core.HashOperations.putAll

org.springframework.data.redis.core.HashOperations.put

org.springframework.data.redis.core.HashOperations.putIfAbsent

org.springframework.data.redis.core.SetOperations.add

org.springframework.data.repository.CrudRepository.save

org.springframework.data.repository.CrudRepository.saveAll

org.springframework.data.jpa.repository.JpaRepository.save 

org.springframework.data.jpa.repository.JpaRepository.saveAll

org.springframework.data.jpa.repository.JpaRepository.saveAndFlush

org.springframework.data.jpa.repository.JpaRepository.flush

Select

org.springframework.data.redis.core.ValueOperations.get

org.springframework.data.redis.core.ValueOperations.multiGet

org.springframework.data.redis.core.ValueOperations.size

org.springframework.data.redis.core.ValueOperations.bitField

org.springframework.data.redis.core.ValueOperations.getAndDelete

org.springframework.data.redis.core.ValueOperations.getAndSet

org.springframework.data.redis.core.ListOperations.range

org.springframework.data.redis.core.ListOperations.size

org.springframework.data.redis.core.ListOperations.index

org.springframework.data.redis.core.ListOperations.indexOf

org.springframework.data.redis.core.ListOperations.lastIndexOf

org.springframework.data.redis.core.HashOperations.hasKey

org.springframework.data.redis.core.HashOperations.get

org.springframework.data.redis.core.HashOperations.multiGet

org.springframework.data.redis.core.HashOperations.keys

org.springframework.data.redis.core.HashOperations.values

org.springframework.data.redis.core.HashOperations.lengthOfValue

org.springframework.data.redis.core.HashOperations.size

org.springframework.data.redis.core.HashOperations.entries

org.springframework.data.redis.core.HashOperations.randomEntries

org.springframework.data.redis.core.HashOperations.randomEntry

org.springframework.data.redis.core.HashOperations.randomKey

org.springframework.data.redis.core.HashOperations.randomKeys

org.springframework.data.redis.core.HashOperations.scan

org.springframework.data.redis.core.SetOperations.size

org.springframework.data.redis.core.SetOperations.isMember

org.springframework.data.redis.core.SetOperations.members

org.springframework.data.repository.CrudRepository.findAll

org.springframework.data.repository.CrudRepository.count

org.springframework.data.repository.CrudRepository.findById

org.springframework.data.repository.CrudRepository.findAllById

org.springframework.data.repository.CrudRepository.existsById

org.springframework.data.repository.PagingAndSortingRepository.findAll

org.springframework.data.jpa.repository.JpaRepository.count

org.springframework.data.jpa.repository.JpaRepository.findAll

org.springframework.data.jpa.repository.JpaRepository.findAllById

org.springframework.data.jpa.repository.JpaRepository.exists

org.springframework.data.jpa.repository.JpaRepository.findOne

org.springframework.data.jpa.repository.JpaRepository.findById

org.springframework.data.jpa.repository.JpaRepository.existsById

Delete

org.springframework.data.redis.core.ListOperations.remove

org.springframework.data.redis.core.ListOperations.rightPop

org.springframework.data.redis.core.ListOperations.leftPop

org.springframework.data.redis.core.HashOperations.delete

org.springframework.data.redis.core.SetOperations.remove

org.springframework.data.redis.core.SetOperations.pop

org.springframework.data.redis.core.ValueOperations.getAndDelete

org.springframework.data.redis.core.RedisTemplate.delete

org.springframework.data.repository.CrudRepository.deleteAll

org.springframework.data.repository.CrudRepository.deleteById

org.springframework.data.repository.CrudRepository.delete

org.springframework.data.jpa.repository.JpaRepository.deleteInBatch

org.springframework.data.jpa.repository.JpaRepository.deleteAllInBatch

org.springframework.data.jpa.repository.JpaRepository.delete

org.springframework.data.jpa.repository.JpaRepository.deleteAll

org.springframework.data.jpa.repository.JpaRepository.deleteAllById

org.springframework.data.jpa.repository.JpaRepository.deleteById

Update

org.springframework.data.redis.core.ValueOperations.increment

org.springframework.data.redis.core.ValueOperations.decrement

org.springframework.data.redis.core.ValueOperations.getAndSet

org.springframework.data.redis.core.ValueOperations.setIfPresent

org.springframework.data.redis.core.ValueOperations.getAndSet

org.springframework.data.redis.core.ListOperations.trim

org.springframework.data.redis.core.ListOperations.leftPushIfPresent

org.springframework.data.redis.core.ListOperations.rightPushIfPresent

org.springframework.data.redis.core.HashOperations.increment

Objects

Icon

Description

Java Redis Connection

Java Redis Collection
Java unknown Redis Connection
Java Unknown Redis Collection
Link type When is this created? Methods Supported
parentLink

Between Redis connection object and Redis collection object

-
useLink

Between the caller Java method object and Redis collection object

  • multiGet
  • get
  • keys
  • entries
  • findAllById
  • findAll
useSelectLink

Between the caller Java method object and Redis collection object

  • multiGet
  • get
  • keys
  • entries
  • findAllById
  • findAll
useInsertLink

Between the caller Java method object and Redis collection object

  •  set
  •  put
  •  putAll
  •  add
  •  leftpush
  • save
  • saveAll

useDeleteLink

Between the caller Java method object and Redis collection object

  • delete
  • remove
  • deleteById
  • deleteAll
useUpdateLink

Between the caller Java method object and Redis collection object

  • increment
  • decrement

What results can you expect?

Some example scenarios are shown below:

Redis Connections and Collections

@Autowired
private ServiceConfigResource serviceConfigResource;

RedisConnectionFactory switchRedisMaster() {
         return getRedisConnectionFactory(serviceConfigResource.getSwitchRedisMaster(), serviceConfigResource.getDisRedisPort());
}

Java based configurations

@Configuration
@RefreshScope
@Getter
public class ServiceConfigResource {

      @Value("${disredis.host.disRedisHost1}")
         private String switchRedisMaster;

      @Value("${disredis.host.disRedisHost2}")
         private String switchRedisSlave1;

         @Value("${disredis.host.disRedisHost3}")
         private String switchRedisSlave2;

        @Value("${disredis.port.disRedisPort1}")
      private int disRedisPort; 

         @Value("${useRoomSharedUsedTable}")
        private int useRoomSharedUsedTable;

}

Xml based configurations

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:p="http://www.springframework.org/schema/p"
  xmlns:redis="http://www.springframework.org/schema/redis"
  xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/redis http://www.springframework.org/schema/redis/spring-redis.xsd
        ">
    
<!-- Jedis Connection -->    
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
   p:host-name="localhost" p:port="6379" />
  
<!-- Redis Template -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
    <property name="valueSerializer">
        <bean id="redisJsonSerializer" class="org.springframework.data.redis.serializer.JacksonJsonRedisSerializer">
            <constructor-arg type="java.lang.Class" value="redis.User"/>
        </bean>   
    </property>
</bean>

<bean class="redis.UserRepository"/>

</beans>

Lettuce

 public ReactiveRedisConnectionFactory build() {
    LettuceClientConfiguration clientConfig;
    LettuceClientConfiguration.LettuceClientConfigurationBuilder builder =
        LettuceClientConfiguration.builder();
    if (ssl) {
      builder.commandTimeout(Duration.ofSeconds(timeout)).useSsl();
    }
    clientConfig = builder.build();

    RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
    configuration.setHostName(host);
    configuration.setPassword(password);
    configuration.setPort(port);
    return new LettuceConnectionFactory(configuration, clientConfig);

RedisHash Domain 

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package io.project.app.domain;

import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.springframework.data.redis.core.RedisHash;

/
 *
 * @author armena
 */
@RedisHash
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class SearchData implements Serializable{
    
    private String id;   //unique id
    private String key; //key for search
    private String title;
    private String content;
    
}

Redis Repo Creation using CrudRepository

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package io.project.app.repositories;

import io.project.app.domain.SearchData;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;

/
 *
 * @author armena
 */
@Repository
@Component
public interface SearchRepository extends CrudRepository<SearchData, String>{
    
    public SearchRepository findByTitle(String title);
    
}

Insert Operation

@Bean(name = "switch_redis_master")
    <T> RedisTemplate<String, T> switchMasterRedis() {
        RedisTemplate template = new RedisTemplate<>();
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        template.setConnectionFactory(switchRedisMaster());
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(fastJsonRedisSerializer);
        return template;
    }

@Autowired
@Qualifier("switch_redis_master")
private RedisTemplate<String, Integer> redisTemplate;


private boolean invokeFrequencyValidate(String agentCode, Date checkInDate, Date checkOutDate) {
        int openingHotelNum = hotelService.getOpeningHotelNum();
        Date currentDate = new Date();
        // 16-90
        if (AbstractDateUtils.isAfter(checkInDate, AbstractDateUtils.getDeltaDateByDays(currentDate, 15))) {
            Integer count = redisTemplate.opsForValue().get(agentCode + "_" + SIXTEEN_TO_NINETY);
            if (count == null) {
                redisTemplate.opsForValue().set(agentCode + "_" + SIXTEEN_TO_NINETY, 1, TIME_PERIOD_THREE, TimeUnit.MINUTES);
                return true;
            }
            if (count >= maxQueryBase + openingHotelNum / FIFTEEN_OUTER_DIVIDED) {
                return false;
            }
            return true;
        }

CrudRepository Insert Operation

  @Autowired
    private SearchRepository searchRepository;

    public SearchData save(SearchData googleSearch) {        
        return searchRepository.save(googleSearch);
    }

Select Operation

private List<RoomShareUsedCountEntity> calculateRoomShareUsedCountWithType(StandardRoomWithTypeRequest standardRoomWithTypeRequest) {
        List<String> validDateList = calculateAllKeyDate(standardRoomWithTypeRequest.getCheckInDate(), standardRoomWithTypeRequest.getCheckOutDate());
        List<String> fullKey = Lists.newArrayList();

        List<UsedShareRoomCount> allUsedShareRoomCountList = Lists.newArrayList();
        for (String key : fullKey) {
            List<UsedShareRoomCount> value = (List<UsedShareRoomCount>) usedShareRoomCountSlaveRedisTemplate.opsForValue().get(key);
        }
        if (CollectionUtils.isEmpty(allUsedShareRoomCountList)) {
            return Lists.newArrayList();
        }
        return convert2RoomShareUsedCountEntityFromUsedShareCount(allUsedShareRoomCountList);
    }

CrudRepository Select Operation

  @Autowired
    private SearchRepository searchRepository;

    public Optional<SearchData> find(String id) {
       return searchRepository.findById(id);
    }

Update Operation

private boolean invokeFrequencyValidate(String agentCode, Date checkInDate, Date checkOutDate) {

        int openingHotelNum = hotelService.getOpeningHotelNum();
        Date currentDate = new Date();
        // 16-90
        if (AbstractDateUtils.isAfter(checkInDate, AbstractDateUtils.getDeltaDateByDays(currentDate, 15))) {
            Integer count = redisTemplate.opsForValue().get(agentCode + "_" + SIXTEEN_TO_NINETY);
            if (count == null) {
                redisTemplate.opsForValue().set(agentCode + "_" + SIXTEEN_TO_NINETY, 1, TIME_PERIOD_THREE, TimeUnit.MINUTES);
                return true;
            }
            if (count >= maxQueryBase + openingHotelNum / FIFTEEN_OUTER_DIVIDED) {
                return false;
            }
            redisTemplate.opsForValue().increment(agentCode + "_" + SIXTEEN_TO_NINETY, 1);
            return true;
        }

Delete Operation

public void delete(String key) {
        template.opsForValue().getOperations().delete(key);
    }

CrudRepository Delete Operation

  @Autowired
    private SearchRepository searchRepository;

    public Optional<SearchData> delete(String id) {
        return searchRepository.deleteById(id);
    }

Known Limitations

  • Unknown Redis connection/collection objects are created in case of unresolved names.