【问题标题】:CrudRepository.save() appears to cascadeCrudRepository.save() 似乎级联
【发布时间】:2020-06-25 18:50:34
【问题描述】:

实体调查:

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

        private Long id;
        private String name;
        private String address;
        private List<Question> questions;

        @Id
        @Column(name = "id")
        public Long getId() {
            return id;
        }

        @Column(name = "name")
        public String getName() {
            return name;
        }

        @Column(name = "address")
        public String getAddress() {
            return address;
        }

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "survey")
        public List<Question> getQuestions() {
            return questions;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public void setName(final String name) {
            this.name = name;
        }

        public void setAddress(final String address) {
            this.address = address;
        }

        public void setQuestions(List<Question> _questions) {
            this.questions = _questions;
        }
    }

问题实体:

@Entity
@Table(name = "Question")
public class Question {

    private Long id;
    private String question;
    private Survey survey;

    @Id
    @Column(name = "id")
    public Long getId() {
        return id;
    }

    @Column(name = "question")
    public String getQuestion() {
        return question;
    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "survey_id")
    public Survey getSurvey() {
        return survey;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public void setQuestion(String question) {
        this.question = question;
    }

    public void setSurvey(Survey survey) {
        this.survey = survey;
    }
}

问题 Crud 回购:

 public interface QuestionRepo extends CrudRepository<Question, Long> {
    }

控制器:

@RestController
@RequestMapping("/default")
public class DefaultEndpoint {

    @Autowired
    private QuestionRepo questionRepo;


    @PostMapping(value = "/saveQuestion")
    public void saveQuestion(@Param("id") Long id, @Param("question") String question, @Param("survey_id") Long survey_id) {
        Question questionObject = new Question();
        questionObject.setId(id);
        questionObject.setQuestion(question);
        Survey survey = surveyRepo.findById(survey_id).get();
        survey.setName("example");
        questionObject.setSurvey(survey);
        questionRepo.save(questionObject);
    }
}

在控制器 sn-p 中,当我执行 survey.setName("example"); 时。 这种变化反映在数据库上。

表示save()操作,是用EntityManager方法MERGE和PERIST实现的, 即使没有指定 Cascade 类型,也会级联到子实体。
这是它应该如何工作,还是我犯了一些愚蠢的错误?
非常感谢 !

【问题讨论】:

    标签: java hibernate spring-boot jpa


    【解决方案1】:

    请检查@ManyToOne注解,看看默认的级联是none。

    public @interface ManyToOne {
       /**
         * (Optional) The operations that must be cascaded to 
         * the target of the association.
         *
         * <p> By default no operations are cascaded.
         */
        CascadeType[] cascade() default {};
    }
    

    没有级联发生。

    您所观察到的效果很可能是 2 个特征的组合:

    如果您正在运行 Web 应用程序,Spring Boot 默认注册 OpenEntityManagerInViewInterceptor 以应用“在视图中打开 EntityManager”模式,以允许在 Web 视图中延迟加载。如果您不希望出现这种行为,则应在 application.properties 中将 spring.jpa.open-in-view 设置为 false。

    Dirty Checking 是众所周知的,但 Open Session In View 往往会让一些开发者感到惊讶(例如,在 Spring - Same entity detached on the @EventListener but attached in the @Service class 中查看另一个相关效果)

    【讨论】:

    • 就是这样!但是..我不知道这个功能,是不是就像在控制器方法中有一个@Transactional注解?
    • 在视图中打开会话与@Transactional:stackoverflow.com/questions/16465269/…
    • 我不明白为什么会发生这种情况:如果我在保存后执行survey.setName("example") 启用了spring.jpa.open-in-view,则更改不会保留..所以我想这不是真的像有一个@transactional 注释?
    • 如上链接所述,过滤器不会刷新会话
    • 哦,是的,是的,所以它是刷新它的保存,所以行为类似于@transactional,最后一个问题,感谢您的帮助!,此功能仅发生在 Controller/RestControllers 中,而不是服务?
    【解决方案2】:

    这是脏检查机制。例如,当您刷新持久性上下文或提交事务时,Hibernate 会检查上下文中实体的脏状态并执行 SQL 更新以将内存中的状态与数据库状态同步。 您可以查看此post 以获取更多详细信息

    【讨论】:

    • 请注意,我没有使用@Transactional,因此当我调用 setName 时,Survey 实例不受管理
    猜你喜欢
    • 1970-01-01
    • 2019-07-31
    • 2016-02-08
    • 2022-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多