What IsolationLevel should I use in my TransactionScopes - entity-framework

What IsolationLevel should I use in my TransactionScopes for:
Reading a single record and I may update that record. This record is
independent of all other data in the database so I only need to lock that one record.
Trying to read a single record. If no record exists, then create a record with that
value in that table. This is independent of all other tables, but it
needs to lock this table so another thread doesn't also find no
record, and then add the same record.
In the 2nd case, I think I need to lock the table to stop an insert on the table and any access on the record read, but allow reads of other records in the table and any access on any other table.
thanks - dave

A am not sure about EF as I have not worked with it, but my answer is following:
It is enough to use 'REPEATABLE READ' since it "Specifies that statements cannot read data that has been modified but not yet committed by other transactions and that no other transactions can modify data that has been read by the current transaction until the current transaction completes."
I would use 'SERIALIZABLE' since "No other transactions can modify data that has been read by the current transaction until the current transaction completes."
You can read more here about isolation levels.

Related

postgres acquire row-level lock

How do I acquire a row-specific lock in Postgres?
According to the documentation, I can acquire a table lock, but I don't want to lock the whole table; I only care about monitoring a specific row in a given transaction.
My use case is that I want to:
read a row
perform some (potentially expensive, potentially race-condition) operations that prepare new rows for another table
when I'm finally ready to insert/update these new rows, I want to make sure no other process beat me to the punch, so I think I want to:
acquire a row-level lock on the same row I read earlier
see if the version or state or column like that is the same as when I read it earlier
if it is the same, I want to insert/update into the other table, then increment this version, then release the lock
if it is not the same version, then I want to abort - I don't care about my possible new/updated rows, they are stale and I don't want to save them (so: do nothing, release the lock)
But, I don't want to lock the entire table for this whole period; I just want to lock that one specific row. I cannot figure out how to do that based on numerous . blog . posts and Postgres . documentation
All I want is an example query that shows me how to explicitly row-level lock.

Does Postgres guarantee to lock rows in the order of supplied update-statements?

I like to do batch updates to Postgres. Sometimes, the batch may contain update-statements to the same record. (*)
To this end I need to be sure that Postgres locks rows based on the order in which the update-statements are supplied.
Is this guaranteed?
To be clear, I'm sending a sequence of single row update-statements, so not a single multi-row update-statement. E.g.:
update A set x='abc', dt='<timeN>' where id='123';
update A set x='def', dt='<timeN+1>' where id='123';
update A set x='ghi', dt='<timeN+2>' where id='123';
*) This might seem redundant: just only save the last one. However, I have defined an after-trigger on the table so history is created in a different table. Therefore I need the multiple updates.
The rows will definitely be locked in the order of the UPDATE statements.
Moreover, locks only affect concurrent transactions, so if all the UPDATEs take place in one database session, you don't have to be afraid to get blocked by a lock.

How to update an aggregate table in a trigger procedure while taking care of proper concurrency?

For illustration, say I'm updating a table ProductOffers and their prices. Mutations to this table are of the form: add new ProductOffer, change price of existing ProductOffer.
Based on the above changes, I'd like to update a Product-table which holds pricing info per product aggregated over all offers.
It seems logical to implement this using a row-based update/insert trigger, where the trigger runs a procedure creating/updating a Product row.
I'd like to properly implement concurrent updates (and thus triggers). I.e.: updating productOffers of the same Product concurrently, would potentially lead to wrong aggregate values (because multiple triggered procedures would concurrently attempt to insert/update the same Product-row)
It seems I cannot use row-based locking on the product-table (i.e.: select .. for update) because it's not guaranteed that a particular product-row already exists. Instead the first time around a Product row must be created (instead of updated) once a ProductOffer triggers the procedure. Afaik, row-locking can't work with new rows to be inserted, which totally makes sense.
So where does that leave me? Would I need to roll my own optimistic locking scheme? This would need to include:
check row not exists => create new row fail if already exists. (which is possible if 2 triggers concurrently try to create a row). Try again afterwards, with an update.
check row exists and has version=x => update row but fail if row.version !=x. Try again afterwards
Would the above work, or any better / more out-of-the-box solutions?
EDIT:
For future ref: found official example which exactly illustrates what I want to accomplish: Example 39-6. A PL/pgSQL Trigger Procedure For Maintaining A Summary Table
Things are much simpler than you think they are, thanks to the I an ACID.
The trigger you envision will run in the same transaction as the data modification that triggered it, and each modification to the aggregate table will first lock the row that it wants to update with an EXCLUSIVE lock.
So if two concurrent transactions cause an UPDATE on the same row in the aggregate table, the first transaction will get the lock and proceed, while the second transaction will have to wait until the first transaction commits (or rolls back) before it can get the lock on the row and modify it.
So data modifications that update the same row in the aggregate table will effectively be serialized, which may hurt performance, but guarantees exact results.

Dead lock occurs even update on different fields

I have been trying to develop replication from a Firebird database to other.
I simply add a new field to tables named replication_flag.
My replication program starts a read committed transaction, select rows, update this replication_flag field of rows then then commits or rollbacks.
My production client(s) does not update this replication_flag field and uses read committed isolation. My only one replication client only update this replication_flag field and does not update any other fields.
I still see dead locks and do not understand why. How can I avoid dead locks?
It seems that your replication app use a large transaction updating each record of each table. Probably, at the end, the whole database has been "locked".
You should consider using transactions by table or record packets. it's also possible to use a read-only transaction to read, and use an other transaction to write, with frequent commit, that allow other transactions to update the record.
An interesting slideshow: http://slideplayer.us/slide/1651121/

ADO Transaction and READPAST

I don't know if this is the best way, if there is a better way, please post.
I have an application that read a file and insert records.
The entire file is processed in one transaction.
Before a record is inserted the table needs to be checked for duplicates
(note: I can't make this a table constraint since there are exceptions)
So the duplicate check is a normal select statement, but the problem is, it reads the uncomitted records from the current transaction.
I have included READPAST and READCOMMITTED hints in the select statement, but that still return the record.
Any ideas?
the only way to implement this within the db is locking table. look at the ISOLATION LEVEL SERIALIZABLE