spring hibernate 集成:spring使用容器JTA事务管理器
来源:互联网 发布:我有域名如何使用 编辑:程序博客网 时间:2024/06/06 00:28
说明:
1.EJB的事务是方法级别的隔离,而spring的拦截事务是类级别的,所以spring管理的jta事务在同一个类的不同方法设置不同的事务传播策略是无效的。
2.使用了spring的事务,就不能显示地使用hibernate的开启事务,提交事务等,spring通过拦截器自动实现这些操作。
正文开始:
spring hibernate 集成,hibernate操作多个数据库需要 jta 事务管理器,spring提供了对容器jta事务管理器的支持,同时hibernate也提供了对容器jta事务管理器的支持,注意两者不能同时使用,只能选择其一来管理事务,如果要使用spring则可以通过配置事务代理或者拦截器的方式实现,如果要使用hibernate则可以配置session工厂使用jta事务管理器同事编码过程中要显示开启事务/提交或回滚事务,显然使用spring管理事务更加优越:1.声明式事务管理,对代码无侵入;2.拦截器使用aop的方式,可以批量对多个业务服务bean植入事务支持,下面是一个完整的使用spring管理事务的例子:
项目的pom文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <parent> <artifactId>eden</artifactId> <groupId>com.conquer.eden</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springtx</artifactId> <packaging>war</packaging> <name>springtx</name> <properties> <springVersion>2.0.1</springVersion> </properties> <dependencies> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.transaction</groupId> <artifactId>javax.transaction-api</artifactId> <version>1.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> <version>2.0.1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>3.1.3</version> <exclusions> <exclusion> <groupId>javax.transaction</groupId> <artifactId>jta</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <build> <finalName>springtx</finalName> </build></project>
注意这里:由于web层没有使用spring管理,所以这里没有配置spring的请求转发器,所以需要手工使用spring的api来初始化spring容器,web.xml代码:
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" ><web-app> <servlet> <servlet-name>test</servlet-name> <servlet-class>com.test.TestServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>test</servlet-name> <url-pattern>/test</url-pattern> </servlet-mapping></web-app>Servlet代码:
package com.test;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.PrintWriter;public class TestServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String data = req.getParameter("data"); if (data == null) data = "00000"; try { SpringTest.testSpring(data); PrintWriter writer = resp.getWriter(); writer.println("ok, check the console output ..."); writer.flush(); } catch (Exception e) { throw new ServletException(e); } }}
下面是spring事务测试的入口,由于没有使用spring管理web,故在这里进行spring容器的初始化:
package com.test;import com.test.service.Service1;import com.test.service.Service2;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class SpringTest { private static Service1 service1; private static Service2 service2; static { /** * 测试使用: * 保证实例是在spring的管理范围内,即在spring的IOC容器中,在spring mvc 的 web 架构中,我们不需要这样显示写出来,注入是自动的 * 这里因为我们的 测试 Servlet 没有被spring 管理,也就不能触发spring的注入机制,所以这里使用编程的方式测试。 */// 使用 代理bean方式 支持事务// ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/*.xml", "spring/tx/tx_proxy.xml"});// 使用 拦截bean方法方式(拦截器) 支持事务 ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"spring/*.xml", "spring/tx/tx_interceptor.xml"}); //直接引用,会导致事务不起作用,必需使用spring的事务代理类,注意:使用拦截器时使用这个,不需要改变,拦截器的实现会自动改变内存里的实现 //拦截器是推荐使用的事务支持方式,好处: // 一:不需要使用新的代理bean(不用担心引用错误造成事务无效) // 二:可以批量配置bean的事务属性(避免事务bean的配置膨胀) service1 = (Service1) context.getBean("service1"); service2 = (Service2) context.getBean("service2"); //使用spring的事务代理类,可使用事务支持// service1 = (Service1) context.getBean("myTxProxy1");// service2 = (Service2) context.getBean("myTxProxy2"); } public static void testSpring(String data) { service1.twoTX(data); }}好了,现在看下spring需要的配置文件:
base.xml:引用容器提供的jndi资源,主要是数据源和JTA事务管理器
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!--通过JNDI查找的对象,最终会强制转为为需要的类型,如这个会强转为 TransactionManager--> <bean id="twJtaTm" class="org.springframework.jndi.JndiObjectFactoryBean"> <!--tw6--> <property name="jndiName" value="java:appserver/TransactionManager"/> <!--twe5--> <!--<property name="jndiName" value="java:internal/TransactionManager"/>--> <!--jboss--> <!--<property name="jndiName" value="java:/TransactionManager"/>--> <!--weblogic--> <!--<property name="jndiName" value="javax.transaction.TransactionManager"/>--> <!--<property name="resourceRef" value="true" />TODO--> </bean> <!--通过JNDI查找的对象,最终会强制转为为需要的类型,如这个会强转为 DataSource--> <bean id="myDataSource1" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="DataSource1"/> <!--<property name="resourceRef" value="true" />TODO--> </bean> <!--通过JNDI查找的对象,最终会强制转为为需要的类型,如这个会强转为 DataSource--> <bean id="myDataSource2" class="org.springframework.jndi.JndiObjectFactoryBean"> <property name="jndiName" value="DataSource1"/> <!--<property name="resourceRef" value="true" />TODO--> </bean></beans>
business_beans.xml:业务bean的配置文件:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!-- 以下是具体业务相关 --> <!--业务类,需要事务配置的类,特别注意,业务中不要直接使用此实例,而应该使用其事务代理:basicTxProxy --> <!-- NOTE:非嵌入式的,命名的,此目标业务 bean 可被直接引用,直接引用将导致 无事务,所以应该使用代理事务bean的引用或使用事务拦截器来处理--> <bean id="baseDAO" abstract="true"> <property name="sessionFactory1" ref="sessionFactory1"/> <property name="sessionFactory2" ref="sessionFactory2"/> </bean> <!--如果使用代理,直接引用这里的bean会导致事务失效,应该引用其代理,而且事务应该加在 服务层(service)--> <bean id="dao1" parent="baseDAO" class="com.test.dao.impl.DAOImpl1"/> <bean id="dao2" parent="baseDAO" class="com.test.dao.impl.DAOImpl2"/> <!--事务应该加在 服务层(service):如果使用代理,直接引用这里的bean会导致事务失效,应该引用其代理--> <bean id="service1" class="com.test.service.impl.Service1Impl"> <property name="dao1" ref="dao1"/> <property name="dao2" ref="dao2"/> <!--如果使用代理,直接引用这里的bean会导致事务失效,应该引用其代理,但是,如果使用的事务拦截器,这里不需要变动,拦截器会自动改掉内存里的实现--> <property name="service2" ref="service2"/> <!--引用事务代理代理,不使用拦截器时使用这个--> <!--<property name="service2" ref="myTxProxy2"/>--> </bean> <bean id="service2" class="com.test.service.impl.Service2Impl"> <property name="dao2" ref="dao2"/> </bean></beans>
hibernate.xml:hibernate session工厂的配置
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!--spring 对 hibernate的支持,用于创建 hibernate的SessionFactory--> <bean id="sessionFactory1" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="hibernateProperties"> <value> <!--这里填写hibernate特定属性,注意不要在这里写 hibernate.transaction.factory_class 和 jta.UserTransaction,因为事务需要交给spring管理 这里写了,只会对代码调用 org.hibernate.Session#getTransaction()方法起效,对于spring配置的事务策略无效,使用spring的事务会忽略此设置 --> hibernate.dialect=org.hibernate.dialect.OracleDialect hibernate.show_sql=true </value> </property> <!--配置hibernate的映射文件,这里配置的是整个 hbm 文件夹下的文件--> <property name="mappingDirectoryLocations"> <list> <value> classpath*:/hbm/ </value> </list> </property> <!--JNDI 查找到的 myDataSource1 是DataSource类型的,所以可以在这里注入--> <property name="dataSource" ref="myDataSource1"/> <!--JNDI 查找到的 twJtaTm 是TransactionManager类型的,所以可以在这里注入 TODO--> <!--<property name="jtaTransactionManager" ref="twJtaTm"/>--> </bean> <!--spring 对 hibernate的支持,用于创建 hibernate的SessionFactory--> <bean id="sessionFactory2" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="hibernateProperties"> <value> <!--这里填写hibernate特定属性,注意不要在这里写 hibernate.transaction.factory_class 和 jta.UserTransaction,因为事务需要交给spring管理 这里写了,只会对代码调用 org.hibernate.Session#getTransaction()方法起效,对于spring配置的事务策略无效,使用spring的事务会忽略此设置 --> hibernate.dialect=org.hibernate.dialect.OracleDialect hibernate.show_sql=true </value> </property> <!--配置hibernate的映射文件,这里配置的是指定的文件--> <property name="mappingResources"> <list> <value>hbm/Student.hbm.xml</value> <value>hbm/Teacher.hbm.xml</value> </list> </property> <!--JNDI 查找到的 myDataSource2 是DataSource类型的,所以可以在这里注入--> <property name="dataSource" ref="myDataSource2"/> <!--JNDI 查找到的 twJtaTm 是TransactionManager类型的,所以可以在这里注入 TODO--> <!--<property name="jtaTransactionManager" ref="twJtaTm"/>--> </bean></beans>
tx_common.xml:事务公共配置,注意是一些公共bean
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!-- 要使用 JTA 事务管理,需要配置 JtaTransactionManager,他需要 TransactionManager 类型的实例,twJtaTm正好是一个 它本身是 PlatformTransactionManager 的实现,可以配合完成 spring 的多种事务配置 --> <bean id="mySpringTransactionManager" class="org.springframework.transaction.jta.JtaTransactionManager"> <property name="transactionManager" ref="twJtaTm"/> </bean></beans>
下面就是重头戏了,spring有至少两种方式配置事务,代理bean和拦截器,下面是这两种的不同配置文件,实际使用其中一种即可:
tx_proxy.xml:使用代理bean支持事务
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!--设置为 abstract,这样可以通过继承的方式,简化子类的代码,如果没有子类就不初始化--> <bean id="baseTxProxyBean" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <!--需要的 transactionManager 是 PlatformTransactionManager 类型,所以不能直接注入 twJtaTm,需要使用 JtaTransactionManager 这个实现类,此实现类依赖 twJtaTm --> <property name="transactionManager" ref="mySpringTransactionManager"/> <property name="transactionAttributes"> <!--Spring中Propagation类的事务属性详解: PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。 --> <props> <!--<prop key="*">PROPAGATION_REQUIRED</prop>--> <prop key="*">PROPAGATION_REQUIRED</prop> <!--<prop key="testTX">PROPAGATION_REQUIRED</prop>--> <!--<prop key="insert*">PROPAGATION_REQUIRED</prop>--> <!--<prop key="*">PROPAGATION_SUPPORTS,readOnly</prop>--> </props> </property> <!--非嵌入式的,命名的,目标业务bean可被直接引用导致无事务--> <!--<property name="target" ref="springTest"/>--> <!--嵌入式的,匿名的,避免目标业务bean被直接引用--> <!--<property name="target">--> <!--<bean class="com.test.SpringTest"/>--> <!--</property>--> </bean> <!-- 代理对象 --> <bean id="myTxProxy1" parent="baseTxProxyBean"> <!--非嵌入式的,命名的,目标业务bean可被直接引用导致无事务,所以应该引用此:baseTxProxyBean--> <property name="target" ref="service1"/> </bean> <!-- 代理对象 --> <bean id="myTxProxy2" parent="baseTxProxyBean"> <property name="transactionAttributes"> <props> <prop key="twoTX">PROPAGATION_REQUIRES_NEW</prop> </props> </property> <!--非嵌入式的,命名的,目标业务bean可被直接引用导致无事务,所以应该引用此:baseTxProxyBean--> <property name="target" ref="service2"/> <!--嵌入式的,匿名的,避免目标业务bean被直接引用--> <!--<property name="target">--> <!--<bean parent="baseDAO" class="com.test.dao.impl.DAOServiceImpl"/>--> <!--</property>--> </bean> <!--以上的代理事务,如果业务类较多会出现配置膨胀,即每个需要事务的业务bean都需要配置一次,虽然使用了 继承 ,减少了代码量,但配置膨胀问题还没有解决 从根本上解决就是用使用 拦截器的配置方式,看 tx_interceptor.xml 定义的的拦截器配置事务方式--></beans>
tx_interceptor.xml:使用拦截器支持事务:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"><beans> <!--tx_proxy.xml中使用的代理事务,如果业务类较多会出现配置膨胀,即每个需要事务的业务bean都需要配置一次,虽然使用了 继承 ,减少了代码量,但配置膨胀问题还没有解决 从根本上解决就是用使用 拦截器的配置方式,看下面的拦截器配置事务方式:利用切面编程思想,自动添加事务支持--> <!-- 定义事务 --> <bean id="txInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager" ref="mySpringTransactionManager" /> <!-- 配置事务属性 --> <property name="transactionAttributes"> <!--Spring中Propagation类的事务属性详解: PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。 PROPAGATION_SUPPORTS:支持当前事务,如果当前没有事务,就以非事务方式执行。 PROPAGATION_MANDATORY:支持当前事务,如果当前没有事务,就抛出异常。 PROPAGATION_REQUIRES_NEW:新建事务,如果当前存在事务,把当前事务挂起。 PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。 PROPAGATION_NESTED:支持当前事务,如果当前事务存在,则执行一个嵌套事务,如果当前没有事务,就新建一个事务。 --> <props> <prop key="*">PROPAGATION_REQUIRED</prop> </props> </property> </bean> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="beanNames"> <list> <!--matches service1 & service2 & service*--> <value>service*</value> </list> </property> <property name="interceptorNames"> <list> <value>txInterceptor</value> </list> </property> </bean></beans>
由于在上面使用了hibernate,所以需要提供下hibernate的映射文件,连个 hbm 文件:
Student.hbm.xml:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.test.model"> <class name="Student" table="STUDENT"> <id name="id"> <generator class="uuid"/> </id> <property name="name"/> </class></hibernate-mapping>
Teacher.hbm.xml:
<?xml version="1.0"?><!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.test.model"> <class name="Teacher" table="TEACHER"> <id name="id"> <generator class="uuid"/> </id> <property name="name"/> </class></hibernate-mapping>
注意:以上spring的配置文件都放到类路径的 spring 目录下,hibernate的两个hbm放到类路径的hbm目录下。
好了,到这里就可以看看具体的java代码了,值得说明的是:spring提供的切面编程支持事务的能力,对代码零侵入,使得我们在编码过程中根本不用关心事务功能,编写好的程序最后通过一个简单的AOP事务配置就支持事务,感慨一下spring的魅力,切面编程的魅力吧!!!
dao层代码:此层直接进行数据库操作,不关心业务,不关心事务,为service层提供支持
service层代码:此层用于完成具体的业务单元,一般一个业务单元需要同时进行多项数据库操作,所以往往事务也在这一次加入
controller层代码:此层用于控制业务逻辑的导向,并完成页面(视图层)交互,本示例没有涉及到此层
dao层代码:
package com.test.dao;public interface DAO2 { void tx1(String data); void tx2(String data);}
package com.test.dao;public interface DAO1 { void tx1(String data); void tx2(String data);}
package com.test.dao.impl;import org.hibernate.SessionFactory;public class BaseDAO { protected SessionFactory sessionFactory1; protected SessionFactory sessionFactory2; public void setSessionFactory1(SessionFactory sessionFactory1) { this.sessionFactory1 = sessionFactory1; } public void setSessionFactory2(SessionFactory sessionFactory2) { this.sessionFactory2 = sessionFactory2; }}
package com.test.dao.impl;import com.test.dao.DAO1;import com.test.model.Student;import com.test.model.Teacher;import org.hibernate.Query;import org.hibernate.Session;import java.util.Date;import java.util.List;public class DAOImpl1 extends BaseDAO implements DAO1 { public void tx1(String data) { System.out.println("=========第 一 次写数据========"); Session studentSession = sessionFactory1.openSession(); insertStudent(studentSession); List<Student> students = queryStudent(studentSession); for (Student u : students) { System.out.println(u); } if (data.equals("1")) throw new RuntimeException("111111111111"); } public void tx2(String data) { System.out.println("=========第 二 次写数据========"); Session teacherSession = sessionFactory2.openSession(); insertStudent(teacherSession); List<Student> students2 = queryStudent(teacherSession); for (Student u : students2) { System.out.println(u); } if (data.equals("2")) throw new RuntimeException("222222222222"); } public void insertStudent(Session session) { Student s = new Student(); s.setName("SpringTest1:" + new Date().toString()); session.save(s); } public List<Student> queryStudent(Session session) { Query query = session.createQuery("from Student"); return query.list(); } public void insertTeacher(Session session) { Teacher s = new Teacher(); s.setName(new Date().toString()); session.save(s); } public List<Student> queryTeacher(Session session) { Query query = session.createQuery("from Teacher"); return query.list(); }}
package com.test.dao.impl;import com.test.dao.DAO2;import com.test.model.Student;import org.hibernate.Query;import org.hibernate.Session;import java.util.Date;import java.util.List;public class DAOImpl2 extends BaseDAO implements DAO2 { public void tx1(String data) { System.out.println("=========第 一 次写数据========"); Session studentSession = sessionFactory1.openSession(); insertStudent(studentSession); List<Student> students = queryStudent(studentSession); for (Student u : students) { System.out.println(u); } if (data.equals("3")) throw new RuntimeException("111111111111"); } public void tx2(String data) { System.out.println("=========第 二 次写数据========"); Session teacherSession = sessionFactory2.openSession(); insertStudent(teacherSession); List<Student> students2 = queryStudent(teacherSession); for (Student u : students2) { System.out.println(u); } if (data.equals("4")) throw new RuntimeException("222222222222"); } private void insertStudent(Session session) { Student s = new Student(); s.setName("SpringTest2:" + new Date().toString()); session.save(s); } private List<Student> queryStudent(Session session) { Query query = session.createQuery("from Student"); return query.list(); }}service层代码:
package com.test.service;public interface Service1 { void twoTX(String data);}
package com.test.service;public interface Service2 { void twoTX(String data);}
package com.test.service.impl;import com.test.dao.DAO1;import com.test.dao.DAO2;import com.test.service.Service1;import com.test.service.Service2;public class Service1Impl implements Service1 { private DAO1 dao1; private DAO2 dao2; private Service2 service2; public void setDao1(DAO1 dao1) { this.dao1 = dao1; } public void setDao2(DAO2 dao2) { this.dao2 = dao2; } public void setService2(Service2 service2) { this.service2 = service2; } public void twoTX(String data) { dao1.tx1(data); dao1.tx2(data); service2.twoTX(data); }}
package com.test.service.impl;import com.test.dao.DAO1;import com.test.dao.DAO2;import com.test.service.Service2;public class Service2Impl implements Service2 { private DAO1 dao1; private DAO2 dao2; public void setDao1(DAO1 dao1) { this.dao1 = dao1; } public void setDao2(DAO2 dao1) { this.dao2 = dao1; } public void twoTX(String data) { dao2.tx1(data); dao2.tx2(data); }}
model类:
package com.test.model;public class Student { private String id; private String name; public String getName() { return name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; }}
package com.test.model;public class Teacher { private String id; private String name; public String getName() { return name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Teacher{" + "id='" + id + '\'' + ", name='" + name + '\'' + '}'; }}
最后说明:
1.EJB的事务是方法级别的隔离,而spring的拦截事务是类级别的,所以spring管理的jta事务在同一个类的不同方法设置不同的事务传播策略是无效的。
2.使用了spring的事务,就不能显示地使用hibernate的开启事务,提交事务等,spring通过拦截器自动实现这些操作。
- spring hibernate 集成:spring使用容器JTA事务管理器
- 使用Spring和Atomikos集成JTA分布式事务
- Atomikos Jta分布式事务spring集成实例
- Spring+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务
- Spring+Hibernate+Atomikos集成构建JTA的分布式事务--解决多数据源跨库事务
- spring+hibernate+tomcat+JTA跨数据库事务
- spring+hibernate+JTA 分布式事务的例子
- spring+hibernate+jta 分布式事务Demo
- Spring + hibernate + struts2 +jotm JTA事务
- spring+hibernate+jta分布式事务Demo
- spring+hibernate+jta 分布式事务Demo
- spring+hibernate+jta 分布式事务Demo
- Spring JTA 分布式事务
- Spring JTA 分布式事务
- Spring在tomcat下使用JTA事务
- Postgresql 分布式事务JTA实现Atomikos与Spring集成实践
- spring+hibernate+jpa配置JTA事务出错,如何解决?
- 分布式事务入门例子(Spring+JTA+Atomikos+Hibernate+JMS)
- 程序员面试宝典第10章面向对象+个人理解版整理笔记
- C 【石头剪刀布 问题】
- Escape BNUOJ 49278
- 面向对象七大设计原则
- Matplotlib: Stacked Bar Graphs
- spring hibernate 集成:spring使用容器JTA事务管理器
- 第六周项目2-变量的变化(2)
- Android Studio 快捷键
- jQuery Modal bootstrap风格对话框插件
- leetcode 173. Binary Search Tree Iterator
- replace限制文本框只能输入数字,数字和字母等的正则表达式
- Educational Codeforces Round 10——B. z-sort
- [Hnoi2006]马步距离 (贪心+A*)
- Android_studio安装步骤