머리말
스프링은 Redis를 쉽게 사용할 수 있도록 비교적 강력한 템플릿을 캡슐화합니다. 나는 이전에 Spring Ecosystem에서 Redis를 사용했지만 해당 상호 작용에 직접 Jedis를 사용했습니다. 이제 RedistemPlate이 구현되는 방법과 사용이 더 편리한 지 살펴 보겠습니다.
Jedis는 여전히 연결 수영장 관리에 사용되므로 Spring-Data-Redis와 Jedis 의존성을 소개하는 것 외에도 POM 파일을 추가하십시오.
<pectionency> <groupId> org.springframework.data </groupid> <artifactid> Spring-Data-Redis </artifactid> <버전> 1.8.4. 4. release </version> </fectionency> <groupID> redis.clients </groupid> <artifactid> jedis </arepifactid> 2.9.0 </version> 2.9.0
직렬화 관련 매개 변수를 지정 해야하는 경우 Jackson도 소개 할 수도 있습니다. 이 기사는 간단한 엔트리 레벨이므로 추가하지 않을 것입니다.
Redis 관련 구성 매개 변수를 준비하십시오. 일반적인 것들은 호스트, 포트, 암호, 시간 초과를 포함합니다 .... 다음은 간단한 구성이며 해당 의미를 제공합니다.
redis.hostname = 127.0.0.1redis.port = 6379redis.password = https : //blog.hhui.top# connection redis.timeout = 100000#최대 공회전 번호 redis.maxidle = 300#maxIdles 인스턴스는 풀에 대해 풀을 대체하기 위해 풀에 할 수 있습니다. Jedis 2.4 인 경우이 속성을 사용하여 redis.maxtotal = 1000#최대 연결 설정 대기 시간에 사용하십시오. 이 시간 이이 시간을 초과하면 예외가 접수됩니다. -1로 설정하면 제한이 없습니다. redis.maxwaitmillis = 1000#연결의 최소 유휴 시간은 기본 18000000ms (30 분) redis.minevictableDletimemillis = 300000#매번 릴리스됩니다. 기본값 3Redis.NumtestSpereVictionRun = 1024#evicting scal의 시간 간격이 아닌 경우 (MS) evicting이 아닌 경우. Default -1redis.timebetweenevictionRunsmillis = 30000# 풀에서 연결을 제거하기 전에 확인 해야하는지 여부, 확인이 실패하면 풀에서 연결을 제거하고 다른 redis.testonborring = true# 유휴 상태에서 유효성을 확인하십시오.
설명
특히 원격 액세스를 허용 할 때 Redis 비밀번호를 설정해야합니다. 비밀번호가없는 경우 기본 포트 번호가 쉽게 스캔되어 스크립트에 주입 된 다음 사람들을위한 채굴을 시작합니다 (개인 경험 ...)
일반적인 아이디어에 따르면 먼저 위의 구성을로드하고 Redis 연결 풀을 작성한 다음 RedistemPlate 객체를 인스턴스화 한 다음 다양한 읽기 및 쓰기 작업을 시작하기 위해이 강점을 유지해야합니다.
javaconfig를 사용하여 주로 두 개의 콩, 구성 파일을 읽으려면 다양한 매개 변수를 설정하고 예상되는 Redistemplate을 구성하십시오.
@configuration @propertySource ( "classpath : redis.properties") public class readisconfig는 jcacheconfigurersupport {@autowired 개인 환경 환경; @bean public readisconnectionfactory readisconnectionfactory () {jedisconnectionfactory fac = new jedisconnectionfactory (); fac.sethostName (Environment.GetProperty ( "redis.hostName")); fac.setport (integer.parseint (Environment.getProperty ( "redis.port"))); fac.setpassword (Environment.getProperty ( "redis.password")); fac.settimeout (integer.parseint (Environment.getProperty ( "redis.timeout"))); fac.getPoolConfig (). setMaxIdle (integer.parseint (Environment.getProperty ( "redis.maxidle"))); fac.getPoolConfig (). setMaxtotal (integer.parseint (환경 .getProperty ( "redis.maxtotal"))); fac.getPoolConfig (). SetMaxWaitMillis (integer.parseint (Environment.getProperty ( "redis.maxwaitmillis"))); fac.getPoolConfig (). setMineVictableDletimemillis (integer.parseint (환경 .getProperty ( "redis.mineVictableDletimemillis"))); fac.getPoolConfig ())))))); fac.getPoolConfig (). setMineVictableDleTletimEmillis (integer.parseint ( "redis.minevictableDletimemillis")); fac.getPoolConfig () .SetNumtestSpereVictionRun (integer.parseint (Environment.getProperty ( "redis.numtestsperevictionRun")); settimebetweenevictionRunsmillis (integer.parseint.getProperty ( "redis.getBetweenvictionruns millis"); fac.getpoolconfig (). getestonbory (boolean.getproperty ( "redis.testonborry") redistemplate (rediscontory redistemplate <>); @RunWith (SpringJunit4classRunner.class) @ContextConfiguration (classs = {readisconfig.class}) public class redistest {@autowired private redistemplate <string, String> redistemplate; @test public void testredisobj () {map <string, object> properties = new Hashmap <> (); properties.put ( "123", "hello"); 속성 .put ( "ABC", 456); redistemplate.opsforhash (). putall ( "Hash", Properties); Map <Object, Object> ans = redistemplate.opsforhash (). entries ( "hash"); System.out.println ( "ans :" + ans); }}실행 후 출력은 다음과 같습니다
ANS : {123 = 안녕하세요, ABC = 456}위의 구성 및 구현에서 판단하면 매우 간단합니다. 기본적으로 원이 없지만 Redis-Cli와 연결하면 해시 키의 내용을 쿼리 할 수 없습니다.
127.0.0.1:6379> HASH (NIL) 127.0.0.1:6379> 키 *1) "/XAC/XAC/XED/x00/X05T/X00/X04HASH"
코드를 사용하여 체크 아웃하는 데 아무런 문제가 없습니다. 콘솔을 직접 연결 하여이 키가 우리가 기대했던 것과 다르며, 접두사가있는 이유는 무엇입니까?
위의 문제를 해결하기 위해서는 디버깅하고 원인을 볼 수 있습니다.
해당 소스 코드 위치 :
// org.springframework.data.redis.core.abtractoperations#rawkeybyte [] rawkey (객체 키) {assert.notnull (키, "null 키가 필요하지 않은"); reture this.keyserializer () == null && key instancof byte []? (byte []) ((byte []) 키) : this.keyserializer (). serialize (key);}이 키가 Key.getBytes ()가 예상 한 것이 아니라 this.keyserializer (). Serialize (키)가 호출된다는 것을 알 수 있습니다. 디버깅의 결과는 기본 세리어 라이저가 jdkserializationredisserializer라는 것입니다.
그런 다음 단서를 따르고 단계별로 더 깊이 가십시오. 링크는 다음과 같습니다.
// org.springframework.core.serializer.serializingconverter#convert // org.springframework.core.serializer.defaultserializer#serializepublic class defaultserializer는 serializer <object> {public defaultserializer () void serialize (대상, outprestrowestrement)를 구현합니다. {if (! (Serializeable의 객체 인스턴스)). } else {ObjectOutputStream ObjectOutputStream = new ObjectOutputStream (outputStream); ObjectOutputStream.writeObject (Object); ObjectOutputStream.flush (); }}}따라서 특정 구현은 매우 명확하며 이는 ObjectOutputStream입니다. 이것은 Java에서 가장 원시적 인 직렬화 된 사산 스트리밍 도구입니다. 유형 정보가 포함되어 있으므로 접두사가 장착됩니다.
따라서이 문제를 해결하기 위해 더 명확합니다. 기본 jdkserializationredisserializer를 교체하여 String으로 변경하여 StringRedisserializer 만 제공하여 RedistemPlate의 구성에서 약간 수정하십시오.
@BeanPublic redistemplate <string, String> redistemplate (RediscOntectionFactory readiscOntectionFactory) {redistemplate <String, String> redis = new redistemplate <> (); redis.setConnectionFactory (readisconnectionFactory); // redis string/value stringserializer stringSredisserializer = new StringRedisserializer ()의 기본 직렬화 방법을 설정합니다. Redis.setKeyserializer (StringRedisserializer); Redis.setValueserializer (StringRedisserializer); redis.sethashkeyserializer (StringRedisserializer); Redis.SethashValueserializer (StringRedisserializer); redis.fterpropertiesset (); RECLES REDIS;}다시 실행하고 당황스러운 일이 일어 났고 예외가 발생했으며 유형 변환이 실패했습니다.
java.lang.classcastException : java.lang.integer는 org.springframework.data.serializer.stringredisserializer.serialize at at at at at at org.springframework.data.redis.core.abstractoperations.rawhashvalue (AbstractOperations.java:171) org.springframework.data.redis.defaulthashoperations.putall (defaulthashoperations.java:129) ...
이전 테스트 사례를 살펴보면 맵의 값에는 정수가 있고 StringRedisserializer가 수신 한 매개 변수는 String이어야하므로 사용하지 마십시오. 여전히 호환되는 것을 작성합니다.
공개 클래스 defaultstrserializer는 Redisserializer <botor> {Private Final Charset Charset을 구현합니다. public defaultstrserializer () {this (charset.forname ( "utf8")); } public defaultstrserializer (charset charset) {assert.notnull (charset, "charset은 null!"); this.charset = charset; } @override public byte [] Serialize (Object O)는 SerializationException {return o == null? null : string.valueof (o) .getBytes (charset); } @Override public object deserialize (byte [] bytes) serializationException {return bytes == null? NULL : 새 문자열 (바이트, 숯); }}그런 다음 실행 후 재미와 테스트를 시작할 수 있습니다.
키 *1) "/xac/xed/x00/x05t/x04hash"2) "Hash"127.0.0.1:6379> Hgetall Hash1) "123"2) "hello"3) "ABC"4) "456"
Redistemplate의 사용 자세를 간단히보고 다른 데이터 구조 (String, List, ZSET, HASH)에 대해 OpsForXXX가 사용하는 호출 방법을 읽고 캡슐화 해 봅시다.
// 해시 데이터 구조 작업 org.springframework.data.redis.core.redistemplate#opsforhash // istorg.springframework.data.redis.core.redistemplate#opsforlist // stringorg.springframework.data.redis.core.redistemplate // setorg.springframework.data.redis.core.redistemplate#opsforzset
위의 사용법 외에도 다른 일반적인 방법은 직접 실행하는 방법입니다. 간단한 경우는 다음과 같습니다
@testpublic void testredis () {String key = "hello"; 문자열 값 = "세계"; redistemplate.execute (((readiscallback <void>) con-> {con.set (key.getBytes (), value.getBytes ()); return null;}); 문자열 ASN = redistemplate.execute ((readiscallback <string>) con-> new String (con.get (key.getBytes ())); System.out.println (ASN); 문자열 hkey = "hkey"; redistemplate.execute (((readiscallback <void>) con-> {con.hset (hkey.getBytes (), "23".getBytes (), "what".getBytes ()); return null;}); map <byte [], byte []> map = redistemplate.execute ((readiscallback <map <byte [], byte []>) con-> con.hgetall (hkey.getBytes ())); for (map.Entry <byte [], byte [] >> entry : map.entryset ()) {system.out.println ( "key :" + new String (enther.getKey ()) + "| value :" + new String (enther.getValue ()); }}출력 결과는 다음과 같습니다
세계
키 : 23 | 가치 : 뭐
자연스럽게 생각할 수있는 질문은 위의 두 방법의 차이점은 무엇입니까?
OpsForXXX의 기본 층은 Execute를 호출하여 수행됩니다. 주로 일부 사용 자세를 캡슐화하고 직렬화를 정의하여 사용하기가 더 쉽고 편리합니다. 이런 식으로 작은 트럼펫은 매번 새로운 기본 XXXXOPERATIONS 객체를 만들어야하며 한 걸음 더 걸립니다. 이를 바탕으로 추가 성능과 메모리 오버 헤드를 가져올 것인가? 나는 그것을 테스트하지 않았지만 개인적으로 그 금액이 작으며 명백한 영향은 없어야합니다. 그리고 QP가 매우 높을 때,이 편리한 최적화가 가져올 수있는 도움은 아마 그리 많지 않을 것입니다.
연구 데모/스프링 레디스
위는이 기사의 전체 내용입니다. 이 기사의 내용에 모든 사람의 연구 나 작업에 대한 특정 참조 가치가 있기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다. Wulin.com을 지원 해주셔서 감사합니다.