This document covers the following topics:
Scenario 1: Read-only Scenario without Consistency Requirements
Scenario 2: Read-only Scenario with Consistency Requirements
In this scenario documents are read from Tamino with the lowest possible consistency requirements. Documents may be read whose content may contain uncommitted changes of other concurrent transactions. This may lead to dirty reads and non-repeatable reads as described above. For an explanation of dirty reads and non-repeatable reads refer to section Concurrency Phenomena in DBMS of this document.
Cursor-free Approach
If no cursoring is required, single read requests (direct reads or queries) may be issued in a session-less connection to Tamino without an explicit transaction context. Just choose the default isolation level for session-less context, namely "uncommittedDocument". This avoids the cost of setting up and maintaining sessions, so this is the fastest alternative.
This choice does not automatically suppress setting locks.
An example Java application which only reads data efficiently in a session-less context without consistency requirements may for instance look like this example:
Open a Tamino connection in auto-commit
mode by invoking the newConnection
method of the class
TConnection
on an instance which had been created using
TConnectionFactory
's method
getInstance
.
TConnection connection = null; String taminoURI = "http://localhost/tamino/myDB"; String collection = "encyclopedia"; // Establish the Tamino connection (by default in auto-commit mode) connection = TConnectionFactory.getInstance().newConnection( taminoURI ); ...
Create an appropriate accessor object by invoking the
newXMLObjectAccessor
method of
TConnection
.
... // Obtain a TXMLObjectAccessor with a DOM object model TXMLObjectAccessor accessor = connection.newXMLObjectAccessor( TAccessLocation.newInstance( collection ), TDOMObjectModel.getInstance() ); ...
You may additionally set the lock mode associated to this accessor object to the value "unprotected" in order to avoid any locks. In this manner the highest possible performance for read operations can be achieved.
... // Set the lock mode to unprotected to avoid any locks accessor.setLockMode(TLockMode.UNPROTECTED); ...
Perform a read access using the class
TQuery
and display the result of the query.
... // execute a query TQuery query = TQuery.newInstance("/jazzMusician[./instrument=\"trumpet\"]/name/first"); TResponse response = accessor.query(query); // display result TXMLObject xmlObject = response.getFirstXMLObject(); System.out.println("result: " + ((Element)xmlObject.getElement()).getFirstChild().getNodeValue()); ...
Or:
Alternatively, if cursoring is required you can implement this scenario also with explicit transactions. A session is therefore required. You need to explicitly specify the lowest possible isolation level "uncommittedDocument" to be used as it is not the default for session context.
Locks will still be set and cannot always be avoided:
X-Query allows using the lockmode "unprotected".
Note:
Dirty reads are possible for both XQuery and
X-Query. However, for some join operations, XQuery (but not X-Query) might have
to read a document more than once. If the document has been changed between the
read operations (which is possible since the query is not using locks), the
XQuery processing detects an inconsistent state and returns an error 6312.
For instance, an example Java application which only reads data efficiently in a session based context without consistency requirements could work in the following manner:
It opens a Tamino connection similarly to the explanation given in the previous example (Cursor-free Approach).
it switches this connection to session mode in order to work with explicit transactions.
... // Establish a transaction context and therefore create a session TLocalTransaction transaction = connection.useLocalTransactionMode(); ...
and creates a new session implicitly.
These two steps are accomplished by invoking the
useLocalTransactionMode
method of the class
TConnection
.
It sets the isolation level of this new session to the value
"UNCOMMITTED_DOCUMENT" by invoking the
setIsolationDegree
method of the class
TConnection
.
... // Set isolation level to UNCOMMITTED_DOCUMENT connection.setIsolationDegree(TIsolationDegree.UNCOMMITTED_DOCUMENT); ...
It creates an appropriate accessor object by invoking the
newXMLObjectAccessor
method of
TConnection
.
It performs a read access using TQuery
and
displays the result.
... // execute a query TQuery query = TQuery.newInstance("/jazzMusician[./instrument=\"trumpet\"]/name/first"); TResponse response = accessor.query(query,5); // display result TXMLObjectIterator xmlObjectIterator = response.getXMLObjectIterator(); while (xmlObjectIterator.hasNext()) { TXMLObject xmlObject = xmlObjectIterator.next(); System.out.println("result: " + ((Element)xmlObject.getElement()).getFirstChild().getNodeValue()); ...
The degree of locking is very low in all versions of this scenario. It is in fact very close to the minimum possible degree of locking at all. Processing with very high performance can therefore be expected.
This scenario is not adequate in the following situations:
For data with high or medium consistency requirements.
For data with frequent changes.
If any changes to the data are required.
Important:
This is the scenario with the lowest degree of consistency of
all the scenarios discussed here.
This scenario uses the isolation level "committedCommand" which protects against dirty reads, but not against non-repeatable reads.
The characteristics of this scenario are:
No lost updates.
No dirty writes.
No dirty reads.
Only results of committed transactions can be read.
Non-repeatable read may still occur.
Shared locks are used for query execution. They are released after command execution has finished.
Tip:
This scenario is recommended for reading access to data with medium
consistency requirements that does not change very frequently. The risk of
non-repeatable read must not be high if this scenario shall be
used.
This scenario is not recommended in the following situations:
For data with high consistency requirements.
For data with frequent changes.
If any changes to the data are required.
Cursor-free Approach
In case no cursoring is required, single read requests (direct reads or queries) can be issued in a session-less connection to Tamino without an explicit transaction context. Just choose the correct isolation level for session-less context, namely "committedCommand". No sessions need to be maintained in this case.
Transaction 1 only uses shared locks which are released after the read command is completely executed.
For instance, a Java application which only reads already committed data in a session-less context with basic consistency requirements could look like this:
First the Java application opens a Tamino connection either in auto-commit mode or in local mode depending on your specific requirements as already described in the previous scenario.
It sets the isolation level of the connection object to the value
"committedCommand" by invoking the
setIsolationDegree
method of the class
TConnection
.
... // Set the isolation level to COMMITTED_COMMAND connection.setIsolationDegree(TIsolationDegree.COMMITTED_COMMAND); ...
It creates an appropriate accessor object by invoking the
newXMLObjectAccessor
method of
TConnection
.
It performs a read access using the class
TQuery
.
It displays the result of the query.
... // display result TXMLObject xmlObject = response.getFirstXMLObject(); System.out.println("result: " + ((Element)xmlObject.getElement()).getFirstChild().getNodeValue()); ...
Transactions belonging to this scenario will only read data which has been already committed by other transactions. In this scenario some locks are set that may lead to transactions having to wait for each other. But locks are only kept per command thus keeping the wait time low. Non-repeatable read situations may still occur but there will definitely be no dirty reads anymore.
A non-repeatable read operation may happen in the following manner:
The following assumptions are made:
Transaction 1 is the transaction considered in this scenario using the isolation level "committedCommand". Transaction 2 can run on an arbitrary isolation level and use any possible locking mode.
Transaction 1 reads document x
Transaction 2 writes document x
Transaction 2 performs a commit
operation.
Transaction 1 reads document x again.
Then transaction 1 performs a non-repeatable read operation.
The second read operation will be performed successfully, but the
delivered result will be different from the result obtained in the first step.
This is due to the fact that there was a commit
operation performed between the two different read attempts, and the chosen
isolation level is "committedCommand" which is
equivalent to showing all committed results to other concurrent transactions.
The locks set by transaction 1 are relinquished after the first read command
completed.
In this scenario either new documents are inserted or existing documents
are updated regardless of the contents of the database. This means that all
database access is done exclusively with the
_process
and no read access or updates via XQuery
occur. Complete documents are replaced in the database without previously
checking whether the document is already present or what its content is. This
scenario represents the maximum of performance for writing access, but it is of
course limited in its applicability.
Execute the _process
commands in session-less
context. Do not specify any isolation level or lock mode
explicitly.
It is recommended to apply this scenario if you have to store large amounts of data independently of conditions.
This scenario cannot be applied if any contents of the database must be read prior to writing to the database.
For instance, a Java application which only reads already committed data in a session-less context with basic consistency requirements could look like this:
First the Java application opens a Tamino connection in auto-commit mode as already described in the previous scenario.
TConnection connection = null; String taminoURI = "http://localhost/tamino/myDB"; String collection = "encyclopedia"; // Establish the Tamino connection in auto-commit mode connection = TConnectionFactory.getInstance().newConnection( taminoURI ); ...
It does not set the isolation level or the lock mode explicitly.
It creates an appropriate accessor object by invoking the
newXMLObjectAccessor
method of
TConnection
.
It performs a sequence of _process
commands in session-less context.
... // process data ...
In this scenario a document is first read and then changed afterwards. At the time the document is read it is clear (or at least likely) that an update of the document will follow. In order to prevent deadlock scenarios, the lock required for the update is already set at read time.
The occurrence of deadlock scenarios of the following type can be avoided if the lock mode is set to "protected" before reading the document:
T1 | T2 | ||
Read doc1 | S on doc1 | ||
Read doc1 | S on doc1 | ||
Update doc1 | Wait for X on doc1 | ||
Update doc1 | Wait for X on doc1 | ||
Deadlock |
The following situation leads to the deadlock as both transactions wait for an X-lock being granted which will never occur. However, if the an X-lock is set already on reading document 1 (this is enforced by setting the lock mode to "protected" before reading the document) the following occurs:
T1 | T2 | ||
Read doc1 | X on doc1 | ||
Read doc1 | S on doc1 (will not be granted) | ||
Update doc1 | As X-lock is already on doc1 | ||
Commit | Relinquish lock on doc1 |
Thus the deadlock is resolved as transaction 1 can continue without waiting.
This scenario only makes sense if:
Deadlock scenarios as described above exist.
It is known or at least very likely that the document read will be updated in the same transaction at the time of the read.
If the conditions above are not met, this may lead to a large number of superfluous X locks. In that case it might be better to avoid possible deadlocks in another way.
In this scenario the same document is read more than once in the same cursor. The content of the document is guaranteed to be identical.
In order to accomplish this, the isolation level must be set to "stableCursor".
Stable Cursor Scenario - Cursor-based Approach
Working with cursors requires a session context and therefore explicit transactions. The isolation level "stableCursor" needs to be specified explicitly as it is not the default for session context.
Caution:
In this scenario locks are kept for the duration of the cursor,
thus keeping these locks for a potentially long period of time.
This choice can be considered to achieve a medium performance.
For instance, an example Java application which only reads data in a session based context without consistency requirements could work in the following manner:
it opens a Tamino connection similarly to the explanation given in the previous examples.
it switches this connection to session mode in order to work with real transactions.
... // Establish a transaction context and therefore create a session TLocalTransaction transaction = connection.useLocalTransactionMode(); ...
and creates a new session implicitly.
These two steps are accomplished by invoking the
useLocalTransactionMode
method of the class
TConnection
.
it sets the isolation level of this new session to the value
"STABLE_CURSOR" by invoking the
setIsolationDegree
method of the class
TConnection
.
... // Set isolation level to STABLE_CURSOR connection.setIsolationDegree(TIsolationDegree.STABLE_CURSOR); ...
it creates an appropriate accessor object by invoking the
newXMLObjectAccessor
method of
TConnection
.
... // Obtain a TXMLObjectAccessor with a DOM object model TXMLObjectAccessor accessor = connection.newXMLObjectAccessor( TAccessLocation.newInstance( collection ), TDOMObjectModel.getInstance() ); ...
it finally accesses the data.
Lock acquisition in a fixed document order can also be used as a means in order to prevent the occurrence of deadlocks.