# Transaction:

**URL:** <https://www.ruby-forum.com/t/transaction/113811>\
**Category:** Rails\
**Created:** [September 5, 2007, 6:49am UTC](https://www.ruby-forum.com/t/transaction/113811 "2007-09-05T06:49:19Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![jhonny](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/919ad9/32.png) [@jhonny](https://www.ruby-forum.com/u/jhonny)\
**Post date:** [September 5, 2007, 6:49am UTC](https://www.ruby-forum.com/t/transaction/113811/1 "2007-09-05T06:49:19Z")

</div>

Transaction::Simple provides a generic way to add active transaction  
support to objects. The transaction methods added by this module will  
work with most objects, excluding those that cannot be Marshaled  
(bindings, procedure objects, IO instances, or singleton objects).

The transactions supported by Transaction::Simple are not backed  
transactions; they are not associated with any sort of data store.  
They are “live” transactions occurring in memory and in the object  
itself. This is to allow “test” changes to be made to an object before  
making the changes permanent.

Transaction::Simple can handle an “infinite” number of transaction  
levels (limited only by memory). If I open two transactions, commit  
the second, but abort the first, the object will revert to the  
original version.

Transaction::Simple supports “named” transactions, so that multiple  
levels of transactions can be committed, aborted, or rewound by  
referring to the appropriate name of the transaction. Names may be any  
object except nil. As with Hash keys, String names will be duplicated  
and frozen before using.

Usage  
include 'transaction/simple’v = “Hello, you.” # -\>  
"Hello, you."v.extend(Transaction::Simple) # -\> "Hello,  
you."v.start\_transaction # -\> … (a Marshal  
string)v.transaction\_open? # -\> truev.gsub!(/you/,  
“world”) # -\> "Hello, world."v.rewind\_transaction #  
-\> "Hello, you."v.transaction\_open? # -\> truev.gsub!(/  
you/, “HAL”) # -\> "Hello,  
HAL."v.abort\_transaction # -\> "Hello,  
you."v.transaction\_open? # -\>  
falsev.start\_transaction # -\> … (a Marshal  
string)v.start\_transaction # -\> … (a Marshal  
string)v.transaction\_open? # -\> truev.gsub!(/you/,  
“HAL”) # -\> "Hello, HAL."v.commit\_transaction # -

> "Hello, HAL."v.transaction\_open? # -\>  
> truev.abort\_transaction # -\> "Hello,  
> you."v.transaction\_open? # -\> false  
> Named Transaction Usage  
> v = “Hello, you.” # -\> "Hello,  
> you."v.extend(Transaction::Simple) # -\> "Hello,  
> you."v.start\_transaction(:first) # -\> … (a Marshal  
> string)v.transaction\_open? # -\> truev.transaction\_open?  
> (:first) # -\> truev.transaction\_open?(:second) # -\> falsev.gsub!  
> (/you/, “world”) # -\> "Hello,  
> world."v.start\_transaction(:second) # -\> … (a Marshal  
> string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
> HAL."v.rewind\_transaction(:first) # -\> "Hello,  
> you."v.transaction\_open? # -\> truev.transaction\_open?  
> (:first) # -\> truev.transaction\_open?(:second) # -\> falsev.gsub!  
> (/you/, “world”) # -\> "Hello,  
> world."v.start\_transaction(:second) # -\> … (a Marshal  
> string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
> HAL."v.transaction\_name # -  
> :secondv.abort\_transaction(:first) # -\> "Hello,  
> you."v.transaction\_open? # -\>  
> falsev.start\_transaction(:first) # -\> … (a Marshal string)v.gsub!  
> (/you/, “world”) # -\> "Hello,  
> world."v.start\_transaction(:second) # -\> … (a Marshal  
> string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
> HAL."v.commit\_transaction(:first) # -\> "Hello,  
> HAL."v.transaction\_open? # -\> false  
> Block Usage  
> v = “Hello, you.” # -\> "Hello,  
> you."Transaction::Simple.start(v) do |tv| # v has been extended  
> with Transaction::Simple and an unnamed # transaction has been  
> started. tv.transaction\_open? # -\> true tv.gsub!(/you/,  
> “world”) # -\> “Hello, world.” tv.rewind\_transaction # -\>  
> “Hello, you.” tv.transaction\_open? # -\> true tv.gsub!(/  
> you/, “HAL”) # -\> “Hello, HAL.” # The following breaks out  
> of the transaction block after # aborting the transaction.  
> tv.abort\_transaction # -\> "Hello, you."end # v still has  
> Transaction::Simple applied from here on  
> out.v.transaction\_open? # -\>  
> falseTransaction::Simple.start(v) do |tv|  
> tv.start\_transaction # -\> … (a Marshal string)  
> tv.transaction\_open? # -\> true tv.gsub!(/you/, “HAL”)

# -\> “Hello, HAL.” # If #commit\_transaction were called without

having started a # second transaction, then it would break out of  
the transaction # block after committing the transaction.  
tv.commit\_transaction # -\> “Hello, HAL.”  
tv.transaction\_open? # -\> true tv.abort\_transaction

# -\> "Hello, you."endv.transaction\_open? # -\> false

Named Transaction Usage  
v = “Hello, you.” # -\> "Hello,  
you."v.extend(Transaction::Simple) # -\> "Hello,  
you."v.start\_transaction(:first) # -\> … (a Marshal  
string)v.transaction\_open? # -\> truev.transaction\_open?  
(:first) # -\> truev.transaction\_open?(:second) # -\> falsev.gsub!  
(/you/, “world”) # -\> "Hello,  
world."v.start\_transaction(:second) # -\> … (a Marshal  
string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
HAL."v.rewind\_transaction(:first) # -\> "Hello,  
you."v.transaction\_open? # -\> truev.transaction\_open?  
(:first) # -\> truev.transaction\_open?(:second) # -\> falsev.gsub!  
(/you/, “world”) # -\> "Hello,  
world."v.start\_transaction(:second) # -\> … (a Marshal  
string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
HAL."v.transaction\_name # -

> :secondv.abort\_transaction(:first) # -\> "Hello,  
> you."v.transaction\_open? # -\>  
> falsev.start\_transaction(:first) # -\> … (a Marshal string)v.gsub!  
> (/you/, “world”) # -\> "Hello,  
> world."v.start\_transaction(:second) # -\> … (a Marshal  
> string)v.gsub!(/world/, “HAL”) # -\> "Hello,  
> HAL."v.commit\_transaction(:first) # -\> "Hello,  
> HAL."v.transaction\_open? # -\> false  
> Thread Safety  
> Threadsafe version of Transaction::Simple and  
> Transaction::Simple::Group exist; these are loaded from ‘transaction/  
> simple/threadsafe’ and ‘transaction/simple/threadsafe/group’,  
> respectively, and are represented in Ruby code as  
> Transaction::Simple::ThreadSafe and  
> Transaction::Simple::ThreadSafe::Group, respectively.

Contraindications  
While Transaction::Simple is very useful, it has some severe  
limitations that must be understood. Transaction::Simple:

uses Marshal. Thus, any object which cannot be Marshaled cannot use  
Transaction::Simple. In my experience, this affects singleton objects  
more often than any other object. It may be that Ruby 2.0 will solve  
this problem.  
does not manage resources. Resources external to the object and its  
instance variables are not managed at all. However, all instance  
variables and objects “belonging” to those instance variables are  
managed. If there are object reference counts to be handled,  
Transaction::Simple will probably cause problems.  
is not inherently thread-safe. In the ACID (“atomic, consistent,  
isolated, durable”) test, Transaction::SimpleTransaction::Simple to  
provide isolation and atomicity. Transactions should be considered  
“critical sections” in multi-threaded applications. If thread safety  
and atomicity is absolutely required, use  
Transaction::Simple::ThreadSafe, which uses a Mutex object to  
synchronize the accesses on the object during the transaction  
operations. provides CD, but it is up to the user of  
does not necessarily maintain Object.id values on rewind or abort.  
This may change for future versions that will be Ruby 1.8 or better  
only. Certain objects that support .replace will maintain Object.id.  
Can be a memory hog if you use many levels of transactions on many  
objects.

Name Value  
SKIP\_TRANSACTION\_VARS [TRANSACTION\_CHECKPOINT,  
“@ **transaction\_level** ”]  
TRANSACTION\_CHECKPOINT “@ **transaction\_checkpoint** ”  
TRANSACTION\_SIMPLE\_VERSION ‘1.3.0’

Public Methods  
abort\_transaction Aborts the transaction. Resets the object state to  
what it was before the transaction was started and closes the  
transaction. If name is specified, then the intervening transactions  
and the named transaction will be aborted. Otherwise, only the current  
transaction is aborted.

commit\_transaction If name is nil (default), the current transaction  
level is closed out and the changes are committed.

debug\_io Returns the Transaction::Simple debug object. It must  
respond to #\<\<.

debug\_io= Sets the Transaction::Simple debug object. It must respond  
to #\<\<. Sets the transaction debug object. Debugging will be performed  
automatically if there’s a debug object. The generic transaction error  
class.

debugging? Returns true if we are debugging.

rewind\_transaction Rewinds the transaction. If name is specified,  
then the intervening transactions will be aborted and the named  
transaction will be rewound. Otherwise, only the current transaction  
is rewound.

start  
start\_named  
start\_transaction Starts a transaction. Stores the current object  
state. If a transaction name is specified, the transaction will be  
named. Transaction names must be unique. Transaction names of nil will  
be treated as unnamed transactions.

transaction Alternative method for calling the transaction methods.  
An optional name can be specified for named transaction support.

transaction\_exclusions Allows specific variables to be excluded from  
transaction support. Must be done after extending the object but  
before starting the first transaction on the object.

transaction\_name Returns the current name of the transaction.  
Transactions not explicitly named are named nil.

transaction\_open? If name is nil (default), then returns true if  
there is currently a transaction open.

Private Methods  
\_\_abort\_transaction  
\_\_commit\_transaction  
\_\_common\_start  
\_\_rewind\_this\_transaction

Thanks N Regards…

K. Chandrahas R.,  
Software Engineer,  
Circlesource Software Technologies Pvt Ltd,  
Bangalore. Ph: 9986182302
