Redis事务与持久化
事务特性
flowchart TD
    Redis事务[Redis事务]
    Redis事务 --> MULTI
    Redis事务 --> EXEC
    Redis事务 --> WATCH
    Redis事务 --> DISCARD
事务特点
- 批量执行但不保证原子性
 - 无回滚机制
 - 执行期间不会被其他命令打断
 - 使用WATCH实现乐观锁
 
持久化机制
RDB快照
# redis.conf配置示例
save 900 1      # 900秒内至少1个key变化
save 300 10     # 300秒内至少10个key变化
dbfilename dump.rdb
AOF日志
appendonly yes
appendfsync everysec  # 每秒同步
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
高可用架构
主从复制
# 从节点配置
replicaof 127.0.0.1 6379
replica-read-only yes
哨兵模式
# sentinel.conf配置
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 5000
sentinel failover-timeout mymaster 60000
Java客户端配置
// 哨兵模式连接
JedisPoolConfig poolConfig = new JedisPoolConfig();
JedisSentinelPool pool = new JedisSentinelPool(
    "mymaster", 
    new HashSet<>(Arrays.asList("sentinel1:26379")),
    poolConfig
);
生产建议
- 根据业务选择持久化方式
 - 主从节点配置合理的内存
 - 哨兵至少部署3个节点
 - 监控持久化状态
 - 定期备份数据
 
Java 操作 Redis 实战
环境准备
1. 添加依赖
<!-- Spring Boot Starter Data Redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
2. 配置文件
spring:
  redis:
    host: localhost
    port: 6379
    password: your_password
    database: 0
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: -1ms
基础操作
1. 配置类
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(factory);
        // 设置key的序列化方式
        template.setKeySerializer(new StringRedisSerializer());
        // 设置value的序列化方式
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        return template;
    }
}
2. 工具类
@Component
public class RedisUtil {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    // 设置缓存
    public void set(String key, Object value, long time) {
        redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
    }
    // 获取缓存
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }
    // 删除缓存
    public Boolean delete(String key) {
        return redisTemplate.delete(key);
    }
    // 设置过期时间
    public Boolean expire(String key, long time) {
        return redisTemplate.expire(key, time, TimeUnit.SECONDS);
    }
}
实战案例
1. 商品缓存
@Service
public class ProductService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private ProductMapper productMapper;
    private static final String PRODUCT_KEY = "product:";
    public Product getProduct(Long id) {
        // 1. 查询缓存
        String key = PRODUCT_KEY + id;
        Product product = (Product) redisTemplate.opsForValue().get(key);
        // 2. 缓存未命中,查询数据库
        if (product == null) {
            product = productMapper.selectById(id);
            if (product != null) {
                // 3. 写入缓存
                redisTemplate.opsForValue().set(key, product, 1, TimeUnit.HOURS);
            }
        }
        return product;
    }
    public void updateProduct(Product product) {
        // 1. 更新数据库
        productMapper.updateById(product);
        // 2. 删除缓存
        redisTemplate.delete(PRODUCT_KEY + product.getId());
    }
}
2. 分布式锁
@Service
public class DistributedLock {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    public boolean lock(String key, String value, long timeout) {
        return redisTemplate.opsForValue()
            .setIfAbsent(key, value, timeout, TimeUnit.SECONDS);
    }
    public boolean unlock(String key, String value) {
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then " +
                       "return redis.call('del', KEYS[1]) else return 0 end";
        return redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),
            Collections.singletonList(key), value);
    }
}
3. 限流器
@Service
public class RateLimiter {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    public boolean isAllowed(String key, int limit, int period) {
        String script = "local current = redis.call('incr', KEYS[1]) " +
                       "if current == 1 then " +
                       "redis.call('expire', KEYS[1], ARGV[1]) end " +
                       "return current <= tonumber(ARGV[2])";
        return redisTemplate.execute(new DefaultRedisScript<>(script, Boolean.class),
            Collections.singletonList(key), period, limit);
    }
}
4. 排行榜
@Service
public class RankingService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    private static final String RANKING_KEY = "ranking:";
    public void addScore(String member, double score) {
        redisTemplate.opsForZSet().add(RANKING_KEY, member, score);
    }
    public Set<ZSetOperations.TypedTuple<Object>> getTop(int count) {
        return redisTemplate.opsForZSet().reverseRangeWithScores(RANKING_KEY, 0, count - 1);
    }
    public Long getRank(String member) {
        return redisTemplate.opsForZSet().reverseRank(RANKING_KEY, member);
    }
}
性能优化
1. Pipeline 批量操作
@Service
public class BatchOperation {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    public void batchSet(Map<String, Object> map) {
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            map.forEach((key, value) -> {
                connection.set(
                    key.getBytes(),
                    value.toString().getBytes()
                );
            });
            return null;
        });
    }
}
2. 本地缓存
@Service
public class LocalCache {
    private LoadingCache<String, Object> cache;
    @PostConstruct
    public void init() {
        cache = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build(new CacheLoader<String, Object>() {
                @Override
                public Object load(String key) {
                    return loadFromRedis(key);
                }
            });
    }
    public Object get(String key) {
        try {
            return cache.get(key);
        } catch (ExecutionException e) {
            return null;
        }
    }
}
最佳实践
1. 异常处理
@Aspect
@Component
public class RedisAspect {
    @Around("execution(* com.example.service.*.*(..))")
    public Object handleRedisException(ProceedingJoinPoint point) {
        try {
            return point.proceed();
        } catch (RedisConnectionFailureException e) {
            // 处理连接异常
            return null;
        } catch (Throwable e) {
            // 处理其他异常
            throw new RuntimeException(e);
        }
    }
}
2. 监控指标
@Component
public class RedisMonitor {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Scheduled(fixedRate = 60000)
    public void monitor() {
        // 监控连接数
        Long clientCount = redisTemplate.execute((RedisCallback<Long>) connection ->
            connection.serverCommands().clientList().stream().count());
        // 监控内存使用
        Properties info = redisTemplate.execute((RedisCallback<Properties>) connection ->
            connection.serverCommands().info());
        // 记录监控数据
        log.info("Redis clients: {}", clientCount);
        log.info("Redis memory: {}", info.getProperty("used_memory"));
    }
}
注意事项
- 
连接池配置:
- 根据并发量设置合适的连接数
 - 定期检查连接状态
 - 实现连接重试机制
 
 - 
序列化选择:
- 使用高效的序列化方式
 - 考虑序列化大小
 - 注意序列化性能
 
 - 
异常处理:
- 实现优雅降级
 - 记录异常日志
 - 设置重试机制
 
 - 
性能优化:
- 使用批量操作
 - 实现本地缓存
 - 避免大键
 - 合理设置过期时间