In our project we created a table(i.e. serial_conf) that has some configuration that user can set. When we need to generate a serial(i.e. 28_12_2019_0001) for a specific entity we call this serial's service class which has @Transactional on it.
The service is doing the following:
- Get the current serial config from the database
- Use the returned object to generate a serial number
- update serial's counter so next time we can generate the correct serial with increasing counter (i.e. 0002)
- return the result String to the caller of the service
Now the problem is that when I used Jmeter to stress test an API(10 threads at the same time). This API is doing alot of operations and one of them is to generate a serial number. Out of 10 threads only 2 or 4 passes and the other threads threw OptimisticLockingFailureException on step 1 of serial's service.
I've read Spring @Transactional with synchronized keyword doesn't work when i tried using synchronized but it didn't work. I even created a singleton class that calls my service with synchronized signature and all APIs that uses the serial service now calls this singleton so they can line after each one other, but it didn't work too.
Now my question is: What is the correct way to handle this issue? should I make the database do a Lock on the table? or should I use database sequence which does not support custom styles(i.e. 28_12_2019_0001)?
(I'm using spring-boot 1.5, hibernate and postgresql)
EDIT 1: lets say the service is something like this:
@Service("SerialService")
@Transactional(readOnly = false)
public class SerialService{
@Autowired
private SerialRepo repo;
public String generate(Long userId){
Serial serial = repo.findByUserId(userId).get();
serial.setCounter(serial.getCounter() + 1);
serial = repo.save(serial);
return "custom_serial_"+serial.getCounter().toString();
}
}