You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@openjpa.apache.org by Cheng Zhang <ch...@yahoo-inc.com> on 2010/03/04 23:59:58 UTC

any spring user here? RE: unexpected update when using many to many relationship

It seems that there is nothing to do with many-to-many relation. I now believe that it's a Spring issue. Could anybody here who is also using Spring please help me out? 

Here is my usage of Spring + OpenJPA.

1. Subject.java
-------------------------------------------------------
package test;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name = "MC_SUBJECT")
public class Subject {
    @Id
    @Column(length=64)
    private String id;

    @Column(length=64)
    private String title;

    public Subject() {
        super();
    }

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

    public String getId() {
        return id;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }
}


2. SubjectComponent.java
-------------------------------------------------------
package test;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class SubjectComponent {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional(readOnly=false, rollbackFor=Exception.class)
    public void create(Subject subject) {
        entityManager.persist(subject);
    }

    @Transactional(readOnly=true)
    public Subject read(String id) {
        Subject sub = entityManager.find(Subject.class, id);
        return sub;
    }
}


3. persistence.xml
-------------------------------------------------------
<?xml version="1.0" encoding="utf-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
    <persistence-unit name="MetadataBrowserPersistenceUnit" transaction-type="RESOURCE_LOCAL">
        <provider>
            org.apache.openjpa.persistence.PersistenceProviderImpl
		</provider>
        <class>test.Subject</class>
    </persistence-unit>
</persistence>


4. applicationContext.xml
-------------------------------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<!--
	Application context definition for PetClinic on JPA.
-->
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
	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/jee http://www.springframework.org/schema/jee/spring-jee.xsd
	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

	<context:property-placeholder location="classpath:jdbc.properties"/>

	<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
		p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.url}" p:username="${jdbc.username}"
		p:password="${jdbc.password}"/>

	<bean id="persistenceUnitManager" class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
		<property name="persistenceXmlLocations">
			<list>
				<value>classpath:META-INF/persistence.xml</value>
			</list>
		</property>
		<property name="defaultDataSource" ref="dataSource"/>
	</bean>

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
		<property name="persistenceUnitManager" ref="persistenceUnitManager"/>
		<property name="jpaVendorAdapter">
			<bean class="org.springframework.orm.jpa.vendor.OpenJpaVendorAdapter"
				p:database="${jpa.database}" p:showSql="${jpa.showSql}" p:generateDdl="true"/>
		</property>
	</bean>

	<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
		<property name="entityManagerFactory" ref="entityManagerFactory" />
	</bean>

	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
		p:entityManagerFactory-ref="entityManagerFactory"/>


	<context:annotation-config/>

	<tx:annotation-driven transaction-manager="transactionManager" />
	
	<context:component-scan base-package="test"/>

</beans>


5. jdbc.properties
--------------------------------------------------------------------
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:mem:test-db
jdbc.username=sa
jdbc.password=
jpa.database=HSQL
jpa.showSql=true


6. Test.java
------------------------------------------------------------------
import org.springframework.context.support.ClassPathXmlApplicationContext;

import test.Subject;
import test.SubjectComponent;

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext springContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        SubjectComponent component = springContext.getBean(SubjectComponent.class);

        Subject subject = new Subject();
        subject.setId("a subject");
        component.create(subject);

        System.out.println("======================");
        Subject read = component.read(subject.getId());
        System.out.println(read.getId());
    }
}


And here is the log:

...................
org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean createNativeEntityManagerFactory
INFO: Building JPA container EntityManagerFactory for persistence unit 'MetadataBrowserPersistenceUnit'
31  MetadataBrowserPersistenceUnit  WARN   [main] openjpa.Runtime - An error occurred while registering a ClassTransformer with PersistenceUnitInfo: name 'MetadataBrowserPersistenceUnit', root URL [file:/C:/Documents%20and%20Settings/chzhang/allnew/m2m/target/classes/]. The error has been consumed. To see it, set your openjpa.Runtime log level to TRACE. Load-time class transformation will not be available.
313  MetadataBrowserPersistenceUnit  INFO   [main] openjpa.Runtime - Starting OpenJPA 1.2.2
953  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> executing prepstmnt 2554341 SELECT SEQUENCE_SCHEMA, SEQUENCE_NAME FROM INFORMATION_SCHEMA.SYSTEM_SEQUENCES
984  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> [31 ms] spent
984  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> executing stmnt 4618641 CREATE TABLE MC_SUBJECT (id VARCHAR(64) NOT NULL, title VARCHAR(64), PRIMARY KEY (id))
984  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> [0 ms] spent
1250  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> executing prepstmnt 27532487 INSERT INTO MC_SUBJECT (id, title) VALUES (?, ?) [params=(String) a subject, (null) null]
1250  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> [0 ms] spent
======================
1297  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> executing prepstmnt 11400638 SELECT t0.title FROM MC_SUBJECT t0 WHERE t0.id = ? [params=(String) a subject]
1297  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> [0 ms] spent
1297  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> executing prepstmnt 654830 UPDATE MC_SUBJECT SET title = ? WHERE id = ? [params=(null) null, (String) a subject]
1297  MetadataBrowserPersistenceUnit  TRACE  [main] openjpa.jdbc.SQL - <t 14706435, conn 9116239> [0 ms] spent
a subject


Very weird!

Cheng








> -----Original Message-----
> From: Cheng Zhang
> Sent: Thursday, March 04, 2010 11:09 AM 无住生什么心?
> To: 'users@openjpa.apache.org'
> Subject: RE: unexpected update when using many to many relationship
> 
> Hi Ravi,
> 
> Yes, calling getters on Subject within a transaction results in update
> statements. The update is on MC_SUBJECT.
> 
> I'm using Spring Transaction for the transaction management.
> 
> I will try to consolidate some of my code so you can have a full picture
> how openjpa is used in this project.
> 
> Thanks,
> Cheng
> 
> 
> > -----Original Message-----
> > From: Ravi Palacherla [mailto:ravi.palacherla@oracle.com]
> > Sent: Thursday, March 04, 2010 10:02 AM 无住生什么心?
> > To: users@openjpa.apache.org
> > Subject: RE: unexpected update when using many to many relationship
> >
> > Hi Cheng,
> >
> > >> I just read some Subject records
> > Do you mean calling getters on Subject with in a transaction, results in
> > update statement ?
> > I do not think it is an expected behavior.
> >
> > Is the update statement on "MC_SUBJECT" table ?
> > I understand from the code snippet you pasted; that it a self-
> referential
> > many2many relationship between subject and subject, correct ?
> > I think pasting the code snippet that reads subject records ( actually
> all
> > the code that is called inside the transaction) will help.
> >
> > Also what type of persistence context are you using, extended or
> > transaction ?
> >
> > Regards,
> > Ravi.
> >
> > -----Original Message-----
> > From: Cheng Zhang [mailto:chzhang@yahoo-inc.com]
> > Sent: Thursday, March 04, 2010 10:38 AM
> > To: users@openjpa.apache.org
> > Subject: unexpected update when using many to many relationship
> >
> > Hi,
> >
> >
> >
> > I found that, if I use many-to-many relationship, there will be
> > unexpected update when the transaction is closed.
> >
> >
> >
> > Here is my code,
> >
> >
> >
> > @Entity
> >
> > @Table(name = "MC_SUBJECT")
> >
> > public class Subject implements Serializable {
> >
> >     @Id
> >
> >     @Column(length=64)
> >
> >     private String id;
> >
> >
> >
> >     @Column
> >
> >     private Date createdDate;
> >
> >
> >
> >     @Column
> >
> >     private String createdBy;
> >
> >
> >
> >     @Column(length=128, nullable=false)
> >
> >     private String title;
> >
> >
> >
> >     @Column(length=128, nullable=false)
> >
> >     private String subjectType;
> >
> >
> >
> >     @Column(length=2048)
> >
> >     private String description;
> >
> >
> >
> >     @Column
> >
> >     private Date modifiedDate;
> >
> >
> >
> >     @Column
> >
> >     private String modifiedBy;
> >
> >
> >
> >     @ManyToMany(fetch=FetchType.LAZY)
> >
> >     @JoinTable(name = "MC_CHILD_SUBJECT", joinColumns = {
> > @JoinColumn(name = "SUBJECT_KEY") }, inverseJoinColumns = {
> > @JoinColumn(name = "CHILD_SUBJECT_KEY") })
> >
> >     private List<Subject> childSubjectCollection;
> >
> >
> >
> > ...... getters and setters
> >
> > }
> >
> >
> >
> > In my code, I just read some Subject records. In the log file, I can see
> > some update statement.
> >
> >
> >
> > However, if I change the many-to-many to one-to-many, everything is fine
> > and no update.
> >
> >
> >
> > Is it expected behavior?
> >
> >
> >
> > Thanks,
> >
> >
> >
> > Cheng
> >
> >
> >
> >