Spring data redis 事务

关系型数据库事务的作用是保证并发访问下数据的一致性,Redis事务有些不同,由于Redis是单线程的处理来自client的指令,所以Redis所有命令的执行都是原子性的,举一个简单的例子,单个Redis服务器下,并发地执行INCR命令,也不会返回相同的结果。

所以Redis事务的意义在于保证命令的批量顺序执行,并且事务执行期间,Redis不会执行来自client的其他请求。有一点需要注意的是,。如果有命令执行失败,还是会继续执行剩下的命令,因为Redis没有异常回滚。

对“Redis事务命令要么全部执行,要么全部不执行”这句事实的理解:如果有命令执行失败,并不是中断事务,而是继续执行剩下的指令,因为Redis不支持异常回滚。全部不执行的情况有 1.没有执行EXEC命令 2.WATCH的key发生改变 3.DISCARD命令放弃事务。本质上开启事务后,所有输入的命令都被缓存在一个队列中,一旦EXEC,队列里的指令被一条一条的执行。

关于事务的API

  • MULTI    开启事务
  • EXEC    执行任务队列里所有命令,并结束事务
  • DISCARD     放弃事务,清空任务队列,全部不执行,并UNWATCH
  • WATCH key [key1]    MULTI执行之前,指定监控某key,如果key发生修改,放弃整个事务执行
  • UNWATCH    手动取消监控

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisPassword;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.jedis.JedisClientConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

/**
 *  配置相关
 *  @author chenjianfei
 */
@Configuration
public class RedisConfiguration {

    @Bean
    public JedisClientConfiguration getJedisClientConfiguration() {
        JedisClientConfiguration.JedisPoolingClientConfigurationBuilder JedisPoolingClientConfigurationBuilder = (
                JedisClientConfiguration.JedisPoolingClientConfigurationBuilder) JedisClientConfiguration.builder();
        GenericObjectPoolConfig GenericObjectPoolConfig = new GenericObjectPoolConfig();
        GenericObjectPoolConfig.setMaxIdle(1000);
        GenericObjectPoolConfig.setMaxTotal(100);
        GenericObjectPoolConfig.setMinIdle(100);
        return JedisPoolingClientConfigurationBuilder.poolConfig(GenericObjectPoolConfig).build();
    }

    @Bean
    public JedisConnectionFactory getJedisConnectionFactory() {
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setDatabase(0);
        redisStandaloneConfiguration.setHostName("localhost");
        redisStandaloneConfiguration.setPassword(RedisPassword.none());
        redisStandaloneConfiguration.setPort(6379);
        return new JedisConnectionFactory(redisStandaloneConfiguration, getJedisClientConfiguration());
    }

    @Bean(value = "stringRedisTemplate")
    public RedisTemplate getStringRedisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(getJedisConnectionFactory());
        //添加事务支持(默认false)
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }

    @Bean(value = "objectRedisTemplate")
    public RedisTemplate getObjectRedisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(getJedisConnectionFactory());
        return redisTemplate;
    }
}
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.RedisSystemException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisConnectionUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author chenjianfei
 */
@Service
public class TestService {
    @Resource(name = "stringRedisTemplate")
    private RedisTemplate stringRedisTemplate;
    @Resource(name = "objectRedisTemplate")
    private RedisTemplate objectRedisTemplate;

    /**
     * 获取String类型值
     *
     * @param key
     * @param value
     */
    public void setStringValue(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * 设置String类型值
     *
     * @param key
     * @return
     */
    public String getStringValue(String key) {
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 设置Object类型值
     *
     * @param key
     * @param value
     */
    public void setObjectValue(String key, Serializable value) {
        objectRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * 获取Object类型值
     *
     * @param key
     * @return
     */
    public Object getObjectValue(String key) {
        return objectRedisTemplate.opsForValue().get(key);
    }

    /**
     * 获取Bound类型值
     *
     * @param key
     * @return
     */
    public void setBoundObjectValue(String key) {
        //如果key存在就修改key的值,如果不存在就创建一个对应的key
        BoundValueOperations boundValueOperations = objectRedisTemplate.boundValueOps(key);
        boundValueOperations.set(new Demo2());
        //会覆盖
        boundValueOperations.set(new Demo3());
        boundValueOperations.expire(60, TimeUnit.MINUTES);
    }

    /**
     * 获取Bound类型值
     *
     * @param key
     * @return
     */
    public Object getBoundObjectValue(String key) {
        BoundValueOperations boundValueOperations = objectRedisTemplate.boundValueOps(key);
        return boundValueOperations.get();
    }

    /**
     * pipeline : 1,正确使用方式
     */
    public void pipelineSample(String key) {
        StringRedisSerializer stringRedisSerializer = (StringRedisSerializer) stringRedisTemplate.getKeySerializer();
        //获取key对应的byte[]
        final byte[] rawKey = stringRedisSerializer.serialize(key);
        //pipeline
        RedisCallback> pipelineCallback = new RedisCallback>() {
            @Override
            public List doInRedis(RedisConnection connection) throws DataAccessException {
                connection.openPipeline();
                //pipeline执行命令
                connection.incr(rawKey);
                connection.incr(rawKey);
                return connection.closePipeline();
            }

        };

        List results = (List) objectRedisTemplate.execute(pipelineCallback);
        for (Object item : results) {
            System.out.println(item.toString());
        }
    }

    //pipeline:备用方式
    public void pipelineSample2(String key) {
        StringRedisSerializer stringRedisSerializer = (StringRedisSerializer) stringRedisTemplate.getKeySerializer();
        //获取key对应的byte[]
        final byte[] rawKey = stringRedisSerializer.serialize(key);
        RedisConnectionFactory factory = objectRedisTemplate.getConnectionFactory();
        RedisConnection redisConnection = factory.getConnection();
        List results;
        try {
            redisConnection.openPipeline();
            redisConnection.incr(rawKey);
            results = redisConnection.closePipeline();
        } finally {
            RedisConnectionUtils.releaseConnection(redisConnection, factory);
        }
        if (results == null) {
            return;
        }
        for (Object item : results) {
            System.out.println(item.toString());
        }
    }

    /**
     * Redis事务
     * @throws RedisSystemException
     */
    public void setTransactionValue() throws RedisSystemException{
        stringRedisTemplate.multi();
        stringRedisTemplate.boundValueOps("k4").set("1000");
        int i = 0;
        try{
            i = 5/i;
            stringRedisTemplate.boundValueOps("k5").set("2000");
            stringRedisTemplate.exec();
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

class Demo2 implements Serializable {

}

class Demo3 implements Serializable {

}
 
  
import org.springframework.context.annotation.*;

@ComponentScan
public class Application {

}
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import vip.fkandy.redis.Application;

import java.io.Serializable;

public class TestServiceTest{
    TestService testService = null;
    @Before
    public void setUp() throws Exception {
        ApplicationContext context =
                new AnnotationConfigApplicationContext(Application.class);
        testService = context.getBean(TestService.class);
    }
    @Test
    public void setStringValue() {
        testService.setStringValue("k1","v1");
    }

    @Test
    public void getStringValue() {
        System.out.println(testService.getStringValue("k1"));
    }

    @Test
    public void setObjectValue() {
        testService.setObjectValue("k2",new Demo());
    }

    @Test
    public void getObjectValue() {
        System.out.println(testService.getObjectValue("k2"));
    }

    @Test
    public void setBoundValue() {
        testService.setBoundObjectValue("k4");
    }

    @Test
    public void pipelineSample() {
        testService.pipelineSample("k4");
    }
    @Test
    public void pipelineSample2() {
        testService.pipelineSample2("k4");
    }
    @Test
    public void setTransactionValue()throws Exception{
        testService.setTransactionValue();
    }
}
class Demo implements Serializable{

}




你可能感兴趣的:(Spring data redis 事务)