복붙노트

[REDIS] 왜 데이터는 봄 데이터와 Jedis를 사용하여 레디 스에서 이상한 키와 함께 저장지고?

REDIS

왜 데이터는 봄 데이터와 Jedis를 사용하여 레디 스에서 이상한 키와 함께 저장지고?

나는 Jedis와 봄 데이터 레디 스를 사용하고 있습니다. $ {list_id로} : 나는 키 VC와 해시를 저장하기 위해 노력하고 있습니다. 나는 성공적 레디 스에 삽입 할 수 있었다. 501381 : 나는 레디 스-CLI를 사용하여 키를 검사 할 때, 나는 키 VC가 표시되지 않습니다. 대신에 나는 \ XAC \ 고정 된 \ x00부터 \ x05t \ x00부터 \ TVC 참조 : 501381는.

왜 이런 일이며 어떻게이 변경합니까?

해결법

  1. ==============================

    1.좋아, 잠시 동안 인터넷 검색 및 http://java.dzone.com/articles/spring-data-redis에 도움을 발견했다.

    좋아, 잠시 동안 인터넷 검색 및 http://java.dzone.com/articles/spring-data-redis에 도움을 발견했다.

    이 때문에 자바 직렬화의 일어났다.

    redisTemplate의 키 시리얼 이렇게 StringRedisSerializer 즉하도록 구성되어야 :

    <bean 
        id="jedisConnectionFactory" 
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" 
        p:host-name="${redis.server}" 
        p:port="${redis.port}" 
        p:use-pool="true"/>
    
    <bean 
        id="stringRedisSerializer" 
        class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
    
    <bean 
        id="redisTemplate" 
        class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory" 
        p:keySerializer-ref="stringRedisSerializer"
        p:hashKeySerializer-ref="stringRedisSerializer" 
    />
    

    이제 레디 스의 핵심은 VC입니다 : 501381.

    @niconic 말씀처럼 또는 다음과 같이, 우리는 또한 문자열 시리얼에 기본 시리얼 자체를 설정할 수 있습니다 :

    <bean 
        id="redisTemplate" 
        class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory" 
        p:defaultSerializer-ref="stringRedisSerializer"
    />
    

    이는 우리의 모든 키와 값은 문자열을 의미합니다. 당신이 당신의 값이 아니라 문자열로 할 수 있기 때문에주의 그러나 이것은 바람직하지 않을 수있다.

    당신의 값이 도메인 객체 인 경우에, 당신은 잭슨 시리얼을 사용할 수 있으며 다음과 같이 여기 즉 언급 한 바와 같이 시리얼 라이저를 구성 :

    <bean id="userJsonRedisSerializer" class="org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer">
        <constructor-arg type="java.lang.Class" value="com.mycompany.redis.domain.User"/>
    </bean>
    

    당신의 템플릿으로 구성 :

    <bean 
        id="redisTemplate" 
        class="org.springframework.data.redis.core.RedisTemplate"
        p:connection-factory-ref="jedisConnectionFactory" 
        p:keySerializer-ref="stringRedisSerializer"
        p:hashKeySerializer-ref="stringRedisSerializer" 
        p:valueSerialier-ref="userJsonRedisSerializer"
    />
    
  2. ==============================

    2.StringRedisTemplate 사용 RedisTemplate을 대체한다.

    StringRedisTemplate 사용 RedisTemplate을 대체한다.

    기본적으로 RedisTemplate는 자바 직렬화를 사용 StringRedisTemplate는 StringRedisSerializer를 사용합니다.

    <bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="jedisConnectionFactory" />
    </bean>
    
  3. ==============================

    3.나는이 질문에 잠시왔다 알고 있지만,이 "반 해시"키가 여기에 스프링 소스 코드의 일부를 통해 이동하여 생성 어떻게 공유하고 싶은, 그래서 나는 다시 최근에이 주제에 대한 몇 가지 조사를했다.

    나는이 질문에 잠시왔다 알고 있지만,이 "반 해시"키가 여기에 스프링 소스 코드의 일부를 통해 이동하여 생성 어떻게 공유하고 싶은, 그래서 나는 다시 최근에이 주제에 대한 몇 가지 조사를했다.

    우선, 봄 @Cacheable, @CacheEvict 또는 @CachePut 등 조언 클래스 (스프링 상황에서도) CacheAspectSupport의 하위 클래스 스프링 컨텍스트 의존에서 CacheInterceptor입니다 같은 해결 주석에 AOP를 활용합니다. 이 설명의 편의를 위해, 나는 여기에 소스 코드의 일부를 통해 이동하는 예로서 @Cacheable을 사용합니다.

    @Cacheable로 주석 메소드가 호출 될 때,이 방법 AOP겠습니까 경로는 <컬렉션을 보호? 그것은이 @Cacheable 주석을 해결하는 것입니다있는 CacheAspectSupport 클래스에서 캐시> getCaches (CacheOperationInvocationContext 컨텍스트, CacheResolver cacheResolver)을 확장합니다. 차례로, 그것은 구현 CacheManager에서이 방법을 공개 캐시 getCache (문자열 이름)의 호출로 연결됩니다. 이 설명은 구현 CacheManage는 (에서 의존성을 봄 - 데이터 - 레디 스) RedisCacheManager 될 것이다.

    캐시가 명중되지 않은 경우, 그것은 캐시를 만들 진행됩니다. 아래 RedisCacheManager에서 키 방법입니다 :

    protected Cache getMissingCache(String name) {
        return this.dynamic ? createCache(name) : null;
    }
    
    @SuppressWarnings("unchecked")
    protected RedisCache createCache(String cacheName) {
        long expiration = computeExpiration(cacheName);
        return new RedisCache(cacheName, (usePrefix ? cachePrefix.prefix(cacheName) : null), redisOperations, expiration,
                cacheNullValues);
    }
    

    본질적으로, 그것은 RedisCache 객체를 생성합니다. 이 작업을 수행하기 위해, 즉 4 개 매개 변수를 필요 cacheName, 접두사 (false로 기본값), redisOperation (일명, 구성된 redisTemplate), 만료 (기본값 0)과 cacheNullValues ​​(문제는이 질문에 대답 관련하여 중요한 매개 변수) . 쇼 아래 생성자는 더 RedisCache에 대해 자세히 설명합니다.

    /**
     * Constructs a new {@link RedisCache} instance.
     *
     * @param name cache name
     * @param prefix must not be {@literal null} or empty.
     * @param redisOperations
     * @param expiration
     * @param allowNullValues
     * @since 1.8
     */
    public RedisCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations,
            long expiration, boolean allowNullValues) {
    
        super(allowNullValues);
    
        Assert.hasText(name, "CacheName must not be null or empty!");
    
        RedisSerializer<?> serializer = redisOperations.getValueSerializer() != null ? redisOperations.getValueSerializer()
                : (RedisSerializer<?>) new JdkSerializationRedisSerializer();
    
        this.cacheMetadata = new RedisCacheMetadata(name, prefix);
        this.cacheMetadata.setDefaultExpiration(expiration);
        this.redisOperations = redisOperations;
        this.cacheValueAccessor = new CacheValueAccessor(serializer);
    
        if (allowNullValues) {
    
            if (redisOperations.getValueSerializer() instanceof StringRedisSerializer
                    || redisOperations.getValueSerializer() instanceof GenericToStringSerializer
                    || redisOperations.getValueSerializer() instanceof JacksonJsonRedisSerializer
                    || redisOperations.getValueSerializer() instanceof Jackson2JsonRedisSerializer) {
                throw new IllegalArgumentException(String.format(
                        "Redis does not allow keys with null value ¯\\_(ツ)_/¯. "
                                + "The chosen %s does not support generic type handling and therefore cannot be used with allowNullValues enabled. "
                                + "Please use a different RedisSerializer or disable null value support.",
                        ClassUtils.getShortName(redisOperations.getValueSerializer().getClass())));
            }
        }
    }
    

    어떤이 RedisCache 접두사의 사용 그래서? ->가이 명령 this.cacheMetadata = 새로운 RedisCacheMetadata (이름, 접두어), 및 방송 아래 RedisCacheMetadata 생성자 자세한 사용된다 대한 생성자와 같이

    /**
         * @param cacheName must not be {@literal null} or empty.
         * @param keyPrefix can be {@literal null}.
         */
        public RedisCacheMetadata(String cacheName, byte[] keyPrefix) {
    
            Assert.hasText(cacheName, "CacheName must not be null or empty!");
            this.cacheName = cacheName;
            this.keyPrefix = keyPrefix;
    
            StringRedisSerializer stringSerializer = new StringRedisSerializer();
    
            // name of the set holding the keys
            this.setOfKnownKeys = usesKeyPrefix() ? new byte[] {} : stringSerializer.serialize(cacheName + "~keys");
            this.cacheLockName = stringSerializer.serialize(cacheName + "~lock");
        }
    

    이 시점에서 우리는 몇 가지 접두사 매개 변수가 RedisCacheMetadata로 설정되어 있는지 알고 있지만 정확히 어떻게 레디 스에서 키를 형성하기 위해 사용이 접두사 (예를 들어, \ XAC \ 고정 된 \ x00부터 \ x05t \ x00부터 \ TVC : 501381 당신이 언급 한 바와 같이) ?

    기본적 CacheInterceptor이어서 RedisOperation에서 RedisCacheMetadata 및 keySerializer에서 접두사를 사용함으로써 RedisCacheKey의 인스턴스를 반환 상술 RedisCache 객체의 메소드 RedisCacheKey getRedisCacheKey 개인 (개체 키)를 호출하기 위해 전진된다.

    private RedisCacheKey getRedisCacheKey(Object key) {
        return new RedisCacheKey(key).usePrefix(this.cacheMetadata.getKeyPrefix())
                .withKeySerializer(redisOperations.getKeySerializer());
    }
    

    이 점에 도달함으로써,이 CacheInterceptor의 조언 완료 "사전", 그리고 @Cacheable에 의해 주석이 실제 방법을 실행하기 앞서 갈 것입니다. 그리고 실제 방법의 실행을 완료 한 후, 그것은 본질적으로 RedisCache에 결과를 넣어 CacheInterceptor의 "POST"조언을 할 것입니다. 다음은 레디 스 캐시에 결과를 넣는 방법은 다음과 같습니다

    public void put(final Object key, final Object value) {
    
        put(new RedisCacheElement(getRedisCacheKey(key), toStoreValue(value))
                .expireAfter(cacheMetadata.getDefaultExpiration()));
    }
    
    /**
     * Add the element by adding {@link RedisCacheElement#get()} at {@link RedisCacheElement#getKeyBytes()}. If the cache
     * previously contained a mapping for this {@link RedisCacheElement#getKeyBytes()}, the old value is replaced by
     * {@link RedisCacheElement#get()}.
     *
     * @param element must not be {@literal null}.
     * @since 1.5
     */
    public void put(RedisCacheElement element) {
    
        Assert.notNull(element, "Element must not be null!");
    
        redisOperations
                .execute(new RedisCachePutCallback(new BinaryRedisCacheElement(element, cacheValueAccessor), cacheMetadata));
    }
    

    RedisCachePutCallback 개체 내에서 실제로 호출 방법 콜백 방법 doInRedis ()는 레디 스의 실제 키를 형성하고, 상기 방법 이름 RedisCacheKey 인스턴스에서 getKeyBytes ()이다. 이 방법의 세부 사항은 쇼 아래 :

    /**
     * Get the {@link Byte} representation of the given key element using prefix if available.
     */
    public byte[] getKeyBytes() {
    
        byte[] rawKey = serializeKeyElement();
        if (!hasPrefix()) {
            return rawKey;
        }
    
        byte[] prefixedKey = Arrays.copyOf(prefix, prefix.length + rawKey.length);
        System.arraycopy(rawKey, 0, prefixedKey, prefix.length, rawKey.length);
    
        return prefixedKey;
    }
    

    우리가 getKeyBytes 방법에서 볼 수 있듯이, 그것은 모두 원시 키 (VC를 : 귀하의 경우 501,381)를 사용하고 접두사 키 (\ XAC \ 고정 된 \ x00부터 \ x05t \ x00부터 \ t를 귀하의 경우).

  4. ==============================

    4.그것은 매우 오래된 질문이다,하지만 내 대답은 봄 부팅을 사용하여 레디 스 작업하는 동안 동일한 문제를 가지고 누군가를 위해 도움이 될 수 있습니다. 레디 스에서 해시 유형의 데이터를 저장하는 동안이 같은 문제에 붙어 있었다. 나는 RedisTemplate에 필요한 구성 파일 변경 사항을 작성했습니다.

    그것은 매우 오래된 질문이다,하지만 내 대답은 봄 부팅을 사용하여 레디 스 작업하는 동안 동일한 문제를 가지고 누군가를 위해 도움이 될 수 있습니다. 레디 스에서 해시 유형의 데이터를 저장하는 동안이 같은 문제에 붙어 있었다. 나는 RedisTemplate에 필요한 구성 파일 변경 사항을 작성했습니다.

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    @ComponentScan(basePackages = "com.redis")
    public class AppCofiguration {
    
        @Bean
        JedisConnectionFactory jedisConnectionFactory() {
            JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
            jedisConFactory.setHostName("127.0.0.1");
            jedisConFactory.setPort(6379);
            return jedisConFactory;
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate() {
            final RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
            template.setConnectionFactory(jedisConnectionFactory());
            template.setKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new StringRedisSerializer());
    
            // the following is not required      
            template.setHashValueSerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
    
            return template;
        }
    
    }
    

    데이터 유형이 문자열 다음 template.setHashValueSerializer 경우 (새 StringRedisSerializer ()); 및 template.setHashKeySerializer (새 StringRedisSerializer ()); 필요하지 않습니다.

  5. ==============================

    5.당신은 당신이 레디 스에 보내는 것을 TEH 객체를 직렬화해야합니다. 다음은 그것의 완전한 실행 예이다. 그것은 직렬화로 DomainObject 인터페이스 사용

    당신은 당신이 레디 스에 보내는 것을 TEH 객체를 직렬화해야합니다. 다음은 그것의 완전한 실행 예이다. 그것은 직렬화로 DomainObject 인터페이스 사용

    다음 단계는

    1) 다음 항아리로 받는다는의 pom.xml을

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
    
        <dependency>
               <groupId>org.springframework.data</groupId>
               <artifactId>spring-data-redis</artifactId>
               <version>1.3.0.RELEASE</version>
            </dependency>
    
                <dependency>
                   <groupId>redis.clients</groupId>
                   <artifactId>jedis</artifactId>
                   <version>2.4.1</version>
                </dependency>
    
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.0</version>
        </dependency>
    

    다음과 같이 2) 구성 XML을

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p"
            xmlns:c="http://www.springframework.org/schema/c"
            xmlns:cache="http://www.springframework.org/schema/cache"
        xsi:schemaLocation="
            http://www.springframework.org/schema/beans     
            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/context 
            http://www.springframework.org/schema/context/spring-context-3.0.xsd
    
            http://www.springframework.org/schema/cache 
            http://www.springframework.org/schema/cache/spring-cache.xsd">
    
    
    
        <bean id="jeidsConnectionFactory"
          class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          p:host-name="localhost" p:port="6379" p:password="" />
    
         <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
          p:connection-factory-ref="jeidsConnectionFactory" />
    
         <bean id="imageRepository" class="com.self.common.api.poc.ImageRepository">
          <property name="redisTemplate" ref="redisTemplate"/>
         </bean>
    
    </beans>
    

    다음과 같이 3) 클래스를 확인

    package com.self.common.api.poc;
    
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    
    import javax.imageio.ImageIO;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    import sun.misc.BASE64Decoder;
    import sun.misc.BASE64Encoder;
    
    public class RedisMainApp {
    
     public static void main(String[] args) throws IOException {
      ApplicationContext applicationContext = new ClassPathXmlApplicationContext("mvc-dispatcher-servlet.xml");
      ImageRepository imageRepository = (ImageRepository) applicationContext.getBean("imageRepository");
    
      BufferedImage img = ImageIO.read(new File("files/img/TestImage.png"));
      BufferedImage newImg;
      String imagestr;
      imagestr = encodeToString(img, "png");
      Image image1 = new Image("1", imagestr);
    
      img = ImageIO.read(new File("files/img/TestImage2.png"));
      imagestr = encodeToString(img, "png");
      Image image2 = new Image("2", imagestr);
    
      imageRepository.put(image1);
      System.out.println(" Step 1 output : " + imageRepository.getObjects());
      imageRepository.put(image2);
      System.out.println(" Step 2 output : " + imageRepository.getObjects());
      imageRepository.delete(image1);
      System.out.println(" Step 3 output : " + imageRepository.getObjects());
    
     }
    
     /**
      * Decode string to image
      * @param imageString The string to decode
      * @return decoded image
      */
     public static BufferedImage decodeToImage(String imageString) {
    
         BufferedImage image = null;
         byte[] imageByte;
         try {
             BASE64Decoder decoder = new BASE64Decoder();
             imageByte = decoder.decodeBuffer(imageString);
             ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
             image = ImageIO.read(bis);
             bis.close();
         } catch (Exception e) {
             e.printStackTrace();
         }
         return image;
     }
    
     /**
      * Encode image to string
      * @param image The image to encode
      * @param type jpeg, bmp, ...
      * @return encoded string
      */
     public static String encodeToString(BufferedImage image, String type) {
         String imageString = null;
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
    
         try {
             ImageIO.write(image, type, bos);
             byte[] imageBytes = bos.toByteArray();
    
             BASE64Encoder encoder = new BASE64Encoder();
             imageString = encoder.encode(imageBytes);
    
             bos.close();
         } catch (IOException e) {
             e.printStackTrace();
         }
         return imageString;
     }
    }
    
    package com.self.common.api.poc;
    
    public class Image implements DomainObject {
    
     public static final String OBJECT_KEY = "IMAGE";
    
     public Image() {
     }
    
     public Image(String imageId, String imageAsStringBase64){
      this.imageId = imageId;
      this.imageAsStringBase64 = imageAsStringBase64;
     }
     private String imageId;
     private String imageAsStringBase64;
    
     public String getImageId() {
      return imageId;
     }
    
     public void setImageId(String imageId) {
      this.imageId = imageId;
     }
    
     public String getImageName() {
      return imageAsStringBase64;
     }
    
     public void setImageName(String imageAsStringBase64) {
      this.imageAsStringBase64 = imageAsStringBase64;
     }
    
     @Override
     public String toString() {
      return "User [id=" + imageAsStringBase64 + ", imageAsBase64String=" + imageAsStringBase64 + "]";
     }
    
     @Override
     public String getKey() {
      return getImageId();
     }
    
     @Override
     public String getObjectKey() {
      return OBJECT_KEY;
     }
    }
    
    package com.self.common.api.poc;
    
    import java.io.Serializable;
    
    public interface DomainObject extends Serializable {
    
     String getKey();
    
     String getObjectKey();
    }
    
    package com.self.common.api.poc;
    
    import java.util.List;
    
    import com.self.common.api.poc.DomainObject;
    
    public interface Repository<V extends DomainObject> {
    
     void put(V obj);
    
     V get(V key);
    
     void delete(V key);
    
     List<V> getObjects();
    }
    
    package com.self.common.api.poc;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import com.self.common.api.poc.DomainObject;
    
    public class ImageRepository implements Repository<Image>{
    
     @Autowired
     private RedisTemplate<String,Image> redisTemplate;
    
     public RedisTemplate<String,Image> getRedisTemplate() {
      return redisTemplate;
     }
    
     public void setRedisTemplate(RedisTemplate<String,Image> redisTemplate) {
      this.redisTemplate = redisTemplate;
     }
    
     @Override
     public void put(Image image) {
      redisTemplate.opsForHash()
        .put(image.getObjectKey(), image.getKey(), image);
     }
    
     @Override
     public void delete(Image key) {
      redisTemplate.opsForHash().delete(key.getObjectKey(), key.getKey());
     }
    
     @Override
     public Image get(Image key) {
      return (Image) redisTemplate.opsForHash().get(key.getObjectKey(),
        key.getKey());
     }
    
     @Override
     public List<Image> getObjects() {
      List<Image> users = new ArrayList<Image>();
      for (Object user : redisTemplate.opsForHash().values(Image.OBJECT_KEY) ){
       users.add((Image) user);
      }
      return users;
     }
    
    }
    

    당신이 볼 수 sprinf jedis에 대한 자세한 참고로 http://www.javacodegeeks.com/2012/06/using-redis-with-spring.html

    샘플 코드는 http://javakart.blogspot.in/2012/12/spring-data-redis-hello-world-example.html에서 가져옵니다

  6. from https://stackoverflow.com/questions/13215024/why-is-data-getting-stored-with-weird-keys-in-redis-when-using-jedis-with-spring by cc-by-sa and MIT license