public class JmsMatsTransactionManager_JmsAndSpringManagedSqlTx extends JmsMatsTransactionManager_Jms
JmsMatsTransactionManager
that in addition to the JMS transaction keeps a Spring
PlatformTransactionManager
employing a JDBC DataSource for which it keeps transaction demarcation along with
the JMS transaction, by means of "Best Effort 1 Phase Commit". Note that you can choose between providing a
DataSource, in which case this JmsMatsTransactionManager internally creates a DataSourceTransactionManager
,
or you can provide a PlatformTransactionManager
employing a DataSource
that you've created
and employ externally (i.e. DataSourceTransactionManager
, JpaTransactionManager
or
HibernateTransactionManager
). In the case where you provide a PlatformTransactionManager
,
you should definitely wrap the DataSource employed when creating it by the method
wrapLazyConnectionDatasource(DataSource)
, so that you get lazy Connection fetching and so that Mats can know
whether the SQL Connection was actually employed within a Mats Stage - this also elides the committing of an empty DB
transaction if a Mats Stage does not actually employ a SQL Connection. Note that whether you use the wrapped
DataSource or the non-wrapped DataSource when creating e.g. JdbcTemplate
s does not matter, as Spring's
DataSourceUtils
and TransactionSynchronizationManager
has an unwrapping strategy when retrieving the
transactionally demarcated Connection.
Explanation of Best Effort 1 Phase Commit:
JmsMatsTransactionManager_Jms
) - and then the Message Broker will probably try to redeliver the message. Also
read the Should I use XA Transactions from Apache
Active MQ.
Wise tip when working with Message Oriented Middleware: Code idempotent! Handle double-deliveries!
The transactionally demarcated SQL Connection can be retrieved from within Mats Stage lambda code user code using
ProcessContext.getAttribute(Connection.class)
- which also is
available using ContextLocal.getAttribute(Connection.class)
.
Notice: In a Spring context, you can also get the transactionally demarcated thread-bound Connection via
DataSourceUtils.getConnection(dataSource)
- this is indeed what
Spring's JDBC Template and friends are doing. If you go directly to the DataSource, you will get a new Connection
not participating in the transaction! This "feature" might sometimes be of interest if you want something to be
performed regardless of whether the stage processing fails or not. (However, if you do such a thing, you must
remember the built-in retry mechanism JMS Message Brokers has: If something fails, whatever database changes you
performed successfully with such a non-tx-managed Connection will not participate in the rollback, and will already
have been performed when the message is retried. This might, or might not, be what you want.).Modifier and Type | Class and Description |
---|---|
protected static class |
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.DeferredConnectionProxyDataSourceWrapper_InfrastructureProxy
Extension of
DeferredConnectionProxyDataSourceWrapper which implements InfrastructureProxy . |
JmsMatsTransactionManager_Jms.TransactionalContext_Jms
JmsMatsTransactionManager.JmsMatsTxContextKey, JmsMatsTransactionManager.ProcessingLambda, JmsMatsTransactionManager.TransactionContext
Modifier and Type | Field and Description |
---|---|
static java.lang.String |
CONTEXT_LOCAL_KEY_CONNECTION_EMPLOYED_STATE_SUPPLIER
A
Supplier<Boolean> bound to MatsFactory.ContextLocal when inside a Mats-transactional
demarcation. |
EXTRA_GRACE_MILLIS, ILLEGAL_CALL_FLOWS, JMS_MSG_PROP_AUDIT, JMS_MSG_PROP_DISPATCH_TYPE, JMS_MSG_PROP_FROM, JMS_MSG_PROP_INITIALIZING_APP, JMS_MSG_PROP_INITIATOR_ID, JMS_MSG_PROP_MATS_MESSAGE_ID, JMS_MSG_PROP_MESSAGE_TYPE, JMS_MSG_PROP_TO, JMS_MSG_PROP_TRACE_ID, MAX_STACK_HEIGHT, MAX_TOTAL_CALL_NUMBER, MDC_MATS_APP_NAME, MDC_MATS_APP_VERSION, MDC_MATS_CALL_NUMBER, MDC_MATS_IN_MESSAGE_SYSTEM_ID, MDC_MATS_INIT, MDC_MATS_OUT_MATS_MESSAGE_ID, MDC_MATS_STAGE, MDC_MATS_STAGE_ID, MDC_TRACE_ID, NO_INVOCATION_POINT, RANDOM_ALPHABET, THREAD_PREFIX, TOTAL_JMS_MSG_PROPS_SIZE
Modifier and Type | Method and Description |
---|---|
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(javax.sql.DataSource dataSource)
Simplest, recommended if you do not need the PlatformTransactionManager in your Spring context! - However,
if you need the PlatformTransaction manager in the Spring context, then make it externally (typically using a
@Bean annotated method, and make sure to wrap the contained DataSource first with
wrapLazyConnectionDatasource(DataSource) ), and use the factory method
create(PlatformTransactionManager) (it will find the DataSource from the PlatformTransactionManager by
introspection). |
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(javax.sql.DataSource dataSource,
java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates an internal
DataSourceTransactionManager for this created JmsMatsTransactionManager, and ensures
that the supplied DataSource is wrapped using the wrapLazyConnectionDatasource(DataSource)
method. |
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager)
Next simplest, recommended if you also need the PlatformTransactionManager in your Spring context!
(otherwise, use the
create(DataSource) factory method). |
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager,
javax.sql.DataSource dataSource)
Creates a
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx from a provided
PlatformTransactionManager (of a type which manages a DataSource) - Do note that you should preferably
have the DataSource within the wrapped using the
wrapLazyConnectionDatasource(DataSource) method. |
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager,
javax.sql.DataSource dataSource,
java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates a
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx from a provided
PlatformTransactionManager (of a type which manages a DataSource) - Do note that you should preferably
have the DataSource within the wrapped using the
wrapLazyConnectionDatasource(DataSource) method. |
static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx |
create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager,
java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates an instance of this class from a provided
PlatformTransactionManager (of a type which manages a
DataSource), where the supplied instance is introspected to find a method getDataSource() from where
to get the underlying DataSource. |
javax.sql.DataSource |
getDataSource() |
javax.sql.DataSource |
getDataSourceUnwrapped() |
org.springframework.transaction.PlatformTransactionManager |
getPlatformTransactionManager() |
static java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> |
getStandardTransactionDefinitionFunctionFor(java.lang.Class<? extends org.springframework.transaction.PlatformTransactionManager> platformTransactionManager)
Returns the standard TransactionDefinition Function for the supplied PlatformTransactionManager.
|
JmsMatsTransactionManager.TransactionContext |
getTransactionContext(JmsMatsTransactionManager.JmsMatsTxContextKey txContextKey)
Provides an implementation of
JmsMatsTransactionManager.TransactionContext . |
static javax.sql.DataSource |
wrapLazyConnectionDatasource(javax.sql.DataSource targetDataSource)
Creates a proxy/wrapper that has lazy connection getting, and monitoring of whether the connection was actually
retrieved.
|
create
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
createFlowId, getInvocationPoint, handleIncomingMessageMatsObject, handleIncomingState, id, id, idThis, ms3, produceAndSendMsgSysMessages, randomString, setConcurrencyWithLog, stageOrInit
public static final java.lang.String CONTEXT_LOCAL_KEY_CONNECTION_EMPLOYED_STATE_SUPPLIER
Supplier<Boolean>
bound to MatsFactory.ContextLocal
when inside a Mats-transactional
demarcation.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(javax.sql.DataSource dataSource)
wrapLazyConnectionDatasource(DataSource)
), and use the factory method
create(PlatformTransactionManager)
(it will find the DataSource from the PlatformTransactionManager by
introspection).
Creates an internal DataSourceTransactionManager
for this created JmsMatsTransactionManager, and ensures
that the supplied DataSource
is wrapped using the wrapLazyConnectionDatasource(DataSource)
method. Also with this way to construct the instance, Mats will know whether the stage or initiation actually
performed any SQL data access.
Uses a default TransactionDefinition
Function, which sets the transaction name, sets Isolation Level to
TransactionDefinition.ISOLATION_READ_COMMITTED
, and sets Propagation Behavior to
TransactionDefinition.PROPAGATION_REQUIRES_NEW
.dataSource
- the DataSource to make a DataSourceTransactionManager
from - which will be wrapped using
wrapLazyConnectionDatasource(DataSource)
if it not already is.JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(javax.sql.DataSource dataSource, java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
DataSourceTransactionManager
for this created JmsMatsTransactionManager, and ensures
that the supplied DataSource
is wrapped using the wrapLazyConnectionDatasource(DataSource)
method. Also with this way to construct the instance, Mats will know whether the stage or initiation actually
performed any SQL data access.
Uses the supplied TransactionDefinition
Function to define the transactions - consider
create(DataSource)
if you are OK with the standard.dataSource
- the DataSource to make a DataSourceTransactionManager
from - which will be wrapped using
wrapLazyConnectionDatasource(DataSource)
if it not already is.transactionDefinitionFunction
- a Function
which returns a DefaultTransactionDefinition
, possibly based on the
provided JmsMatsTxContextKey
(e.g. different isolation level for a special endpoint).JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager)
create(DataSource)
factory method). Creates an instance of this class from a
provided PlatformTransactionManager
(of a type which manages a DataSource), where the supplied instance
is introspected to find a method getDataSource()
from where to get the underlying DataSource. Do
note that you should preferably have the DataSource
within the
PlatformTransactionManager
wrapped using the
wrapLazyConnectionDatasource(DataSource)
method. If not wrapped as such, Mats will not be able to
know whether the stage or initiation actually performed data access.
Uses the standard TransactionDefinition
Function, which sets the transaction name, sets Isolation Level
to TransactionDefinition.ISOLATION_READ_COMMITTED
(unless HibernateTxMgr), and sets Propagation Behavior
to TransactionDefinition.PROPAGATION_REQUIRES_NEW
- see
getStandardTransactionDefinitionFunctionFor(Class)
.platformTransactionManager
- the DataSourceTransactionManager
to use for transaction management.JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
PlatformTransactionManager
(of a type which manages a
DataSource), where the supplied instance is introspected to find a method getDataSource()
from where
to get the underlying DataSource. Do note that you should preferably have the DataSource
within the
PlatformTransactionManager
wrapped using the
wrapLazyConnectionDatasource(DataSource)
method. If not wrapped as such, Mats will not be able to
know whether the stage or initiation actually performed data access.
Uses the supplied TransactionDefinition
Function to define the transactions - consider
create(PlatformTransactionManager)
if you are OK with the standard.platformTransactionManager
- the DataSourceTransactionManager
to use for transaction management.JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource)
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
from a provided
PlatformTransactionManager
(of a type which manages a DataSource) - Do note that you should preferably
have the DataSource
within the PlatformTransactionManager
wrapped using the
wrapLazyConnectionDatasource(DataSource)
method. If not wrapped as such, Mats will not be able to know
whether the stage or initiation actually performed data access.
Note: Only use this method if the variants NOT taking a DataSource fails to work. It is imperative that
the DataSource and the PlatformTransactionManager provided "match up", meaning that the DataSource provided is
actually the instance which the PlatformTransactionManager handles.
Uses the standard TransactionDefinition
Function, which sets the transaction name, sets Isolation Level
to TransactionDefinition.ISOLATION_READ_COMMITTED
(unless HibernateTxMgr), and sets Propagation Behavior
to TransactionDefinition.PROPAGATION_REQUIRES_NEW
- see
getStandardTransactionDefinitionFunctionFor(Class)
.platformTransactionManager
- the DataSourceTransactionManager
to use for transaction management.dataSource
- the DataSource
which the supplied PlatformTransactionManager
handles.JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource, java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
from a provided
PlatformTransactionManager
(of a type which manages a DataSource) - Do note that you should preferably
have the DataSource
within the PlatformTransactionManager
wrapped using the
wrapLazyConnectionDatasource(DataSource)
method. If not wrapped as such, Mats will not be able to know
whether the stage or initiation actually performed data access.
Note: Only use this method if the variants NOT taking a DataSource fails to work. It is imperative that
the DataSource and the PlatformTransactionManager provided "match up", meaning that the DataSource provided is
actually the instance which the PlatformTransactionManager handles.
Uses the supplied TransactionDefinition
Function to define the transactions - consider
create(PlatformTransactionManager, DataSource)
if you are OK with the standard.platformTransactionManager
- the PlatformTransactionManager
to use for transaction management (must be one employing a
DataSource).dataSource
- the DataSource
which the supplied PlatformTransactionManager
handles.transactionDefinitionFunction
- a Function
which returns a DefaultTransactionDefinition
, possibly based on the
provided JmsMatsTxContextKey
(e.g. different isolation level for a special endpoint).JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
.public static java.util.function.Function<JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> getStandardTransactionDefinitionFunctionFor(java.lang.Class<? extends org.springframework.transaction.PlatformTransactionManager> platformTransactionManager)
ISOLATION_READ_COMMITTED
(unless
HibernateTransactionManager, which does not support setting Isolation Level) and Propagation Behavior to
PROPAGATION_REQUIRES_NEW
- and also sets the name of the
transaction to JmsMatsTxContextKey
.toString().public static javax.sql.DataSource wrapLazyConnectionDatasource(javax.sql.DataSource targetDataSource)
DataSource-taking
factories of this class which makes an internal DataSourceTransactionManager
, but
should also be employed if you externally create another type of PlatformTransactionManager
, e.g. the
HibernateTransactionManager, and provide that to the factories of this class taking a PlatformTransactionManager.
It returns an instance of DeferredConnectionProxyDataSourceWrapper
, but as an extension that also
implements Spring's InfrastructureProxy
.
We want this Lazy-and-Monitored DataSource which is returned here to "compare equals" with that of the DataSource
which is supplied to us - and which might be employed by other components "on the outside" of Mats - wrt. how
Spring's DataSourceUtils
compare them in its ThreadLocal cache-hackery. Therefore, the proxy implement
InfrastructureProxy
(read its JavaDoc!), which means that Spring can trawl its way down to the actual
DataSource when it needs to compare. Note: You will find this proxy-handling in the
TransactionSynchronizationManager.getResource(Object)
, which invokes
TransactionSynchronizationUtils.unwrapResourceIfNecessary(..)
, where the instanceof-check for
InfraStructureProxy resides.
"The magnitude of this hack compares favorably with that of the US-of-A's national debt."
Note: It is not a problem if the DataSource supplied is already wrapped in a
LazyConnectionDataSourceProxy
, but it is completely unnecessary.
Tip: If you would want to check/understand how the LazyConnection stuff work, you may within a Mats stage do a
DataSourceUtil.getConnection(dataSource) - if the returned Connection's toString() looks like
"DeferredConnectionProxy@3ec11999 WITHOUT actual Connection from DataSource@3406472c..."
then the
actual Connection is still not gotten. When it is gotten (e.g. after having done a SQL CRUD operation), the
toString() will look like "DeferredConnectionProxy@3ec11999 WITH actual Connection@b5cc23a"
public org.springframework.transaction.PlatformTransactionManager getPlatformTransactionManager()
PlatformTransactionManager
, which either was created by this instance if this
instance was created using one of the DataSource-taking factory methods, or it was provided if this
instance was created using one of the PlatformTransactionManager-taking methods.public javax.sql.DataSource getDataSource()
DataSource
, which either was provided when creating this instance (and thus
wrapped), or was reflected out of the provided PlatformTransactionManager
. It is hopefully
wrapped using the wrapLazyConnectionDatasource(DataSource)
, which is done automatically if this
instance was created using one of the DataSource-taking factory methods. However, if this instance was
created using one of the PlatformTransactionManager-taking factory methods, it is up to the user to have
wrapped it. Note that it works unwrapped too, but SpringJmsMats cannot then know whether the stages
actually employ the SQL Connection, and must do full transaction demarcation around every stage.public javax.sql.DataSource getDataSourceUnwrapped()
getDataSource()
- note that it is only any InfrastructureProxy
s
that are unwrapped; Any wrapping done by a database pool is left intact.public JmsMatsTransactionManager.TransactionContext getTransactionContext(JmsMatsTransactionManager.JmsMatsTxContextKey txContextKey)
JmsMatsTransactionManager
JmsMatsTransactionManager.TransactionContext
. (JMS Connection and Session handling is done by
JmsMatsJmsSessionHandler
).getTransactionContext
in interface JmsMatsTransactionManager
getTransactionContext
in class JmsMatsTransactionManager_Jms
txContextKey
- for which JmsMatsStage
or JmsMatsInitiator
this request for JmsMatsTransactionManager.TransactionContext
is for.JmsMatsTransactionManager.TransactionContext
for the supplied txContextKey.