Overview:
In this tutorial, I would like to show you Redis Lua Script with Spring Boot to execute a set of operations as a single transaction or to have some kind of constraints when you do Redis transactions.
Redis Lua Script:
When a client wants to execute a set of operations on Redis Database, instead of sending all the commands one by one on a network, we could create our own extensions (kind of) on Redis Database using Lua Script and execute the operations as a single transaction.
The Redis Lua Script gets compiled for the first time and then using the SHA, the loaded script can be invoked any time.
Sample Application:
We are going to consider a simple Bank application in which Redis is the primary DB. We have set of accounts. The users can transfer money from 1 account to another.
Lets see how to implement the money transfer by using Redis Lua Script with Spring Boot.
Project Setup:
Create a Spring Boot project with below dependencies.
We are going to assume that Redis maintains all the accounts in an account hash as shown below. a and b are account names and the values are the corresponding account balances.
{
"a": "100",
"b": "20"
}
Redis Lua Script – Money Transfer:
The following lua script is responsible for the money transfer business functionality.
- The script will be invoked with 2 keys and 1 arg.
- key 1 represents the from account and key 2 represents to account.
- The arg is the amount to be transferred.
- If the from account has enough balance, then we will deduct money from 1 account and transfer to another account.
--moneyTransfer.lua
local account = 'account'
local fromBalance = tonumber(redis.call('HGET', account, KEYS[1]))
local toBalance = tonumber(redis.call('HGET', account, KEYS[2]))
local amount = tonumber(ARGV[1])
if fromBalance >= amount
then
redis.call('HSET', account, KEYS[1], fromBalance - amount)
redis.call('HSET', account, KEYS[2], toBalance + amount)
return true
end
return false
- the above script is located under src/main/resources/scripts.
Redis Lua Script – Money Transfer Service:
- First create a RedisScript bean show here.
@Configuration
public class ScriptConfig {
@Bean
public RedisScript<Boolean> script() {
Resource scriptSource = new ClassPathResource("scripts/moneyTransfer.lua");
return RedisScript.of(scriptSource, Boolean.class);
}
}
- Create a service class which accepts fromAccout, toAccount and the amount to be transferred. We would invoke the RedisScript by passing the parameters.
@Service
public class MoneyTransferService {
@Autowired
private RedisScript<Boolean> script;
@Autowired
private RedisTemplate<String, String> redisTemplate;
public void transfer(String fromAccount, String toAccount, int amount){
this.redisTemplate
.execute(script, List.of(fromAccount, toAccount), String.valueOf(amount));
}
}
Demo:
Once everything is ready, We can test as shown here.
@SpringBootApplication
public class RedisLuaScriptApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(RedisLuaScriptApplication.class, args);
}
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Autowired
private MoneyTransferService service;
@Override
public void run(String... args) throws Exception {
// initialize few accounts
this.redisTemplate.opsForHash().put("account", "a", "100");
this.redisTemplate.opsForHash().put("account", "b", "20");
// transfer money with lua script
this.service.transfer("a", "b", 20);
// check the results
System.out.println(
this.redisTemplate.opsForHash().get("account", "a")
);
System.out.println(
this.redisTemplate.opsForHash().get("account", "b")
);
}
}
Output:
80
40
Summary:
we were able to successfully demonstrate a business functionality as a single transaction by using Redis Lua Script with Spring Boot.
Learn more about Redis with Spring Boot.
- Redis Stream With Spring Boot
- Redis Master Slave With Spring Boot
- Microservice Pattern – Priority-Queue Pattern With Spring Boot + Redis
The source code is available here.
Happy learning 🙂