<div id="user_nav">
<a href="/login" class="welcome" title="登录">您还未登录 !</a>
<a href="/login">登录</a>
<a href="/signup" class="nobg">注册</a>
</div>
<div id="page">
<div id="branding" class="clearfix">
<div id="blog_name">
<h1><a href="/">好好学习,天天向上</a></h1>
</div>
<div id='fd'></div>
<div id="blog_navbar">
<ul>
<li class='blog_navbar_for'><a href="http://haohaoxuexi.iteye.com"><strong>博客</strong></a></li>
<li ><a href="/weibo">微博</a></li>
<li ><a href="/album">相册</a></li>
<li ><a href="/link">收藏</a></li>
<li ><a href="/blog/guest_book">留言</a></li>
<li ><a href="/blog/profile">关于我</a></li>
</ul>
<div class="search">
<form action="/blog/search" method="get">
<input class="search_text" id="query" name="query" style="margin-left: 10px;width: 110px;" type="text" value="" />
<input class="submit_search" type="submit" value="" />
</form>
</div>
<div id="fd"></div>
</div>
</div>
<div id="content" class="clearfix">
<div id="main">
Spring提供了一个JmsTransactionManager用于对JMS ConnectionFactory做事务管理。这将允许JMS应用利用Spring的事务管理特性。JmsTransactionManager在执行本地资源事务管理时将从指定的ConnectionFactory绑定一个ConnectionFactory/Session这样的配对到线程中。JmsTemplate会自动检测这样的事务资源,并对它们进行相应操作。
在Java EE环境中,ConnectionFactory会池化Connection和Session,这样这些资源将会在整个事务中被有效地重复利用。在一个独立的环境中,使用Spring的SingleConnectionFactory时所有的事务将公用一个Connection,但是每个事务将保留自己独立的Session。
JmsTemplate可以利用JtaTransactionManager和能够进行分布式的 JMS ConnectionFactory处理分布式事务。
在Spring整合JMS的应用中,如果我们要进行本地的事务管理的话非常简单,只需要在定义对应的消息监听容器时指定其sessionTransacted属性为true,如:
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="queueDestination" /> <property name="messageListener" ref="consumerMessageListener" /> <property name="sessionTransacted" value="true"/> </bean>
该属性值默认为false,这样JMS在进行消息监听的时候就会进行事务控制,当在接收消息时监听器执行失败时JMS就会对接收到的消息进行回滚,对于SessionAwareMessageListener在接收到消息后发送一个返回消息时也处于同一事务下,但是对于其他操作如数据库访问等将不属于该事务控制。
这里我们可以来做一个这样的测试:我们如上配置监听在queueDestination的消息监听容器的sessionTransacted属性为true,然后把我们前面提到的消息监听器ConsumerMessageListener改成这样:
public class ConsumerMessageListener implements MessageListener {
public void onMessage(Message message) {
//这里我们知道生产者发送的就是一个纯文本消息,所以这里可以直接进行强制转换,或者直接把onMessage方法的参数改成Message的子类TextMessage
TextMessage textMsg = (TextMessage) message;
System.out.println("接收到一个纯文本消息。");
try {
System.out.println("消息内容是:" + textMsg.getText());
if (1 == 1) {
throw new RuntimeException("Error");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
我们可以看到在上述代码中我们的ConsumerMessageListener在进行消息接收的时候抛出了一个RuntimeException,根据我们上面说的,因为我们已经在对应的监听容器上定义了其sessionTransacted属性为true,所以当这里抛出异常的时候JMS将对接收到的消息进行回滚,即下次进行消息接收的时候该消息仍然能够被接收到。为了验证这一点,我们先执行一遍测试代码,往queueDestination发送一个文本消息,这个时候ConsumerMessageListener在进行接收的时候将会抛出一个RuntimeException,已经接收到的纯文本消息将进行回滚;接着我们去掉上面代码中抛出异常的语句,即ConsumerMessageListener能够正常的进行消息接收,这个时候我们再运行一次测试代码,往ConsumerMessageListener监听的queueDestination发送一条消息。如果之前在接手时抛出了异常的那条消息已经回滚了的话,那么这个时候将能够接收到两条消息,控制台将输出接收到的两条消息的内容。具体结果有兴趣的朋友可以自己验证一下。
如果想接收消息和数据库访问处于同一事务中,那么我们就可以配置一个外部的事务管理同时配置一个支持外部事务管理的消息监听容器(如DefaultMessageListenerContainer)。要配置这样一个参与分布式事务管理的消息监听容器,我们可以配置一个JtaTransactionManager,当然底层的JMS ConnectionFactory需要能够支持分布式事务管理,并正确地注册我们的JtaTransactionManager。这样消息监听器进行消息接收和对应的数据库访问就会处于同一数据库控制下,当消息接收失败或数据库访问失败都会进行事务回滚操作。
<bean id="jmsContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer"> <property name="connectionFactory" ref="connectionFactory" /> <property name="destination" ref="queueDestination" /> <property name="messageListener" ref="consumerMessageListener" /> <property name="transactionManager" ref="jtaTransactionManager"/> </bean> <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
当给消息监听容器指定了transactionManager时,消息监听容器将忽略sessionTransacted的值。
关于使用JtaTransactionManager来管理上述分布式事务,我们这里也可以来做一个试验。
首先:往Spring配置文件applicationContext.xml中添加如下配置:
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="dataSource" ref="dataSource"/> </bean> <jee:jndi-lookup jndi-name="jdbc/mysql" id="dataSource"/> <bean id="jtaTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"/> <tx:annotation-driven transaction-manager="jtaTransactionManager"/>
我们可以看到,在这里我们引入了一个jndi数据源,定义了一个JtaTransactionManager,定义了Spring基于注解的声明式事务管理,定义了一个Spring提供的进行Jdbc操作的工具类jdbcTemplate。
接下来把我们的ConsumerMessageListener改为如下形式:
public class ConsumerMessageListener implements MessageListener {
@Autowired
private TestDao testDao;
private int count = 0;
public void onMessage(Message message) {
//这里我们知道生产者发送的就是一个纯文本消息,所以这里可以直接进行强制转换,或者直接把onMessage方法的参数改成Message的子类TextMessage
TextMessage textMsg = (TextMessage) message;
System.out.println(new Date().toLocaleString() + "接收到一个纯文本消息。");
try {
String text = textMsg.getText();
System.out.println("消息内容是:" + text);
System.out.println("当前count的值是:" + count);
testDao.insert(text + count);
if (count == 0) {
count ++;
throw new RuntimeException("Error! 出错啦!");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
}
我们可以看到,在ConsumerMessageListener中我们定义了一个实例变量count,其初始值为0;在onMessage里面,我们可以看到我们把接收到的消息内容作为参数调用了testDao的insert方法;当count值为0,也就是进行第一次消息接收的时候会将count的值加1,同时抛出一个运行时异常。那么我们这里要测试的就是进行第一次接收的时候testDao已经把相关内容插入数据库了,接着在onMessage里面抛出了一个异常同时count加1,我们预期的结果应该是此时数据库进行回滚,同时JMS也回滚,这样JMS将继续尝试接收该消息,此时同样会调用testDao的insert方法将内容插入数据库,再接着count已经不为0了,所以此时将不再抛出异常,JMS成功进行消息的接收,testDao也成功的将消息内容插入到了数据库。要证明这个预期我们除了看数据库中插入的数据外,还可以看控制台的输出,正常情况控制台将输出两次消息接收的内容,且第一次时count为0,第二次count为1。
TestDao是一个接口,其TestDaoImpl对insert的方法实现如下:
@Transactional(readOnly=false)
public void insert(final String name) {
jdbcTemplate.update("insert into test(name) values(?)", name);
}
这里我们使用支持JtaTransactionManager的Weblogic来进行测试,因为是Web容器,所以我们这里定义了一个Controller来进行消息的发送,具体代码如下:
@Controller
@RequestMapping("test")
public class TestController {
@Autowired
@Qualifier("queueDestination")
private Destination destination;
@Autowired
private ProducerService producerService;
@RequestMapping("first")
public String first() {
producerService.sendMessage(destination, "你好,现在是:" + new Date().toLocaleString());
return "/test/first";
}
}
接下来就是启用Weblogic服务器,进入其控制台,定义一个名叫“jdbc/mysql”的JNDI数据源,然后把该项目部署到Weblogic服务器上并进行启动。接下来我们就可以访问/test/first.do访问到上述first方法。之后控制台会输出如下信息:
我们可以看到当count为0时接收了一次,并随后抛出了异常,之后count为1又接收了一次,这说明在count为0时抛出异常后我们的JMS进行回滚了,那么我们的数据库是否有进行回滚呢?接着我们来看数据库中的内容:
我们可以看到数据库表中只有一条记录,而且最后一位表示count的值的为1,这说明在JMS进行消息接收抛出异常时我们的数据库也回滚了。关于使用JtaTransactionManager进行分布式事务管理的问题就说到这里了,有兴趣的朋友可以自己试验一下。
<ul style="display:none;">
<li><a href="https://i-blog.csdnimg.cn/blog_migrate/a6be417bb1262d2dcfa86c3c0b8dda3c.png" target="_blank"><img src='http://dl2.iteye.com/upload/attachment/0091/7448/655db0fd-c363-3ebb-9165-9e3c59515307-thumb.png' class='magplus' title='点击查看原始大小图片' /></a></li>
<li>大小: 35.6 KB</li>
</ul>
<ul style="display:none;">
<li><a href="https://i-blog.csdnimg.cn/blog_migrate/07249f49863adaafbeeae902a90f7cc3.png" target="_blank"><img src='http://dl2.iteye.com/upload/attachment/0091/7450/7196d8b4-8947-3ca9-aee2-c0831cc15061-thumb.png' class='magplus' title='点击查看原始大小图片' /></a></li>
<li>大小: 2.2 KB</li>
</ul>
<ul>
<li><a href="http://dl.iteye.com/topics/download/9ce2644a-9e06-3a27-ae6a-717ed5688c3a">SpringInteJMS.zip</a> (109.4 KB)</li>
<li>下载次数: 392</li>
</ul>
<ul>
<li><a href="#" onclick="$$('div.attachments ul').invoke('show');$(this).up(1).hide();return false;">查看图片附件</a></li>
</ul>
src="/iframe_ggbd/794" scrolling="no" width="468" height="60">
顶
踩
- 2013-12-01 20:36
- 浏览 9522
- 评论(13)
<li>分类:<a href="http://www.iteye.com/blogs/category/industry">行业应用</a></li>
<li class='last'><a href="http://www.iteye.com/wiki/blog/1983532" target="_blank" class="more">相关推荐</a></li>
</ul>
博文里面已经展示了对应的测试情况。是不是哪里配置有误啥的?
我应该是直接拿它的代码跑的 要说配置 除了改了下jtaTransactionManager 例子中的跑步起来 我就改成这样 <bean id=”jtaTransactionManager”
class=”org.springframework.transaction.jta.JtaTransactionManager”>
<property name=”transactionManager”>
<ref bean=”atomikosTransactionManager” />
</property>
<property name=”userTransaction”>
<ref bean=”atomikosUserTransaction” />
</property>
</bean>
还有dataSource jndi的配置也改成c3p0的了 我觉得应该没有影响
你能跑起来么 可以发我邮箱谢谢 zzsszz0106@163.com
dataSource就需要是jndi配置的。
博文里面已经展示了对应的测试情况。是不是哪里配置有误啥的?
我应该是直接拿它的代码跑的 要说配置 除了改了下jtaTransactionManager 例子中的跑步起来 我就改成这样 <bean id=”jtaTransactionManager”
class=”org.springframework.transaction.jta.JtaTransactionManager”>
<property name=”transactionManager”>
<ref bean=”atomikosTransactionManager” />
</property>
<property name=”userTransaction”>
<ref bean=”atomikosUserTransaction” />
</property>
</bean>
还有dataSource jndi的配置也改成c3p0的了 我觉得应该没有影响
你能跑起来么 可以发我邮箱谢谢 zzsszz0106@163.com
博文里面已经展示了对应的测试情况。是不是哪里配置有误啥的?
直接指定sessionTransacted=”true”,在从JMS容器接收消息的时候就会有对消息接收的事务管理了,不需要自己再去配置JmsTransactionManager。如果要自己配置的话配置方式跟文中介绍的JtaTransactionManager的配置方式类似,只是其需要多注入一个ConnectionFactory。至于HibernateTransactionManager应该是不支持对JMS进行事务管理的。
消息接收的事务管理使用sessionTransacted=”true”管理就可以了,同意lz的观点。如果接收消息的同时支持数据库事务管理貌似必须使用JtaTransactionManager事务管理了,且需要应用服务器支持JtaTransactionManager的配置方式。如Weblogic、JBoos等。如果使用tomcat需要使用第三方支持XA协议的JTOM或者atomikos。网址: http://www.jakubkorab.net/2011/08/configuring-activemq-transactions-in-spring.html比较清晰。多谢lz的回答!
文中有提到分布式事务管理需要使用JtaTransactionManager的,即可以让JMS事务与数据库事务处于同一事务中。
直接指定sessionTransacted=”true”,在从JMS容器接收消息的时候就会有对消息接收的事务管理了,不需要自己再去配置JmsTransactionManager。如果要自己配置的话配置方式跟文中介绍的JtaTransactionManager的配置方式类似,只是其需要多注入一个ConnectionFactory。至于HibernateTransactionManager应该是不支持对JMS进行事务管理的。
消息接收的事务管理使用sessionTransacted=”true”管理就可以了,同意lz的观点。如果接收消息的同时支持数据库事务管理貌似必须使用JtaTransactionManager事务管理了,且需要应用服务器支持JtaTransactionManager的配置方式。如Weblogic、JBoos等。如果使用tomcat需要使用第三方支持XA协议的JTOM或者atomikos。网址: http://www.jakubkorab.net/2011/08/configuring-activemq-transactions-in-spring.html比较清晰。多谢lz的回答!
直接指定sessionTransacted=”true”,在从JMS容器接收消息的时候就会有对消息接收的事务管理了,不需要自己再去配置JmsTransactionManager。如果要自己配置的话配置方式跟文中介绍的JtaTransactionManager的配置方式类似,只是其需要多注入一个ConnectionFactory。至于HibernateTransactionManager应该是不支持对JMS进行事务管理的。
dp.SyntaxHighlighter.HighlightAll('code', true, true);
var post_id = 1983532;
var location = window.location;
source_url = location.protocol + "//" + location.host + location.pathname + location.search;
pre.writeAttribute('codeable_id', post_id);
pre.writeAttribute('codeable_type', "Blog");
pre.writeAttribute('source_url', source_url);
pre.writeAttribute('pre_index', index);
pre.writeAttribute('title', 'Spring整合JMS(四)——事务管理');
});
fix_image_size(
var post_id = comment.id.substr(2);
</div>
<div id="local">
<div class="local_top"></div>
<div id="blog_owner">
<div id="blog_actions">
<ul>
<li>浏览: 1206463 次</li>
<li>性别: <img alt="Icon_minigender_1" src="http://www.iteye.com/images/icon_minigender_1.gif?1324994303" title="男" /></li>
<li>来自: 长沙</li>
<li><img src='/images/status/offline.gif'/></li>
</ul>
</div>
<div id="user_visits" class="clearfix">
<h5>最近访客 <span style='font-weight:normal;font-size:12px;padding-left:30px;'><a href="/blog/user_visits">更多访客>></a></span></h5>
<div class="user_visit">
<div class="logo"><a href='http://fengyuwuzudavid.iteye.com' target='_blank'><img alt="fengyuwuzudavid的博客" class="logo" src="http://www.iteye.com/images/user-logo-thumb.gif?1324994303" title="fengyuwuzudavid的博客: " width="48px" /></a></div>
<div class="left"><a href='http://fengyuwuzudavid.iteye.com' target='_blank' title='fengyuwuzudavid'>fengyuwuzudavid</a></div>
</div>
<div class="user_visit">
<div class="logo"><a href='http://wzm123.iteye.com' target='_blank'><img alt="wzm123的博客" class="logo" src="http://www.iteye.com/images/user-logo-thumb.gif?1324994303" title="wzm123的博客: " width="48px" /></a></div>
<div class="left"><a href='http://wzm123.iteye.com' target='_blank' title='wzm123'>wzm123</a></div>
</div>
<div class="user_visit">
<div class="logo"><a href='http://chenxu-8456.iteye.com' target='_blank'><img alt="chenxu_8456的博客" class="logo" src="http://www.iteye.com/images/user-logo-thumb.gif?1324994303" title="chenxu_8456的博客: " width="48px" /></a></div>
<div class="left"><a href='http://chenxu-8456.iteye.com' target='_blank' title='chenxu_8456'>chenxu_8456</a></div>
</div>
<div class="user_visit">
<div class="logo"><a href='http://molgee.iteye.com' target='_blank'><img alt="molgee的博客" class="logo" src="http://www.iteye.com/images/user-logo-thumb.gif?1324994303" title="molgee的博客: " width="48px" /></a></div>
<div class="left"><a href='http://molgee.iteye.com' target='_blank' title='molgee'>molgee</a></div>
</div>
</div>
<div>
<h5>博客专栏</h5>
-
Oracle基础
浏览量:42260
-
springMVC介绍
浏览量:315263
-
Mybatis简介
浏览量:339243
-
Spring整合JMS
浏览量:63035
-
Ehcache简介
浏览量:24826
-
Cas简介
浏览量:10052
-
Spring Securi…
浏览量:19554
</div>
<div id="blog_menu">
<h5>文章分类</h5>
<ul>
<li><a href="/">全部博客 (204)</a></li>
<li><a href="/category/164370">配置文件 (2)</a></li>
<li><a href="/category/155097">dwr (2)</a></li>
<li><a href="/category/176065">安全 (1)</a></li>
<li><a href="/category/172948">电子邮件 (3)</a></li>
<li><a href="/category/299032">cxf (3)</a></li>
<li><a href="/category/324785">Cas (9)</a></li>
<li><a href="/category/161765">CKEDITOR (3)</a></li>
<li><a href="/category/319453">ehcache (10)</a></li>
<li><a href="/category/158024">extjs4 (6)</a></li>
<li><a href="/category/159974">freemarker (2)</a></li>
<li><a href="/category/154983">hibernate (5)</a></li>
<li><a href="/category/156571">itext (1)</a></li>
<li><a href="/category/182974">JasperReport (4)</a></li>
<li><a href="/category/155852">java (18)</a></li>
<li><a href="/category/131097">jbpm4 (2)</a></li>
<li><a href="/category/155042">jfreeChart (3)</a></li>
<li><a href="/category/157196">jquery (7)</a></li>
<li><a href="/category/202499">jsp (4)</a></li>
<li><a href="/category/265283">Linux (1)</a></li>
<li><a href="/category/181358">Lucene (1)</a></li>
<li><a href="/category/269897">maven (7)</a></li>
<li><a href="/category/131096">mybatis (9)</a></li>
<li><a href="/category/165959">MySQL (5)</a></li>
<li><a href="/category/156935">oracle (29)</a></li>
<li><a href="/category/156541">poi (7)</a></li>
<li><a href="/category/304463">Servlet (4)</a></li>
<li><a href="/category/156737">实用技巧 (5)</a></li>
<li><a href="/category/156657">Spring (12)</a></li>
<li><a href="/category/175984">SpringMVC (13)</a></li>
<li><a href="/category/182468">spring Security (13)</a></li>
<li><a href="/category/154645">struts2 (5)</a></li>
<li><a href="/category/155732">swing (1)</a></li>
<li><a href="/category/177387">svn (1)</a></li>
<li><a href="/category/156444">web前端 (5)</a></li>
<li><a href="/category/253146">Weblogic (3)</a></li>
<li><a href="/category/156645">问题 (2)</a></li>
<li><a href="/category/186746">xml (2)</a></li>
<li><a href="/category/268768">面试 (1)</a></li>
</ul>
</div>
<div id='month_blogs'>
<h5>社区版块</h5>
<ul>
<li><a href="/blog/news">我的资讯</a> (0)</li>
<li>
<a href="/blog/post">我的论坛</a> (17)
</li>
<li><a href="/blog/answered_problems">我的问答</a> (4)</li>
</ul>
</div>
<div id="month_blogs">
<h5>存档分类</h5>
<ul>
<li><a href="/blog/monthblog/2015-05">2015-05</a> (1)</li>
<li><a href="/blog/monthblog/2014-12">2014-12</a> (3)</li>
<li><a href="/blog/monthblog/2014-11">2014-11</a> (9)</li>
<li><a href="/blog/monthblog_more">更多存档...</a></li>
</ul>
</div>
<div id="comments_top">
<h5>评论排行榜</h5>
<ul>
<li><a href="/blog/2123030" title="Spring使用Cache、整合Ehcache">Spring使用Cache、整合Ehcache</a></li>
<li><a href="/blog/2119737" title="Ehcache(08)——可阻塞的Cache——BlockingCache">Ehcache(08)——可阻塞的Cache——Bloc ...</a></li>
<li><a href="/blog/2154299" title="Spring Security(01)——初体验">Spring Security(01)——初体验</a></li>
<li><a href="/blog/2119353" title="Ehcache(06)——监听器">Ehcache(06)——监听器</a></li>
<li><a href="/blog/2163997" title="Spring Security(12)——Remember-Me功能">Spring Security(12)——Remember-Me功 ...</a></li>
</ul>
</div>
<div id="guest_books">
<h5>最新评论</h5>
<ul>
<li>
<a href='http://demonu.iteye.com' target='_blank' title='DEMONU'>DEMONU</a>:
牛逼,大神啊 <br />
<a href="/blog/1979837#bc2372073">Java Socket编程</a>
</li>
<li>
<a href='http://kangkai8864233.iteye.com' target='_blank' title='真三武侯'>真三武侯</a>:
仔细看看 <br />
<a href="/blog/1827778#bc2372072">Maven简介(一)——Maven的安装和settings.xml的配置</a>
</li>
<li>
<a href='http://2047699523.iteye.com' target='_blank' title='2047699523'>2047699523</a>:
可以参考最新的文档:如何在eclipse jee中检出项目并转 ...<br />
<a href="/blog/2059080#bc2371856">Maven简介(七)——整合Eclipse</a>
</li>
<li>
<a href='http://aone.iteye.com' target='_blank' title='aone'>aone</a>:
ehcache需要配置成分布式的,即要配置<cacheE ...<br />
<a href="/blog/2119353#bc2371681">Ehcache(06)——监听器</a>
</li>
<li>
<a href='http://haohaoxuexi.iteye.com' target='_blank' title='234390216'>234390216</a>:
effort0829 写道加上这行 <security ...<br />
<a href="/blog/2163997#bc2371485">Spring Security(12)——Remember-Me功能</a>
</li>
</ul>
</div>
<div class="local_bottom"></div>
</div>
</div>
<div id="footer" class="clearfix">
<div id="copyright">
<hr/>
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。若作者同意转载,必须以超链接形式标明文章原始出处和作者。<br />
© 2003-2015 ITeye.com. All rights reserved. [ 京ICP证110151号 京公网安备110105010620 ]
</div>
</div>
</div>
<script type="text/javascript">
document.write(“http://stat.iteye.com/?url=“+ encodeURIComponent(document.location.href) + “&referrer=” + encodeURIComponent(document.referrer) + “&user_id=’ width=’0’ height=’0’ />”);
评论
13 楼
http://u013803082.iteye.com’ target=’_blank’ title=’u013803082’>u013803082
2015-04-19