This guide is addressed to developers who intend to enhance persistent objects' beans.
The transaction control as discussed here aims at preventing errors that may occur because of (pipeline-based) transactions that have been triggered in parallel, like, for example, double-clicking a link or a button in the storefront.
Changing a PO bean requires a transaction, for example when:
With POs, there are no implicit transactions (as in EJBs). Changing an object without transaction leads to an exception. There are two basic alternatives for transaction handling in this context:
It is possible to open and close transactions manually using the ORM engine API. To get the transaction for the current thread:
ORMMgr mgr = (ORMMgr) NamingMgr.getInstance().lookupManager(ORMMgr.REGISTRY_NAME); ORMEngine engine = mgr.getORMEngine(); Transaction txn = engine.getTransactionManager().getCurrentTransaction(); txn.begin(); txn.store(); txn.commit();
Transactions are reusable, hence multiple begin - commit - begin - ... cycles are allowed. Note, however, that transaction nesting is not supported by the ORM engine.
The ORM transaction exposes a method to set a cache synchronization mode. The respective method is:
public void com.intershop.beehive.orm.capi.transaction.Transaction.setSynchronizationMode (com.intershop.beehive.orm.capi.synchronization.SynchronizationMode mode)
The synchronization mode is considered only if cache synchronization is switched on. The mode is one of NONE, INSTANCE, CLASS or CACHE.
At pipelet and pipeline level, it is possible to explicitly control transaction demarcation, i.e., to define at which point the pipeline processor should begin, commit or rollback a database transaction. This makes it possible to execute a single pipelet or a series of pipelets within a single database transaction. The transaction context extends into pipelines joined by call or jump nodes.
If a pipelet defines transaction-sensitive methods, the pipelet property "Transaction Required" can be set. This forces the pipeline processor to open a transaction before executing the pipelet and to attempt a commit immediately afterwards. This is also true if the pipelet exits through the error exit.
When designing pipelines that contain such a pipelet, you can leave transaction demarcation to the pipeline processor (implicit transaction demarcation) or you can explicitly define at which point during pipeline execution a transaction should begin, commit or rollback.
Consider the simple example in the figure below, each pipeline containing a pipelet which requires a database transaction (marked with a 'T' in the VPM). In the pipeline with the Start1
start node, no explicit transaction points have been set, thus transaction demarcation is handled implicitly by the pipeline processor. The pipeline processor begins a transaction before executing Pipelet2, and commits once the pipelet has been executed. Therefore, the transaction context only spans Pipelet2, but excludes Pipelet1 and Pipelet3.
In the pipeline beginning with start node Start2
, it has been defined at the pipeline level that a transaction should begin before processing Pipelet1, and that a commit should take place after processing Pipelet2. Here, the transaction context spans Pipelet1 and Pipelet2, excluding Pipelet3. Pipelet2 joins the transaction opened at the pipeline level.
As illustrated in the figure, explicit transaction demarcation at the pipeline level is expressed via properties of transitions connecting pipeline nodes (see the table below).
Property | Description |
---|---|
None | Default setting. If you do not need an explicit transaction, this value is set automatically and does not need to be changed. |
Begin | Ensures that a transaction is active. If a transaction is already active, the nested transaction counter is incremented. |
Commit | Decrements the nested transaction counter and commits the transaction to the database when the outermost nested transaction is reached. If no transaction is active, nothing happens. |
Savepoint | Used to write any data that has been changed within the current transaction. Any following rollback will only be effective to this point. |
Flush | Used to store the current transaction to the database without committing it. In addition, the transactional ORM cache is cleared. |
Store | Used to store the current transaction to the database without committing it. |
Rollback | Used to undo any change done on processed data to the beginning of the outermost nested transaction. |
The following basic properties of transaction demarcation are important:
Commit
is necessary.For further information, refer to Reference - Pipeline Node Reference.
It is possible to nest transactions in pipelines, using multiple begin
/ commit
pairs. The pipeline manager tracks nested transactions with a counter. A begin
raises the count by 1, a commit
decreases it by one. If, after its one-unit decrease, the count is 0, a true database commit
is performed. This behavior can become complicated with commits
and savepoints
in nested transactions.
A commit
decreases the count by 1, but a real database commit only takes place if the counter is 0. A savepoint writes the active transaction to the database (and so makes the changes available to, e.g., JDBC select statements) and does not change the value of the counter.
Pipeline transaction synchronization allows for globally switching on transaction synchronization in pipelines. A transaction to be start through a transactional pipelet or a pipeline transition with mode "begin transaction" may be blocked as long as another transaction for the same session (the synchronization scope) is active. Based on a given set of synchronization objects the granularity of synchronization can be controlled. Three synchronization objects exist:
CurrentRequest
Transactions of all incoming requests for the same session are synchronized. No transaction blocking occurs if sessions are different (which also applies to the other synchronization objects discussed below).
To switch this synchronization behavior on, add the following two lines to the is_home/share/system/config/cluster/appserver.properties file:
intershop.pipelines.transaction.DefaultSynchronizationScope=CurrentSession intershop.pipelines.transaction.DefaultSynchronizationObject=CurrentRequest
CurrentPipeline
Transactions of all incoming requests are synchronized if they belong to the same session and the pipeline that was initially called to trigger the request has the same name. Thus, jump nodes and call nodes are not evaluated separately.
To switch this synchronization behavior on, add the following two lines to the is_home/share/system/config/cluster/appserver.properties file:
intershop.pipelines.transaction.DefaultSynchronizationScope=CurrentSession intershop.pipelines.transaction.DefaultSynchronizationObject=CurrentPipeline
CurrentStartNode
Transactions of all incoming requests are synchronized if they belong to the same session and the pipeline that was initially called to trigger the request has the same name and the same start node name. Again, jump nodes and call nodes are not evaluated separately.
To switch this synchronization behavior on, add the following two lines to the is_home/share/system/config/cluster/appserver.properties file:
intershop.pipelines.transaction.DefaultSynchronizationScope=CurrentSession intershop.pipelines.transaction.DefaultSynchronizationObject=CurrentStartNode
If the application server properties are missing or one of the properties has an invalid value assigned, no transaction synchronization takes place. The properties are case sensitive.