今天遇到一个很奇怪的问题,向redis中添加哈希结构的值,不知道为什么每个key都只会加最后一条 并不是所有的值。
这是我的Java代码:
对于问题:如何向redis中添加哈希值,并保证每个key都能正确添加对应的值,而不是仅添加最后一条值?
一种解决方案是使用分布式锁来保证并发操作时数据的正确性。
以下是Java代码实现:
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.exceptions.JedisException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
public class RedisHashAddDemo {
private final JedisPool jedisPool;
public RedisHashAddDemo(JedisPool jedisPool) {
this.jedisPool = jedisPool;
}
public void addHashValue(String hashKey, Map<String, String> values) {
Jedis jedis = null;
Lock lock = null;
try {
jedis = jedisPool.getResource();
//获取分布式锁
lock = RedisLockUtil.acquireLock(jedis, hashKey, 30, TimeUnit.SECONDS);
//添加哈希值
jedis.hmset(hashKey, values);
} catch (JedisException e) {
e.printStackTrace();
} finally {
if (lock != null) {
//释放锁
RedisLockUtil.releaseLock(lock, jedis, hashKey);
}
if (jedis != null) {
jedis.close();
}
}
}
public static void main(String[] args) {
JedisPool jedisPool = new JedisPool("localhost", 6379);
RedisHashAddDemo redisHashAddDemo = new RedisHashAddDemo(jedisPool);
Map<String, String> values = new HashMap<>();
values.put("key1", "value1");
values.put("key2", "value2");
values.put("key3", "value3");
redisHashAddDemo.addHashValue("hashKey", values);
}
}
其中需要用到分布式锁的实现类RedisLockUtil,以下是实现代码:
import redis.clients.jedis.Jedis;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class RedisLockUtil implements Lock {
private Jedis jedis;
private String lockKey;
private String lockValue;
public RedisLockUtil(Jedis jedis, String lockKey) {
this.jedis = jedis;
this.lockKey = lockKey;
}
@Override
public void lock() {
while (!tryLock()) {
try {
//等待锁释放
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
@Override
public void lockInterruptibly() throws InterruptedException {
throw new UnsupportedOperationException("不支持中断加锁操作");
}
@Override
public boolean tryLock() {
lockValue = System.currentTimeMillis() + Thread.currentThread().getName();
String result = jedis.set(lockKey, lockValue, "NX", "PX", 30000);
return "OK".equals(result);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
long timeout = unit.toMillis(time);
while (timeout > 0) {
if (tryLock()) {
return true;
}
timeout -= 100;
//休眠100ms
TimeUnit.MILLISECONDS.sleep(100);
}
return false;
}
@Override
public void unlock() {
String lockValue = jedis.get(lockKey);
if (lockValue != null && lockValue.equals(this.lockValue)) {
jedis.del(lockKey);
}
}
@Override
public Condition newCondition() {
throw new UnsupportedOperationException("不支持条件变量操作");
}
public static Lock acquireLock(Jedis jedis, String lockKey, long timeout, TimeUnit timeUnit) {
RedisLockUtil redisLock = new RedisLockUtil(jedis, lockKey);
try {
if (redisLock.tryLock(timeout, timeUnit)) {
return redisLock;
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return null;
}
public static void releaseLock(Lock lock, Jedis jedis, String lockKey) {
if (lock != null) {
lock.unlock();
}
jedis.close();
}
}
在添加哈希值时,获取分布式锁,然后执行哈希值的添加操作。如果有其他线程在此期间获取到了锁,则会等待锁的释放。在操作结束后,需要释放锁。这样即可保证每个key正确添加对应的值,而不是仅添加最后一条值。
打印出 jdbcList 看看内容,或者在 forEach 里面打印出几个关键的值。
key被覆盖了,所以永远是最后一条数据