This project is archived and is in readonly mode.

#383 ✓committed
Sean Kirby

ActiveRecord should use savepoints for nested transactions

Reported by Sean Kirby | June 10th, 2008 @ 06:54 PM

From in the old rails trac.

Jonathan Viney has created a patch that enables doesn't break existing transaction semantics but allows for transactional behaviour to be tested in transactional fixtures.

Comments and changes to this ticket

  • Jeremy Kemper

    Jeremy Kemper June 10th, 2008 @ 10:35 PM

    • Assigned user set to “Jeremy Kemper”

    I'd love to support savepoints. We've had the discussion regarding the default behavior of nested transactions, though, and it's not the way to go. Nested transactions should be explicit, otherwise we're going to flood the database with junk transactions that really only mean "include me in a transaction" not "start a new transaction". Let's extend the existing semantics instead of stepping on them. And add better test coverage ;)

  • Jeremy Kemper
  • Tarmo Tänav

    Tarmo Tänav June 16th, 2008 @ 08:02 PM

    Jeremy, the plugin by Jonathan Viney actually does make transaction{} only create a nested transaction if an explicit ":force => true" option is passed to it. The only exception being transactional tests where one additional level of non-explicit transactions can be created (because the test class itself uses the first level).

    So these changes should not change rails behavior outside tests.

    This plugin however does not include the ability to configure rails behavior for implicit transactions (those automatically created by save/destroy). Which means that you will not be able to make some activerecord model always create an implicit transaction for saving itself, even if a higher level transaction already exists. But this is a capability not strictly neccessary for the nested transactions feature to be useful, as you can always create an explicit "transaction :force => true" block around a save if you need it.

  • Jonathan Viney

    Jonathan Viney July 3rd, 2008 @ 01:12 PM

    • Tag set to activerecord, nested, savepoint, transaction

    I'd like to see #533 included first (moving the transaction counter from Thread.current to the connection object), and then I'll add an updated patch for the savepoints.

  • Jeremy Kemper

    Jeremy Kemper August 30th, 2008 @ 05:10 AM

    • State changed from “new” to “open”

    #533 is in -- interested in porting your work over to Rails master?

  • Jonathan Viney

    Jonathan Viney August 31st, 2008 @ 11:38 AM

    I've attached a patch for master.

    The handling of increment/decrement_open_transactions has been moved to the connection object rather than handling it in AR::Base.transaction, seemed better to me.

    I've added a transactional_fixtures accessor to the connection which is set by the fixtures. Not the nicest, but I wasn't sure what else to do.

    There are some failures for databases that don't support savepoints (eg. sqlite). These are a bit hard to avoid unless we add a supports_savepoints? to the connection.

    Anyway, this should get the ball rolling.

  • Hongli Lai

    Hongli Lai October 1st, 2008 @ 03:19 PM

    I think ':force => true' is a bit confusing. How about ':nested => true'?

  • Hongli Lai

    Hongli Lai October 9th, 2008 @ 12:22 PM

    savepoints-3.diff doesn't apply cleanly om master. Here's an updated patch, with conflicts resolved.

    It doesn't pass the unit tests however. More investigation will be required.

  • Hongli Lai

    Hongli Lai October 9th, 2008 @ 12:25 PM

    Jonathan, is there a reason why you changed

    def transaction(start_db_transaction = false)


    def transaction(start_db_transaction = false)


  • Hongli Lai

    Hongli Lai October 9th, 2008 @ 03:27 PM

    Never mind my last message, I already figured it out. :)

    Here's an updated patch which passes all unit tests, for MySQL, PostgreSQL and SQLite3. Changes are:

    • Much improved documentation, including documentation about potential caveats on MySQL.
    • :force option renamed to :nest, which is probably clearer.
    • I had to revert commit 045713ee240fff815edb5962b25d668512649478 by Jeremy Kemper, "PostgreSQL: introduce transaction_active? rather than tracking activity ourselves". It conflicts with the savepoint code.
  • Hongli Lai

    Hongli Lai October 9th, 2008 @ 05:00 PM

    After speaking with Koz I've reimplemented Jeremy's transaction state introspection feature. The old implementation was incompatible with the old 'postgres' driver, which I fixed. I also added unit tests for this feature.

  • Hongli Lai

    Hongli Lai October 9th, 2008 @ 05:18 PM

    Koz said that it's probably not feasible to include this feature in 2.2, seeing that we're in a feature freeze. If anybody wants to help, I'm maintaining this savepoint stuff in the following git repository:

    git:// branch 'savepoints'

  • Pratik

    Pratik October 17th, 2008 @ 05:14 PM

    • Milestone set to 2.x
  • Michael Koziarski
  • Jeremy Kemper

    Jeremy Kemper December 9th, 2008 @ 12:00 AM

    Is git:// still available?

  • Hongli Lai

    Hongli Lai December 9th, 2008 @ 12:45 AM

    Yes it is. I've just merged the patches against latest edge, and all unit tests pass.

  • Jeremy Kemper

    Jeremy Kemper December 9th, 2008 @ 02:40 AM

    $ git remote add phusion git://
    $ git fetch phusion
    fatal: The remote end hung up unexpectedly
  • Hongli Lai

    Hongli Lai December 9th, 2008 @ 11:24 AM

    Oops, a little git-daemon configuration problem, sorry. It should be up now.

  • Jeremy Kemper

    Jeremy Kemper January 10th, 2009 @ 08:50 PM

         def transaction(start_db_transaction = false)
           start_db_transaction ||= open_transactions == 0 || (open_transactions == 1 && transactional_fixtures)

    This is an unexpected change of behavior: your transactions are nested in tests by default, but not in development or production without :nest => true.

    There should be a clearer distinction between wanting to participate in a transaction and requiring a new transaction boundary.

    To keep Base#transaction compatible with existing apps, we should :nest => true by default but disable for save/destroy callback transactions.

  • Jeremy Kemper

    Jeremy Kemper January 10th, 2009 @ 11:13 PM

    • State changed from “open” to “committed”
  • Repository

    Repository January 10th, 2009 @ 11:30 PM

    (from [ab0ce052ba23a4cce7a84ecade0d00d9cc518ebd]) Introduce transaction_joinable flag to mark that the fixtures transaction can't joined, a new savepoint is required even if :requires_new is not set. Use :requires_new option instead of :nest. Update changelog.

    [#383 state:committed]

  • Greg

    Greg January 16th, 2009 @ 09:07 PM

    Can we ensure there's a way to easily debug issues one has when using the feature. I'm thinking of setting out the development database logs with the SQL trace in a fashion where it's easy to see what: (a) transaction it's part of (b) what save point section it's part of (if that makes sense)

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href=""></a>


Referenced by