Transaction Closure Object

Transaction/Closure/Object - what's the difference?

Is rollback an intrinsic property of objects?

What's the difference between rolling back a transaction and destroying an object?


Transaction scope and object lifetime are orthogonal issues, not directly related to each other: While performing a UnitOfWork, I may create and discard many individual objects. (Particularly true if the objects are fine-grained, like integer, string, and point.) On the other hand, a transaction may involve calling only one method on an object, changing only a small part of its state.

The ideal relationship between objects and transactions would be that rolling back a transaction would cause all objects involved in that transaction to revert back to their previous state. This is probably only achieved with some OO databases and particularly sophisticated OO to relational mapping products. (I suspect that this issue is one of the main reasons for Microsoft's strange object lifetime rules in MicrosoftTransactionServer.)

You can create objects, like AcidCommand, that directly represent transaction semantics (or database resources). But such objects are the exception rather than the rule. -- JeffGrigg


    raise(Employee_number, Raise) ->
         Closure = fun() ->
                     [Employee] = mnesia:read({employee, Employee_number}),
                     Salary = Employee#employee.salary + Raise,
                     Updated_employee = Employee#employee{salary = Salary},
                     mnesia:write(Updated_employee)
                   end,
         mnesia:transaction(Closure).

The "raise" function will give an employee, identified by the Employee_number, a raise in the amount of Raise. To do this, it defines a function, bound to the variable "Closure", and asks the mnesia database to execute that function as a transaction (i.e. all the database changes succeed or all fail, etc.)

The function will read the current employee data from the database, update its salary, and write the updated employee data to the database.

-- PatrickLogan


Offhand, it looks to me that closures in this instance are an implementation detail of the MnesiaDatabase interface: I would guess that mnesia:transaction() puts some kind of marker in the closure it's given. mnesia:read() and mnesia:write() pick up this marker to join the transaction. -- JeffGrigg

It's not that magical. The closure is just a regular Erlang closure. The mnesia:transaction function creates a new transaction in a concurrent mnesia process (an Erlang process is a lightweight thread). Then the closure is executed. Each mnesia call will execute in that mnesia process that has an active transaction. Then the mnesia:transaction function commits the transaction in that mnesia process. A concurrent transaction can be executed from another Erlang process. It is not necessary to pass a connection argument to the mnesia:transaction function. A concurrent transaction works with its own mnesia process. The process is the connection. Erlang is efficient enough to execute tens of thousands of concurrent processes. They are very lightweight. --PatrickLogan

A similar concept in the OO world could look like this:

  1. You make a class that inherits from the database's "Transaction" class.
  2. You pass an instance of that class to the database's "perform a transaction" function.
  3. The database starts a transaction, calls the "Perform Work" function on your class (You overrode the base class' definition), and then commits the work.

Am I anywhere close? -- JeffGrigg

That's it, Jeff. It shows the correspondence between a closure and an object relative to a transaction. --PatrickLogan


CategoryClosure


EditText of this page (last edited March 4, 2003) or FindPage with title or text search