<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: transactions</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/transactions.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-02-17T07:04:22+00:00</updated><author><name>Simon Willison</name></author><entry><title>What to do about SQLITE_BUSY errors despite setting a timeout</title><link href="https://simonwillison.net/2025/Feb/17/sqlite-busy/#atom-tag" rel="alternate"/><published>2025-02-17T07:04:22+00:00</published><updated>2025-02-17T07:04:22+00:00</updated><id>https://simonwillison.net/2025/Feb/17/sqlite-busy/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://berthub.eu/articles/posts/a-brief-post-on-sqlite3-database-locked-despite-timeout/"&gt;What to do about SQLITE_BUSY errors despite setting a timeout&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Bert Hubert takes on the challenge of explaining SQLite's single biggest footgun: in WAL mode you may see &lt;code&gt;SQLITE_BUSY&lt;/code&gt; errors even when you have a generous timeout set if a transaction attempts to obtain a write lock after initially running at least one &lt;code&gt;SELECT&lt;/code&gt;. The fix is to use &lt;code&gt;BEGIN IMMEDIATE&lt;/code&gt; if you know your transaction is going to make a write.&lt;/p&gt;
&lt;p&gt;Bert provides the clearest explanation I've seen yet of &lt;em&gt;why&lt;/em&gt; this is necessary:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When the transaction on the left wanted to upgrade itself to a read-write transaction, SQLite could not allow this since the transaction on the right might already have made changes that the transaction on the left had not yet seen.&lt;/p&gt;
&lt;p&gt;This in turn means that if left and right transactions would commit sequentially, the result would not necessarily be what would have happened if all statements had been executed sequentially within the same transaction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I've written about this a few times before, so I just started a &lt;a href="https://simonwillison.net/tags/sqlite-busy/"&gt;sqlite-busy tag&lt;/a&gt; to collect my notes together on a single page.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://lobste.rs/s/yapvon/what_do_about_sqlite_busy_errors_despite"&gt;lobste.rs&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/databases"&gt;databases&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite-busy"&gt;sqlite-busy&lt;/a&gt;&lt;/p&gt;



</summary><category term="databases"/><category term="sqlite"/><category term="transactions"/><category term="sqlite-busy"/></entry><entry><title>Datasette 1.0a10</title><link href="https://simonwillison.net/2024/Feb/18/datasette-10a10/#atom-tag" rel="alternate"/><published>2024-02-18T05:10:13+00:00</published><updated>2024-02-18T05:10:13+00:00</updated><id>https://simonwillison.net/2024/Feb/18/datasette-10a10/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://docs.datasette.io/en/latest/changelog.html#a10-2024-02-17"&gt;Datasette 1.0a10&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
The only changes in this alpha release concern the way Datasette handles database transactions. The database.execute_write_fn() internal method used to leave functions to implement transactions on their own—it now defaults to wrapping them in a transaction unless they opt out with the new transaction=False parameter.&lt;/p&gt;

&lt;p&gt;In implementing this I found several places inside Datasette—in particular parts of the JSON write API—which had not been handling transactions correctly. Those are all now fixed.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/projects"&gt;projects&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datasette"&gt;datasette&lt;/a&gt;&lt;/p&gt;



</summary><category term="projects"/><category term="sqlite"/><category term="transactions"/><category term="datasette"/></entry><entry><title>How to implement a “dry run mode” for data imports in Django</title><link href="https://simonwillison.net/2022/Oct/13/dry-run-mode/#atom-tag" rel="alternate"/><published>2022-10-13T16:22:09+00:00</published><updated>2022-10-13T16:22:09+00:00</updated><id>https://simonwillison.net/2022/Oct/13/dry-run-mode/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://adamj.eu/tech/2022/10/13/dry-run-mode-for-data-imports-in-django/"&gt;How to implement a “dry run mode” for data imports in Django&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Adam Johnson describes in detail a beautiful pattern for implementing a dry-run mode for a Django management command, by executing ORM calls inside an &lt;code&gt;atomic()&lt;/code&gt; transaction block, showing a summary of changes that are made and then rolling the transaction back at the end.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/adamchainz/status/1580551858858627072"&gt;@adamchainz&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/adam-johnson"&gt;adam-johnson&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="transactions"/><category term="adam-johnson"/></entry><entry><title>The trouble with transaction.atomic</title><link href="https://simonwillison.net/2020/Nov/20/trouble-transactionatomic/#atom-tag" rel="alternate"/><published>2020-11-20T15:57:03+00:00</published><updated>2020-11-20T15:57:03+00:00</updated><id>https://simonwillison.net/2020/Nov/20/trouble-transactionatomic/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://seddonym.me/2020/11/19/trouble-atomic/"&gt;The trouble with transaction.atomic&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
David Seddon provides a detailed explanation of Django’s nestable transaction.atomic() context manager and describes a gotcha that can occur if you lose track of whether your code is already running in a transaction block, since you may be working with savepoints instead—along with some smart workarounds.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://twitter.com/adamchainz/status/1329790716239810561"&gt;@adamchainz&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="transactions"/></entry><entry><title>Django now has fast tests</title><link href="https://simonwillison.net/2009/Jan/16/fast/#atom-tag" rel="alternate"/><published>2009-01-16T11:40:20+00:00</published><updated>2009-01-16T11:40:20+00:00</updated><id>https://simonwillison.net/2009/Jan/16/fast/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://ericholscher.com/blog/2009/jan/15/django-now-has-fast-tests/"&gt;Django now has fast tests&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Changeset 9756 switched Django’s TestCase class to running tests inside a transaction and rolling back at the end (instead of doing a full dump and reload). “Ellington’s test suite, which was taking around 1.5-2 hours to run on Postgres, has been reduced to 10 minutes.”


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/ellington"&gt;ellington&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/eric-holscher"&gt;eric-holscher&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="ellington"/><category term="eric-holscher"/><category term="python"/><category term="testing"/><category term="transactions"/></entry><entry><title>Django Unit Tests and Transactions</title><link href="https://simonwillison.net/2008/Jul/7/transactions/#atom-tag" rel="alternate"/><published>2008-07-07T14:14:00+00:00</published><updated>2008-07-07T14:14:00+00:00</updated><id>https://simonwillison.net/2008/Jul/7/transactions/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.stereoplex.com/two-voices/django-unit-tests-and-transactions"&gt;Django Unit Tests and Transactions&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
If you’re using a transactional database engine (MySQL with InnoDB, Postgres or SQLite) you can speed things up by running each of your unit tests inside a transaction and rolling back in tearDown().


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/innodb"&gt;innodb&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/mysql"&gt;mysql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/postgresql"&gt;postgresql&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/sqlite"&gt;sqlite&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/testing"&gt;testing&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/transactions"&gt;transactions&lt;/a&gt;&lt;/p&gt;



</summary><category term="django"/><category term="innodb"/><category term="mysql"/><category term="postgresql"/><category term="python"/><category term="sqlite"/><category term="testing"/><category term="transactions"/></entry></feed>