实现原理: redis集群对象JedisCluster不支持事务,但是,集群里面的每个节点支持事务。我们可以把这个key临时插入到集群中的某一个节点上,然后遍历集群的节点,获取临时key所在的那个节点,这样我们就可以开启这个节点的事务,最后删除临时key。
第一步:找到需要set的值插入到哪个节点上(比如set("姓名","张三"),找到"姓名"这个key所要插入的节点),并开启此节点事务。
public static Map<String, Transaction> multi(JedisCluster jedisCluster, String... keys)
{
Map<String, Transaction> txMap = new HashMap();
if ((keys != null) && (keys.length > 0))
{
String[] arrayOfString;
int j = (arrayOfString = keys).length;
for (int i = 0; i < j; i++)
{
String key = arrayOfString[i];
//此时查看集群中是否有这个key的值
boolean clusterExists = jedisCluster.exists(key).booleanValue();
if (!clusterExists) {
//如果节点没有此值,那么用这个key作为临时key,插入
jedisCluster.set(key, "");
}
//获取集群所有的节点,遍历
Map<String, JedisPool> mapNodes = jedisCluster.getClusterNodes();
for (Map.Entry<String, JedisPool> node : mapNodes.entrySet())
{
JedisPool pool = (JedisPool)node.getValue();
Jedis jedis = pool.getResource();
try
{
//查看临时key在哪个节点上
if (jedis.exists(key).booleanValue())
{
if (!clusterExists) {
//删除此节点上的临时key
jedisCluster.del(key);
}
//把此节点保存并返回
txMap.put(key, jedis.multi());
}
}
catch (Exception localException) {}
}
if (!clusterExists) {
jedisCluster.del(key);
}
}
}
return txMap;
}
第二步:拿到key所在的节点,插入值,并预提交事务
public static void set(Map<String, Transaction> txMap, Map<String, String> kvMap)
{
if (!kvMap.isEmpty()) {
for (Map.Entry<String, String> entry : kvMap.entrySet())
{
String key = (String)entry.getKey();
String value = (String)entry.getValue();
Transaction tx = (Transaction)txMap.get(key);
tx.set(key, value);
}
}
}
第三步:提交事务并返回结果
public static List<Object> exec(Map<String, Transaction> txMap)
{
List<Object> result = new ArrayList();
if (!txMap.isEmpty()) {
for (Map.Entry<String, Transaction> entry : txMap.entrySet()) {
result.addAll(((Transaction)entry.getValue()).exec());
}
}
return result;
}
第四步:测试
public void Test{
public static void main(...){
Map<String,String> kvMapT = new HashMap<>();
String key1T = "xingm";
String key2T = "nianl";
kvMapT.put(key1T, "zhangsan");
kvMapT.put(key2T, "32");
//开启事物
Map<String, Transaction> txMapT = JedisClusterUtil.multi(jedisCluster, key1T,key2T);
//添加数据 此处为预提交事务
JedisClusterUtil.set(txMapT, kvMapT);
//提交事物
JedisClusterUtil.exec(txMapT);
}
}
结尾:原理就是提前拿key去插入,计算出此key插入到哪个节点,然后开启对应节点的事务并提交。