Aldian
Aldian

Reputation: 2622

Do Hibernate Isolation work on insertion?

I have a problem that could probably be addressed in various ways including re-challenging database design, but my manager has a bias for the Hibernate annotations and here we are.

We want to insert family members in a table. Some of the columns are the following:

(I am mentioning this because there will be one and only one family member with the type ME and a given client_id, not sure how this can help me there however since there might be several CHILD and thus I can not add a unicity constraint on the two columns)

Assuming a user possibly new just connected our app and imported family data from a partner service. We want to persist it to our database if it does not exists. And we also want to prevent parallel insertion from another thread or instance. Here is what I came up with.

@Transactional(isolation = Isolation.SERIALIZABLE)
public void firstCreateFamily(List<FamilyMember> members, long clientId) {
    if(!this.familyMemberRepository.existByClientId(clientId)) {
        this.familyMemberRepository.save(members);
    }
}

According to the documentation, using the SERIALIZABLE isolation level will drain a lot of the database performance but my manager does not care since we won't need to do it very often. Nevertheless, this isolation level should guarantee that all transactions will be executed in a sequence and yet I am not very comfortable about this because I can't figure out what the framework will do to make it work.

I think we are expecting it to apply only to this method and work a bit as if we had made it synchronized, but with the synchronization applying simultaneously over all the instances running our app. Yet I can't imagine how that would work without Hibernate applying a lock into the whole table in the database and blocking every other requests to this table. And I even have some doubts about Hibernate actually doing that.

I thought about alternatives like using a lock, but I think checking for "non existence" is the tricky part and I wonder how will Hibernate proceed on comparing two consecutive read on the request.

Could someone help me figure out how to set up that business and if it has chances to work as intended?

(BTW I hesitated to ask my question on code review, but this is more about Hibernate internals than about my snippet that I am bothered)

Upvotes: 0

Views: 586

Answers (1)

Kayaman
Kayaman

Reputation: 73568

This isn't about Hibernate. A database transaction has an isolation level, that annotation is only requesting that the DB transaction has an isolation level of SERIALIZABLE.

It's best that you don't try to "imagine" how that will work, because you will certainly be wrong. Especially if you're thinking that it's Hibernate that's doing something, when Hibernate is just working normally and it's the database that is behaving differently according to the different isolation level (assuming the common default READ COMMITTED).

You can't also expect that a single transaction with SERIALIZABLE isolation level to be correct, as other transactions will have the default isolation level of READ COMMITTED. Only if all transactions have the SERIALIZABLE isolation level they are given guarantees, but even then they're not actually run one after another as that would be terrible for performance. See for example this discussion on Postgres' implementation.

Making that transaction SERIALIZABLE may solve your problem, but without knowing the big picture there's no guarantee, and it might work by chance rather than by design. If you're not very experienced with databases, I recommend seeking outside professional DBA help. Or at least stroll around on DBA until you realize how complex the issue is.

Upvotes: 1

Related Questions