为什么Spring Data会忽略带有JPA的FetchMode以及它是如何工作的

时间:2017-05-07 21:21:22

标签: json hibernate spring-boot spring-data spring-data-jpa

我在Spring Boot 1.5.3.RELEASE中使用Spring Data和JPA, 我有3个实体声明如下: A类:

@Entity
@Table(name = "A")
public class A implements Serializable {

    @Id
    private String id;
    private String attribute1;
    private String attribute2;
    @Fetch(FetchMode.JOIN)
    @ManyToOne
    @JoinColumn(name = "B_ID")
    private B b;

    //Getters et Setters

B组:

@Entity
@Table(name = "B")
public class B implements Serializable {

    @Id
    private String id;
    @Fetch(FetchMode.JOIN)
    @ManyToOne
    @JoinColumn(name = "C_ID")
    private C c;
    private String attribute1;
    private String attribute2;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "b")
    private List<A> as;
        //Getters et Setters

C类:

@Entity
@Table(name = "C")
public class C implements Serializable {

    @Id
    private String id;
    private String attribute1;
    private String attribute2;
    @OneToMany(fetch = FetchType.LAZY, mappedBy = "c")
    private List<B> bs;

    //Getters and Setters

并添加了我的存储库和服务,如下所示: ARepository

@Repository
public interface ARepository extends JpaRepository<A, String> {
}

AService

@Service
@Transactional
public class AServiceImpl implements AService {

    @Autowired
    private ARepository aRepository;

    @Override
    public List<A> findAll() {
        return aRepository.findAll();
    }
}

AController

@RestController
public class AController {

    @Autowired
    private transient AService aService;

    @RequestMapping("/test")
    public List<A> test() {

        return aService.findAll();
    }

SpringBoot的最后一个类是MyApp

@SpringBootApplication
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = {"fr.dao"})
@EntityScan(basePackages = {"fr.entities"})
@ComponentScan({"fr.dao",
                "fr.service",
                "fr.web"})
public class App {

    public static void main(String[] args) {

        SpringApplication.run(App.class, args);
    }
}

当我执行http://localhost:8080/test时,我希望获取A的所有记录,如果存在B,我想在C中找到B的列表没有初始化(只是代理)。 此外,我希望项目FetchMode中的Join Select而不是A B。 但我得到的是一个select查询(有Join)和Spring Data试图加载C中的所有B个对象, 这个例外:

Hibernate: select a0_.id as id1_0_, a0_.attribute1 as attribute2_0_, a0_.attribute2 as attribute3_0_, a0_.b_id as b_id4_0_ from a a0_
Hibernate: select b0_.id as id1_1_0_, b0_.attribute1 as attribute2_1_0_, b0_.attribute2 as attribute3_1_0_, b0_.c_id as c_id4_1_0_, c1_.id as id1_2_1_, c1_.attribute1 as attribute2_2_1_, c1_.attribute2 as attribute3_2_1_ from b b0_, c c1_ where b0_.c_id=c1_.id(+) and b0_.id=?
Hibernate: select b0_.id as id1_1_0_, b0_.attribute1 as attribute2_1_0_, b0_.attribute2 as attribute3_1_0_, b0_.c_id as c_id4_1_0_, c1_.id as id1_2_1_, c1_.attribute1 as attribute2_2_1_, c1_.attribute2 as attribute3_2_1_ from b b0_, c c1_ where b0_.c_id=c1_.id(+) and b0_.id=?
Hibernate: select b0_.id as id1_1_0_, b0_.attribute1 as attribute2_1_0_, b0_.attribute2 as attribute3_1_0_, b0_.c_id as c_id4_1_0_, c1_.id as id1_2_1_, c1_.attribute1 as attribute2_2_1_, c1_.attribute2 as attribute3_2_1_ from b b0_, c c1_ where b0_.c_id=c1_.id(+) and b0_.id=?
Hibernate: select bs0_.c_id as c_id4_1_0_, bs0_.id as id1_1_0_, bs0_.id as id1_1_1_, bs0_.attribute1 as attribute2_1_1_, bs0_.attribute2 as attribute3_1_1_, bs0_.c_id as c_id4_1_1_ from b bs0_ where bs0_.c_id=?

2017-05-07 22:13:01.347 ERROR 8476 --- [io-8090-exec-10] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON document: Infinite recursion (StackOverflowError) (through reference chain: fr.entities.B["c"]->fr.entities.C["bs"]->org.hibernate.collection.internal.PersistentBag[0]->....->fr.entities.B["c"])] with root cause

java.lang.StackOverflowError: null
    at java.lang.ClassLoader.defineClass1(Native Method) ~[na:1.8.0_111]
    at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ~[na:1.8.0_111]
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) ~[na:1.8.0_111]
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:467) ~[na:1.8.0_111]
    at java.net.URLClassLoader.access$100(URLClassLoader.java:73) ~[na:1.8.0_111]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:368) ~[na:1.8.0_111]
    at java.net.URLClassLoader$1.run(URLClassLoader.java:362) ~[na:1.8.0_111]
    at java.security.AccessController.doPrivileged(Native Method) ~[na:1.8.0_111]

有谁知道如何更改配置以获得我想要的内容?

0 个答案:

没有答案