javascript
带有Atomikos示例的Tomcat中的Spring JTA多个资源事务
在本教程中,我們將向您展示如何使用Atomikos Transaction Manager在Tomcat服務器中實現JTA多個資源事務。 Atomicos事務管理器為分布式事務提供支持。 這些是多階段事務,通常使用多個數據庫,必須以協調的方式提交。 分布式事務由XA standard描述。 XA事務管理器(例如Atomikos)如何告知數據庫什么事務作為正在進行的事務的一部分,以及如何在每次事務結束時執行兩階段提交(2PC)協議。
在這里,我們將創建映射到兩個不同數據庫的簡單實體類,并嘗試使用一個分布式事務將這些類的對象持久保存到數據庫中。 我們還將看到當基礎事務之一回滾時會發生什么。
我們首選的開發環境是Eclipse 。 我們正在使用Eclipse Juno(4.2)版本以及Maven Integration插件版本3.1.0。 您可以從Eclipse的這里從和Maven Eclipse插件這里 。 用于Eclipse的Maven插件的安裝不在本教程的討論范圍內,因此將不予討論。 我們還使用Spring 3.2.3和JDK 7_u_21。
Tomcat 7是使用的應用程序服務器。 Hibernate版本為4.1.9,示例中使用的數據庫為MySQL Database Server 5.6。
讓我們開始,
1.創建一個新的Maven項目
轉到文件->項目-> Maven-> Maven項目。
在向導的“選擇項目名稱和位置”頁面中,確保未選中 “創建簡單項目(跳過原型選擇)”選項,單擊“下一步”以繼續使用默認值。
在這里,必須添加用于創建Web應用程序的Maven原型。 單擊“添加原型”并添加原型。 將“ Archetype組ID”變量設置為"org.apache.maven.archetypes" ,將“ Archetype構件ID”變量設置為"maven-archetype-webapp" ,將“ Archetype版本”設置為"1.0" 。 點擊“確定”繼續。
在向導的“輸入工件ID”頁面中,您可以定義項目的名稱和主程序包。 將“ Group Id”變量設置為"com.javacodegeeks.snippets.enterprise" ,將“ Artifact Id”變量設置為"springexample" 。 前面提到的選擇將主項目包組成為"com.javacodegeeks.snippets.enterprise.springexample" ,項目名稱為"springexample" 。 將“ Package”變量設置為"war" ,以便創建一個war文件以部署到tomcat服務器。 點擊“完成”退出向導并創建您的項目。
Maven項目結構如下所示:
- 它包含以下文件夾:
- / src / main / java文件夾,其中包含應用程序動態內容的源文件,
- / src / test / java文件夾包含用于單元測試的所有源文件,
- / src / main / resources文件夾包含配置文件,
- / target文件夾包含已編譯和打包的可交付成果,
- / src / main / resources / webapp / WEB-INF文件夾包含Web應用程序的部署描述符,
- pom.xml是項目對象模型(POM)文件。 包含所有項目相關配置的單個文件。
2.添加Spring 3.2.3依賴項
- 在POM編輯器的“概述”頁面上找到“屬性”部分,并進行以下更改:
創建一個新屬性,名稱為org.springframework.version ,值3.2.3RELEASE 。 - 導航到POM編輯器的“依賴關系”頁面,并創建以下依賴關系(您應在該頁面的“依賴關系詳細信息”部分中填寫“ GroupId”,“工件ID”和“版本”字段):
組ID: org.springframework工件ID: spring-web版本: $ {org.springframework.version}
另外,您可以在Maven的pom.xml文件中添加Spring依賴項,方法是直接在POM編輯器的“ Pom.xml”頁面上對其進行編輯,如下所示:
pom.xml:
如您所見,Maven以聲明方式管理庫依賴關系。 創建本地存儲庫(默認情況下,位于{user_home} /。m2文件夾下),所有必需的庫都從公共存儲庫下載并放置在該庫中。 此外,庫內的依賴關系會自動解決和處理。
3.添加所有必需的依賴項
此處設置了設置atomosos事務管理器所需的所有依賴項。
pom.xml
4.創建實體類
EmployeeA.java和EmployeeB.java是Entity類。 他們使用javax.persistence批注映射到不同數據庫中的表EMPLOYEEA和EMPLOYEEB 。 特別地, @Entity注釋指定每個類是一個實體。 @Table注釋指定帶注釋的實體的主表。 @Column批注用于為持久字段指定一個映射列,而@Id批注指定每個實體的主鍵字段。
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.創建DAO類
實現的數據訪問對象是EmployeeADAOImpl.java和EmployeeBDAOImpl.java類。 它們使用@Service注釋進行注釋,表明它們是Spring Bean,因此允許Spring自動檢測它們。 它們都使用javax.persistence.EntityManager與數據庫進行交互。
EntityManager實例與持久性上下文關聯。 持久性上下文是一組實體實例,其中對于任何持久性實體標識,都有一個唯一的實體實例。 在持久性上下文中,管理實體實例及其生命周期。 EntityManager API用于創建和刪除持久實體實例,通過其主鍵查找實體以及查詢實體。 在persistence.xml文件中配置了EntityManager ,對此進行了描述
在8.1節中。
可以由給定EntityManager實例管理的實體集由持久性單元定義。 持久性單元定義了與應用程序相關或分組的所有類的集合,并且所有類在映射到單個數據庫時必須共置。
EntityManager通過@PersistenceContext注釋注入到每個DAO中,在該注釋中設置了每個持久性單元的名稱,如persistence.xml文件中所定義。
在兩個DAO中都實現了一種基本的persist方法,使用EntityManager的persist(Object entity) API方法為數據庫創建一個對象。
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.創建服務類
EmployeeADAOImpl.java和EmployeeBDAOImpl.java類被注入EmployeeServiceImpl.java類。 因此,在此處實現的persistEmployees(EmployeeA employeeA, EmployeeB employeeB)方法中,將調用DAO的方法來執行與數據庫的基本交互。 EmployeeServiceImpl.java類也帶有@Service注釋,表明它是一個Spring Bean,因此允許Spring自動檢測到它。
@Transactional批注放置在方法之前,以表示在調用該方法時創建了一個事務。 該事務是全局容器管理的事務,將在Spring配置文件中進行配置。
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.創建一個servlet以運行該應用程序
AppServlet.java類是一個簡單的servlet,它實現org.springframework.web.HttpRequestHandler并覆蓋其handleRequest(HttpServletRequest req, HttpServletResponse resp) API方法。 EmployeeService通過@Autowire注釋注入到此處。 在handleRequest(HttpServletRequest req, HttpServletResponse resp) API方法中使用它來持久存儲新的EmployeeA和新的EmployeeB對象。 如果該方法成功返回,則該方法還返回成功消息,如果該方法引發異常,則返回回滾消息。
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.配置應用程序
8.1配置持久性單元
如上所述,在persistence.xml文件中配置了entityManager和與每個數據庫關聯的持久性單元。 在這里,我們定義了兩個持久性單元。 在每個persistence-unit元素中,我們定義與持久性單元關聯的實體類。 hibernate.transaction.manager_lookup_class屬性設置為com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup 。 hibernate.transaction.factory_class屬性設置為org.hibernate.transaction.CMTTransactionFactory 。
persistence.xml
8.2配置Spring容器
applicationContext.xml文件是Spring的配置文件。
<context:component-scan/>元素用于設置包含容器必須掃描以檢測Spring Bean的所有類的包。
還使用<tx:annotation-driven/>元素,以便Spring具有@Transactional感知,并可以檢測@Transactional注釋以配置具有事務行為的適當bean。
<jta-transaction-manager/>元素用于檢測基礎服務器并選擇可用于平臺的事務管理器。
在dataSourceA和dataSourceB bean中,我們定義了數據源。 com.atomikos.jdbc.AtomikosDataSourceBean是此處設置的類。 它使用支持Atomikos JTA的連接池。 它具有兩個要配置的屬性。 com.mysql.jdbc.jdbc2.optional.MysqlXADataSource類設置為xaDataSourceClass屬性,而在xaProperties我們可以設置屬性(名稱,值對)以配置XADataSource 。
在entityManagerFactoryA和entityManagerFactoryB bean中,我們設置了org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean類。 它是一個FactoryBean ,可根據JPA的標準容器引導合同創建JPA EntityManagerFactory 。 我們可以在其persistenceXmlLocation屬性中設置persistence.xml位置。 我們可以在persistenceUnitName屬性中設置用于創建此EntityManagerFactory的持久性單元的名稱。 datasource屬性是對適當的dataSource bean的引用。 jpaVendorAdapter屬性設置為org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter ,它是Hibernate EntityManager的實現。
最后,使用org.springframework.transaction.jta.JtaTransactionManager定義transactionManager bean。 它具有兩個要配置的屬性。 transactionManager和atomikosTransactionManager 。 它們分別引用了com.atomikos.icatch.jta.UserTransactionManager類和com.atomikos.icatch.jta.J2eeUserTransaction類的兩個bean。
applicationContext.xml
8.3配置Web應用程序部署描述符
web.xml文件是定義服務器需要了解的有關應用程序的所有內容的文件。 此處設置了Servlet和其他組件,如過濾器或偵聽器,初始化參數,容器管理的安全性約束,資源,歡迎頁面等。
servlet元素聲明AppServlet ,并聲明實現它的org.springframework.web.context.support.HttpRequestHandlerServlet類。 servlet-mapping元素指定在瀏覽器中調用servlet的/appServlet URL模式。 在context-param元素中,我們設置了contextConfigLocation參數,其中定義了applicationContext.xml文件位置。 在listener元素中,將Bootstrap偵聽器設置為啟動Spring的applicationContext.xml 。 在兩個數據源中都設置了resource-ref元素,以定義對資源的引用查找名稱。 這允許servlet代碼通過在部署時映射到實際位置的“虛擬”名稱來查找資源。
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中運行應用程序
為了在tomcat中運行應用程序,我們首先必須構建項目。 產生的war被放置在tomcat的webapps文件夾中。 然后,我們啟動服務器。 撞上之后
localhost:8080/springexample/appServlet
在瀏覽器中,我們可以檢查在MySQL,這兩個數據庫, companyA和companyB表EmployeeA和EmployeeB有一個記錄。 瀏覽器中返回的消息是以下消息:
10.回滾情況
現在,讓我們看看如果兩個事務之一失敗了會發生什么。 我們將更改EmployeeBDAOImpl.java類的persistEmployee(EmployeeB employee)方法,以引發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();} }我們再次構建該項目,并將新的war文件放入tomcat的webapps文件中。 再次啟動tomcat之后,結果如下:
這是由于事務之一引發異常而導致分布式事務也會回滾。
這是使用Atomikos事務管理器在Tomcat服務器中進行JTA多個資源事務的示例。 下載本教程的Eclipse項目: SpringJTAatomicosTomcatExample.zip
翻譯自: https://www.javacodegeeks.com/2013/07/spring-jta-multiple-resource-transactions-in-tomcat-with-atomikos-example.html
總結
以上是生活随笔為你收集整理的带有Atomikos示例的Tomcat中的Spring JTA多个资源事务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陌陌号是什么 陌陌号是啥
- 下一篇: 在Spring中使用Future对象调用