tags:

views:

168

answers:

2

My application is storing some data in SQL Table called Transactions. Users are able to sell something from Client1 to Client2 and then Client2 has it. I am storing it in a table the following way:

Client 1 | Buy  | Something | Price  | External |
Client 1 | Sell | Something | Price2 | Client 2 |
Client 2 | Buy  | Something | Price2 | Client 1 |

First Client1 bought it (brought it in or just has it for all it matters). Then he sells it to another client.

And all that is fine, it works but my application has a short time when it doesn't check if Client 1 still has what it claims to have (when data is loaded into gui). So if 2 users would make run for it it's possible that product from Client1 could be sold multiple times. Most likely it won't happen since my users tend to share their work on what they are doing but there's always BUT...

How to prevent this? Would simple select query check just before insert transaction be sufficient or should this be done differently? (I can imagine situation when multiple people make run for it and some would succeed). How is this handled in real world situations on heavy systems? Like when you pick money from one bank account with 2 cards from 2 different CashMachines (although i believe they would just let balance go under 0 in this case even if it wouldn't be allowed).

So what options do I have? What is your take on this?

+3  A: 

I assume this is not a real inventory tracking system, where the database merely record real world events, but instead is a some virtual auction or market place sort of application, where 'reality' is whatever the application believe it is.

If you only keep history, you'll never have the current state. W/o a current state, you can't make efficient correctness decisions. So keep a current state. Have a table of items and their current owner. The problem you ask then become a simple problem of 'How to I prevent a lost update?' or 'How do I prevent a blind write'? (ie. a write-write conflict) and the answer is well known in database application: use optimistic concurrency control.

For a detailed discussion of how to use Optimistic Concurrency with C# and SQL, see Optimistic Concurrency (ADO.NET).

Remus Rusanu
It's not a crucial real time system but something that has to make things easy for department. Real data is in banking systems so we just import it daily and do some moves on it and then finally print a report to our customer.
MadBoy
If the data comes from the banking systems, then you don't do any write and you cannot do any mistake, right? If you *do* writes, then my comment applies no matter what the data is, where is come from or what it represents.
Remus Rusanu
I'm actually not updating the values but inserting new rows to keep historical progress of what has been done. So i'll never overwrite data. I will have 4 rows more (2 sell, 2 buy) instead of just 2.
MadBoy
Well some data comes from one banking system, some from market, some data has to be entered manually by our employees (private stock offerings, outside of global stock exchange). And this is something that can be sold between clients and database has to keep track of it (and this has to be intact with accounts balance).
MadBoy
Can you not store the state and the transaction record?
Travis Gockel
'I never overwrite data' but that is exactly the point of my post, read again: **if you only save the history, you don't know the state**. So modify your system to *keep* the state.
Remus Rusanu
@Travis G what you mean? I do store transactions record. The example of table data i posted holds all the data (history or not). There's no "current data table" and "historical data table". When you buy something it inerts one row. When you sell it it inserts another one and if that was sold to client within database you get 1 more row on the other client.
MadBoy
@Remus i do keep the state. Last transaction for particular client is his state. I do counting like Buy = 1 Sell = -1 and if in the end it comes out i have +1 it means client has it.
MadBoy
No, you don't keep state. What you describe is *history*, not state. You **count**, meaning you have to always *recreate the history to discover the state* and that is the very root of your problem.
Remus Rusanu
So you would recommend to add a table with "current state" and keep the old one as historical one and add new rows to it as things go? Problem is they do Evaluation over time so "counting" is required for proper evaluation as they often go back up to couple of months to evaluate client earnings / success fee, management fee and depending on that counting which is done daily some fees are charged on our customer.
MadBoy
@MadBoy: Yes, add a table with the current state and keep the transaction record as well. You can create some stored procedures to help you manage this stuff, too.
Travis Gockel
A: 

I calculate running totals, store them in the same row, and use a constraint to make sure that running totals are non-negative. Described here: Denormalizing to enforce business rules: Running Totals

AlexKuznetsov