Java调用redis lua脚本实现原子性操作

本文介绍如何在Java中使用Jedis库调用Redis的Lua脚本,以确保复杂的数据库操作具备原子性,避免并发问题。通过示例展示Lua脚本的编写和执行过程,帮助开发者理解这一高效的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

import java.net.URI;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;


import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.util.JedisURIHelper;

@Slf4j
@Component
public class RedisLogic {
	@Autowired
	private IConfigPropertyService configPropertyService;
	private JedisPool jedisPool;
	public static String order_limit = null;
	@PostConstruct
	public void init() throws Exception {
		JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
		URI uri = null;
		// 从数据库中加载redis配置
		List<ConfigProperty> redisConfigs = configPropertyService.listConfigPropertyByPropertyTypeNotAll("redis_config");
		// 从数据库中加载配置到缓存中
		if (!CollectionUtils.isEmpty(redisConfigs)) {
			for (ConfigProperty redisConfig : redisConfigs) {
				if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "maxTotal")) {
					jedisPoolConfig.setMaxTotal(Integer.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "maxIdle")) {
					jedisPoolConfig.setMaxIdle(Integer.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "minIdle")) {
					jedisPoolConfig.setMinIdle(Integer.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "maxWaitMillis")) {
					jedisPoolConfig.setMaxWaitMillis(Long.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "true")) {
					jedisPoolConfig.setLifo(Boolean.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "testOnBorrow")) {
					jedisPoolConfig.setTestOnBorrow(Boolean.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "testOnReturn")) {
					jedisPoolConfig.setTestOnReturn(Boolean.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "testWhileIdle")) {
					jedisPoolConfig.setTestWhileIdle(Boolean.valueOf(redisConfig.getPropertyValue()));
				} else if (StringUtils.equalsIgnoreCase(redisConfig.getPropertyKey(), "url")) {
					uri = URI.create(redisConfig.getPropertyValue());
				}
			}
		} else {
			throw new RuntimeException("请在数据库中配置redis连接参数!");
		}
		if (JedisURIHelper.isValid(uri)) {
			String host = uri.getHost();
			int port = uri.getPort();
			String password = JedisURIHelper.getPassword(uri);
			jedisPool = new JedisPool(jedisPoolConfig, host, port, 2000, password);
		}
		cacheLuaFile();
	}
	
	/**
	 * 缓存lua文件
	 * @throws Exception 
	 */
	private void cacheLuaFile() throws Exception {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			order_limit = jedis.scriptLoad(IOUtils.toString(new ClassPathResource("order_limit.lua").getInputStream(), "UTF-8"));
			log.info("order_limit={}", order_limit);
		} catch (Exception e) {
			throw e;
		} finally {
			returnResource(jedis);
		}
	}
	
	/**
	 * 订单限量管控
	 * @param key
	 * @param limitKey
	 * @param limitValue
	 * @return
	 */
	public boolean orderLimit(String key, String limitKey, String limitValue) {
		Jedis jedis = null;
		try {
			jedis = jedisPool.getResource();
			return "true".equals(jedis.evalsha(order_limit, Arrays.asList(key, limitKey), Arrays.asList(limitValue)));
		} catch (Exception ex) {
			log.error("redis设置 key 对应的值为 string 类型的 value,并指定此键值对应的有效期异常:[key={}]" , key, ex);
		} finally {
			returnResource(jedis);
		}
		return false;
	}
	
	/**
	 * 
	 * @param jedis
	 */
	private void returnResource(Jedis jedis) {
		if (jedis == null) {
			return;
		}
		try {
			jedis.close();
			jedis = null;
		} catch (Exception e) {
			log.error("returnResource error.", e);
		}
	}
}
-- order_limit.lua

local key = KEYS[1]
local key2 = KEYS[2]
local value = ARGV[1]
if redis.call('EXISTS',key) == 0 then
    redis.call('INCR',key)
    return "true"
else
    if tonumber(redis.call('GET',key)) < tonumber(value) then
        redis.call('INCR',key)
        return "true"
    else
         if redis.call('EXISTS',key2) == 0 then
         	redis.call('SET',key2, "true")
         end
         return "false"
    end
end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值