Does Android SQLite support nested transactions?

Source: Internet
Author: User

Android SQLite-related java source code has repeatedly mentioned support for nested transaction.

SQLite itself does not support nested transactions and can only be replaced by savepoint.

Nested transactions are similar

 

BEGIN     BEGIN     ......

Not many people may write this statement directly. In more cases, one program calls other programs while others have their own transactions.

 

By viewing the Android source code, we found that:

Android only blocks the begin end of a subtransaction and only applies the begin end of the outermost transaction. At the same time, a subtransaction error may cause an error in the entire nested transaction and the entire rollback.

Of course, SQL SERVER does not seem to support real nested transactions, so it is not very detailed.

Bytes --------------------------------------------------------------------------------------

Android SQLite processes nested transactions in SqliteSession. Most database-related operations are called through SQLiteDataBase --> SqliteSeesion --> SqliteConnectionPool --> SqliteConnection. Detailed analysis later. You only need to know That SQLiteDatabase. beginTransacion () calls SQLiteSeesion. beginTransacion. As follows:

 

Public void beginTransaction () {beginTransaction (null, true);} private void beginTransaction (SQLiteTransactionListener transactionListener, boolean exclusive) {acquireReference (); try {getThreadSession (). beginTransaction (// --- get the thread session and start the transaction exclusive? SQLiteSession. TRANSACTION_MODE_EXCLUSIVE: SQLiteSession. TRANSACTION_MODE_IMMEDIATE, transactionListener, getthreaddefaconnecticonnectionflags (false/* readOnly */), null);} finally {releaseReference ();}}
--------------------------------------------------------------------

 

In SQLiteSeesion, note the following:

 

Private Transaction mTransactionPool; // Transaction pool private Transaction mTransactionStack; // Transaction stack private static final class Transaction {public Transaction mParent; public int mMode; public SQLiteTransactionListener mListener; public boolean mMarkedSuccessful; public boolean mChildFailed ;}
We can guess that the transaction stack and transaction pool are actually two transaction chains linked with mParent.

 

First look at beginTransaction.

 

Public void beginTransaction (/* omitted parameter */) {throwIfTransactionMarkedSuccessful (); beginTransactionUnchecked (/* omitted parameter */);} private void beginTransactionUnchecked (/* omitted parameter */) {//... if (mTransactionStack = null) {// obtain the new connection acquireConnection (null, connectionFlags, cancellationSignal) as the transaction stack is empty;} try {if (mTransactionStack = null) {// if the transaction stack is empty, execute "begin" switch (transactionMode) {// if the transaction stack is not empty, directly skip case TRANSACTION_MODE_IMMEDIATE: mConnection.exe cute (begin immediate;, null, cancellationSignal ); break; case TRANSACTION_MODE_EXCLUSIVE: mConnection.exe cute (begin exclusive;, null, cancellationSignal); break; default: mConnection.exe cute (BEGIN;, null, cancellationSignal); break ;}} //... listening for transactionListener Transaction transaction = obtainTransaction (transactionMode, transactionListener) is omitted; // obtain the new transaction Transaction. mParent = mTransactionStack; // Add the transaction to the transaction stack mTransactionStack = transaction;} finally {if (mTransactionStack = null) {releaseConnection (); // might throw }}}
Obtain the new transaction obtainTransaction () as follows:

 

 

Private Transaction obtainTransaction (int mode, SQLiteTransactionListener listener) {Transaction transaction = mTransactionPool; // a transaction exists in the Transaction pool and the Transaction if (transaction! = Null) {mTransactionPool = transaction. mParent; transaction. mParent = null; transaction. mMarkedSuccessful = false; transaction. mChildFailed = false;} else {transaction = new Transaction (); // otherwise new} transaction. mMode = mode; transaction. mListener = listener; return transaction ;}

As can be seen from the above, the transaction stack starts to be empty, and the transaction will be added to the transaction stack when the beginTransaction is continuously performed. How do transactions in the transaction pool come from?

 

In endTransaction:

 

Public void endTransaction (CancellationSignal cancellationSignal) {throwIfNoTransaction (); assert mConnection! = Null; endTransactionUnchecked (cancellationSignal, false);} private void endTransactionUnchecked (CancellationSignal cancellationSignal, boolean yielding) {final Transaction top = mTransactionStack; // obtain the top transaction boolean successful = (top. mMarkedSuccessful | yielding )&&! Top. mChildFailed ;//... listening to mTransactionStack = top is omitted. mParent; // remove the top from the transaction stack recycleTransaction (top); // put the top in the transaction pool if (mTransactionStack! = Null) {// transaction stack is not empty if (! Successful) {// if the transaction fails, set the sub-transaction of the transaction to the failed mTransactionStack. mChildFailed = true ;}} else {try {// The transaction stack is empty if (successful) {// if yes, COMMIT the transaction. This means that all transactions have been successfully mConnection.exe cute (COMMIT ;, null, cancellationSignal);} else {// roll back when a sub-transaction fails, the entire transaction system fails mConnection.exe cute (ROLLBACK;, null, cancellationSignal );}} finally {releaseConnection ();}}}
Private void recycleTransaction (Transaction transaction) {transaction. mParent = mTransactionPool; // put the transaction into the transaction pool Transaction. mListener = null; mTransactionPool = transaction ;}

 

As you can see, transactions in the transaction pool are composed of transactions used in the transaction stack. You do not need to put it into the transaction pool. It is extracted directly when used and the status is initialized.

We can also see that the Transaction pool is used to avoid the overhead of multiple new delete operations in Transaction. The transaction stack stores the ongoing nested transactions.

The transaction stack and transaction pool are as follows:

SetTransactionSuccessful () is relatively simple:

 

Public void setTransactionSuccessful () {// mark successful throwIfNoTransaction (); success (); mTransactionStack. mMarkedSuccessful = true; // mTransactionStack points to a recent transaction}

 

 

----------------------------------------------------------------------


Execute beginTransaction ():

When the transaction stack is empty, it means there is no outer transaction. Get transaction, execute "BEGIN", and then put transaction into the transaction stack.

If the transaction stack is not empty, it indicates that it contains an outer transaction, obtains the transaction, does not execute "BEGIN", and puts the transaction into the transaction stack.

Execute endTransaction ():

Check successful. If the transaction succeeds and the internal transaction succeeds, the transaction is successfully migrated from the transaction stack to the transaction pool.

When the transaction stack is not empty, it indicates that there are still outer transactions. If successful is the price, the transaction fails to be set as a sub-transaction.

If the transaction stack is empty, it indicates that it is already the outermost transaction. If successful is used, the transaction is committed; otherwise, the transaction is rolled back.

As you can see, in a nested transaction, no matter which transaction has an error, it will mark the transaction from its start to the outermost layer as false and roll back. It is successful only when each layer is marked successfully.

It should be noted that yield will affect the tag of the nested transaction successful, so that the current transaction is marked as successful in any way. Yield is not recommended for nested transactions in android.

 

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.