在 JBoss 中设置分布式事务管理的步骤
Steps to setup distributed transaction management in JBoss
我正在尝试在 JBoss EAP 6.2 应用程序服务器中实现分布式事务 (XA),以便可以在单个协调的原子事务中访问多个数据存储。更准确地说,我希望我的事务服务方法以这样的方式写入数据库 table 和消息队列,使得这两个操作要么同时提交,要么一致回滚(全部或全部) .
我的方法基于以下几点:
- 使用Spring JTA 事务管理器
- 配置实体管理器以使用 XA JDBC 数据源,在 JBoss 应用程序服务器中定义并通过 JNDI 名称访问
- 使用 ActiveMQ XA 连接工厂进行消息传递
我遇到的问题是只有数据库操作被回滚了。无论事务回滚与否,写入ActiveMQ队列的消息总是提交。
我的配置的关键要素:
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
...
<property name="jpaProperties">
<props>
...
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="xaDataSource"/>
<bean id="xaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="true"/>
</bean>
我终于搞定了。关键是在 JBoss 资源适配器中配置 JMS 连接工厂。详细步骤如下:
1。安装 Apache ActiveMQ
使用的版本:5.11.3
可以找到详细的安装说明 here。
安装 ActiveMQ 后,创建一个名为 TEST_QUEUE 的队列(使用管理控制台:http://127.0.0.1:8161/admin/index.jsp)
2。设置 Spring 应用程序上下文
关键要素:
- 使用Spring JTA事务管理器标签:这会提示使用
应用服务器事务管理器;
- 配置数据源 bean 以使用应用服务器中定义的 XA 数据源(参见 XA JDBC 数据源设置);
- 将实体管理器工厂的
jtaDataSource
属性连接到 XA 数据源;
- 将休眠 属性
manager_lookup_class
设置为 JBossTransactionManagerLookup
;
- 配置连接工厂 bean 以使用应用程序服务器中定义的 XA 连接工厂 bean(参见 XA 连接工厂设置);
- 将连接工厂 bean 的 属性
transactedSession
设置为 false
。
e
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jpa:repositories base-package="com.company.app.repository" />
<context:component-scan base-package="com.company.app" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
<property name="packagesToScan" value="com.company.app.domain" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="jdbc/xaDataSource"/>
<bean id="xaConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="activemq/ConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="false"/>
</bean>
3。设置应用程序服务器(JBoss)
要使分布式事务正常工作,所有涉及的数据源都必须是 XA 类型。 JBoss 开箱即用地支持 JDBC XA 数据源(xa-datasource 标签)。 JMS 数据源的 XA 配置是通过定义适当的资源适配器来实现的。
3.1。 XA JDBC 数据源
在 <subsystem xmlns="urn:jboss:domain:datasources:1.1"> <datasources>
下的 standalone.xml
添加一个 XA JDBC 数据源:
<xa-datasource jndi-name="java:/jdbc/xaDataSource" pool-name="jdbc/xaDataSource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:@<hostname>:<port_number>/<SID>
</xa-datasource-property>
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
<driver>ojdbc6-11.2.0.3.jar</driver>
<security>
<user-name>db_user</user-name>
<password>password</password>
</security>
</xa-datasource>
3.2。 XA 连接工厂
资源适配器是来自 J2EE 连接器架构 (JCA) 的概念,用于与企业信息系统交互,即应用服务器外部的系统(例如,关系数据库、大型机、面向消息的中间件、会计系统)等)。
首先,您需要在 JBoss 中安装 ActiveMQ RAR(资源适配器 ARchive),方法是从 maven central 下的 \standalone\deployments 中删除适当的 RAR 文件。然后,在 standalone.xml
中的 <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">
下添加以下内容:
<resource-adapters>
<resource-adapter id="activemq-rar.rar">
<archive>
activemq-rar-5.11.3.rar
</archive>
<transaction-support>XATransaction</transaction-support>
<config-property name="Password">
admin
</config-property>
<config-property name="UserName">
admin
</config-property>
<config-property name="ServerUrl">
tcp://localhost:61616?jms.rmIdFromConnectionId=true
</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" pool-name="ConnectionFactory">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>false</prefill>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
</connection-definition>
</connection-definitions>
</resource-adapter>
</resource-adapters>
有关在 JBoss 中安装 ActiveMQ RAR 的更多详细信息,请参阅 RedHat documentation。
4。使您的服务方法具有事务性
@Service
public class TwoPhaseCommitService {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private JmsTemplate jmsTemplate;
@Transactional
public void writeToDbAndQueue() {
final Employee employee = new Employee();
employee.setFirstName("John");
employee.setLastName("Smith");
// persist entity to database
employeeRepository.save(employee);
// write message to TEST_QUEUE
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(employee.getFirstName());
}
});
// To test rollback uncomment code below:
// throw new RuntimeException("something went wrong. Transaction must be rolled back!!!");
}
}
我正在尝试在 JBoss EAP 6.2 应用程序服务器中实现分布式事务 (XA),以便可以在单个协调的原子事务中访问多个数据存储。更准确地说,我希望我的事务服务方法以这样的方式写入数据库 table 和消息队列,使得这两个操作要么同时提交,要么一致回滚(全部或全部) .
我的方法基于以下几点:
- 使用Spring JTA 事务管理器
- 配置实体管理器以使用 XA JDBC 数据源,在 JBoss 应用程序服务器中定义并通过 JNDI 名称访问
- 使用 ActiveMQ XA 连接工厂进行消息传递
我遇到的问题是只有数据库操作被回滚了。无论事务回滚与否,写入ActiveMQ队列的消息总是提交。
我的配置的关键要素:
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
...
<property name="jpaProperties">
<props>
...
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="xaDataSource"/>
<bean id="xaConnectionFactory" class="org.apache.activemq.ActiveMQXAConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="true"/>
</bean>
我终于搞定了。关键是在 JBoss 资源适配器中配置 JMS 连接工厂。详细步骤如下:
1。安装 Apache ActiveMQ
使用的版本:5.11.3
可以找到详细的安装说明 here。
安装 ActiveMQ 后,创建一个名为 TEST_QUEUE 的队列(使用管理控制台:http://127.0.0.1:8161/admin/index.jsp)
2。设置 Spring 应用程序上下文
关键要素:
- 使用Spring JTA事务管理器标签:这会提示使用 应用服务器事务管理器;
- 配置数据源 bean 以使用应用服务器中定义的 XA 数据源(参见 XA JDBC 数据源设置);
- 将实体管理器工厂的
jtaDataSource
属性连接到 XA 数据源; - 将休眠 属性
manager_lookup_class
设置为JBossTransactionManagerLookup
; - 配置连接工厂 bean 以使用应用程序服务器中定义的 XA 连接工厂 bean(参见 XA 连接工厂设置);
- 将连接工厂 bean 的 属性
transactedSession
设置为false
。
e
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:jms="http://www.springframework.org/schema/jms" xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd">
<jpa:repositories base-package="com.company.app.repository" />
<context:component-scan base-package="com.company.app" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<tx:jta-transaction-manager/>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="jtaDataSource" ref="xaDataSource" />
<property name="packagesToScan" value="com.company.app.domain" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.JBossTransactionManagerLookup</prop>
</props>
</property>
</bean>
<jee:jndi-lookup id="xaDataSource" jndi-name="jdbc/xaDataSource"/>
<bean id="xaConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="activemq/ConnectionFactory" />
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="xaConnectionFactory" />
<property name="defaultDestinationName" value="TEST_QUEUE" />
<property name="sessionTransacted" value="false"/>
</bean>
3。设置应用程序服务器(JBoss)
要使分布式事务正常工作,所有涉及的数据源都必须是 XA 类型。 JBoss 开箱即用地支持 JDBC XA 数据源(xa-datasource 标签)。 JMS 数据源的 XA 配置是通过定义适当的资源适配器来实现的。
3.1。 XA JDBC 数据源
在 <subsystem xmlns="urn:jboss:domain:datasources:1.1"> <datasources>
下的 standalone.xml
添加一个 XA JDBC 数据源:
<xa-datasource jndi-name="java:/jdbc/xaDataSource" pool-name="jdbc/xaDataSource" enabled="true">
<xa-datasource-property name="URL">
jdbc:oracle:thin:@<hostname>:<port_number>/<SID>
</xa-datasource-property>
<xa-datasource-class>oracle.jdbc.xa.client.OracleXADataSource</xa-datasource-class>
<driver>ojdbc6-11.2.0.3.jar</driver>
<security>
<user-name>db_user</user-name>
<password>password</password>
</security>
</xa-datasource>
3.2。 XA 连接工厂
资源适配器是来自 J2EE 连接器架构 (JCA) 的概念,用于与企业信息系统交互,即应用服务器外部的系统(例如,关系数据库、大型机、面向消息的中间件、会计系统)等)。
首先,您需要在 JBoss 中安装 ActiveMQ RAR(资源适配器 ARchive),方法是从 maven central 下的 \standalone\deployments 中删除适当的 RAR 文件。然后,在 standalone.xml
中的 <subsystem xmlns="urn:jboss:domain:resource-adapters:1.1">
下添加以下内容:
<resource-adapters>
<resource-adapter id="activemq-rar.rar">
<archive>
activemq-rar-5.11.3.rar
</archive>
<transaction-support>XATransaction</transaction-support>
<config-property name="Password">
admin
</config-property>
<config-property name="UserName">
admin
</config-property>
<config-property name="ServerUrl">
tcp://localhost:61616?jms.rmIdFromConnectionId=true
</config-property>
<connection-definitions>
<connection-definition class-name="org.apache.activemq.ra.ActiveMQManagedConnectionFactory" jndi-name="java:/activemq/ConnectionFactory" enabled="true" pool-name="ConnectionFactory">
<xa-pool>
<min-pool-size>1</min-pool-size>
<max-pool-size>20</max-pool-size>
<prefill>false</prefill>
<is-same-rm-override>false</is-same-rm-override>
</xa-pool>
</connection-definition>
</connection-definitions>
</resource-adapter>
</resource-adapters>
有关在 JBoss 中安装 ActiveMQ RAR 的更多详细信息,请参阅 RedHat documentation。
4。使您的服务方法具有事务性
@Service
public class TwoPhaseCommitService {
@Autowired
private EmployeeRepository employeeRepository;
@Autowired
private JmsTemplate jmsTemplate;
@Transactional
public void writeToDbAndQueue() {
final Employee employee = new Employee();
employee.setFirstName("John");
employee.setLastName("Smith");
// persist entity to database
employeeRepository.save(employee);
// write message to TEST_QUEUE
jmsTemplate.send(new MessageCreator() {
public Message createMessage(Session session) throws JMSException {
return session.createTextMessage(employee.getFirstName());
}
});
// To test rollback uncomment code below:
// throw new RuntimeException("something went wrong. Transaction must be rolled back!!!");
}
}