Redis分散ロック実装例

2094 ワード

今日面接官はRedis分布式ロック実装コードの簡単な手順を聞いて、その中の1つの面接官はset操作とタイムアウト設定が2行のコードでなければならないと主張して、私はその時ぼんやりしていて、私はこれが「原子」操作に違反しているとしか言えません.以下は私の実装例コードです.
鍵をかける:
	@Override
	public boolean lock(String lockKey, String requestId, Long expireTime) {

		Assert.isTrue(StringUtils.isNotBlank(lockKey), "lockKey    ");
		Assert.isTrue(StringUtils.isNotBlank(requestId), "        ");

		Object result = stringRedisTemplate.execute(new RedisCallback() {

			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {

				Expiration expiration = Expiration.milliseconds(null == expireTime ? 1000L * 60 : expireTime);
				byte[] key = lockKey.getBytes(Charset.forName("UTF-8"));
				byte[] value = requestId.getBytes(Charset.forName("UTF-8"));

				return connection.set(key, value, expiration, SetOption.SET_IF_ABSENT);

			}
		});

		return (null == result) ? false : result.equals(true);

	}

ロックの解除:
	@Override
	public boolean unlock(String lockKey, String requestId) {

		Assert.isTrue(StringUtils.isNotBlank(lockKey), "lockKey    ");
		Assert.isTrue(StringUtils.isNotBlank(requestId), "        ");

		String lua = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";

		Object result = stringRedisTemplate.execute(new RedisCallback() {

			@Override
			public Boolean doInRedis(RedisConnection connection) throws DataAccessException {

				byte[] script = lua.getBytes(Charset.forName("UTF-8"));
				byte[] key = lockKey.getBytes(Charset.forName("UTF-8"));
				byte[] value = requestId.getBytes(Charset.forName("UTF-8"));

				Long result = connection.eval(script, ReturnType.INTEGER, 1, key, value);
				return (null == result ? false : result.equals(1L));

			}
		});

		return (null == result) ? false : result.equals(true);

		/*  redis 2.6.0    ,    lua  ,      redisTemplate.delete  ,          */

	}

関連項目:Redis分散ロックの正しい実装方法(Java版)