关系型数据库事务的作用是保证并发访问下数据的一致性,Redis事务有些不同,由于Redis是单线程的处理来自client的指令,所以Redis所有命令的执行都是原子性的,举一个简单的例子,单个Redis服务器下,并发地执行INCR命令,也不会返回相同的结果。
所以Redis事务的意义在于保证命令的批量顺序执行,并且事务执行期间,Redis不会执行来自client的其他请求。有一点需要注意的是,。如果有命令执行失败,还是会继续执行剩下的命令,因为Redis没有异常回滚。
对“Redis事务命令要么全部执行,要么全部不执行”这句事实的理解:如果有命令执行失败,并不是中断事务,而是继续执行剩下的指令,因为Redis不支持异常回滚。全部不执行的情况有 1.没有执行EXEC命令 2.WATCH的key发生改变 3.DISCARD命令放弃事务。本质上开启事务后,所有输入的命令都被缓存在一个队列中,一旦EXEC,队列里的指令被一条一条的执行。
关于事务的API
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
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{
}