javascript
jta atomikos_带有Atomikos示例的Tomcat中的Spring JTA多个资源事务
jta atomikos
在本教程中,我們將向您展示如何使用Atomikos Transaction Manager在Tomcat服務(wù)器中實(shí)現(xiàn)JTA多個(gè)資源事務(wù)。 Atomicos事務(wù)管理器為分布式事務(wù)提供支持。 這些是多階段事務(wù),通常使用多個(gè)數(shù)據(jù)庫(kù),必須以協(xié)調(diào)的方式提交。 分布式事務(wù)由XA standard描述。 XA控制事務(wù)管理器(例如Atomikos)如何告知數(shù)據(jù)庫(kù)作為什么事務(wù)的一部分正在進(jìn)行的工作,以及如何在每個(gè)事務(wù)結(jié)束時(shí)執(zhí)行兩階段提交(2PC)協(xié)議。
在這里,我們將創(chuàng)建映射到兩個(gè)不同數(shù)據(jù)庫(kù)的簡(jiǎn)單實(shí)體類,并嘗試使用一個(gè)分布式事務(wù)將這些類的對(duì)象持久保存到數(shù)據(jù)庫(kù)中。 我們還將看到當(dāng)基礎(chǔ)事務(wù)之一回滾時(shí)會(huì)發(fā)生什么。
我們首選的開(kāi)發(fā)環(huán)境是Eclipse 。 我們正在使用Eclipse Juno(4.2)版本以及Maven Integration插件版本3.1.0。 您可以從Eclipse的這里從和Maven Eclipse插件這里 。 用于Eclipse的Maven插件的安裝不在本教程的討論范圍之內(nèi),因此不再討論。 我們還使用Spring 3.2.3和JDK 7_u_21。
Tomcat 7是使用的應(yīng)用程序服務(wù)器。 Hibernate版本為4.1.9,示例中使用的數(shù)據(jù)庫(kù)為MySQL Database Server 5.6。
讓我們開(kāi)始,
1.創(chuàng)建一個(gè)新的Maven項(xiàng)目
轉(zhuǎn)到文件->項(xiàng)目-> Maven-> Maven項(xiàng)目。
在向?qū)У摹斑x擇項(xiàng)目名稱和位置”頁(yè)面中,確保未選中 “創(chuàng)建簡(jiǎn)單項(xiàng)目(跳過(guò)原型選擇)”選項(xiàng),單擊“下一步”以繼續(xù)使用默認(rèn)值。
在這里,必須添加用于創(chuàng)建Web應(yīng)用程序的Maven原型。 單擊“添加原型”并添加原型。 將“ Archetype組ID”變量設(shè)置為"org.apache.maven.archetypes" ,將“ Archetype構(gòu)件ID”變量設(shè)置為"maven-archetype-webapp" ,將“ Archetype版本”設(shè)置為"1.0" 。 點(diǎn)擊“確定”繼續(xù)。
在向?qū)У摹拜斎牍ぜ蘒D”頁(yè)面中,您可以定義項(xiàng)目的名稱和主程序包。 將“ Group Id”變量設(shè)置為"com.javacodegeeks.snippets.enterprise" ,將“ Artifact Id”變量設(shè)置為"springexample" 。 前面提到的選擇將主項(xiàng)目程序包組成為"com.javacodegeeks.snippets.enterprise.springexample" ,項(xiàng)目名稱為"springexample" 。 將“ Package”變量設(shè)置為"war" ,以便創(chuàng)建一個(gè)war文件以部署到tomcat服務(wù)器。 點(diǎn)擊“完成”退出向?qū)Р?chuàng)建您的項(xiàng)目。
Maven項(xiàng)目結(jié)構(gòu)如下所示:
- 它由以下文件夾組成:
- / src / main / java文件夾,其中包含應(yīng)用程序動(dòng)態(tài)內(nèi)容的源文件,
- / src / test / java文件夾包含用于單元測(cè)試的所有源文件,
- / src / main / resources文件夾包含配置文件,
- / target文件夾包含已編譯和打包的可交付成果,
- / src / main / resources / webapp / WEB-INF文件夾包含Web應(yīng)用程序的部署描述符,
- pom.xml是項(xiàng)目對(duì)象模型(POM)文件。 包含所有項(xiàng)目相關(guān)配置的單個(gè)文件。
2.添加Spring 3.2.3依賴項(xiàng)
- 在POM編輯器的“概述”頁(yè)面上找到“屬性”部分,然后執(zhí)行以下更改:
創(chuàng)建一個(gè)新屬性,名稱為org.springframework.version ,值3.2.3RELEASE 。 - 導(dǎo)航到POM編輯器的“依賴關(guān)系”頁(yè)面,并創(chuàng)建以下依賴關(guān)系(您應(yīng)在該頁(yè)面的“依賴關(guān)系詳細(xì)信息”部分的“ GroupId”,“工件ID”和“版本”字段中進(jìn)行填充):
組ID: org.springframework工件ID: spring-web版本: $ {org.springframework.version}
另外,您可以在Maven的pom.xml文件中添加Spring依賴項(xiàng),方法是直接在POM編輯器的“ Pom.xml”頁(yè)面上對(duì)其進(jìn)行編輯,如下所示:
pom.xml:
如您所見(jiàn),Maven以聲明方式管理庫(kù)依賴關(guān)系。 創(chuàng)建本地存儲(chǔ)庫(kù)(默認(rèn)情況下,位于{user_home} /。m2文件夾下),所有必需的庫(kù)都從公共存儲(chǔ)庫(kù)下載并放置在該庫(kù)中。 此外,庫(kù)內(nèi)的依賴關(guān)系會(huì)自動(dòng)解決和處理。
3.添加所有必需的依賴項(xiàng)
此處設(shè)置了設(shè)置atomosos事務(wù)管理器所需的所有依賴項(xiàng)。
pom.xml
4.創(chuàng)建實(shí)體類
EmployeeA.java和EmployeeB.java是Entity類。 他們使用javax.persistence批注映射到不同數(shù)據(jù)庫(kù)中的表EMPLOYEEA和EMPLOYEEB 。 特別地, @Entity注釋指定每個(gè)類是一個(gè)實(shí)體。 @Table注釋指定帶注釋的實(shí)體的主表。 @Column批注用于為持久字段指定一個(gè)映射列,而@Id批注指定每個(gè)實(shí)體的主鍵字段。
EmployeeA.java
package com.javacodegeeks.snippets.enterprise.model;import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;@Entity @Table(name = "EMPLOYEEA") public class EmployeeA {@Id@Column(name = "ID", nullable = false)private String id;@Column(name = "NAME", nullable = false)private String name;@Column(name = "AGE", nullable = false)private long age;public EmployeeA() {}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public long getAge() {return age;}public void setAge(long age) {this.age = age;}}EmployeeB.java
package com.javacodegeeks.snippets.enterprise.model;import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table;@Entity @Table(name = "EMPLOYEEB") public class EmployeeB {@Id@Column(name = "ID", nullable = false)private String id;@Column(name = "NAME", nullable = false)private String name;@Column(name = "AGE", nullable = false)private long age;public EmployeeB() {}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public long getAge() {return age;}public void setAge(long age) {this.age = age;}}5.創(chuàng)建DAO類
實(shí)現(xiàn)的數(shù)據(jù)訪問(wèn)對(duì)象是EmployeeADAOImpl.java和EmployeeBDAOImpl.java類。 它們使用@Service注釋進(jìn)行注釋,表明它們是Spring Bean,因此允許Spring自動(dòng)檢測(cè)它們。 它們都使用javax.persistence.EntityManager與數(shù)據(jù)庫(kù)進(jìn)行交互。
EntityManager實(shí)例與持久性上下文關(guān)聯(lián)。 持久性上下文是一組實(shí)體實(shí)例,其中對(duì)于任何持久性實(shí)體標(biāo)識(shí),都有一個(gè)唯一的實(shí)體實(shí)例。 在持久性上下文中,管理實(shí)體實(shí)例及其生命周期。 EntityManager API用于創(chuàng)建和刪除持久實(shí)體實(shí)例,通過(guò)其主鍵查找實(shí)體以及查詢實(shí)體。 在persistence.xml文件中配置了EntityManager ,對(duì)此進(jìn)行了描述
在第8.1段中。
可以由給定EntityManager實(shí)例管理的實(shí)體集由持久性單元定義。 持久性單元定義了與應(yīng)用程序相關(guān)或分組的所有類的集合,這些類必須在它們到單個(gè)數(shù)據(jù)庫(kù)的映射中共置。
EntityManager通過(guò)@PersistenceContext注釋注入到每個(gè)DAO中,在該注釋中設(shè)置了每個(gè)持久性單元的名稱,如persistence.xml文件中所定義。
在兩個(gè)DAO中都實(shí)現(xiàn)了一種基本的持久方法,即使用EntityManager的persist(Object entity) API方法來(lái)創(chuàng)建數(shù)據(jù)庫(kù)的對(duì)象。
DAO及其接口如下所示:
雇員ADAO.java
package com.javacodegeeks.snippets.enterprise.dao;import com.javacodegeeks.snippets.enterprise.model.EmployeeA;public interface EmployeeADAO {void persistEmployee(EmployeeA employee); }雇員ADAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;import org.springframework.stereotype.Service;import com.javacodegeeks.snippets.enterprise.model.EmployeeA;@Service public class EmployeeADAOImpl implements EmployeeADAO {@PersistenceContext(unitName="PersistenceUnitA")private EntityManager entityManager;public void persistEmployee(EmployeeA employee) {entityManager.persist(employee);}}雇員BDAO .java
package com.javacodegeeks.snippets.enterprise.dao;import com.javacodegeeks.snippets.enterprise.model.EmployeeB;public interface EmployeeBDAO {void persistEmployee(EmployeeB employee) throws Exception;}雇員BDAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;import org.springframework.stereotype.Service;import com.javacodegeeks.snippets.enterprise.model.EmployeeB;@Service public class EmployeeBDAOImpl implements EmployeeBDAO {@PersistenceContext(unitName="PersistenceUnitB")private EntityManager entityManager;public void persistEmployee(EmployeeB employee) throws Exception {entityManager.persist(employee); // throw new Exception();} }6.創(chuàng)建服務(wù)類
EmployeeADAOImpl.java和EmployeeBDAOImpl.java類被注入EmployeeServiceImpl.java類。 因此,在此處實(shí)現(xiàn)的persistEmployees(EmployeeA employeeA, EmployeeB employeeB)方法中,將調(diào)用DAO的方法來(lái)執(zhí)行與數(shù)據(jù)庫(kù)的基本交互。 EmployeeServiceImpl.java類也帶有@Service注釋,表明它是一個(gè)Spring Bean,因此允許Spring自動(dòng)檢測(cè)到它。
@Transactional批注放置在方法之前,以表示在調(diào)用該方法時(shí)創(chuàng)建了一個(gè)事務(wù)。 該事務(wù)是全局容器管理的事務(wù),將在Spring配置文件中進(jìn)行配置。
EmployeeService.java
EmployeeServiceImpl.java
package com.javacodegeeks.snippets.enterprise.service;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional;import com.javacodegeeks.snippets.enterprise.dao.EmployeeADAO; import com.javacodegeeks.snippets.enterprise.dao.EmployeeBDAO; import com.javacodegeeks.snippets.enterprise.model.EmployeeA; import com.javacodegeeks.snippets.enterprise.model.EmployeeB;@Service("employeeService") public class EmployeeServiceImpl implements EmployeeService{@AutowiredEmployeeADAO employeeADAO;@AutowiredEmployeeBDAO employeeBDAO;@Transactional(rollbackFor=Exception.class)public void persistEmployees(EmployeeA employeeA, EmployeeB employeeB) throws Exception {System.out.println("Persist A");employeeADAO.persistEmployee(employeeA);System.out.println("Persist A OK - persist B");employeeBDAO.persistEmployee(employeeB);System.out.println("Persist B okk");}}7.創(chuàng)建一個(gè)servlet以運(yùn)行該應(yīng)用程序
AppServlet.java類是一個(gè)簡(jiǎn)單的servlet,它實(shí)現(xiàn)org.springframework.web.HttpRequestHandler并覆蓋其handleRequest(HttpServletRequest req, HttpServletResponse resp) API方法。 EmployeeService通過(guò)@Autowire注釋注入到此處。 在handleRequest(HttpServletRequest req, HttpServletResponse resp) API方法中使用它來(lái)持久存儲(chǔ)新的EmployeeA和新的EmployeeB對(duì)象。 如果該方法成功返回,則該方法還返回一條成功消息,如果該方法拋出異常,則返回回滾消息。
AppServlet.java
package com.javacodegeeks.snippets.enterprise.servlet;import java.io.IOException; import java.io.PrintWriter;import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.web.HttpRequestHandler;import com.javacodegeeks.snippets.enterprise.model.EmployeeA; import com.javacodegeeks.snippets.enterprise.model.EmployeeB; import com.javacodegeeks.snippets.enterprise.service.EmployeeService;@Component("appServlet") public class AppServlet implements HttpRequestHandler {@Autowiredprivate EmployeeService employeeService;public void handleRequest(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {EmployeeA em1 = new EmployeeA();em1.setId("123");em1.setName("John");em1.setAge(35);EmployeeB em2 = new EmployeeB();em2.setId("123");em2.setName("Mary");em2.setAge(31);try {employeeService.persistEmployees(em1, em2);resp.setContentType("text/html");PrintWriter out = resp.getWriter();out.println("<html>");out.println("<head>");out.println("<title>Hello World!</title>");out.println("</head>");out.println("<body>");out.println("<h1>Java Code Geeks </h1>");out.println("<h2>Both employees are inserted!</h2>");out.println("</body>");out.println("</html>");} catch (Exception e) {resp.setContentType("text/html");PrintWriter out = resp.getWriter();out.println("<html>");out.println("<head>");out.println("<title>Hello World!</title>");out.println("</head>");out.println("<body>");out.println("<h1>Java Code Geeks </h1>");out.println("<h2>Transaction Rollback!</h2>");out.println("</body>");out.println("</html>");e.printStackTrace();}} }8.配置應(yīng)用程序
8.1配置持久性單元
如上所述,在persistence.xml文件中配置了每個(gè)數(shù)據(jù)庫(kù)的entityManager和與其關(guān)聯(lián)的持久性單元。 在這里,我們定義了兩個(gè)持久性單元。 在每個(gè)persistence-unit元素中,我們定義與持久性單元關(guān)聯(lián)的實(shí)體類。 hibernate.transaction.manager_lookup_class屬性設(shè)置為com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup 。 hibernate.transaction.factory_class屬性設(shè)置為org.hibernate.transaction.CMTTransactionFactory 。
persistence.xml
8.2配置Spring容器
applicationContext.xml文件是Spring的配置文件。
<context:component-scan/>元素用于設(shè)置包含容器必須掃描以檢測(cè)Spring Bean的所有類的包。
還使用<tx:annotation-driven/>元素,以便Spring具有@Transactional感知,并可以檢測(cè)@Transactional注釋以配置具有事務(wù)行為的適當(dāng)bean。
<jta-transaction-manager/>元素用于檢測(cè)基礎(chǔ)服務(wù)器并選擇可用于平臺(tái)的事務(wù)管理器。
在dataSourceA和dataSourceB bean中,我們定義了數(shù)據(jù)源。 com.atomikos.jdbc.AtomikosDataSourceBean是此處設(shè)置的類。 它使用支持Atomikos JTA的連接池。 它具有兩個(gè)要配置的屬性。 com.mysql.jdbc.jdbc2.optional.MysqlXADataSource類設(shè)置為xaDataSourceClass屬性,而在xaProperties我們可以設(shè)置屬性(名稱,值對(duì))以配置XADataSource 。
在entityManagerFactoryA和entityManagerFactoryB bean中,我們?cè)O(shè)置了org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean類。 它是一個(gè)FactoryBean ,可根據(jù)JPA的標(biāo)準(zhǔn)容器引導(dǎo)合同創(chuàng)建JPA EntityManagerFactory 。 我們可以在其persistenceXmlLocation屬性中設(shè)置persistence.xml位置。 我們可以在persistenceUnitName屬性中設(shè)置用于創(chuàng)建此EntityManagerFactory的持久性單元的名稱。 datasource屬性是對(duì)適當(dāng)?shù)膁ataSource bean的引用。 jpaVendorAdapter屬性設(shè)置為org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter ,它是Hibernate EntityManager的實(shí)現(xiàn)。
最后,使用org.springframework.transaction.jta.JtaTransactionManager定義transactionManager bean。 它包含兩個(gè)要配置的屬性。 transactionManager和atomikosTransactionManager 。 它們分別引用了com.atomikos.icatch.jta.UserTransactionManager類和com.atomikos.icatch.jta.J2eeUserTransaction類的兩個(gè)bean。
applicationContext.xml
8.3配置Web應(yīng)用程序部署描述符
web.xml文件是定義服務(wù)器需要了解的有關(guān)應(yīng)用程序的所有內(nèi)容的文件。 此處設(shè)置了Servlet和其他組件,例如過(guò)濾器或偵聽(tīng)器,初始化參數(shù),容器管理的安全性約束,資源,歡迎頁(yè)面等。
servlet元素聲明AppServlet ,并聲明實(shí)現(xiàn)它的org.springframework.web.context.support.HttpRequestHandlerServlet類。 servlet-mapping元素指定在瀏覽器中調(diào)用servlet的/appServlet URL模式。 在context-param元素中,我們?cè)O(shè)置了contextConfigLocation參數(shù),其中定義了applicationContext.xml文件位置。 在listener元素中,將Bootstrap偵聽(tīng)器設(shè)置為啟動(dòng)Spring的applicationContext.xml 。 在兩個(gè)數(shù)據(jù)源中都設(shè)置了resource-ref元素,以定義對(duì)資源的引用查找名稱。 這允許Servlet代碼通過(guò)在部署時(shí)映射到實(shí)際位置的“虛擬”名稱來(lái)查找資源。
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><display-name>javacodegeeks</display-name><context-param><param-name>contextConfigLocation</param-name><param-value>/WEB-INF/applicationContext.xml</param-value></context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><servlet><display-name>AppServlet</display-name><servlet-name>appServlet</servlet-name><servlet-class>org.springframework.web.context.support.HttpRequestHandlerServlet</servlet-class></servlet><servlet-mapping><servlet-name>appServlet</servlet-name><url-pattern>/appServlet</url-pattern></servlet-mapping><resource-ref><description>MySQL DS</description><res-ref-name>jdbc/DataSourceA</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref><resource-ref><description>MySQL DS</description><res-ref-name>jdbc/DataSourceB</res-ref-name><res-type>javax.sql.DataSource</res-type><res-auth>Container</res-auth></resource-ref></web-app>9.在Tomcat中運(yùn)行應(yīng)用程序
為了在tomcat中運(yùn)行應(yīng)用程序,我們首先必須構(gòu)建項(xiàng)目。 產(chǎn)生的war位于tomcat的webapps文件夾中。 然后,我們啟動(dòng)服務(wù)器。 撞上之后
localhost:8080/springexample/appServlet
在瀏覽器中,我們可以檢查在MySQL,這兩個(gè)數(shù)據(jù)庫(kù), companyA和companyB表EmployeeA和EmployeeB有一個(gè)記錄。 瀏覽器中返回的消息是以下消息:
10.回滾情況
現(xiàn)在,讓我們看看如果兩個(gè)事務(wù)之一失敗了會(huì)發(fā)生什么。 我們將更改EmployeeBDAOImpl.java類的persistEmployee(EmployeeB employee)方法,以引發(fā)Exception 。
雇員BDAO Impl.java
package com.javacodegeeks.snippets.enterprise.dao;import javax.persistence.EntityManager; import javax.persistence.PersistenceContext;import org.springframework.stereotype.Service;import com.javacodegeeks.snippets.enterprise.model.EmployeeB;@Service public class EmployeeBDAOImpl implements EmployeeBDAO {@PersistenceContext(unitName="PersistenceUnitB")private EntityManager entityManager;public void persistEmployee(EmployeeB employee) throws Exception { // entityManager.persist(employee);throw new Exception();} }我們?cè)俅螛?gòu)建該項(xiàng)目,并將新的war文件放入tomcat的webapps文件中。 再次啟動(dòng)tomcat之后,結(jié)果如下:
這是由于事務(wù)之一引發(fā)異常而導(dǎo)致分布式事務(wù)也會(huì)回滾。
這是使用Atomikos事務(wù)管理器在Tomcat服務(wù)器中進(jìn)行JTA多個(gè)資源事務(wù)的示例。 下載本教程的Eclipse項(xiàng)目: SpringJTAatomicosTomcatExample.zip
翻譯自: https://www.javacodegeeks.com/2013/07/spring-jta-multiple-resource-transactions-in-tomcat-with-atomikos-example.html
jta atomikos
總結(jié)
以上是生活随笔為你收集整理的jta atomikos_带有Atomikos示例的Tomcat中的Spring JTA多个资源事务的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 连续交付友好的Maven版本
- 下一篇: 如何使用JPA和Hibernate映射J