Spring数据,JPA,Hibernate - 双向关系无限递归

时间:2016-06-07 15:04:59

标签: java spring hibernate spring-data-jpa

由于无限递归,我遇到StackOverflowError问题。 我的配置:

applicatinContext.xml(part)

<bean id="entityManagerFactory"
      class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" lazy-init="true"
    p:persistenceProviderClass="org.hibernate.jpa.HibernatePersistenceProvider"
    p:persistenceXmlLocation="classpath:persistence.xml"
    p:persistenceUnitName="hibernate-persistent"
    p:packagesToScan="pl.roszkow.webpage.entities"/>

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

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<jpa:repositories base-package="pl.roszkow.webpage.repositories"/>
<tx:annotation-driven transaction-manager="transactionManager"/>

persistance.xml

<persistence-unit name="hibernate-persistent" transaction-type="RESOURCE_LOCAL">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <properties>
        <property name="hibernate.ejb.cfgfile" value="classpath:hibernate.cfg.xml"/>
    </properties>
</persistence-unit>

的hibernate.cfg.xml

<hibernate-configuration>
<session-factory>
    <property name="hibernate.connection.driver_class">org.sqlite.JDBC</property>
    <property name="hibernate.connection.url">jdbc:sqlite::resource:roszkow.db</property>
    <property name="hibernate.connection.username"/>
    <property name="hibernate.connection.password"/>

    <!-- SQL -->
    <property name="hibernate.dialect">pl.roszkow.webpage.utils.SQLiteDialect</property>
    <property name="hibernate.hbm2ddl.auto">update</property>
    <property name="hibernate.show_sql">true</property>
    <property name="hibernate.format_sql">true</property>

    <!-- C3P0 -->
    <property name="hibernate.c3p0.acquire_increment">2</property>
    <property name="hibernate.c3p0.max_size">10</property>
    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.timeout">180</property>
    <property name="hibernate.c3p0.idle_test_period">100</property>
</session-factory>
</hibernate-configuration>

的web.xml

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:/applicationContext.xml
        classpath:/securityContext.xml
    </param-value>
</context-param>

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/securityContext.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
    <init-param>
        <param-name>entityManagerFactoryBeanName</param-name>
        <param-value>entityManagerFactory</param-value>
    </init-param>
    <init-param>
        <param-name>flushMode</param-name>
        <param-value>AUTO</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>SpringOpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

现在是我的实体,User.java

@Entity
@Table(name = "users")
public class User implements UserDetails, Serializable {
    private static final long serialVersionUID = -3170642319755386686L;

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

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false)
    private String password;

    @Column(name = "first_name", nullable = false)
    private String firstName;

    @Column(name = "last_name", nullable = false)
    private String lastName;

    @Column(name = "birth_date", nullable = false)
    private Timestamp birthDate;

    private Boolean enabled = false;

    private String role = "ROLE_USER";

    @OneToMany(mappedBy = "author")
    private List<Article> articles;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority(this.role));
        return authorities;
    }

    @Override
    public String getUsername() {
        return this.email;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return this.enabled;
    }
}

和Article.java

@Entity
@Table(name = "articles")
public class Article implements Serializable {
    private static final long serialVersionUID = -6523854154438579850L;

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

    @NotBlank(message = "{article.title.notBlank}")
    @Column(nullable = false)
    private String title;

    @NotBlank(message = "{article.content.notBlank}")
    @Column(nullable = false)
    private String content;

    @Column(name = "add_date", nullable = false)
    private Timestamp addDate;

    @ManyToOne
    @JoinColumn(name = "author_id", nullable = false)
    private User author;

    /*@OneToMany(mappedBy = "article")
    private List<Image> images;*/
}

存储库,UsersRepo.java

@Repository
public interface UsersRepository extends CrudRepository<User, Long> {

List<User> findAll();

User findOne(Long id);

User findByEmail(String email);

User save(User user);
}

ArticlesRepo.java

@Repository
public interface ArticlesRepository extends CrudRepository<Article, Long> {

@Query("select a from Article a order by a.addDate desc")
List<Article> findAll();

Article findOne(Long id);

Article save(Article article);

void delete(Long id);
}

当应用尝试在用户实体中加载文章集合时发生错误。但是随着延迟加载,这个集合根本不会被加载。从课堂上删除集合时,一切正常。

有人能说我的应用程序出了什么问题吗?我认为延迟加载不能正常工作。

早些时候我也遇到过LazyInitializationException问题,但是通过将SpringOpenEntityManagerInViewFilter添加到web.xml来解决它。

堆栈跟踪

java.lang.StackOverflowError
java.lang.Long.stringSize(Long.java:306)
java.lang.Long.toString(Long.java:242)
java.lang.Long.toString(Long.java:100)
java.lang.String.valueOf(String.java:2945)
java.lang.Long.toString(Long.java:740)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.Article.toString(Article.java:30)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractCollection.toString(AbstractCollection.java:422)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.User.toString(User.java:35)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.Article.toString(Article.java:30)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractCollection.toString(AbstractCollection.java:422)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.User.toString(User.java:35)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.Article.toString(Article.java:30)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractCollection.toString(AbstractCollection.java:422)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.User.toString(User.java:35)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.Article.toString(Article.java:30)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractCollection.toString(AbstractCollection.java:422)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.User.toString(User.java:35)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
pl.roszkow.webpage.entities.Article.toString(Article.java:30)
java.lang.String.valueOf(String.java:2826)
java.lang.StringBuilder.append(StringBuilder.java:115)
java.util.AbstractCollection.toString(AbstractCollection.java:422)
org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:510)
java.lang.String.valueOf(String.java:2826)

2 个答案:

答案 0 :(得分:0)

试试这个:添加@JsonBackReference

@JsonBackReference
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private User author;

修改

尝试

@JsonManagedReference
  @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "author_id", nullable = false)
    private User author;

答案 1 :(得分:0)

试试这个:

@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Table(name = "users")
public class User implements UserDetails, Serializable {
    private static final long serialVersionUID = -6523854154438579850L;

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

@Entity
@JsonIdentityInfo(generator = ObjectIdGenerators.PropertyGenerator.class, property = "id")
@Table(name = "articles")
public class Article implements Serializable {
    private static final long serialVersionUID = -6523854154438579850L;

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