Package io.mats3.spring.jms.tx
Class JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
- java.lang.Object
-
- io.mats3.impl.jms.JmsMatsTransactionManager_Jms
-
- io.mats3.spring.jms.tx.JmsMatsTransactionManager_JmsAndSpringManagedSqlTx
-
- All Implemented Interfaces:
io.mats3.impl.jms.JmsMatsStatics,io.mats3.impl.jms.JmsMatsTransactionManager
public class JmsMatsTransactionManager_JmsAndSpringManagedSqlTx extends io.mats3.impl.jms.JmsMatsTransactionManager_JmsImplementation ofJmsMatsTransactionManagerthat in addition to the JMS transaction keeps a SpringPlatformTransactionManageremploying 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 aDataSourceTransactionManager, or you can provide aPlatformTransactionManageremploying aDataSourcethat you've created and employ externally (i.e.DataSourceTransactionManager,JpaTransactionManagerorHibernateTransactionManager). In the case where you provide aPlatformTransactionManager, you should definitely wrap the DataSource employed when creating it by the methodwrapLazyConnectionDatasource(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.JdbcTemplates does not matter, as Spring'sDataSourceUtilsandTransactionSynchronizationManagerhas an unwrapping strategy when retrieving the transactionally demarcated Connection. Explanation of Best Effort 1 Phase Commit:- JMS transaction is entered (a transactional JMS Connection is always within a transaction)
- JMS Message is retrieved.
- SQL transaction is entered
- Code is executed, including SQL statements and production of new "outgoing" JMS Messages.
- SQL transaction is committed - Any errors also rollbacks the JMS Transaction, so that none of them have happened.
- JMS transaction is committed.
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 usingProcessContext.getAttribute(Connection.class)- which also is available usingContextLocal.getAttribute(Connection.class). Notice: In a Spring context, you can also get the transactionally demarcated thread-bound Connection viaDataSourceUtils.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.).
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description protected static classJmsMatsTransactionManager_JmsAndSpringManagedSqlTx.DeferredConnectionProxyDataSourceWrapper_InfrastructureProxyExtension ofDeferredConnectionProxyDataSourceWrapperwhich implementsInfrastructureProxy.
-
Field Summary
Fields Modifier and Type Field Description static java.lang.StringCONTEXT_LOCAL_KEY_CONNECTION_EMPLOYED_STATE_SUPPLIERASupplier<Boolean>bound toMatsFactory.ContextLocalwhen inside a Mats-transactional demarcation.-
Fields inherited from interface io.mats3.impl.jms.JmsMatsStatics
EXTRA_GRACE_MILLIS, ILLEGAL_CALL_FLOWS, JMS_MSG_PROP_AUDIT, JMS_MSG_PROP_DISPATCH_TYPE, JMS_MSG_PROP_DLQ_APP_VERSION_AND_HOST, JMS_MSG_PROP_DLQ_DELIVERY_COUNT, JMS_MSG_PROP_DLQ_DLQ_COUNT, JMS_MSG_PROP_DLQ_EXCEPTION, JMS_MSG_PROP_DLQ_REFUSED, JMS_MSG_PROP_DLQ_STAGE_ORIGIN, JMS_MSG_PROP_EXPIRES, JMS_MSG_PROP_FROM, JMS_MSG_PROP_INITIATING_APP, JMS_MSG_PROP_INITIATOR_ID, JMS_MSG_PROP_INTERACTIVE, JMS_MSG_PROP_MATS_MESSAGE_ID, JMS_MSG_PROP_MESSAGE_TYPE, JMS_MSG_PROP_NO_AUDIT, JMS_MSG_PROP_NON_PERSISTENT, 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_MATS_MESSAGE_ID, MDC_MATS_IN_MESSAGE_SYSTEM_ID, MDC_MATS_INIT, MDC_MATS_OUT_MATS_MESSAGE_ID, MDC_MATS_STAGE, MDC_MATS_STAGE_ID, MDC_MATS_STAGE_INDEX, MDC_MATS_TOTAL_CALL_NUMBER, MDC_TRACE_ID, NO_INVOCATION_POINT, RANDOM_ALPHABET, THREAD_PREFIX, TOTAL_JMS_MSG_PROPS_SIZE
-
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(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 withwrapLazyConnectionDatasource(DataSource)), and use the factory methodcreate(PlatformTransactionManager)(it will find the DataSource from the PlatformTransactionManager by introspection).static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(javax.sql.DataSource dataSource, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)Creates an internalDataSourceTransactionManagerfor this created JmsMatsTransactionManager, and ensures that the suppliedDataSourceis wrapped using thewrapLazyConnectionDatasource(DataSource)method.static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(org.springframework.transaction.PlatformTransactionManager platformTransactionManager)Next simplest, recommended if you also need the PlatformTransactionManager in your Spring context! (otherwise, use thecreate(DataSource)factory method).static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)Creates an instance of this class from a providedPlatformTransactionManager(of a type which manages a DataSource), where the supplied instance is introspected to find a methodgetDataSource()from where to get the underlying DataSource.static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource)Creates aJmsMatsTransactionManager_JmsAndSpringManagedSqlTxfrom a providedPlatformTransactionManager(of a type which manages a DataSource) - Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(DataSource)method.static JmsMatsTransactionManager_JmsAndSpringManagedSqlTxcreate(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)Creates aJmsMatsTransactionManager_JmsAndSpringManagedSqlTxfrom a providedPlatformTransactionManager(of a type which manages a DataSource) - Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(DataSource)method.javax.sql.DataSourcegetDataSource()javax.sql.DataSourcegetDataSourceUnwrapped()org.springframework.transaction.PlatformTransactionManagergetPlatformTransactionManager()static java.util.function.Function<io.mats3.impl.jms.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.java.lang.StringgetSystemInformation()io.mats3.impl.jms.JmsMatsTransactionManager.TransactionContextgetTransactionContext(io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey txContextKey)static javax.sql.DataSourcewrapLazyConnectionDatasource(javax.sql.DataSource targetDataSource)Creates a proxy/wrapper that has lazy connection getting, and monitoring of whether the connection was actually retrieved.
-
-
-
Field Detail
-
CONTEXT_LOCAL_KEY_CONNECTION_EMPLOYED_STATE_SUPPLIER
public static final java.lang.String CONTEXT_LOCAL_KEY_CONNECTION_EMPLOYED_STATE_SUPPLIER
ASupplier<Boolean>bound toMatsFactory.ContextLocalwhen inside a Mats-transactional demarcation.- See Also:
- Constant Field Values
-
-
Method Detail
-
create
public 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 withwrapLazyConnectionDatasource(DataSource)), and use the factory methodcreate(PlatformTransactionManager)(it will find the DataSource from the PlatformTransactionManager by introspection). Creates an internalDataSourceTransactionManagerfor this created JmsMatsTransactionManager, and ensures that the suppliedDataSourceis wrapped using thewrapLazyConnectionDatasource(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 defaultTransactionDefinitionFunction, which sets the transaction name, sets Isolation Level toTransactionDefinition.ISOLATION_READ_COMMITTED, and sets Propagation Behavior toTransactionDefinition.PROPAGATION_REQUIRES_NEW.- Parameters:
dataSource- the DataSource to make aDataSourceTransactionManagerfrom - which will be wrapped usingwrapLazyConnectionDatasource(DataSource)if it not already is.- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
create
public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(javax.sql.DataSource dataSource, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates an internalDataSourceTransactionManagerfor this created JmsMatsTransactionManager, and ensures that the suppliedDataSourceis wrapped using thewrapLazyConnectionDatasource(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 suppliedTransactionDefinitionFunction to define the transactions - considercreate(DataSource)if you are OK with the standard.- Parameters:
dataSource- the DataSource to make aDataSourceTransactionManagerfrom - which will be wrapped usingwrapLazyConnectionDatasource(DataSource)if it not already is.transactionDefinitionFunction- aFunctionwhich returns aDefaultTransactionDefinition, possibly based on the providedJmsMatsTransactionManager.JmsMatsTxContextKey(e.g. different isolation level for a special endpoint).- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
create
public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager)
Next simplest, recommended if you also need the PlatformTransactionManager in your Spring context! (otherwise, use thecreate(DataSource)factory method). Creates an instance of this class from a providedPlatformTransactionManager(of a type which manages a DataSource), where the supplied instance is introspected to find a methodgetDataSource()from where to get the underlying DataSource. Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(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 standardTransactionDefinitionFunction, which sets the transaction name, sets Isolation Level toTransactionDefinition.ISOLATION_READ_COMMITTED(unless HibernateTxMgr), and sets Propagation Behavior toTransactionDefinition.PROPAGATION_REQUIRES_NEW- seegetStandardTransactionDefinitionFunctionFor(Class).- Parameters:
platformTransactionManager- theDataSourceTransactionManagerto use for transaction management.- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
create
public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates an instance of this class from a providedPlatformTransactionManager(of a type which manages a DataSource), where the supplied instance is introspected to find a methodgetDataSource()from where to get the underlying DataSource. Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(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 suppliedTransactionDefinitionFunction to define the transactions - considercreate(PlatformTransactionManager)if you are OK with the standard.- Parameters:
platformTransactionManager- theDataSourceTransactionManagerto use for transaction management.- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
create
public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource)
Creates aJmsMatsTransactionManager_JmsAndSpringManagedSqlTxfrom a providedPlatformTransactionManager(of a type which manages a DataSource) - Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(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 standardTransactionDefinitionFunction, which sets the transaction name, sets Isolation Level toTransactionDefinition.ISOLATION_READ_COMMITTED(unless HibernateTxMgr), and sets Propagation Behavior toTransactionDefinition.PROPAGATION_REQUIRES_NEW- seegetStandardTransactionDefinitionFunctionFor(Class).- Parameters:
platformTransactionManager- theDataSourceTransactionManagerto use for transaction management.dataSource- theDataSourcewhich the suppliedPlatformTransactionManagerhandles.- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
create
public static JmsMatsTransactionManager_JmsAndSpringManagedSqlTx create(org.springframework.transaction.PlatformTransactionManager platformTransactionManager, javax.sql.DataSource dataSource, java.util.function.Function<io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey,org.springframework.transaction.support.DefaultTransactionDefinition> transactionDefinitionFunction)
Creates aJmsMatsTransactionManager_JmsAndSpringManagedSqlTxfrom a providedPlatformTransactionManager(of a type which manages a DataSource) - Do note that you should preferably have theDataSourcewithin thewrapped using thePlatformTransactionManagerwrapLazyConnectionDatasource(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 suppliedTransactionDefinitionFunction to define the transactions - considercreate(PlatformTransactionManager, DataSource)if you are OK with the standard.- Parameters:
platformTransactionManager- thePlatformTransactionManagerto use for transaction management (must be one employing a DataSource).dataSource- theDataSourcewhich the suppliedPlatformTransactionManagerhandles.transactionDefinitionFunction- aFunctionwhich returns aDefaultTransactionDefinition, possibly based on the providedJmsMatsTransactionManager.JmsMatsTxContextKey(e.g. different isolation level for a special endpoint).- Returns:
- a new
JmsMatsTransactionManager_JmsAndSpringManagedSqlTx.
-
getStandardTransactionDefinitionFunctionFor
public static java.util.function.Function<io.mats3.impl.jms.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. Sets Isolation Level toISOLATION_READ_COMMITTED(unless HibernateTransactionManager, which does not support setting Isolation Level) and Propagation Behavior toPROPAGATION_REQUIRES_NEW- and also sets the name of the transaction toJmsMatsTransactionManager.JmsMatsTxContextKey.toString().
-
wrapLazyConnectionDatasource
public 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. This again enables SpringJmsMats implementation to see if the SQL Connection was actually employed (i.e. a Statement was created) - not only whether we went into transactional demarcation, which a Mats stage always does. This method is internally employed with theDataSource-takingfactories of this class which makes an internalDataSourceTransactionManager, but should also be employed if you externally create another type ofPlatformTransactionManager, e.g. the HibernateTransactionManager, and provide that to the factories of this class taking a PlatformTransactionManager. It returns an instance ofDeferredConnectionProxyDataSourceWrapper, but as an extension that also implements Spring'sInfrastructureProxy. 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'sDataSourceUtilscompare them in its ThreadLocal cache-hackery. Therefore, the proxy implementInfrastructureProxy(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 theTransactionSynchronizationManager.getResource(Object), which invokesTransactionSynchronizationUtils.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 aLazyConnectionDataSourceProxy, 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"
-
getPlatformTransactionManager
public org.springframework.transaction.PlatformTransactionManager getPlatformTransactionManager()
- Returns:
- the employed Spring
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.
-
getDataSource
public javax.sql.DataSource getDataSource()
- Returns:
- the employed
DataSource, which either was provided when creating this instance (and thus wrapped), or was reflected out of the providedPlatformTransactionManager. It is hopefully wrapped using thewrapLazyConnectionDatasource(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.
-
getDataSourceUnwrapped
public javax.sql.DataSource getDataSourceUnwrapped()
- Returns:
- the unwrapped variant of
getDataSource()- note that it is only anyInfrastructureProxys that are unwrapped; Any wrapping done by a database pool is left intact.
-
getTransactionContext
public io.mats3.impl.jms.JmsMatsTransactionManager.TransactionContext getTransactionContext(io.mats3.impl.jms.JmsMatsTransactionManager.JmsMatsTxContextKey txContextKey)
- Specified by:
getTransactionContextin interfaceio.mats3.impl.jms.JmsMatsTransactionManager- Overrides:
getTransactionContextin classio.mats3.impl.jms.JmsMatsTransactionManager_Jms
-
getSystemInformation
public java.lang.String getSystemInformation()
- Specified by:
getSystemInformationin interfaceio.mats3.impl.jms.JmsMatsTransactionManager- Overrides:
getSystemInformationin classio.mats3.impl.jms.JmsMatsTransactionManager_Jms
-
-