Multithreading 启用事务支持时,spring data redis连接是否未正确释放?

Multithreading 启用事务支持时,spring data redis连接是否未正确释放?,multithreading,transactions,redis,spring-data,spring-data-redis,Multithreading,Transactions,Redis,Spring Data,Spring Data Redis,在我们的Spring4项目中,我们希望有涉及Redis和Hibernate的数据库事务。每当Hibernate失败时,例如由于乐观锁定,Redis事务也应该中止 这似乎对我有用 单线程事务执行 多线程事务执行,只要事务只包含一个Redis调用 如果Hibernate被排除在我们的配置之外,则使用多个Redis调用执行多线程事务 一旦一个事务包含多个Redis调用,并且Hibernate被配置为参与事务,那么连接绑定和多线程似乎就会出现问题。线程卡在RedisConnectionUtils.bin

在我们的Spring4项目中,我们希望有涉及Redis和Hibernate的数据库事务。每当Hibernate失败时,例如由于乐观锁定,Redis事务也应该中止

这似乎对我有用

  • 单线程事务执行
  • 多线程事务执行,只要事务只包含一个Redis调用
  • 如果Hibernate被排除在我们的配置之外,则使用多个Redis调用执行多线程事务
  • 一旦一个事务包含多个Redis调用,并且Hibernate被配置为参与事务,那么连接绑定和多线程似乎就会出现问题。线程卡在
    RedisConnectionUtils.bindConnection()
    ,可能是因为
    redispool
    的连接用完了

    这可以复制如下

    @Service
    public class TransactionalService {
    
        @Autowired
        @Qualifier("redisTemplate")
        private RedisTemplate<String, Object> redisTemplate;
    
        @Transactional
        public void processTask(int i){
    
            redisTemplate.convertAndSend("testChannel", new Message());
            redisTemplate.convertAndSend("testChannel", new Message());
        }
    }
    
    运行此操作将导致所有taskExecutor线程挂起在JedisPool.getResource()中:

    这是spring data redis中的一个bug,还是我们的配置有问题?

    在我使用opsForHAsh和放置多个键处理完全相同的问题之前,我(巧合地)发现了您的问题。线程转储证实了这一点

    我发现帮助我开始的是增加配置中的线程池。我将它设置为128,这让我再次上路

    @Bean
    JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(128);
        return jedisPoolConfig;
    }
    

    在我的例子中,我假设池太小,所有线程都在用于我的事务,所以我们会无限期地等待。将total设置为128允许我继续。尝试将您的配置设置为对您的应用程序有意义的maxTotal。

    我遇到了一个非常类似的问题,但是如果线程真的没有被释放,碰撞maxTotal线程会困扰我。取而代之的是,我有一些代码,可以快速地执行get和set。我把它放在一个会话回调中,它表现得更好。希望这能有所帮助。

    您是否找到导致这种行为的原因。目前,我在一个只有redis的环境中也面临同样的问题。
      "taskExecutor-1" - Thread t@18
       java.lang.Thread.State: WAITING
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for <1b83c92c> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
        at org.apache.commons.pool2.impl.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:524)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:438)
        at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:361)
        at redis.clients.util.Pool.getResource(Pool.java:40)
        at redis.clients.jedis.JedisPool.getResource(JedisPool.java:84)
        at redis.clients.jedis.JedisPool.getResource(JedisPool.java:10)
        at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.fetchJedisConnector(JedisConnectionFactory.java:90)
        at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:143)
        at org.springframework.data.redis.connection.jedis.JedisConnectionFactory.getConnection(JedisConnectionFactory.java:41)
        at org.springframework.data.redis.core.RedisConnectionUtils.doGetConnection(RedisConnectionUtils.java:128)
        at org.springframework.data.redis.core.RedisConnectionUtils.bindConnection(RedisConnectionUtils.java:66)
        at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:175)
        at org.springframework.data.redis.core.RedisTemplate.execute(RedisTemplate.java:152)
        at org.springframework.data.redis.core.RedisTemplate.convertAndSend(RedisTemplate.java:675)
        at test.TransactionalService.processTask(TransactionalService.java:23)
        at test.TransactionalService$$FastClassBySpringCGLIB$$9b3de279.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:708)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:98)
        at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:262)
      at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
      at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
      at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:644)
      at test.TransactionalService$$EnhancerBySpringCGLIB$$a1b3ba03.processTask(<generated>)
      at test.TaskRunnerService$1.run(TaskRunnerService.java:28)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
    
       Locked ownable synchronizers:
        - locked <7d528cf7> (a java.util.concurrent.ThreadPoolExecutor$Worker)   
    
    @Configuration
    public class RedisConfig {
    
        @Bean
        public JedisConnectionFactory jedisConnectionFactory() {
            JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
            jedisConnectionFactory.setPoolConfig(new JedisPoolConfig());
            return jedisConnectionFactory;
        }
    
        @Bean
        public Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer() {
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new     Jackson2JsonRedisSerializer(Object.class);
            jackson2JsonRedisSerializer.setObjectMapper(objectMapper());
            return jackson2JsonRedisSerializer;
        }
    
        @Bean
        public StringRedisSerializer stringRedisSerializer() {
            return new StringRedisSerializer();
        }
    
        @Bean
        public RedisTemplate<String, Object> redisTemplate() {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
            redisTemplate.setConnectionFactory(jedisConnectionFactory());
            redisTemplate.setKeySerializer(stringRedisSerializer());
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer());
            redisTemplate.setEnableTransactionSupport(true);
            return redisTemplate;
        }
    
        @Bean
        public ObjectMapper objectMapper() {
            ObjectMapper objectMapper = new ObjectMapper();
            objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
            objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
            return objectMapper;
        }
    }
    
    @EnableTransactionManagement
    @Configuration
    public class HibernateConfig {
    
        @Bean
        public LocalContainerEntityManagerFactoryBean admin() {
    
            LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new     LocalContainerEntityManagerFactoryBean();
            entityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
            entityManagerFactoryBean.setPersistenceUnitName("test");
    
            return entityManagerFactoryBean;
        }
    
        @Bean
        public JpaTransactionManager transactionManager(
                @Qualifier("admin") LocalContainerEntityManagerFactoryBean     entityManagerFactoryBean) {
    
            JpaTransactionManager transactionManager = new JpaTransactionManager();
            transactionManager.setEntityManagerFactory(entityManagerFactoryBean.getObject());
            transactionManager.setDataSource(entityManagerFactoryBean.getDataSource());
    
            return transactionManager;
        }
    }
    
    @Bean
    JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(128);
        return jedisPoolConfig;
    }