I'm using Entity Framework 5.0. I need to restrict access to a row while I'm reading and Updating it.
My application run on more that 10 machines and when I use TransactionScope ,some time some other application on other machines (randomly) dump and can not update or read data from that table.
I think TransactionScope restricted access to my table while its reading or updating and other update or reading request will dump.
How can I handle other requests from other applications to update or read data from that table when one application did not done TransactionScope action?
How can I handle it?
using (var myDB = new MyDBEntities())
{
using (TransactionScope scope = new TransactionScope())
{
// read and update myDB object with some code in here
// ...
myDB.SaveChanges();
scope.Complete();
}
}
When using transaction scopes you can hold another transaction to select/update the same row.
Also, you can hide uncommitted data from another transaction using special table hint called as READPAST.
Example:
session1
BEGIN TRANSACTION
update users with (SERIALIZABLE) set name='test' where Id = 1
-- COMMIT --not committed yet
session2
select * from users where Id = 1
--waits session1 to finish its job
--rows returns after commit
session3
select * from users with (READPAST) where Id = 1 --returns 0 row
While you're not commit the transaction, other sessions could not read or update the data. When you commit the transaction on session1, session2 will be able to read the row.
http://omerc.blogspot.com.tr/2010/04/transaction-and-locks-in-ms-sql-2008.html
https://technet.microsoft.com/en-us/library/jj856598(v=sql.110).aspx
https://www.codeproject.com/Articles/690136/All-About-TransactionScope
Be aware that data is still open to lost updates. To prevent it you may consider to use optimistic/pessimistic locking.
https://logicalread.com/sql-server-concurrency-lost-updates-w01/#.WskuNNNuZ-U
Related
I would like to lock a table for writing during a period of time, while leaving it available for reading.
Is that possible ?
Ideally I would like to lock the table with a predicate (for example prevent writing rows "where country = france").
If you really want to lock against such inserts, i.e. the query should hang and only continue when you allow it, you would have to place a SHARE lock on the table and keep the transaction open.
This is usually not a good idea.
If you want to prevent any such inserts, i.e. throw an error when such an insert is attempted, create a BEFORE INSERT trigger that throws an exception if the NEW row satisfies the condition.
You can use FOR SHARE lock, which blocks other transactions from performing like UPDATE and DELETE, while allowing SELECT FOR SHARE. (Read the docs for details: https://www.postgresql.org/docs/9.4/explicit-locking.html [13.3.2])
For example, there are 2 processes accessing table user_table, in the following sequence:
Process A: BEGIN;
Process A: SELECT username FROM user_table WHERE country = france FOR SHARE;
Process B: SELECT * FROM user_table FOR SHARE; (In here, process B can still read all the rows of the table)
Process B: UPDATE user_table SET username = 'test' WHERE country = france; (In here, process B is blocked and is waiting for process A to finish its transaction)
I am new to Postgres so this may be obvious (or very difficult, I am not sure).
I would like to force a table or row to be "locked" for at least a few seconds at a time. Which will cause a second operation to "wait".
I am using golang with "github.com/lib/pq" to interact with the database.
The reason I need this is because I am working on a project that monitors postgresql. Thanks for any help.
You can also use select ... for update to lock a row or rows for the length of the transaction.
Basically, it's like:
begin;
select * from foo where quatloos = 100 for update;
update foo set feens = feens + 1 where quatloos = 100;
commit;
This will execute an exclusive row-level lock on foo table rows where quatloos = 100. Any other transaction attempting to access those rows will be blocked until commit or rollback has been issued once the select for update has run.
Ideally, these locks should live as short as possible.
See: https://www.postgresql.org/docs/current/static/explicit-locking.html
This is what the sp does:
SET TRANSACTION ISOLATION LEVEL Serializable
begin transaction
IF EXISTS( SELECT 1 FROM dbo.Portfolio WHERE RawMessageID = #RawMessageID)
begin
----do some cleaning job like delete the portfolio, or something
end
insert into Portfolio
select #a,#b,#c,#d
commit
Randomly, I see deadlock happen and this deadlock graph showing the detail.
So it has to be that one instance of the call hold the shared lock from the select statement and asking for an null resource lock. Another instance holds the null resource lock and asks for shared lock.
Is my guess right? I was trying to write an simplified version to demo this, but never can trigger this deadlock.
Can someone help?
I have a database table 'MyTable' that has a trigger upon update of field 'Status' in it.
Below is a dummy-code of what i'm trying to do:
MyTable table = new Mytable();
table.setTableId(1);
table.setStatus ("NEW");
em.persist (table); //At this point the trigger did not kick in since this inserted a new record
...
MyTable table2 = em.find(MyTable.class, 1);
table2.setStatus ("NEW");
em.merge(table2)//Even though im updating the record with the same status with the same value, i still want the trigger to kick. However the trigger is not being activated.
...
MyTable table3 = em.find(MyTable.class, 1);
table3.setStatus ("OLD");
em.merge(table3)//The trigger is being activated here since the status is different the status value when it was inserted the first time.
Long story short, how can i make the changes done to 'transfer2' to trigger an update even though the status is the same?
-Thanks
Use em.flush(); to synchronize the persistence context to the underlying database. Your pending queries shall be send to database, but you still can have a complete rollback.
JPA does not update object that have no changes.
You could try changing to something else (flush), then changing it back.
You could also use a JPQL update query to update it.
Depending on your JPA provider you could probably force it to update fields that have not changed, but this would lead to very bad performance.
Could you please try updating the enity and commit the transaction, without using merge.
Like
em.getTransaction().begin();
MyTable table2 = em.find(MyTable.class, 1);
table2.setStatus ("NEW");
//em.merge(table2)//Even though im updating the record with the same status with the
// same value, i still want the trigger to kick. However the trigger is not being activated.
em.getTransaction().commit();
I'm using Npsql with PostgreSQL. I want to see uncommitted changes of one transaction in a different one.
This is how I create my connection and transaction:
// create connection
m_Connection = new NpgsqlConnection(connectionString);
m_Connection.Open();
//create transaction
m_Transaction = m_Connection.BeginTransaction(IsolationLevel.ReadUncommitted);
In one thread I insert a row like so:
NpgsqlCommand command = CreateCommand("INSERT INTO TABLEA ....", parameters, commandTimeout)
command.ExecuteNonQuery();
and process something else without committing or rolling back the transaction.
In a different thread I read a row like so:
NpgsqlCommand command = CreateCommand("SELECT COUNT(*) FROM TABLEA", parameters, commandTimeout);
command.ExecuteScalar();
but somehow I don't see the results of the first INSERT. I don't see the results of the insert in pgAdmin either (even after running SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED).
What am I doing wrong? Any help will be appreciated.
PostgreSQL does not support uncommitted reads.
You will never be able to see changes from other transactions that are not committed.