Hibernate 4(Jpa 2.0 + Jta使用Atomikos事务管理器)不将对象保存在mysql架构中

时间:2013-06-12 19:02:15

标签: java spring hibernate jpa jta

我正在阅读Pro Spring 3一书,在有关全局事务的章节中,有一些示例代码用于将对象持久化为两个不同的mysql模式。 我正在运行代码,但对象没有保存在两个模式中的任何一个中。 这是代码。

tx-jta-app-context.xml:

<?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"
       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">

    <context:annotation-config />
    <context:component-scan base-package="foo.bar.service.jta"/>

    <bean id="dataSourceA" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="uniqueResourceName">
            <value>XADBMSA</value>
        </property>
        <property name="xaDataSourceClassName">
            <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
        </property>
        <property name="xaProperties">
            <props>
                <prop key="databaseName">prospring3_ch13a</prop>
                <prop key="user">prospring3_ch13a</prop>
                <prop key="password">prospring3_ch13a</prop>
            </props>
        </property>
        <property name="poolSize">
            <value>1</value>
        </property>
    </bean>
    <bean id="dataSourceB" class="com.atomikos.jdbc.AtomikosDataSourceBean" init-method="init" destroy-method="close">
        <property name="uniqueResourceName">
            <value>XADBMSB</value>
        </property>
        <property name="xaDataSourceClassName">
            <value>com.mysql.jdbc.jdbc2.optional.MysqlXADataSource</value>
        </property>
        <property name="xaProperties">
            <props>
                <prop key="databaseName">prospring3_ch13b</prop>
                <prop key="user">prospring3_ch13b</prop>
                <prop key="password">prospring3_ch13b</prop>
            </props>
        </property>
        <property name="poolSize">
            <value>1</value>
        </property>
    </bean>

    <!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
    <bean id="atomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init" destroy-method="close">
        <!-- when close is called, should we force transactions to terminate or not? -->
        <property name="forceShutdown">
            <value>true</value>
        </property>
    </bean>

    <!-- Also use Atomikos UserTransactionImp, needed to configure Spring -->
    <bean id="atomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
        <property name="transactionTimeout">
            <value>300</value>
        </property>
    </bean>

    <!-- Configure the Spring framework to use JTA transactions from Atomikos -->
    <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
        <property name="transactionManager">
            <ref bean="atomikosTransactionManager"/>
        </property>
        <property name="userTransaction">
            <ref bean="atomikosUserTransaction"/>
        </property>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>

    <bean id="emfBase" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" abstract="true">
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="packagesToScan" value="foo.bar.domain"/>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.transaction.factory_class">
                    ${com.atomikos.icatch.jta.hibernate3.AtomikosJTATransactionFactory}
                </prop>
                <prop key="hibernate.transaction.manager_lookup_class">
                    ${com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup}
                </prop>
                <prop key="hibernate.dialect">
                    org.hibernate.dialect.MySQL5Dialect
                </prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.jdbc.fetch_size">50</prop>
                <prop key="hibernate.jdbc.batch_size">10</prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
    </bean>

    <bean id="emfA" parent="emfBase">
        <property name="dataSource" ref="dataSourceA"/>
    </bean>

    <bean id="emfB" parent="emfBase">
        <property name="dataSource" ref="dataSourceB"/>
    </bean>
</beans>

foo / bar / service / jta / ContactServiceImpl.java:

package foo.bar.service.jta;

import foo.bar.domain.Contact;
import foo.bar.service.ContactService;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.List;


@Service("contactService")
@Repository
@Transactional
public class ContactServiceImpl implements ContactService{

    @PersistenceContext(unitName = "emfA")
    private EntityManager emA;

    @PersistenceContext(unitName = "emfB")
    private EntityManager emB;

    @Override
    @Transactional(readOnly = true)
    public List<Contact> findAll() {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    @Transactional(readOnly = true)
    public Contact findById(Long id) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Override
    public Contact save(Contact contact) {
        Contact contactB = new Contact();
        contactB.setFirstName(contact.getFirstName());
        contactB.setLastName(contact.getLastName());
        if (contact.getId() == null)
        {
            emA.persist(contact);
            emB.persist(contactB);
            //throw new JpaSystemException(new PersistenceException());
        }
        else
        {
            emA.merge(contact);
            emB.merge(contact);
        }

        return contact;
    }

    @Override
    public long countAll() {
        return 0;  //To change body of implemented methods use File | Settings | File Templates.
    }
}

富/酒吧/域/ Contact.java:

package foo.bar.domain;

import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;

import static javax.persistence.GenerationType.IDENTITY;

@Entity
@Table(name = "contact")
@NamedQueries({
        @NamedQuery(name = "Contact.findAll", query="select c from Contact c"),
        @NamedQuery(name = "Contact.countAll", query="select count(c) from Contact c")
})
public class Contact implements Serializable{

    private Long id;
    private int version;
    private String firstName;
    private String lastName;
    private Date birthDate;

    public Contact()
    {

    }

    //getters and setters
    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "ID")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Version
    @Column(name = "VERSION")
    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    @Column(name = "FIRST_NAME")
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Column(name = "LAST_NAME")
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Temporal(TemporalType.DATE)
    @Column(name = "BIRTH_DATE")
    public Date getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(Date birthDate) {
        this.birthDate = birthDate;
    }

    //other methods
    public String toString()
    {
        return "Contact - Id: " + id + ", First name: " + firstName + ", Last name: " + lastName + ", Birthday: " + birthDate;
    }
}

富/酒吧/ TxJtaSample.java:

package foo.bar;

import foo.bar.domain.Contact;
import foo.bar.service.ContactService;
import org.springframework.context.support.GenericXmlApplicationContext;


public class TxJtaSample {

    public static void main(String[] args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext("tx-jta-app-context.xml");

        ContactService contactService = ctx.getBean("contactService", ContactService.class);

        Contact contact = new Contact();
        contact.setFirstName("Jta");
        contact.setLastName("Manager");
        contactService.save(contact);

        System.out.println("Contact saved successfully");
    }
}

的pom.xml:

<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">
    <modelVersion>4.0.0</modelVersion>
    <groupId>foo.bar</groupId>
    <artifactId>SimpleProject26</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SimpleProject26</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>3.2.3.RELEASE</spring.version>
        <aspectj.version>1.7.2</aspectj.version>
    </properties>

    <dependencies>
        <!-- Core Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <!-- Spring Data -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.3.2.RELEASE</version>
        </dependency>

        <!-- Commons Dbcp Driver -->
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <!-- Hibernate -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.2.1.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.0.1.Final</version>
        </dependency>

        <!-- MySql Driver -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.25</version>
        </dependency>

        <!-- JUnit testing framework -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <scope>test</scope>
        </dependency>

        <!-- Logging -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.16</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.2</version>
        </dependency>

        <!-- Javax validation -->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>

        <!-- Joda time for Hibernate 4 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
            <version>2.2</version>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time-hibernate</artifactId>
            <version>1.3</version>
        </dependency>
        <dependency>
            <groupId>org.jadira.usertype</groupId>
            <artifactId>usertype.core</artifactId>
            <version>3.1.0.CR6</version>
        </dependency>

        <!-- Google Guava -->
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>14.0.1</version>
        </dependency>

        <!-- AspectJ Framework -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>${aspectj.version}</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>${aspectj.version}</version>
        </dependency>

        <!-- Atomikos Transaction Framework -->
        <dependency>
            <groupId>com.atomikos</groupId>
            <artifactId>transactions-jdbc</artifactId>
            <version>3.8.0</version>
        </dependency>
        <dependency>
            <groupId>com.atomikos</groupId>
            <artifactId>transactions-hibernate3</artifactId>
            <version>3.8.0</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>SpringApp</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <includes>
                        <include>**/*Tests.java</include>
                    </includes>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

我在控制台上获得的输出如下:

http://pastebin.com/VV8ukbwy

1 个答案:

答案 0 :(得分:1)

在测试代码之后,我在tx-jta-app-context.xml bean的声明中对emfBase配置文件进行了3次修改:

  1. 当您使用JPA时,我按照this page中的说明删除了密钥hibernate.transaction.factory_class
  2. 我删除了com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup类中的$ {...}(可能你在项目中定义了一个变量,但是如果你没有,你应该删除它们)。
  3. 我在jpaProperties中添加了一个属性:<prop key="javax.persistence.transactionType">jta</prop>。 @Jukka在他的评论中告诉你看一个文件,最后,他们说要添加这个属性,它适用于他们。
  4. 经过这些修改,它适用于我(我可以更新2个数据库,如果我在事务期间生成错误,则在两个数据库中正确执行回滚)。我在这里给出了emfBase bean的结果定义:

        <bean id="emfBase" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" abstract="true">
            <property name="jpaVendorAdapter">
                <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
            </property>
            <property name="packagesToScan" value="foo.bar.domain"/>
            <property name="jpaProperties">
                <props>
                    <prop key="hibernate.transaction.manager_lookup_class">
                        com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup
                    </prop>
                    <prop key="hibernate.dialect">
                        org.hibernate.dialect.MySQL5Dialect
                    </prop>
                    <prop key="hibernate.max_fetch_depth">3</prop>
                    <prop key="hibernate.jdbc.fetch_size">50</prop>
                    <prop key="hibernate.jdbc.batch_size">10</prop>
                    <prop key="hibernate.show_sql">true</prop>
                    <prop key="javax.persistence.transactionType">jta</prop>
                </props>
            </property>
        </bean>
    

    我希望这可以解决你的问题。