{"id":1597,"date":"2024-06-14T09:57:39","date_gmt":"2024-06-14T08:57:39","guid":{"rendered":"https:\/\/marketaylor.synology.me\/?p=1597"},"modified":"2024-06-14T09:57:41","modified_gmt":"2024-06-14T08:57:41","slug":"mq-spring-boot-advanced-configuration-and-transactions","status":"publish","type":"post","link":"https:\/\/marketaylor.synology.me\/?p=1597","title":{"rendered":"MQ Spring Boot: Advanced Configuration and Transactions"},"content":{"rendered":"\n<p>I was talking recently with an MQ customer who said they were considering a solution that used <a href=\"https:\/\/github.com\/ibm-messaging\/mq-jms-spring\" target=\"_blank\" rel=\"noreferrer noopener\">Spring Boot for an MQ application<\/a> that would move messages reliably from one queue manager to another, doing some processing on the way. &#8220;Can we do that?&#8221; they asked. &#8220;Of course&#8221; was my reply. But naturally I had to then try it out myself. <\/p>\n\n\n\n<p>To implement the idea, I had to dig into two aspects. I&#8217;d consider these as reasonably advanced features of Spring Boot. One part was being able to configure more than one queue manager&#8217;s connection in the resource properties file. The other was working with global JTA\/XA transactions.<\/p>\n\n\n\n<!--more-->\n\n\n\n<h4 class=\"wp-block-heading\">The sample programs<\/h4>\n\n\n\n<p>What I&#8217;ve ended up with is a pair of <a href=\"https:\/\/github.com\/ibm-messaging\/mq-jms-spring\/tree\/master\/samples\" target=\"_blank\" rel=\"noreferrer noopener\">sample programs<\/a> that both implement the first part, but have different flow patterns, and hence different ways of managing the XA transactions. The two samples are in the <em>s4.jms3<\/em> and <em>s4a.jms3<\/em> subdirectories of the repository. I&#8217;ll refer to them as <strong><code>s4<\/code><\/strong> and <strong><code>s4a<\/code><\/strong> in places, for simplicity.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Multiple Connection Definitions<\/h3>\n\n\n\n<p>The MQ Spring Boot starter, like other starters, makes it easy to configure the managed resource. In this case, connections to queue managers. Attributes like the channel name can be set externally through environment variables, properties files, yaml files etc. The Spring Boot libraries convert the different external formats into a common set of Java properties that can be used, in our case, to build a ConnectionFactory (CF).<\/p>\n\n\n\n<p>But that simplicity comes from being able to make certain assumptions such as there only being a single definition in the properties. You set various things under the <code>ibm.mq<\/code> tree prefix, such as a userid, and Spring drives the auto-configuration to create the necessary Beans. No user-written code is necessary for this creation. But if you want to work with more than one queue manager from the same configuration file, in the same process, then it&#8217;s not quite so simple.<\/p>\n\n\n\n<p>Instead, we have to tell Spring a bit more about the ConnectionFactories we need. <\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Multiple CF classes<\/h4>\n\n\n\n<p>In these samples I know that the applications are going to connect to two different queue managers. So I&#8217;ve written two classes that nominate the configuration attributes to be pulled in. <\/p>\n\n\n\n<p>Looking at <em>QM1Config.java<\/em>, we can see:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">@Bean\n@ConfigurationProperties(\"qm1\")\nMQConfigurationProperties qm1ConfigProperties() {\n  return new MQConfigurationProperties();\n}<\/pre>\n\n\n\n<p>That makes Spring parse the MQConfiguration attributes that are understood by the MQ Boot Starter to create a CF, but to use <code>qm1<\/code> instead of <code>ibm.mq<\/code> as the starting point. In the <code>application.yml<\/code> file you can see the required details to reach this queue manager:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">qm1:\n  queueManager: \"QM1\"\n  channel: \"SYSTEM.DEF.SVRCONN\"\n  connName: \"localhost(1414)\"<\/pre>\n\n\n\n<p>The other part of the <em>QM1Config<\/em> class shows how to get a CF that is based on these properties.  The two samples do slightly different things with the CF creation because of the different transaction flow model. But that will show up in the next section.<\/p>\n\n\n\n<p>The <em>QM2Config<\/em> class is essentially the same, but referring to the other prefix for attributes.<\/p>\n\n\n\n<p>When the samples run with DEBUG logging, we can see both sets of configuration being used:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">c.i.m.s.b.MQConfigurationProperties - constructor\nc.i.m.s.b.MQConnectionFactoryFactory - constructor\nc.i.m.s.b.MQConnectionFactoryFactory - createConnectionFactory for class MQXAConnectionFactory\nc.i.m.s.b.MQConnectionFactoryFactory - configuring TLS Store system properties\nc.i.m.s.b.MQConnectionFactoryFactory - createConnectionFactoryInstance for class MQXAConnectionFactory\nc.i.m.s.b.MQConnectionFactoryFactory - configureConnectionFactory\nc.i.m.s.b.MQConfigurationProperties - queueManager    : QM1\nc.i.m.s.b.MQConfigurationProperties - applicationName : null\n\n....\n\nc.i.m.s.b.MQConfigurationProperties - constructor\nc.i.m.s.b.MQConnectionFactoryFactory - constructor\nc.i.m.s.b.MQConnectionFactoryFactory - createConnectionFactory for class MQXAConnectionFactory\nc.i.m.s.b.MQConnectionFactoryFactory - configuring TLS Store system properties\nc.i.m.s.b.MQConnectionFactoryFactory - createConnectionFactoryInstance for class MQXAConnectionFactory\nc.i.m.s.b.MQConnectionFactoryFactory - configureConnectionFactory\nc.i.m.s.b.MQConfigurationProperties - queueManager    : Q2\nc.i.m.s.b.MQConfigurationProperties - applicationName : null\n\n....<\/pre>\n\n\n\n<h5 class=\"wp-block-heading\">IDE Validation<\/h5>\n\n\n\n<p>One thing I noticed when editing the programs and configuration file in Eclipse, was a set of warnings. The Eclipse editors know about valid attributes in the Spring environment, and said that &#8220;qm1&#8221; and &#8220;qm2&#8221; were not valid elements in the <em>application.yml<\/em> file. We just have to live with those warnings or tell Eclipse to ignore them for this project.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Adding more queue managers to the application flow<\/h5>\n\n\n\n<p>There are <a href=\"https:\/\/dev.to\/adzubla\/using-multiple-jms-servers-with-spring-boot-3cbm#dynamic-creation-of-listeners\" target=\"_blank\" rel=\"noreferrer noopener\">approaches<\/a> to permit definition of an arbitrary set of queue manager configurations, using something like a list structure in the YAML file. That would mean we don&#8217;t have to create an explicit number of classes to match the number of queue managers for this application. But I felt that was going too far, and even more advanced than was needed for these samples.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Global Transactions<\/h3>\n\n\n\n<p>The basic flow in both of these samples is to receive a message from a queue on one queue manager, do some processing, and then send it to another queue on a different queue manager. It must be reliable &#8211; capable of dealing with errors at any point. We don&#8217;t want to lose or duplicate messages during that flow. And that implies the use of a global transaction &#8211; also known as two-phase, XA or (as we&#8217;re in a Java world) a JTA transaction. <\/p>\n\n\n\n<p>A JEE environment, such as the Liberty application server, includes a JTA coordinator capability. In a standalone Spring environment, we have to include a coordinator as part of the application. There are several possible choices, but I picked <a href=\"https:\/\/www.atomikos.com\" target=\"_blank\" rel=\"noreferrer noopener\">Atomikos<\/a> as the coordinator. It&#8217;s one system I&#8217;ve previously seen people wanting to use with MQ, so it seemed a good selection.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Atomikos<\/h4>\n\n\n\n<p>Adding Atomikos is just a matter of adding a Spring Boot starter component to the build definition. This is how it&#8217;s done in <em>build.gradle<\/em>:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">dependencies {\n  implementation(group:\"com.ibm.mq\", name:\"mq-jms-spring-boot-starter\", version:starterVersion)\n  implementation(group:\"com.atomikos\", name:\"transactions-spring-boot3-starter\", version:\"6.0.0\")\n}<\/pre>\n\n\n\n<p>Note that this Atomikos library is not part of the Spring-provided components (it used to be) but comes direct from the company that also offers commercial offerings around the technology. For our purposes, we can use the &#8220;free&#8221; package in this sample. Though it will always print out a message about being unregistered unless you follow the instructions to register it.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Two samples<\/h4>\n\n\n\n<p>The two sample programs have different flows.<\/p>\n\n\n\n<p>The first one, <strong>s4<\/strong>, is based around having a loop that does an MQGET(wait) followed by an MQPUT. Each loop starts a global transaction and then either commits or rolls back. Apart from using Spring to create the MQXAConnectionFactory objects, it basically uses standard JMS operations with none of the additional Spring simplifications. I chose not to use some of the Atomikos-provided Spring analogue capabilities such as its own JmsTemplate class. It&#8217;s easier to understand and control what&#8217;s happening with the basic JMS operations.<\/p>\n\n\n\n<p>The second sample, <strong>s4a<\/strong>, uses the Spring <strong>JmsListener<\/strong> pattern: each message causes an asynchronous method invocation. That method then copies the message to the other queue manager. In this pattern, we do not explicitly create or resolve transactions; successful completion of the method causes a commit. Throwing an exception in the callback automatically causes the rollback.<\/p>\n\n\n\n<p>In both cases, the samples exit after doing a rollback. That&#8217;s so we don&#8217;t get into an infinite loop of reprocessing the same message. In a real application, you would have a better approach to dealing with that &#8211; perhaps using the MQ JMS client&#8217;s capability of automatically sending messages to another queue. That uses the BOTHRESH and BOQNAME attributes of the queue you are reading from.<\/p>\n\n\n\n<p>For the transactions to work, the Atomikos coordinator has to know about the CFs. We do that with the <code>AtomikosConnectionFactoryBean.setXaConnectionFactory<\/code> call. The Spring Boot startup automatically initialises the overall Atomikos framework. The CFs themselves are built within the corresponding <em>QMxConfig<\/em> class. For <strong>s4a<\/strong>, we also need a<code>JmsListenerContainerFactory<\/code> Bean for one of the queue manager connections. <\/p>\n\n\n\n<p>At that point, we have everything ready.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Application testing<\/h4>\n\n\n\n<p>The <code>RUNME.sh<\/code> scripts in each sample directory build and execute the programs. In each case, what we want to see at the end is one message on the original input queue with a non-zero backout count, and one message on the other queue manager&#8217;s queue. The output from the s4a sample looks like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">========================================\nMQ JMS XA Transaction Sample started.\n========================================\nReceived message: COMMIT   Message for Spring Fri 14 Jun 09:30:04 BST 2024\nExecuting: Commit\nReceived message: ROLLBACK Message for Spring Fri 14 Jun 09:30:05 BST 2024\nExecuting: Rollback\nIn Error Handler:\n  [1] Listener method 'public void sample4a.Listener.receiveMessage(jakarta.jms.Session,jakarta.jms.TextMessage) throws jakarta.jms.JMSException,java.lang.RuntimeException' threw exception\n  [2] Doing XA rollback\nReceived message: ROLLBACK Message for Spring Fri 14 Jun 09:30:05 BST 2024\nExiting because delivery count indicates repeated delivery. Count: 2\nExecuting: Rollback\nIn Error Handler:\n  [1] Listener method 'public void sample4a.Listener.receiveMessage(jakarta.jms.Session,jakarta.jms.TextMessage) throws jakarta.jms.JMSException,java.lang.RuntimeException' threw exception\n  [2] Doing XA rollback\nStopping listener\nDone.<\/pre>\n\n\n\n<p>The final stage of the output can vary depending on timing and the precise state of the flow (we might see the rolledback message more than once). But it does eventually exit cleanly. And checking that messages have ended up how we want:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat checkOutput\necho \"=== QM1 ===\"\namqsbcg DEV.QUEUE.1 QM1 | grep messages | grep -v No\necho \"=== QM2 ===\"\namqsbcg DEV.QUEUE.1 QM2 | grep messages | grep -v No\n\n$ .\/checkOutput\n=== QM1 ===\n 1 messages browsed.\n=== QM2 ===\n 1 messages browsed.<\/pre>\n\n\n\n<p>Fully testing that transaction coordination works can be difficult without being able to do things like interrupt the coordinator at interesting places, such as half-way through the PREPARE sequence. I know that tests run for the MQ Java client and the queue manager to ensure reliability. So that&#8217;s not something I am trying to exercise here. But I do want to verify that the XA flows happen at all, just to ensure the Atomikos framework has properly registered the CFs.<\/p>\n\n\n\n<p>The easiest way to do that is to take take a queue manager trace and see if XA function appear. You don&#8217;t really need to know the MQ internals to get that information from the trace output. Running <code>grep -i xaopen \/var\/mqm\/trace\/*<\/code> gives the structure of the function names to look for. And so I search for <code>zlaXA<\/code> functions:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">---{ zlaXAOpen\n---} zlaXAOpen rc=OK FunctionTime=59\n---{ zlaXAStart\n---} zlaXAStart rc=OK FunctionTime=1047\n---{ zlaXAEnd\n---} zlaXAEnd rc=OK FunctionTime=284\n---{ zlaXAPrepare\n---} zlaXAPrepare rc=OK FunctionTime=335235\n---{ zlaXACommit\n---} zlaXACommit rc=OK FunctionTime=109165\n---{ zlaXAStart\n---} zlaXAStart rc=OK FunctionTime=756\n---{ zlaXAEnd\n---} zlaXAEnd rc=OK FunctionTime=388\n---{ zlaXARollback\n---} zlaXARollback rc=OK FunctionTime=351397\n<\/pre>\n\n\n\n<p>I can see here that the coordinator has indeed managed a two-phase transaction to this queue manager. The right operations have run in the right sequence to first commit a transaction and then roll back a second operation.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Summary<\/h3>\n\n\n\n<p>As I find so often with Spring applications, it can be hard to find documentation or samples on how to use some of these advanced features. Hopefully this will help.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I was talking recently with an MQ customer who said they were considering a solution that used Spring Boot for an MQ application that would move messages reliably from one queue manager to another, doing some processing on the way. &#8220;Can we do that?&#8221; they asked. &#8220;Of course&#8221; was my reply. But naturally I had &hellip; <a href=\"https:\/\/marketaylor.synology.me\/?p=1597\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;MQ Spring Boot: Advanced Configuration and Transactions&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[5],"tags":[133,35,20,51,52],"class_list":["post-1597","post","type-post","status-publish","format-standard","hentry","category-mq","tag-atomikos","tag-ibmmq","tag-mqseries","tag-spring","tag-spring-boot"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/marketaylor.synology.me\/?p=1597\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog\" \/>\n<meta property=\"og:description\" content=\"I was talking recently with an MQ customer who said they were considering a solution that used Spring Boot for an MQ application that would move messages reliably from one queue manager to another, doing some processing on the way. &#8220;Can we do that?&#8221; they asked. &#8220;Of course&#8221; was my reply. But naturally I had &hellip; Continue reading &quot;MQ Spring Boot: Advanced Configuration and Transactions&quot;\" \/>\n<meta property=\"og:url\" content=\"https:\/\/marketaylor.synology.me\/?p=1597\" \/>\n<meta property=\"og:site_name\" content=\"Mark Taylor&#039;s Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-06-14T08:57:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-06-14T08:57:41+00:00\" \/>\n<meta name=\"author\" content=\"Mark\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@marketaylor\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Mark\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"9 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597\"},\"author\":{\"name\":\"Mark\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/#\\\/schema\\\/person\\\/2d6f4113ff54187023e20c20186bbb3c\"},\"headline\":\"MQ Spring Boot: Advanced Configuration and Transactions\",\"datePublished\":\"2024-06-14T08:57:39+00:00\",\"dateModified\":\"2024-06-14T08:57:41+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597\"},\"wordCount\":1474,\"commentCount\":1,\"keywords\":[\"atomikos\",\"ibmmq\",\"mqseries\",\"spring\",\"spring boot\"],\"articleSection\":[\"IBM MQ\"],\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597\",\"url\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597\",\"name\":\"MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/#website\"},\"datePublished\":\"2024-06-14T08:57:39+00:00\",\"dateModified\":\"2024-06-14T08:57:41+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/#\\\/schema\\\/person\\\/2d6f4113ff54187023e20c20186bbb3c\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/?p=1597#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/marketaylor.synology.me\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"MQ Spring Boot: Advanced Configuration and Transactions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/#website\",\"url\":\"https:\\\/\\\/marketaylor.synology.me\\\/\",\"name\":\"Mark Taylor&#039;s Blog\",\"description\":\"Messaging, Music and Moving Around\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/marketaylor.synology.me\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/marketaylor.synology.me\\\/#\\\/schema\\\/person\\\/2d6f4113ff54187023e20c20186bbb3c\",\"name\":\"Mark\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g\",\"caption\":\"Mark\"},\"sameAs\":[\"https:\\\/\\\/x.com\\\/marketaylor\"],\"url\":\"https:\\\/\\\/marketaylor.synology.me\\\/?author=1\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/marketaylor.synology.me\/?p=1597","og_locale":"en_GB","og_type":"article","og_title":"MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog","og_description":"I was talking recently with an MQ customer who said they were considering a solution that used Spring Boot for an MQ application that would move messages reliably from one queue manager to another, doing some processing on the way. &#8220;Can we do that?&#8221; they asked. &#8220;Of course&#8221; was my reply. But naturally I had &hellip; Continue reading \"MQ Spring Boot: Advanced Configuration and Transactions\"","og_url":"https:\/\/marketaylor.synology.me\/?p=1597","og_site_name":"Mark Taylor&#039;s Blog","article_published_time":"2024-06-14T08:57:39+00:00","article_modified_time":"2024-06-14T08:57:41+00:00","author":"Mark","twitter_card":"summary_large_image","twitter_creator":"@marketaylor","twitter_misc":{"Written by":"Mark","Estimated reading time":"9 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/marketaylor.synology.me\/?p=1597#article","isPartOf":{"@id":"https:\/\/marketaylor.synology.me\/?p=1597"},"author":{"name":"Mark","@id":"https:\/\/marketaylor.synology.me\/#\/schema\/person\/2d6f4113ff54187023e20c20186bbb3c"},"headline":"MQ Spring Boot: Advanced Configuration and Transactions","datePublished":"2024-06-14T08:57:39+00:00","dateModified":"2024-06-14T08:57:41+00:00","mainEntityOfPage":{"@id":"https:\/\/marketaylor.synology.me\/?p=1597"},"wordCount":1474,"commentCount":1,"keywords":["atomikos","ibmmq","mqseries","spring","spring boot"],"articleSection":["IBM MQ"],"inLanguage":"en-GB","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/marketaylor.synology.me\/?p=1597#respond"]}]},{"@type":"WebPage","@id":"https:\/\/marketaylor.synology.me\/?p=1597","url":"https:\/\/marketaylor.synology.me\/?p=1597","name":"MQ Spring Boot: Advanced Configuration and Transactions - Mark Taylor&#039;s Blog","isPartOf":{"@id":"https:\/\/marketaylor.synology.me\/#website"},"datePublished":"2024-06-14T08:57:39+00:00","dateModified":"2024-06-14T08:57:41+00:00","author":{"@id":"https:\/\/marketaylor.synology.me\/#\/schema\/person\/2d6f4113ff54187023e20c20186bbb3c"},"breadcrumb":{"@id":"https:\/\/marketaylor.synology.me\/?p=1597#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/marketaylor.synology.me\/?p=1597"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/marketaylor.synology.me\/?p=1597#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/marketaylor.synology.me\/"},{"@type":"ListItem","position":2,"name":"MQ Spring Boot: Advanced Configuration and Transactions"}]},{"@type":"WebSite","@id":"https:\/\/marketaylor.synology.me\/#website","url":"https:\/\/marketaylor.synology.me\/","name":"Mark Taylor&#039;s Blog","description":"Messaging, Music and Moving Around","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/marketaylor.synology.me\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-GB"},{"@type":"Person","@id":"https:\/\/marketaylor.synology.me\/#\/schema\/person\/2d6f4113ff54187023e20c20186bbb3c","name":"Mark","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/secure.gravatar.com\/avatar\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9a5ae091c43730194cba7cabb5d65c1dc3f48d05caaddec6ff2319a1ce66376f?s=96&d=mm&r=g","caption":"Mark"},"sameAs":["https:\/\/x.com\/marketaylor"],"url":"https:\/\/marketaylor.synology.me\/?author=1"}]}},"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/posts\/1597","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1597"}],"version-history":[{"count":7,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/posts\/1597\/revisions"}],"predecessor-version":[{"id":1604,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=\/wp\/v2\/posts\/1597\/revisions\/1604"}],"wp:attachment":[{"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1597"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1597"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marketaylor.synology.me\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1597"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}