Bidirectional OneToOne association lazy loading support

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhyhang/article/details/53638182

Project environment:

Spring 3.4.3
Spring Data JPA 1.10.4
Hibernate 5.2.5
JPA2.1

Problem

  • OneToOne properties not lazy loading, although specifying fetch=LAZY
  • OneToOne properties can lazy loading, specifying fetch=LAZY, optional=false, but save new entity error

Define Entity Phone and PhoneDetails, they are have bidirectional OneToOne associations.

    @Entity(name = "Phone")
    public class Phone {

        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;

        @Column(name = "number")
        private String number;

        @OneToOne(mappedBy = "phone", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
        @PrimaryKeyJoinColumn
        private PhoneDetails details;

        public Phone() {
        }

        public Long getId() {
        return id;
        }

        public String getNumber() {
        return number;
        }

        public PhoneDetails getDetails() {
        return details;
        }

        public void setDetails(PhoneDetails details) {
        this.details = details;
        }

    }
    @Entity
    public class PhoneDetails {

        @Id
        private Long id;

        private String provider;

        private String technology;

        @OneToOne(fetch = FetchType.LAZY)
        @MapsId
        @JoinColumn(name = "id")
        private Phone phone;

        public PhoneDetails() {
        }

        public String getProvider() {
            return provider;
        }

        public String getTechnology() {
            return technology;
        }

        public void setTechnology(String technology) {
            this.technology = technology;
        }

        public Phone getPhone() {
            return phone;
        }

        public void setPhone(Phone phone) {
            this.phone = phone;
        }
    }

Save a new phone with new details:

    Phone phone = new Phone();
    PhoneDetails details = new PhoneDetails();
    phone.setDetails(details);
    details.setPhone(phone);
    phoneDao.save(phone);
  • When setting association specifying “optional=true” (i.e. default value), above codes work OK. But phone’s details property can not lazy loading, although specify “fetch = FetchType.LAZY”. Other associations (e.g. ManyToOne, ManyToMany, OneToMany) lazy load normally.
  • Runing above codes specifying “optional=false” in two entities, will throw exception like following:
org.springframework.orm.jpa.JpaSystemException: null id generated for:class PhoneDetails; nested exception is org.hibernate.id.IdentifierGenerationException: null id generated for:class PhoneDetails

Solution(for me using solution 3):

1.using hibernate bytecode enhance build time

  • toOne(OneToOne, ManyToOne) properties annotation with (no_proxy, lazy,optional=true)
  • no need to change save codes.
  • need to setting build time hibernate enhance plugin
    for maven:
                <build>
                    <plugins>
                    [...]
                    <plugin>
                        <groupId>org.hibernate.orm.tooling</groupId>
                        <artifactId>hibernate-enhance-maven-plugin</artifactId>
                        <version>${hibernateVersion}</version>
                        <executions>
                        <execution>
                            <configuration>
                            <failOnError>true</failOnError>
                            <enableLazyInitialization>true</enableLazyInitialization>
                            <enableDirtyTracking>false</enableDirtyTracking>
                            < >false</enableAssociationManagement>
                            </configuration>
                            <goals>
                            <goal>enhance</goal>
                            </goals>
                        </execution>
                        </executions>
                    </plugin>
                    [...]
                    </plugins>
                </build>

if eclipse reporting error, add settings:

                <pluginManagement>
                    <plugins>
                        [...]
                        <plugin>
                            <groupId>org.eclipse.m2e</groupId>
                            <artifactId>lifecycle-mapping</artifactId>
                            <version>1.0.0</version>
                            <configuration>
                                <lifecycleMappingMetadata>
                                    <pluginExecutions>
                                        <pluginExecution>
                                            <pluginExecutionFilter>
                                                <groupId>org.hibernate.orm.tooling</groupId>
                                                <artifactId>hibernate-enhance-maven-plugin</artifactId>
                                                <versionRange>[1.0.0,)</versionRange>
                                                <goals>
                                                    <goal>enhance</goal>
                                                </goals>
                                            </pluginExecutionFilter>
                                            <action>
                                                <execute />
                                            </action>
                                        </pluginExecution>                          
                                </lifecycleMappingMetadata>
                            </configuration>
                        </plugin>
                        [...]
                    </plugins>
                </pluginManagement>

notice:

  • get one lazy property will trigger all lazy properties loading, because they are in one lazy group.
  • ManyToMany propertis possiblly not loading(v5.25), save the entity caused to lose the association.
  • enableDirtyTracking and enableAssociationManagement existing some issues in version 5.25?

2.using jpa bytecode enhance run time

reference hibernate document, in my test, not success.

3.split two steps for saving entity:

  • save parent entity(phone) first,
  • save child entity(phoneDetails) secondly.
            Phone phone = new Phone();
            PhoneDetails details = new PhoneDetails();
            phoneDao.save(phone);
            phone.setDetails(details);
            details.setPhone(phone);
            detailDao.save(details);    

above codes work normally.

Conclution

From my test, hibernate bytecode enhance build time and runing time possiblly have certain issues, run time more servere, please care to use. Futhermore, bytecode enhance must add Hibernate Annotations in your domain entities, not JPA specification. Good news is we can avoid to use bytecode enhance, like solution 3, meanwhile eliminate Hibernate Annations and enhance plugin setting.

阅读更多
换一批

没有更多推荐了,返回首页