java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

javax.persistence笔记

最近在做一个项目,刚开始设计数据库的时候,遇到“一对多”和“多对一”以及“多对多”的情况,手头书上没有详细介绍,于是上网找了很多资料,虽然不是很系统的介绍,但也懂了一些。

当我调试两个类的时候,关系是一对多:

Created with Raphaël 2.1.0 实例表 RoleType权限表 RoleType权限表 Admin管理员表 Admin管理员表 OneToMany ManyToOne
**RoleType类**
@OneToMany(cascade = {CascadeType.ALL},fetch = FetchType.EAGER)//CascadeType.ALL表示RoleType在所有情况下都级联
    @JoinColumn(name = "roleID", referencedColumnName = "roleId")
    private Set<Admin> adminList;

**Admin类**
 @ManyToOne(cascade = {CascadeType.MERGE,CascadeType.PERSIST},fetch = FetchType.EAGER)//Admin在更新和保存的时候级联
    @JoinColumn(name = "roleID", referencedColumnName = "roleId")
    private RoleType roleType;

当我使用测试Controller:

@RestController
public class TestController {

    @Autowired
    AdminRepository adminRepository;
    @Autowired
    RoleRepository roleRepository;

    @RequestMapping("/saveAdmin")
    public Admin saveAdmin() {
        RoleType r1 = new RoleType((short) 2,"ROLE_INNER", new HashSet<>());
        Admin a1 = new Admin(111L,"inner", "123456", "计算机学院", r1);
        r1.getAdminList().add(a1);
        return adminRepository.save(a1);
    }
}

可见,我在Admin中添加了一个角色类型RoleType;
又在RoleType集合中添加了此Admin管理员对象。

访问链接后:

报了如下错误:

Hibernate: select roletype0_.role_id as role_id1_3_0_, roletype0_.name as name2_3_0_, adminlist1_.roleid as roleid5_0_1_, adminlist1_.admin_id as admin_id1_0_1_, adminlist1_.admin_id as admin_id1_0_2_, adminlist1_.college as college2_0_2_, adminlist1_.password as password3_0_2_, adminlist1_.roleid as roleid5_0_2_, adminlist1_.user_name as user_nam4_0_2_ from role_type roletype0_ left outer join admin adminlist1_ on roletype0_.role_id=adminlist1_.roleid where roletype0_.role_id=?
2016-08-10 12:02:50.006  WARN 6576 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Infinite recursion (StackOverflowError) (through reference chain: com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]->com.scut.cs.domain.RoleType["adminList"]->org.hibernate.collection.internal.PersistentSet[0]->com.scut.cs.domain.Admin["roleType"]-
***此处省略许多许多的重复错误信息***
2016-08-10 12:02:50.010  WARN 6576 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Handling of [org.springframework.http.converter.HttpMessageNotWritableException] resulted in Exception

java.lang.IllegalStateException: Cannot call sendError() after the response has been committed

java.lang.StackOverflowError: null

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: getOutputStream() has already been called for this response

浏览器没有任何的输出
查看数据库,已经添加了相应的表项。
AdminTable:

admin_idcollegepassworduser_nameroleid
111计算机学院123456inner2

RoleTypeTable:

role_idname
2ROLE_INNER

RoleTypeAdminTable:

role_type_role_idadmin_list_admin_id
2111

1. 现在情况是:RoleTypeAdminTable里记录着每一个RoleType和Admin的对应关系,而AdminTable里又有外键roleid指向RoleTypeTable,所以会造成查询某一个admin或者roletype的时候陷入两者无限嵌套查询。
2. 我第一个想到的解决方法是:将两个注解@ManyToOne 和@OneToMany,前者改为fetch=FetchType.EAGER,后者改为fetch=FetchType.LAZY。个人理解为前者快加载,查询的时候,在此例会把One一起查询。而慢加载,查询的时候,在此例不会去Many一方的Set集合查询。可是结果报一样的错
3. 于是继续查资料:API-OneToManyAPI-ManyToOne
4. 看到在OneToMany一端不需要@JoinColumn一行。在ManyToOne一端有就可以了。另外:name = “roleID”为Many端表中外键名称roleID,referencedColumnName = “roleId”为One端表中的主键名称roleId。
5. 现在添加两个测试数据:
AdminTable:

admin_idcollegepassworduser_nameroleid
110计算机学院123456admin1
111计算机学院123456inner2
112计算机学院123456outer3

RoleTypeTable:

role_idname
1ROLE_ADMIN
2ROLE_INNER
3ROLE_OUTER

RoleTypeAdminTable:

role_type_role_idadmin_list_admin_id
1110
2111
3112

6. 稍微做一个调整:将AdminTable中的admin_id=110的role_id改为null;将RoleTypeAdminTable中的第三条数据删去;
AdminTable:

admin_idcollegepassworduser_nameroleid
110计算机学院123456adminnull
111计算机学院123456inner2
112计算机学院123456outer3

RoleTypeTable:

role_idname
1ROLE_ADMIN
2ROLE_INNER
3ROLE_OUTER

RoleTypeAdminTable:

role_type_role_idadmin_list_admin_id
1110
2111

7. 现在形成控制变量对照组:admin_id=110和112的数据查询成功;

{
"id": 110,
"userName": "admin",
"password": "123456",
"college": "计算机学院",
"roleType": null
}
{
"id": 112,
"userName": "outer",
"password": "123456",
"college": "计算机学院",
"roleType": {
"id": 3,
"name": "ROLE_OUTER",
"adminList": []
}
}

role_id=1和3的数据查询成功:

{
"id": 1,
"name": "ROLE_ADMIN",
"adminList": [
{
"id": 110,
"userName": "admin",
"password": "123456",
"college": "计算机学院",
"roleType": null
}
]
}
{
"id": 3,
"name": "ROLE_OUTER",
"adminList": []
}

8.. 好了现在总结一下:
1) 在@OneToMany一方设置好cascade和fetch后,在@ManyToOne一方除了设置好cascade和fetch,还要设置@JoinColumn;
2) 存对象数据的时候,只用添加一方的数据即可,比如:

@RequestMapping("/saveRole")
    public RoleType saveAdmin() {
        RoleType r1 = new RoleType((short) 4,"ROLE_OUTER", new HashSet<>());
        Admin a1 = new Admin(113L,"outer", "123456", "计算机学院", null);
        r1.getAdminList().add(a1);//只把admin对象添加进RoleType集合中,不在admin对象中添加roletype对象;如上面例子的admin_id=110
        return roleRepository.save(r1);
    }
    @RequestMapping("/saveAdmin")
    public Admin saveRole() {
        RoleType r1 = new RoleType((short) 5,"ROLE_OUTER", new HashSet<>());
        Admin a1 = new Admin(114L,"outer", "123456", "计算机学院", r1);//只把roletype对象添加进admin对象中,不在roletype集合中添加这个admin对象;如上面例子的admin_id=112
        return adminRepository.save(a1);
    }

两种情况按实际需求自己选择!!
按照我这个项目要求,会选择第二种。

本人刚开始学Spring MVC和Spring Boot,有错误烦请赐教~


2016.8.11.日更新:
今天用manyTomany处理另外两个表的时候,按照此博客
将两个表都设置为主控方,但是发现又出现上述的陷入循环取对象中,出错。后来把一方的@JoinTable(…)去掉,只保留主控方的@JoinTable(…),这样就解决了!!由于项目需要,把两边都设置成Eager。


再更新
ManyToMany 的循环嵌套误解:是由于json的序列化漏洞
所以上面8.11.的更新不用去掉一方的@JoinTable,同时要将name设成一样,这样就不会创建两个关联表了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值