JPA object references an unsaved transient instance - save the transient instance before flushing

nested exception is org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : top.lingkang.jpademo.entity.UserRole.role -> top.lingkang.jpademo.entity.Role; nested exception is java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : top.lingkang.jpademo.entity.UserRole.role -> top.lingkang.jpademo.entity.Role] with root cause

当你用jpa或者hibernate进行save时,报以上错误说明你对关联对象进行了修改或者这个管理对象不存在于表中。
例如下面的

/**
 * @author lingkang
 * Created by 2022/7/13
 */
@Data
@Entity
@Table(name = "j_user_role")
public class UserRole {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)//主键递增策略
    private Integer id;

    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne
    @JoinColumn(name = "role")
    private Role role;

    @Column
    private String remark;
}

你想直接save一个对象:

    @Transactional
    @GetMapping("add")
    public Object add(){
        UserRole userRole=new UserRole();
        Role role=new Role();
        role.setRole("user");// 随意搞个角色
        role.setDescription("普通用户");
        userRole.setRole(role);
        userRoleRepository.save(userRole);
        return userRole;
    }

就会报以上错误,因为关联关系的值在数据库中不能为空,这里的role角色表少了user这角色导致的。你应该先新增一个角色,否则关联关系不成立。hibernate是一个强关联的ORM,于是改成下面这样就成功了:

    @Transactional
    @GetMapping("add")
    public Object add(){
        UserRole userRole=new UserRole();
        Role role=new Role();
        role.setRole("user");// 随意搞个角色
        role.setDescription("普通用户");
        roleRepository.save(role);// 先保存
        userRole.setRole(role);
        userRoleRepository.save(userRole);
        return userRole;
    }

使用hibernate的关联关系时,尤其要注意关联的对象一定要存在于数据库。

当关联对象不存在,你自己new一个时,他会将你的new的对象持久化

    @Transactional
    @GetMapping("add2")
    public Object add2(){
        List<UserRole> all = userRoleRepository.findAll();
        for (UserRole role:all){
            if (role.getUser()==null){// 关联对象不存在时,他会将你的new的对象持久化
                User user=new User();
                user.setUsername("999999999999999999999999");
                role.setUser(user);
                userRoleRepository.save(role);
            }
        }
        return all;
    }

查看用户表你会发现多了个数据
在这里插入图片描述
所以理清多对多关系比较重要,现在的数据库设计一般都是非强关联的,甚至连个外键都没有。一用hibernate深似海,从此强行联系在一起。

hibernate性能比不上mybatis,多一步查询关联关系(可能会全表扫描),特别是数据极多的时候(一百万以上),性能成吨下降。

posted @ 2022-09-16 00:08  凌康  阅读(295)  评论(0编辑  收藏  举报