1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
|
#pragma once
namespace sql {
class DBConnection;
/**
* RAII-style object to start a transaction for a database connection.
*
* The default behavior is for the class to start a transaction when an instance is constructed,
* and rolling back the transaction in the destructor. To inhibit this behavior and explicitly
* commit the transaction, call the `commit` member function.
*
* The default behavior can be altered by passing the `end` parameter to the constructor.
*
* Note that nested transactions are handled by simply keeping the topmost one going (some
* databases do not support nested transactions at all). As such, commit/rollback calls on
* nested transactions are ignored.
*
* Note: Nested transactions can possibly be emulated with chained transactions for
* MariaDB/MySQL or with savepoints in SQLite.
*/
class Transaction {
STORM_VALUE;
public:
// How to end a transaction.
enum End {
STORM_NAME(endNothing, nothing),
STORM_NAME(endCommit, commit),
STORM_NAME(endRollback, rollback),
};
// Start a new transaction. The transaction ends by rolling back any changes unless `commit`
// or `rollback` are called.
STORM_CTOR Transaction(DBConnection *c);
// Start a new transaction, specifying how the class should handle behave if neither
// `commit` nor `rollback` are called.
STORM_CTOR Transaction(DBConnection *c, End end);
// Destroy, potentially end the transaction.
~Transaction();
// Copy, for bookkeeping.
Transaction(const Transaction &other);
Transaction &operator =(const Transaction &other);
// Commit the transaction now, overriding the default behavior specified in the constructor.
void STORM_FN commit();
// Rollback the transaction now, overriding the default behavior specified in the constructor.
void STORM_FN rollback();
private:
friend class DBConnection;
/**
* Transaction state, to keep track of topmost currently active transaction.
*
* Note, we are sloppy with the types to save template instantiations and since the type is
* private.
*/
class State : public Object {
STORM_CLASS;
public:
// Create.
State(DBConnection *c, End end);
// Update refcount.
void ref() {
atomicIncrement(refs);
}
void unref() {
if (atomicDecrement(refs) == 0) {
finish();
}
}
// Commit/rollback.
void commit();
void rollback();
private:
// Connection.
DBConnection *connection;
// Parent state (may be null).
State *parent;
// What to do when the transaction is finished.
End end;
// Number of references to this object.
Nat refs;
// Finish the transaction.
void finish();
};
// State for this transaction.
State *state;
};
}
|