Object is not saved in mysql schema by Hibernate 4 (Jpa 2.0 + Jta using Atomikos transaction manager)

梦想与她 提交于 2019-12-24 02:24:16

问题


I am reading the book Pro Spring 3 and in the chapter about Global Transactions there is some example code for persisting an object into two different mysql schemas. I am running the code but the object is not saved in any of the two schemas. Here is the code.

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.
    }
}

foo/bar/domain/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;
    }
}

foo/bar/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>

The output I get on my console is the following:

http://pastebin.com/VV8ukbwy


回答1:


After testing your code, I made 3 modifications, all them in the tx-jta-app-context.xml configuration file, in the declaration of the emfBase bean:

  1. I removed the key hibernate.transaction.factory_class, as explained in this page, when you work with JPA.
  2. I removed the ${...} around the class com.atomikos.icatch.jta.hibernate3.TransactionManagerLookup (maybe you have a variable defined in your project, but if you haven't, you should remove them).
  3. I added a property to the jpaProperties: <prop key="javax.persistence.transactionType">jta</prop>. @Jukka told you in his comment to have a look at a document, and at the end, they say to add this property and it works for them.

After these modifications, it works for me (I can update the 2 databases and if I generate an error during the transaction, rollback is correctly executed in both databases). I give you here the resulting definition of the 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>

I hope this can solve your problem.



来源:https://stackoverflow.com/questions/17073281/object-is-not-saved-in-mysql-schema-by-hibernate-4-jpa-2-0-jta-using-atomikos

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!