[
https://issues.apache.org/jira/browse/OPENJPA-444?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12710871#action_12710871
]
Craig Russell commented on OPENJPA-444:
---------------------------------------
I found that the "before image" was being created prior to populating data from
the datastore, so it always appears that the data changed.
There's no way for a StoreManager to create a new state image because the
method is protected.
I haven't looked at it any more since I decided to use build enhancement but
thought that this information might be useful to whoever looks at the issue.
> Unnecessary updates during flush operation.
> -------------------------------------------
>
> Key: OPENJPA-444
> URL: https://issues.apache.org/jira/browse/OPENJPA-444
> Project: OpenJPA
> Issue Type: Bug
> Components: kernel, UnenhancedClasses
> Affects Versions: 1.0.1
> Environment: OpenJPA without field tracking. (JDK 5.0 )
> Reporter: Sławomir Wojtasiak
> Attachments: updatebug.zip
>
>
> OpenJPA performs unnecessary updates during flush operation. For example:
> When we are trying to persist versioned entity with collection of other
> entities:
> |Article|1-------------*|Quantity| ( Relation owner. )
> ************ CODE *************
> EntityManagerFactory factory = Persistence.createEntityManagerFactory(
> "testjpa", System.getProperties() );
> EntityManager em = factory.createEntityManager();
> em.getTransaction().begin();
> Article a = new Article();
> a.setName( "atricle" );
>
> Quantity q = new Quantity();
> q.setName( "quantity" );
> q.setArticle( a );
>
> a.getQuantities().add( q );
>
> em.persist( a );
> em.flush();
> em.flush();
> ************* END OF CODE ************
> Following queries are generated after first flush operation:
> SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE
> [params=(int) 0]
> UPDATE OPENJPA_SEQUENCE_TABLE SET SEQUENCE_VALUE = ? WHERE ID = ? AND
> SEQUENCE_VALUE = ? [params=(long) 2651, (int) 0, (long) 2601]
> SELECT SEQUENCE_VALUE FROM OPENJPA_SEQUENCE_TABLE WHERE ID = ? FOR UPDATE
> [params=(int) 0]
> UPDATE OPENJPA_SEQUENCE_TABLE SET SEQUENCE_VALUE = ? WHERE ID = ? AND
> SEQUENCE_VALUE = ? [params=(long) 2701, (int) 0, (long) 2651]
> INSERT INTO Article (id, name, version) VALUES (?, ?, ?) [params=(long) 2601,
> (String) atricle, (int) 1]
> INSERT INTO Quantity (id, name, version, article_id) VALUES (?, ?, ?, ?)
> [params=(long) 2651, (String) quantity, (int) 1, (long) 2601]
> Everything looks ok but after next flush we will get version update:
> UPDATE Article SET version = ? WHERE id = ? AND version = ? [params=(int) 2,
> (long) 2601, (int) 1]
> I am not completely sure that this analysis is correct, but I hope it helps
> anyway:
> During persist operation SaveFieldManager sets collection of quantities as
> unloaded and unsaved field (Because this field is mutable). During next
> flush, StateManager checks which fields are dirty by comparing its values to
> those stored by SaveFieldManager. Method dirtyCheck() of the StateManager is
> responsible for that. (It's necessary taking into consideration fact that I
> do not use OpenJPA enhancer with JDK 5.0). SaveFieldManager always returns
> false from its isFieldEqual() method because this collection (Collection of
> quantities) is treated as unsaved ( Comment from OpenJPA code: if the field
> is not available, assume that it has changed) so StateManager sets it as
> dirty and clears its flush bit. Then AbstractUpdateManager try to add
> UPDATE_ACTION for this dirty collection, but with no effect because this
> field is not set as updatable and insertable ( I think so. ). In next step
> AbstractUpdateManager adds UPDATE_ACTION for version field because
> StateManager is marked as dirty. It causes unnecessary update of entity
> version field because nothing changed in the database.
> I didn't check how it works with field tracking.
> ******************** EXAMPLE ENTITIES ******************
> @Entity
> public class Article {
> private long id;
> private long version;
> private String name;
> private Set<Quantity> quantities = new HashSet<Quantity>();
> @Id
> @GeneratedValue( strategy = GenerationType.SEQUENCE )
> public long getId() {
> return id;
> }
> public void setId( long id ) {
> this.id = id;
> }
> @Version
> public long getVersion() {
> return version;
> }
> public void setVersion( long version ) {
> this.version = version;
> }
> @Basic
> public String getName() {
> return name;
> }
> public void setName( String name ) {
> this.name = name;
> }
> @OneToMany( mappedBy = "article", cascade = { CascadeType.MERGE,
> CascadeType.PERSIST }, fetch = FetchType.LAZY )
> public Set<Quantity> getQuantities() {
> return quantities;
> }
> public void setQuantities( Set<Quantity> quantities ) {
> this.quantities = quantities;
> }
> }
> @Entity
> public class Quantity {
> private long id;
> private long version;
> private String name;
> private Article article;
> @Id
> @GeneratedValue( strategy = GenerationType.SEQUENCE )
> public long getId() {
> return id;
> }
> public void setId( long id ) {
> this.id = id;
> }
> @Version
> public long getVersion() {
> return version;
> }
> public void setVersion( long version ) {
> this.version = version;
> }
> @Basic
> public String getName() {
> return name;
> }
> public void setName( String name ) {
> this.name = name;
> }
> @ManyToOne( optional = false, cascade = { CascadeType.PERSIST,
> CascadeType.MERGE }, fetch = FetchType.LAZY )
> public Article getArticle() {
> return article;
> }
> public void setArticle( Article article ) {
> this.article = article;
> }
> }
--
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.