Resolve write after read race condition - database

Here is a race condition scenario that I need help with:
We are trying to create Item A and item B in the DB and we want to persist that item B is a "childOf" item A. Let's assume the request to create item B along with the "childOf" relationship data arrives before request to create item A.
here are the steps assuming a single job process these requests one at a time
Request to create item B arrives first with the "childOf" relationship data that says item B is a child of item A
First, we check if item A exists
If item A exists item B is created and a "childOf" relationship record is created between item B and item A
If item A doesn't exist, the process creates a pending record in the db saying item A is not yet created
When a request to create item A arrives, item A is created, the db is checked for any "pending" records associated with item A as parent, if there is a pending record, a "childOf" relationship is added between item B and item A now that item A is created in the db.
If there are multiple jobs running concurrently, here is a race condition that can occur:
Process A
Process B
req to create item B
check db for item A and item A is not found
req to create item A arrives and item A is created
since item A doesn't exist when it was checked last time, create a pending record in db with the relationship details
the pending record stays in the DB forever since item A is already created by process A while the pending record hasn't been inserted in the DB yet
How do I resolve this race condition? Sorry if this is too abstract. let me know if I should elaborate further.

I would create a “pending” object not as a separate, different object, but in the very place where a “real” object would be, just with a flag to indicate its state.
CREATE TABLE object (
name varchar(100)
CONSTRAINT object_pkey PRIMATY KEY,
pending boolean DEFAULT FALSE NOT NULL
);
Now I would add a regular object like this:
INSERT INTO object (name)
VALUES ('A')
ON CONFLICT ON CONSTRAINT object_pkey
DO UPDATE SET pending = FALSE;
A pending object is inserted like this:
INSERT INTO onject (name, pending)
VALUES ('A', TRUE)
ON CONFLICT ON CONSTRAINT object_pkey
DO NOTHING;
Then you don't need to check for existence before you add an object, and the race condition is gone. INSERT ... ON CONFLICT is designed to be atomic and free from race conditions.

Related

Insert foreign key records first to avoid racing condition?

I have 4 tables.
Table1 (primary)
Id
Table2 (foreign 1)
Id
Table1Id
Table3 (foreign 2)
Id
Table1Id
Etc
Table1 could have a record without table2,3 and 4 as well.
Now we have many records added to these tables and our application fetches to construct a response based on IDs in Table1.
You would normally add records in Table1 first then table 2 and 3 etc..
Our problem is that our polling (runs every 30seconds) application picks Ids from table1 but fails to get its linked records from Table2,3 and 4 because the application tries to fetch before linked records get saved in table 2,3 and 4 after saving a record in table1.
Is there a way of preventing this? Can we save foreign key records first? This way, the application won't see a record in table1 untill all linked records get saved in table2 and 3? Is it a common and safe practice?
Any advice would be great!
Thank you in advance
Depending on your system design you could always have this race condition. For example in a web application if you have a page that allows you to add a TableA, save it, then click a button to enter a related TableB, there is a period of time where a query on TableAs would receive an incomplete representation.
The solution is to either design the system or the data in a way that it can always be counted on to indicate that the data is in a complete state. For example, instead of designing it so that page-by-page entities in the relationship are saved independently, the user is given the ability to create the entire object graph. Entity Framework works with navigation properties for managing relationships, so if the client-side process walks through capturing the data for a Table A, then related Table B, and C etc. then passing all of those details in a structure to be persisted, you can have a single "Save" operation that creates the associated entities all in one go with one call to SaveChanges. This ensures all entities are committed together, or not at all. (if there is an exception) EF can take care of ensuring the tables are populated in the right order and assigning the FKs where needed. You don't need to "save" a TableA to get it's ID to populate in the TableB:
var tableA = new TableA
{
Name = viewModel.Name,
TableB = new TableB
{
Name = viewModel.BsName,
// ... or use biewModel.BDetails.Name, etc.
},
TableC = new TableC
{
// ....
}
};
context.TableAs.Add(tableA);
context.SaveChanges(); // Saves the A, B, and related C, etc.
If the data is rather large and complex and it doesn't make sense to try and capture everything at once, for instance if the data might be entered over a significant span of time given the user has to accumulate or check data etc. before the record state is considered complete enough to be queried on, then you can consider using something like a Status on your top level table. (TableA) This could be something like an enumeration. When you create your TableA record initially, the status would be defaulted to something like "InProgress". Any query reporting or such looking at TableAs would know only to query records with a Status of "Complete". As the user enters their Table B, C, etc. there would be either an automatic validation or manual assertion to determine if the TableA record can be marked off as "Complete", updating the status. From that point the report/summary query views would start seeing that row in results.

Deleting a record without deleting related records in another Access table

I have enabled Referential Integrity in Access 2007. I want to delete a customer record from customer table but want to keep related bill details of that particular customer in another table called bill table. When I try to delete a customer record I get an error message: "The record cannot be deleted or changed because table 'bill' includes related records".
You can't have it both ways: You can either have Referential Integrity enforced, or you can allow orphaned child records to be created when the parent record is deleted (i.e., by disabling the enforcement of Referential Integrity).
As mentioned in the comment to your question, you could add a Yes/No field named [Inactive] or [Deleted] to the parent table and then use queries that only consider "active" parent records, e.g.
SELECT * FROM [Customer] WHERE NOT [Inactive]
Another possibility is to have a separate "archive" database to store deleted items. You copy all related records (parent and child) to the archive database and then delete them (child first, then parent) from the main database.

Outbound message on merging records

When I merge accounts, I want to trigger an outbound message. When I merge account, there is 1 record that is updated and and the other record that goes to recycle bin. I want to fetch Record Id of one that is merged with and the one that is updated. Is it possible with any conditions or do i need to code?
Yes you need to write a trigger for this although a rather simple one.
As stated in documentation merge doesn't trigger they own event instead delete and uppate events triggered.
From Documentation :
To determine which records were deleted as a result of a merge operation use the
MasterRecordId field in Trigger.old. When a record is deleted after losing a merge
operation, its MasterRecordId field is set to the ID of the winning record.
Link to full page

Get unique ids for updated timeline items

When you schedule an update for a timeline item do you get a unique item id or the same one?
My question is can you chain multiple updates after one another and get unique ids? https://developers.google.com/glass/v1/reference/timeline/update
The current result isn't clear in the current documentation.
This way if a user stops the process you can easily access all the future timeline items and delete them?
The same one.
If you update a timelineItem via update or patch, the item which is returned will have the same ID that you passed in.

how we delete a row from parent table when child table connected with paren table by forigen key

hi all i am getting a problem while i attenpting to delete a row from parent table, actuall i have created 2 table custmer and account.i make cutomer id(primary key) in customer and customer id (forigen key ) in account.after created it i have filled data inside both table.
at this point while i am trying to delete a row from first table (customer ) then it give failure message is that it can't be deleted bcs it is refrenced as forigen key some thing like that............but while we delete row from account table then it's delete sucess fully.
.......i want to function like that if i delete a row from parent table(customer) then its in child table that row which has same customer id (account table) is delete automatically............
watch out on the cascade deletes! a user will accidentally click on the application's little trash can icon and delete the customer, and then all the cascades will remove every trace of that customer, orders, invoices, payments, history, etc from your database. After the user call you to tell you about their little mistake, you'll have to restore a backup and try to pull the info back into the database.
I would look into "soft deletes" where you only change the customer's status from "active" to "inactive". the rows is not deleted, preserving all foreign key data. This allows reports to run on the data, because it still exists, as well as easy an "undo".
Soft deletes are not the end all only way to go, it is a business decision on how to handle this, purge the data or mark it inactive. That is only something you can decide, because I don't know your application or business logic. I just thought that I would offer it as an alternative.
You need to set up the foreign key with on delete cascade to achieve this.
For SQL Server 2008 see the article Cascading Referential Integrity Constraints
Edit Just to add a somewhat redundant health warning you should be aware that adding on delete cascade will mean that when you delete the row from the parent table associated rows from the child table will be deleted. However as this is exactly the behaviour you state that you want I can't see that would be an issue.

Resources