Database Reference
In-Depth Information
db
.
accounts
.
update
(
{
'_id'
:
destination
},
{
'$inc'
: {
'balance'
:
amt
} } )
The problem with this approach is that, if an exception occurs between the source account be-
ing debited and the destination account being credited, the funds are lost.
WARNING
You should be exceedingly careful if you find yourself designing an application-level, two-
phase commit protocol. It's easy to miss a particular failure scenario, and there are many
opportunities to miss a race condition and introduce inconsistency into your data, by a
small oversight in design or a bug in implementation. As a rule of thumb, whenever it's
possible to structure your schema such that all your atomic updates occur
within
a docu-
ment boundary, you should do so, but it's nice to know you can still fall back to two-phase
commit if you absolutely have to.
A better approach to this problem is to emulate transactions in the data model. Our basic ap-
proach here will be to create a “transaction” collection containing documents that store the
state of all outstanding transfers:
▪ Any transaction in the “new” state may be rolled back if it times out.
▪ Any transaction in the “committed” state will always (eventually) be retired.
▪ Any transaction in the “rollback” state will always (eventually) be reversed.
Our transaction collection contains documents of the following format:
{
_id
:
ObjectId
(...),
state
:
'new'
,
ts
:
ISODateTime
(...),
amt
:
55.22
,
src
:
1
,
dst
:
2
}