What's the Difference between Conflict Serializable and Serializable? - conflict

My understanding is that conflict serializable implies serializable. I'm not sure how that makes them different. Does serializable mean conflict serializable?

Conflict serializable is a subset of serializable, so just because a schedule is conflict serializable does mean it is serializable.
See cow book Database Management System 2rd Ed Cha19.1.1 P541
Every conflict serializable schedule is serializable.
A serializable but not conflict serializable schedule is
T1 : R(A) W(A) C
T2 : W(A) C
T3 : W(A) C
This is not conflict serializable (by precedence graph) but is equivalent to serializable schedule
T1 T2 T3
because T3 blind writes the output in both schedule.

Conflict serializability is a subset of serializability. If a schedule is conflict serializable, it is implied that this schedules is serializable.
It is computationally easier to determine if something is conflict serializable as opposed to just serializable. Simply construct a precedence graph. If the graph is non-cyclic, then this schuedule is conflict-equivalent to some serial schedule described by the pathing of the graph.
Imagine transactions A B and C, all writing to the same page. A writes, then B, then C, then A again. There is no serializable schedule that is conflict-equivalent. A must go first, because B and C have a conflict after A. But A must also go last, since B and C have a conflict before A. Hence the cycle in the graph.
But just because it is not conflict serializable does not mean it is not serializable. For example, if the last write of A was exactly the same as C's write, then ABC would be a serial schedule equivalent to the original, because the last write didn't end up mattering.

Conflict serializable is a subset of view serializable. "A schedule can be conflict serializable but not view serializable(as in case of blind writes)

In simple Words,
Suppose there is a schedule(S) with two transaction T1,T2.
Let Result1, Result2 be two variables, where
Result1 is produced after running T1 and then T2, i.e T1->T2;(serially)
Result2 is produced after running T2 and then T1, i.e T2->T1;(serially)
Now suppose we interleave the actions of the two transaction, let us call it schedule S, now if the net result produced after running S is equivalent to Result1 or Result2 then we call it serializable.
But, if we can swap the non-conflicting actions and produce a serial schedule that is equal to a schedule in which T1 is run first and then T2(T1->T2), or T2 is run first and then T1(T2->T1) then we call it conflict-serializable.
Now if a schedule is conflict-serializable then it is bound to be serializable as it can be changed to some serial order by swapping the non-conflicting actions.
Hence we can conclude, every conflict-serializable schedule is serializable but not all serializable schedule are conflict-serializable.

Straight Definition with the understanding of conflicting actions:
A schedule is conflict serializable if it is conflict equivalent to some serial schedule. Every conflict serializable schedule is serializable.
The above example is serializable but not conflict serializable. There is no such serial that has the same conflicting actions. Serializable because it still achieves concurrency to serial T1->T2->T3, but does not share conflicting actions. The writes of T1 and T2 are in different order in the example opposed to the serial.

Serializability has two types: Conflict and View.
Conflict serializable determines if a schedule is equivalent to some serial schedule keeping the conflicting operations(R-W or W-R or W-W) in the same sequence as in the original schedule.

Related

Check if relation is not exists and update another entity

I have a Product table, a Location table and ProductLocationRel table, which is relation table with locationId to productId.
I need to update Location entity (mark deactivated) if there is no relation with given location exists.
I thought about having a single SQL query for that, I'd like to keep such business rule on the code level, rather then delegating it to database.
Therefore, the idea then is programmatically check if there are any relation exist in a single transaction with SERIALIZABLE isolation level through find relation, check condition and then update steps, like so:
(pseudocode)
t = transaction.start()
exist = t.find(relation with locationId).
if(exist) throw Error("can't do this");
location.isActive = false;
t.update(location);
t.commit();
But I'm not sure how transaction would behave itself in this case.
The questions on this one which I have are:
If during transaction new relation records appear in DB, would transaction fail? I think yes, but I'm not sure.
Would that approach block whole relation table for this operation? This might become a bottleneck in this case.
If it would be just simple location delete, I wouldn't need to care, as db level reference integrity would catch this on delete step, but this is not the case.
I don't think it's relevant, as this touches purely transactions execution and SQL, but the database is postgres and runtime is node.js.

Unique constraint violated due to value too large for column (Oracle)

Is it possible to get an
ORA-00001: unique constraint (XXX) violated
dueto an
ORA-12899: value too large for column (XXX)
in an oracle database using Hibernate (as is stated in this confluence page)?
(The columns for each error are in different tables but relatad to each other)
In that case, how is this possible?
* UPDATE *
I can confirm the causal relation between the exceptions. The given scenario is as follows:
The are a number processes that perform different operations to the database. This operations are stacked until Hibernate session flush. When you invoke the flush method, the queries are performed in the same transaction.
In my particular case I have the entities A and B that both have inside an entity C (the reference of the entity is the same, there is no copy for each father entity). When the program tries to save A (with a string field too large), first executes the C insert query, and then the insert to the entity itself that leads to a "ORA-12899: value too large for column". At this point C is in the database but not yet commited.
Then the next process tries to save B that contains a C entity and this leads to "ORA-00001: unique constraint violated" on C entity.
My questions are:
When the first process doesnt have errors (no column too large) the second one doesnt try to insert C again, only make the insert to entity B (probably detached state of the entity C?).
Why the execution is not aborted on the first error?
Both exceptions (unique constraint and value too large for column) are related. There are serveral processes executed in a single transaction. Those processes make calls to the methods save() or saveOrUpdate() stacking queries until the flush() of the Hibernate session or commit the transaction.
At some point a flush() of the session is invoked with the given scenario:
Entity A and B both contains the same reference of entity C. The first process tries to insert entity A, so first executes the insert of C without problem, later tries to insert A but fails due to a too large column exception. At this point C is in the database (not yet commited) but the hibernate session is in an incoherent state due to the previous fail and Hibernate doesnt know about C being inserted (a fail on session flush doesnt trigger a rollback, is responsability of the developer).
Then a second process is executed and tries to insert B into the database. If the previous process went ok, Hibernate only inserts the entity B because he knows C is already in the database. Due to the incoherent session state, Hibernate tries to save the C entity again in the database raising a unique constraint exception.

Concurrent insert into entity collection

I have bidirectional mapping between Family and Person:
#Entity class Family {
#OneToMany(mappedBy = "family", ...)
Set<Person> persons;
...
}
#Entity class Person {
#ManyToOne
Family family;
...
}
My problem is that I can concurrently add and/or remove elements from the collection, which it breaks atomicity in the updates, as adding a new person creates INSERT INTO Person ... statement that does not collide with the other insert. #Version field does not help, since I am not updating the Family entity as row in the table, just logically.
What should I do to enable only atomic updates of the collection? I have tried loading Family with LockMode.PESSIMISTIC_WRITE, which can synchronize the updates on the Family itself, but that does not allow second-level caching for the read of Family. I would prefer optimistic transactions with kind of predicate constraint in the DB.
You can use OPTIMISTIC_FORCE_INCREMENT:
entityManager.lock(family, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
This way version will be checked and incremented in the corresponding Family entity instance.
EDIT
Since you are using L2 cache, and for some reason (bug, design decision, or just a missing feature) Hibernate does not update the version in the L2 cache after the force increment, you will have to actually load the entity with this lock for everything to work properly:
entityManager.find(Family.class, id, LockModeType.OPTIMISTIC_FORCE_INCREMENT);
However, now you will have to take care to be consistent and to load the Family entities this way always prior to updating them (to avoid working with stale version values because L2 cache is not in sync with the database).
To overcome this, you could add an artificial column to the Family entity, like lastUpdateTime or something, and update the Family instance without using any explicit lock. Then the regular version check would occur and everything would be synchronized with the L2 cache.

Transaction isolation level - choosing the right one

I'm a sql beginner and I need help concerning isolation levels of transactions.
I need to know which isolation level is the best for the following situation and why:
There are 3 tables in the database:
Animals (that are registered by inserting a chip into them) KEY - ID_CHIP REF CHIPS
Chips (that can but dont have to be inserted into an animal) KEY - ID_CHIP. One of the attributes is "INSERTED_BY" which references to the third table PEOPLE (gives ID of a person who inserted the chip, and NULL if it wasnt inserted yet)
People - KEY: ID
Now let's consider the following transactions: a new chip has been inserted into an animal. A person who updates the database has to change two things:
add a new entity to ANIMALS
update the chip record that was inserted (change the INSERTED_BY attribute from NULL to ID of a person who inserted the chip)
The second transaction is a controller transaction, who checks if the number of entities in ANIMALS is equal to the numer of CHIPS that have the attribute INSERTED_BY not equal to NULL.
A situation is shown by the image below:
Can anyone tell me which of the fours isolation levels is best and why? I'm stuck here.. Any help would be appreciated.
Your situation is easy because one of the transactions a purely read transaction. Look into snapshot isolation. Running the reader under SNAPSHOT isolation level will give it a point-in-time consistent view of the entire database. No locks will be taken or waited on.
This means that at t2 the insert will not be visible to C2.
This is very easy to implement and solves the problem completely.
Without SNAPSHOT isolation you'd need SERIALIZABLE isolation and you'll deadlock a lot. Now you need to investigate locking hints. Much more complex, not necessary.

NHibernate transaction and race condition

I've got an ASP.NET app using NHibernate to transactionally update a few tables upon a user action. There is a date range involved whereby only one entry to a table 'Booking' can be made such that exclusive dates are specified.
My problem is how to prevent a race condition whereby two user actions occur almost simultaneously and cause mutliple entries into 'Booking' for >1 date. I can't check just prior to calling .Commit() because I think that will still leave be with a race condition?
All I can see is to do a check AFTER the commit and roll the change back manually, but that leaves me with a very bad taste in my mouth! :)
booking_ref (INT) PRIMARY_KEY AUTOINCREMENT
booking_start (DATETIME)
booking_end (DATETIME)
make the isolation level of your transaction SERIALIZABLE (session.BeginTransaction(IsolationLevel.Serializable) and check and insert in the same transaction. You should not in general set the isolationlevel to serializable, just in situations like this.
or
lock the table before you check and eventually insert. You can do this by firing a SQL query through nhibernate:
session.CreateSQLQuery("SELECT null as dummy FROM Booking WITH (tablockx, holdlock)").AddScalar("dummy", NHibernateUtil.Int32);
This will lock only that table for selects / inserts for the duration of that transaction.
Hope it helped
The above solutions can be used as an option. If I sent 100 request by using "Parallel.For" while transaction level is serializable, yess there is no duplicated reqeust id but 25 transaction is failed. It is not acceptable for my client. So we fixed the problem with only storing request id and adding an unique index on other table as temp.
Your database should manage your data integrity.
You could make your 'date' column unique. Therefore, if 2 threads try to get the same date. One will throw a unique key violation and the other will succeed.