README
## 说明
这是JPA实现级联操作的demo。
为了实现方便,就没有写service和impl层,直接写了dao层。(理解级联操作的思路就好)
### 数据库说明
在application.properties中配置您对应的数据库信息。
无需在mysql数据库设计表。运行该项目,则自动生成数据库表。
### 注意点
- 在被维护的一方,比如Survey,添加所有的问题,一定要添加 @ToString.Exclude。
否则报错:$HibernateProxy$Bo3T1LuZ.toString(Unknown Source) ~[classes/:na]
@OneToMany(mappedBy = "survey",cascade=CascadeType.ALL,orphanRemoval = true)
@ToString.Exclude
private List<Question> questions=new LinkedList<>();
### 关系说明
一个问卷有多个题目
一个题目有多个选项
### 级联删除
删除问卷,会把相关的问题和选项都删除。
### 级联更新
目前的思路实现是新增一个问题,把以前的无关问题全部删除。详情看TestController的test6.
如果你想更新部分问题,又不想把以前的无关问题删除。
1.这个想法的思路我暂时这么实现。
2.获取以前的问题。
3.使用survey.getQuestions().clear();删除全部的问题
4.将以前的问题进行修改,再重新生成问题
### 级联查询
根据问卷id,能够查询全部的问题和选项
### 级联标签
CascadeType.PRESIST 级联持久化(保存)操作(持久保存拥有方实体时,也会持久保存该实体的所有相关数据。)
CascadeType.REMOVE 级联删除操作(删除一个实体时,也会删除该实体的所有相关数据。)
CascadeType.MERGE 级联更新(合并)操作(将分离的实体重新合并到活动的持久性上下文时,也会合并该实体的所有相关数据。)
CascadeType.REFRESH 级联刷新操作 (只会查询获取操作)
CascadeType.ALL 包含以上全部级联操作
目录
entity
Survey问卷类
package com.lyr.demo.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.LinkedList;
import java.util.List;
@ApiModel("问卷")
@Entity
@Data
@Table(name = "t_survey")
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonIgnoreProperties(value = {"hibernateLazyInitializer"})
public class Survey {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@Column
private String title;
@OneToMany(mappedBy = "survey", cascade = CascadeType.ALL,orphanRemoval = true)
@JsonBackReference
private List<Question> questions = new LinkedList <>();
public void addQuestion (Question q) {
if (null != q) {
questions.add(q);
}
}
}
Question问题类
package com.lyr.demo.entity;
import com.fasterxml.jackson.annotation.JsonBackReference;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.LinkedList;
import java.util.List;
@ApiModel("问题")
@Entity
@Data
@Table(name = "t_question")
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class Question {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@Column
private String title;
@ManyToOne
@JoinColumn(name = "belong_survey_id",nullable = false)
@JsonManagedReference
@ToString .Exclude
private Survey survey;
@OneToMany(mappedBy = "question",cascade=CascadeType.ALL,orphanRemoval = true)
@JsonBackReference
private List<Option> options=new LinkedList <>();
public void addOption (Option option) {
if (null !=option){
options.add(option);
}
}
}
Option选项类
package com.lyr.demo.entity;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
@ApiModel("选项")
@Entity
@Data
@Table(name = "t_option")
@AllArgsConstructor
@NoArgsConstructor
@ToString
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
public class Option {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
@Column
private String title;
@ManyToOne
@JoinColumn(name = "quid",nullable = false)
@JsonManagedReference
@ToString .Exclude
private Question question;
}
dao层
SurveyDao
package com.lyr.demo.dao;
import com.lyr.demo.entity.Survey;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SurveyDao extends JpaRepository <Survey,String> {
}
QuestionDao
package com.lyr.demo.dao;
import com.lyr.demo.entity.Question;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface QuestionDao extends JpaRepository <Question,String> {
}
OptionDao
package com.lyr.demo.dao;
import com.lyr.demo.entity.Option;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface OptionDao extends JpaRepository <Option,String> {
}
TestController
package com.lyr.demo.controller;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.lyr.demo.dao.OptionDao;
import com.lyr.demo.dao.QuestionDao;
import com.lyr.demo.dao.SurveyDao;
import com.lyr.demo.entity.Option;
import com.lyr.demo.entity.Question;
import com.lyr.demo.entity.Survey;
import com.lyr.demo.utils.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class TestController {
@Autowired
private SurveyDao surveyDao;
@Autowired
private QuestionDao questionDao;
@Autowired
private OptionDao optionDao;
@GetMapping("/test1")
public Result test1 () {
Result result = new Result ();
Survey survey = new Survey ();
survey.setTitle("s1" );
Question q1 = new Question ();
q1.setTitle("q1" );
q1.setSurvey(survey);
Option op1 = new Option ();
op1.setTitle("op1" );
op1.setQuestion(q1);
Question q2 = new Question ();
q2.setTitle("q2" );
q2.setSurvey(survey);
Option op2 = new Option ();
op2.setTitle("op2" );
op2.setQuestion(q2);
q1.addOption(op1);
q2.addOption(op2);
survey.addQuestion(q1);
survey.addQuestion(q2);
surveyDao.save(survey);
return result;
}
@GetMapping("/test2")
public Result test2 () {
Result result = new Result ();
surveyDao.deleteById("4028fe8179ef78b80179ef7968160000" );
return result;
}
@GetMapping("/test3")
public Result test3 () {
Result result = new Result ();
questionDao.deleteById("4028fe8179ef65ce0179ef67eaa90001" );
return result;
}
@GetMapping("/test4")
public Result test4 () {
Result result = new Result ();
optionDao.deleteById("4028fe8179ef7cc10179ef7dbdbd0002" );
return result;
}
@GetMapping("/test5")
public Result test5 () {
Result result = new Result ();
Survey entity = surveyDao.getOne("4028fe8179ef7e470179ef9186350000" );
if (null != entity) {
JSONObject all = new JSONObject ();
all.put("id" , entity.getId());
all.put("title" , entity.getTitle());
List<Question> questions = entity.getQuestions();
JSONArray arrQuesstions = new JSONArray ();
int size = questions.size();
if (0 != size) {
for (int i = 0 ; i < size; i++) {
JSONObject jsonQuestion = new JSONObject ();
Question question = questions.get(i);
jsonQuestion.put("id" , question.getId());
jsonQuestion.put("title" , question.getTitle());
JSONArray arrOptions = new JSONArray ();
List<Option> options = question.getOptions();
int opSize = options.size();
if (0 != opSize) {
for (int j = 0 ; j < opSize; j++) {
JSONObject jsonOp = new JSONObject ();
Option option = options.get(j);
jsonOp.put("id" , option.getId());
jsonOp.put("title" , option.getTitle());
arrOptions.add(j, jsonOp);
}
jsonQuestion.put("options" , arrOptions);
}
arrQuesstions.add(i, jsonQuestion);
}
all.put("questions" , arrQuesstions);
return result.putCode(0 ).putMsg("成功装载数据" ).putData(all);
}
}
return result;
}
@GetMapping("/test6")
public Result test6 () {
Result result = new Result ();
Survey survey = surveyDao.getOne("4028fe8179f396280179f39de6c20006" );
survey.getQuestions().clear();
Question question=new Question ();
question.setTitle("新的问题" );
question.setSurvey(survey);
survey.addQuestion(question);
surveyDao.save(survey);
return result;
}
@GetMapping("/test7")
public Result test7 () {
Result result = new Result ();
return result;
}
@GetMapping("/test8")
public Result test8 () {
Result result = new Result ();
return result;
}
}
Result类(主要是controller层的返回标准实现,我自己自定义的)
package com.lyr.demo.utils;
import io.swagger.annotations.ApiModelProperty;
import java.util.HashMap;
import lombok.Data;
@Data
public class Result extends HashMap <String, Object> {
@ApiModelProperty(value = "0-成功 1-失败")
private int code=0 ;
@ApiModelProperty(value = "描述信息")
private String msg="" ;
@ApiModelProperty(value = "传递的数据")
public Object data="" ;
public Result () {
super ();
this .put("code" ,code);
this .put("msg" ,msg);
this .put("data" ,data);
}
@Override
public Result put (String key, Object value) {
super .put(key,value);
return this ;
}
public Result putData (Object data) {
this .put("data" , data);
return this ;
}
public Result putMsg (String msg) {
this .put("msg" , msg);
return this ;
}
public Result putCode (int code) {
this .put("code" , code);
return this ;
}
}
运行类
package com.lyr.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@EnableSwagger2
@SpringBootApplication
public class RunApplication {
public static void main (String[] args) {
SpringApplication.run(RunApplication.class,args);
}
}
application.properties
## port
server.port=8091
## 事务管理
spring.transaction.rollback-on-commit-failure=true
## local mysql
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.url=jdbc:mysql://localhost:3306/lyr?useUnicode=true&characterEncoding=utf-8&allowMultiQueries=true&serverTimezone=GMT%2B8
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.jpa.hibernate.ddl-auto=update
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns ="http://maven.apache.org/POM/4.0.0"
xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation ="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
<modelVersion > 4.0.0</modelVersion >
<groupId > com.lyr</groupId >
<artifactId > jpa级联操作</artifactId >
<version > 1.0-SNAPSHOT</version >
<parent >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-parent</artifactId >
<version > 2.2.6.RELEASE</version >
<relativePath />
</parent >
<dependencies >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
<dependency >
<groupId > mysql</groupId >
<artifactId > mysql-connector-java</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-aop</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-data-jpa</artifactId >
<version > 2.4.1</version >
</dependency >
<dependency >
<groupId > org.projectlombok</groupId >
<artifactId > lombok</artifactId >
<optional > true</optional >
</dependency >
<dependency >
<groupId > com.alibaba</groupId >
<artifactId > fastjson</artifactId >
<version > 1.2.60</version >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-freemarker</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-test</artifactId >
<scope > test</scope >
<exclusions >
<exclusion >
<groupId > org.junit.vintage</groupId >
<artifactId > junit-vintage-engine</artifactId >
</exclusion >
</exclusions >
</dependency >
<dependency >
<groupId > junit</groupId >
<artifactId > junit</artifactId >
<scope > test</scope >
</dependency >
<dependency >
<groupId > io.springfox</groupId >
<artifactId > springfox-swagger2</artifactId >
<version > 2.9.2</version >
</dependency >
<dependency >
<groupId > io.springfox</groupId >
<artifactId > springfox-swagger-ui</artifactId >
<version > 2.9.2</version >
</dependency >
<dependency >
<groupId > com.github.caspar-chen</groupId >
<artifactId > swagger-ui-layer</artifactId >
<version > 1.1.3</version >
</dependency >
<dependency >
<groupId > org.apache.commons</groupId >
<artifactId > commons-lang3</artifactId >
<version > 3.4</version >
</dependency >
</dependencies >
<build >
<finalName > QuestionnaireSystem</finalName >
<plugins >
<plugin >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-maven-plugin</artifactId >
</plugin >
<plugin >
<artifactId > maven-surefire-plugin</artifactId >
<configuration >
<skipTests > true</skipTests >
</configuration >
</plugin >
</plugins >
<resources >
<resource >
<directory > src/main/java</directory >
<includes >
<include > **/*.xml</include >
<include > **/*.properties</include >
</includes >
<filtering > false</filtering >
</resource >
<resource >
<directory > src/main/resources</directory >
<includes >
<include > **/*.xml</include >
<include > **/*.properties</include >
<include > **/*.xls</include >
</includes >
<filtering > false</filtering >
</resource >
</resources >
</build >
</project >
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」