Prefacio
Spring encapsula una plantilla relativamente potente para su uso fácil en el uso de Redis; Utilicé Redis en el ecosistema de primavera antes, pero utilicé directamente JEDIS para las interacciones correspondientes. Ahora echemos un vistazo a cómo se implementa redistemplate y si es más conveniente de usar.
JEDIS todavía se usa para la gestión del grupo de conexión, por lo que además de introducir Data-Redis de Spring, más dependencias de JEDIS, agregue el archivo POM
<Spendency> <MoupRoMID> org.springframework.data </groupid> <artifactid> spring-data-redis </arfactid> <verserse> 1.8.4.release </verversion> </dependency> <epardency> <proupid> redis.clients </groupid> <artifactid> jédis </artifactid> <versers
Si necesita especificar parámetros relacionados con la serialización, también puede introducir Jackson. Este artículo es simple de nivel de entrada, por lo que no agregará esto
Prepare los parámetros de configuración relacionados con Redis, los comunes incluyen host, puerto, contraseña, tiempo de espera ... la siguiente es una configuración simple y ofrece los significados correspondientes.
redis.hostName = 127.0.0.1redis.port = 6379Redis.password = https: //blog.hhui.top# timeout de conexión redis.timeout = 10000#número de inactividad máximo redis.maxidle = 300#controla cuántas instancias de JEDIS se pueden asignar para reemplazar el reemplazo anterior Redis.maxactive. Si es JEDIS 2.4, use esta propiedad a Redis.MaxToTal = 1000#Tiempo de espera de establecimiento de conexión máxima. Si este tiempo excede esta vez, se recibirá una excepción. Establecido en -1 significa que no hay límite. redis.maxwaitmillis = 1000#El tiempo mínimo de conexión inactivo de la conexión es predeterminado 1800000000ms (30 minutos) Redis.MineVictableIdLetImillis = 300000#El número máximo de conexiones se libera cada vez, predeterminado 3Redis.numTestsPerevictrun = 1024#El intervalo de tiempo para evitar el escaneo (MS) si es negativo, el hilo evicional no se ejecuta. Predeterminado -1redis.timebetweenEvictionRunsmillis = 30000# si se debe verificar antes de eliminar la conexión del grupo, si la verificación falla, elimine la conexión del grupo e intente eliminar otro redis.testonborrow = verdadero# verificar la validez cuando inactividad, falla predeterminada.testHhileDle = true = true = true = true.
ilustrar
Recuerde establecer la contraseña de Redis, especialmente al permitir el acceso remoto. Si no tiene una contraseña, el número de puerto predeterminado se escaneará e inyectará fácilmente en el script, y luego comenzará a extraer para personas (experiencia personal ...)
Según la idea general, primero, debe cargar la configuración anterior, crear un grupo de conexión Redis, luego instanciar el objeto Redistemplate y finalmente mantener esta fuerza para iniciar varias operaciones de lectura y escritura
Use Javaconfig para configurar, principalmente dos frijoles, leer el archivo de configuración para establecer varios parámetros y la implementación redistente esperada
@Configuration @PropertySource ("classpath: redis.properties") public class Redisconfig extiende jcacheconfigurersupport {@aUtowired private entorno privado; @Bean public redisConnectionFactory redisConnectionFactory () {JEDISCONNECTIONFACTORY fac = new JEdisconnectionFactory (); fac.SetHostName (ambiente.getProperty ("redis.hostname")); fac.setport (Integer.ParseInt (Environment.getProperty ("Redis.port"))); fac.setpassword (entorno.getproperty ("redis.password")); fac.SetTimeOut (Integer.ParseInt (Environment.getProperty ("Redis.TimeOut"))); fac.getPoolConfig (). SetMaxidle (Integer.ParseInt (Environment.getProperty ("Redis.maxidle")); fac.getPoolConfig (). SetMaTtotal (Integer.ParseInt (Environment.getProperty ("Redis.MaxToTal"))); fac.getPoolConfig (). SetMaxWaitMillis (Integer.ParseInt (Environment.GetProperty ("Redis.maxWaitMillis"))); fac.getPoolConfig (). SetMinEvictableIdLetimEmillis (Integer.ParseInt (Environment.GetProperty ("Redis.MinevictableDletImemillis"))); fac.getPoolConfig (). SetMineVicTableDletImemillis "))); fac.getPoolConfig (). SetMinEvictableDetLetimillis (Integer.ParseInt (Environment.getProperty (" Redis.MinevictableDetLetimEmillis ")); Fac.GetPoolConfig () .SetNumTestSpereVictionRun (Integer.ParseInt (Environment.getProperty ("Redis.numTestsPerevictionRun")); fac.getPoolConfig (). SetTonBorrow (Boolean.ParseBoolean (Environdea.getProperty ("Redis.TestonBorrow")) String> Redistemplate (redisConnectionFactory RedisconnectionFactory) {Redistemplate <String, String> Redis = New Redistemplate <> (); @RunWith (SpringJunit4ClassRunner.class) @ContextConfiguration (classes = {redisConfig.class}) clase pública redistest {@aUtowired private redistemplate <string, string> redistemplate; @Test public void testRedisObj () {MAP <String, Object> Properties = new HashMap <> (); Properties.put ("123", "Hola"); Properties.put ("ABC", 456); redistemplate.opsforhash (). putall ("hash", propiedades); Mapa <objeto, objeto> ans = redistemplate.opsforhash (). Entradas ("hash"); System.out.println ("ANS:" + ANS); }}Después de la ejecución, la salida es la siguiente
Ans: {123 = Hello, ABC = 456}A juzgar por la configuración e implementación anterior, es muy simple. Básicamente no hay círculo alrededor, pero cuando lo conectas con Redis-Cli, no puedes consultar el contenido de la tecla hash
127.0.0.1:6379> Obtenga el hash (nulo) 127.0.0.1:6379> claves *1) "/xac/xed/x00/x05t/x00/x04hash"
No hay ningún problema para usar el código para verlo. Conecté directamente la consola y descubrí que esta clave es diferente de lo que esperábamos, con algunos prefijos, ¿por qué?
Para resolver el problema anterior, solo puedo depurarlo y ver qué lo causó.
Ubicación del código fuente correspondiente:
// org.springframework.data.redis.core.abstractOperations#rawkeyte [] rawkey (clave de objeto) {afirmo.notnull (clave, "requerida la clave no nula"); devuelve this.KeySerializer () == NULL && Key instancia de byte []? (byte []) ((byte []) clave): this.KeySerializer (). Serialize (clave);}Puede ver que esta clave no es la clave.getBytes () que esperamos, pero se llama a este.KeySerializer (). Serialize (clave). El resultado de la depuración es que el serializador predeterminado es JDKSerializationRedisSerializer.
Luego siga las pistas y avance más paso a paso, el enlace es el siguiente
// org.springframework.core.serializer.serializingConverter#convert // org.springframework.core.serializer.defaultSerializer#serializePublic class defaultserializer implementa serializer <ject> {public defaultSerializer () {} public void serializ (? } else {ObjectOutputStream ObjectOutputStream = new ObjectOutputStream (outputStream); ObjectOutputStream.WriteObject (objeto); ObjectOutputStream.Flush (); }}}Entonces, la implementación específica es muy clara, que es ObjectOutputStream. Esta cosa es la herramienta de transmisión deserial serializada más primitiva en Java. Contendrá información de tipo, por lo que estará equipado con el prefijo.
Entonces, para resolver este problema, es más claro. Reemplace el jdkserializationRediserializer nativo y cámbielo a la cadena, que solo proporciona un stringrediserializer, por lo que en la configuración de la plantilla redist.
@BeanPublic Redistemplate <String, String> redistemplate (redisConnectionFactory redisConnectionFactory) {redistemplate <string, string> redis = new Redistemplate <> (); redis.setConnectionFactory (redisConnectionFactory); // Establezca el método de serialización predeterminado de Redis String/Value StringRedisSerializer StringDredisSerializer = new StringRedisSerializer (); redis.setKeySerializer (stringRedisSerializer); redis.setValuueSerializer (stringRedisSerializer); redis.sethashkeyserializer (stringredisserializer); redis.sethashValuueSerializer (stringDredisSerializer); redis.AfterPropertiesSet (); devolver redis;}Ejecutar nuevamente, y lo vergonzoso sucedió, se lanzó la excepción y la conversión de tipo falló
java.lang.classcastException: java.lang.integer no se puede lanzar a java.lang.string en org.springframework.data.redis.serializer.stringredisserializer.serialize (stringredisserializer.java:33) AT org.springframework.data.redis.core.abstractOperations.rawhashvalue (abstractOperations.java:171) en org.springframework.data.redis.core.defaulthashoperations.putall (Defaulthashoperations.Java:129) ... ...
Mirando el caso de prueba anterior, el valor en el mapa tiene entero, y el parámetro recibido por StringRedisSerializer debe ser cadena, así que no use esto y aún así escribirá uno compatible.
Public Class DefaultStrserializer implementa RedisSerializer <ject> {Charset de charset final privado; public DefaultStrserializer () {this (charset.forname ("utf8")); } public DefaultStrserializer (Charset Charset) {ASSERT.NOTNULL (Charset, "Charset no debe ser nulo!"); this.charset = charset; } @Override public byte [] serialize (objeto o) arroja serializationException {return o == null? nulo: string.valueOf (o) .getBytes (charset); } @Override Public Object Deserialize (byte [] bytes) arroja SerializationException {return bytes == null? nulo: nueva cadena (bytes, charset); }}Entonces puede comenzar a divertirse y probar después de la ejecución
teclas *1) "/xac/xed/x00/x05t/x00/x04hash" 2) "hash" 127.0.0.1:6379> hgetall hash1) "123" 2) "hola" 3) "ABC" 4) "456"
Veamos brevemente la postura de uso de Redistemplate, y lea y encapsulemos el método de llamadas utilizado por OPSFORXXX para diferentes estructuras de datos (String, List, ZSet, Hash).
// Hash Estructura de datos Operación org.springframework.data.redis.core.redistemplate#opsforhash // listorg.springframework.data.redis.core.redistemplate#opsforlist setorg.springframework.data.redis.core.redistemplate#opsforzset
Además del método de uso anterior, otro común es usar ejecutar directamente. Un caso simple es el siguiente
@Testpublic void testredis () {string key = "hello"; Valor de cadena = "Mundo"; redistemplate.execute ((rediscallback <void>) con -> {con.set (key.getBytes (), value.getBytes ()); return null;}); String asn = redistemplate.execute ((rediscallback <string>) con -> new String (con.get (key.getBytes ())); System.out.println (ASN); Cadena HKEY = "HKEY"; redistemplate.execute ((rediscallback <void>) con -> {con.hset (hkey.getBytes (), "23" .getBytes (), "What" .getBytes ()); return null;}); Map <byte [], byte []> map = redistemplate.execute ((rediscallback <map <byte [], byte []>) con -> con.hgetall (hkey.getbytes ())); para (map.entry <byte [], byte [] >> Entry: map.entryset ()) {System.out.println ("Key:" + new String (Entry.getKey ()) + "| Valor:" + nueva cadena (Entry.getValue ())); }}El resultado de la salida es el siguiente
mundo
Clave: 23 | valor: que
Una pregunta que se puede pensar naturalmente es ¿cuál es la diferencia entre los dos métodos anteriores?
La capa subyacente de OPSFORXXX se realiza llamando a Execute. Encapsula principalmente algunas posturas de uso y define la serialización, lo que hace que sea más fácil y más conveniente de usar. De esta manera, la pequeña trompeta es que necesita crear un nuevo objeto predeterminadoxxxxperaciones cada vez, y toma un paso más. Según esto, ¿traerá un rendimiento adicional y gastos generales de memoria? No lo he probado, pero personalmente siento que la cantidad es pequeña, no debería haber un impacto obvio; Y cuando el QPS es muy alto, la ayuda que esta optimización conveniente puede traer probablemente no sea mucho.
Estudio-Demo/Spring-Redis
Lo anterior es todo el contenido de este artículo. Espero que el contenido de este artículo tenga cierto valor de referencia para el estudio o el trabajo de todos. Si tiene alguna pregunta, puede dejar un mensaje para comunicarse. Gracias por su apoyo a Wulin.com.