2012-06-21 22 views
6

Toda la configuración de Spring está escrita correctamente. Las operaciones Non-Multi-Exec Redis funcionan perfectamente.Cómo implementar Redis Multi-Exec mediante Spring-data-Redis

@Autowired 
@Qualifier("stringRedisTemplate") 
StringRedisTemplate template; 

void test(){ 
    template.multi(); 
    template.boundValueOps("somevkey").increment(1); 
    template.boundZSetOps("somezkey").add("zvalue", timestamp); 
    template.exec(); 
} 

Después de ejecutar el código anterior a través de Junit Test, se producen excepciones.

org.springframework.data.redis.RedisSystemException: Unknown exception; nested exception is org.springframework.data.redis.RedisSystemException: Unknown jedis exception; nested exception is java.lang.NullPointerException 
     at org.springframework.data.redis.connection.jedis.JedisUtils.convertJedisAccessException(JedisUtils.java:93) 
     at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.translateExceptionIfPossible(JedisConnectionFactory.java:155) 
     at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:58) 
     at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) 
     at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:163) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
     at $Proxy66.appendUserStream(Unknown Source) 
     at com.uniu.test.repository.StreamCacheRepositoryTest.testAppendUserStream(StreamCacheRepositoryTest.java:23) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) 
     at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) 
     at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) 
     at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) 
     at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) 
     at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74) 
     at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83) 
     at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72) 
     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49) 
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) 
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) 
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) 
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) 
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) 
     at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) 
     at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71) 
     at org.junit.runners.ParentRunner.run(ParentRunner.java:236) 
     at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174) 
     at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49) 
     at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) 
     at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197) 
    Caused by: org.springframework.data.redis.RedisSystemException: Unknown jedis exception; nested exception is java.lang.NullPointerException 
     at org.springframework.data.redis.connection.jedis.JedisConnection.convertJedisAccessException(JedisConnection.java:119) 
     at org.springframework.data.redis.connection.jedis.JedisConnection.exec(JedisConnection.java:523) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.springframework.data.redis.core.CloseSuppressingInvocationHandler.invoke(CloseSuppressingInvocationHandler.java:58) 
     at $Proxy70.exec(Unknown Source) 
     at org.springframework.data.redis.core.RedisTemplate$1.doInRedis(RedisTemplate.java:416) 
     at org.springframework.data.redis.core.RedisTemplate$1.doInRedis(RedisTemplate.java:412) 
     at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:162) 
     at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:133) 
     at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:121) 
     at org.springframework.data.redis.core.RedisTemplate.exec(RedisTemplate.java:412) 
     at com.uniu.repository.impl.StreamCacheRepositoryRedisImpl.appendUserStream(StreamCacheRepositoryRedisImpl.java:37) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:155) 
     ... 33 more 
    Caused by: java.lang.NullPointerException 
     at redis.clients.jedis.BinaryTransaction.exec(BinaryTransaction.java:31) 
     at org.springframework.data.redis.connection.jedis.JedisConnection.exec(JedisConnection.java:521) 
     ... 54 more 

Reviso el servidor redis, los dos comandos anteriores se han ejecutado y el resultado es correcto. Entonces, el problema viene en la última línea del código (template.exec()). Cuando JedisClient subyacente intenta obtener respuesta multibulk de EXEC, parece lanzar NullPointerException

Utilizo spring-data-redis 1.0.0.RELEASE Gracias por su ayuda.

Respuesta

8

El motivo de la excepción es probablemente que la implementación de la plantilla Spring no reutiliza la misma conexión para .multi() y .exec(). Puede intentar utilizar execute() a través de una devolución de llamada:

private RedisTemplate template = ...; 

template.execute(

    new RedisCallback() { 

    @Override 
    public Object doInRedis(RedisConnection connection) 
     throws DataAccessException { 

     connection.multi(); 

     //do whatever you need, like deleting and repopulating some keys 

     connection.expire(CHANNEL_KEY.getBytes(), EXPIRE_SECS); 
     connection.exec(); 
     return null; 
    } 

    } 

); 
+0

No creo que esto es cierto. Siempre que se llame al multi y al ejecutor a través de la misma fábrica y la transacción esté habilitada, cualquier llamada intermedia utilizará la misma conexión. Puedes ver desde RedisConnectionUtils – Olayinka

5
template.setEnableTransactionSupport(true); 

tal vez se puede permitir que el usuario esta transacción a