How to guarantee constraint between SQL rows?
We are developing online schedule application. One schedule can be edited simultaneously by several users. There is one very important business constraint. There must be only three events in one day.
Technically speaking and simplifying, there is a table开发者_如何学Go in database with columns: | id | event | date |. Application runs in transaction "select... count... where..." and if result is less than 3, it inserts new event.
Wich approaches can be used to guarantee that two threads will not create four events in one day? This is a classical check-and-write problem. And we wonder how it can be solved on database level?
Using transactions doesn`t guarantee that in the second transaction another thread will not do the same: checks that number of events is less than 3 and makes insert. Locking the whole table is not acceptable because it will reduce response time, concurrency, etc.
Application is developed in Java using Spring, Hibernate, MySQL.
Thanks in advance for any pieces of advice.
For blocking process you should use Select ... FOR UPDATE statement. But this one works only in innodb.
Example:
//java logic
try {
//mysql logic
start transaction;
select * from where 'some condition' FOR UPDATE
INSERT INTO TABLE ....
commit;
//java logic
catch (Exception e) {
rollback;
}
See more info about specific row locking http://dev.mysql.com/doc/refman/5.1/en/innodb-locking-reads.html
With your data model you could use a check constraint to count the number of rows. AFAIK MySQL doesn't natively support this type of constraint, but it looks like it's possible to emulate them with a trigger
Alternatively you could consider a different data model with a days
table and an events
table. You could use optimistic locking of days
to ensure that a second transaction didn't have an out of date understanding of the data.
Since you are going through Spring, and since there is a concurrency issue, try synchronizing execution at the Java layer, rather than at the DB layer. We've had similar issues when trying to use a DB to maintain concurrency.
Perhaps you could make the execution block in Java synchronized
so that it forces execution to block; inside the synchronized method, check that all of your business logic returns true. if true, continue with normal execution. If false, abort with an exception.
精彩评论