Java 减少hibernate中的数据量,同时仍使用hibernate功能
假设我有这样一个数据库:(不是实际的数据库,但足以说明问题) Complete和total字段只是isComplete和每个条件(每个任务列表或每个项目)的总任务记录的计数器。它们被重复(数据库去规范化?)以便于获取,因为在每个阶段我都希望包含一个进度计数器 我有这样的实体:Java 减少hibernate中的数据量,同时仍使用hibernate功能,java,mysql,spring,spring-boot,hibernate,Java,Mysql,Spring,Spring Boot,Hibernate,假设我有这样一个数据库:(不是实际的数据库,但足以说明问题) Complete和total字段只是isComplete和每个条件(每个任务列表或每个项目)的总任务记录的计数器。它们被重复(数据库去规范化?)以便于获取,因为在每个阶段我都希望包含一个进度计数器 我有这样的实体: // other fields, getter and setters omitted for brevity @Entity @Table(name = "user_info") public c
// other fields, getter and setters omitted for brevity
@Entity
@Table(name = "user_info")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "username")
private String userName;
@Column(name = "image")
private String imageUrl;
@ManyToMany
@JoinTable(name = "project_user",
joinColumns = @JoinColumn(name="user_id"),
inverseJoinColumns = @JoinColumn(name="project_id"))
private Set<Project> projects;
}
@Entity
@Table(name = "project")
public class Project {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
@OneToOne
@JoinColumn(name = "creator_id")
private User creator;
@Column(name = "image")
private String imageUrl;
@Column(name = "creation_date")
private Date createdAt;
@Column(name = "total")
private int total;
@Column(name = "complete")
private int complete;
@ManyToMany
@JoinTable(name = "project_user",
joinColumns = @JoinColumn(name="project_id"),
inverseJoinColumns = @JoinColumn(name="user_id"))
@JsonIgnoreProperties(value = {"projects", "connected", "notifications"})
private Set<User> members;
@OneToMany(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id")
private Set<TaskList> taskLists;
}
@Entity
@Table(name = "task_list")
public class TaskList {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
@Column(name = "image")
private String imageUrl;
@Column(name = "creation_date")
private Date createdAt;
@Column(name = "complete")
private int complete;
@Column(name = "total")
private int total;
@OneToMany
@JoinColumn(name = "task_list_id")
private Set<Task> tasks;
}
@Entity
@Table(name = "task")
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "description")
private String description;
@Column(name = "title")
private String title;
@ElementCollection
@CollectionTable(name = "task_images", joinColumns = @JoinColumn(name="task_id"))
@Column(name = "image")
private Set<String> imageUrls;
@OneToMany
@JoinColumn(name = "task_id")
private Set<TaskMember> handledBy;
@Transient
private Set<Note> notes;
@Column(name = "complete")
private boolean complete;
@Column(name = "creation_date")
private Date createdAt;
@Column(name = "completion_date")
private Date completeDate;
}
@Entity
@Table(name = "task_handler")
public class TaskMember {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@OneToOne
@JoinColumn(name = "id", referencedColumnName = "user_id")
private User user;
@Column(name = "assignmentType")
private String assignmentType; //maybe change to enum?
}
user: {
//fields
projects: [{
//fields
tasklist: [{
//fields
tasks: [{
//fields
}]
}]
}]
}
这不仅是一个巨大的响应(包含几乎所有的数据),而且占用了服务器上的大量空间。
我想要的是:
request to sign in:
user: {
//fields
}
request to endpoint1 with parameter user id
projects: [{
// fields
}]
request to endpoint2 with parameter project id
tasklist: [{
// fields
}]
request to endpoint3 with parameter tasklist id
tasks: [{
// fields
}]
这将使在尽可能使api无状态的情况下更容易更新客户端的任何更改(除了会话和安全性内容之外,我不希望服务器内存中有任何数据)
我知道有一种方法是删除实体,并以纯sql的方式进行操作,但这意味着我失去了hibernate的功能,如级联和数据完整性
我的选择是什么?如果实体关系或数据库设计中存在错误,请告知我。
提前感谢:)
编辑:我不使用任何自定义序列化程序类,只使用基类jackson。用@jsonIgnoreProperty注释属性可以防止对不需要的字段进行序列化,但我认为这不会首先阻止获取它们(这里可能是错误的)
@RestController
公共类Hello控制器{
@自动连线
私人用户服务;
@GetMapping(“/”)
公共列表getAllData(){
//只运行一个基本的“来自用户”查询
List users=userService.findAll();
返回用户;
}
}
显然,我误解了hibernate的工作原理。在对它有了更多的了解和玩弄之后。我相信我终于明白了。事实证明,即使它是相关的,除非请求它,否则它不会获取数据
一个选项是在隐藏属性上使用jsonignore来阻止jackson访问getter(这反过来又不会获取对象),但这意味着我以后无法自定义它
更好的方法是使用DTO
感谢@Thomas的评论显然,我误解了hibernate的工作原理。在对它有了更多的了解和玩弄之后。我相信我终于明白了。事实证明,即使它是相关的,除非请求它,否则它不会获取数据 一个选项是在隐藏属性上使用jsonignore来阻止jackson访问getter(这反过来又不会获取对象),但这意味着我以后无法自定义它 更好的方法是使用DTO
谢谢@Thomas的评论我想你想向用户展示他的任务,对吗?因此,不要获取
Project
s,而是通过TaskHandler
和所有这些东西。好吧,提供查询/存储库方法来获取端点所需的数据应该不会太难。你面临什么问题?@M.Prokhorov不,我想向用户展示他的项目。然后,当他单击一个项目时,显示任务列表。单击任务列表将显示任务。(我知道如何处理点击和请求)@Movsac,那么具体的问题是什么?将抓取定义为惰性,并确保序列化程序不会对其进行拉取。如果您还展示了一个序列化代码的示例,那么会更简单。这可能是问题所在:您直接将内部模型(实体)暴露给外部世界(REST客户端)。相反,您可能希望构建另一个模型,例如,使用仅表示该端点所需数据的数据传输对象(使用映射库(如mapstruct)移动数据)或通过提供自定义序列化/反序列化(Jackson实现这一点的一种方法可能是mixin——为每个端点提供具有不同注释的mixin)。我认为您希望向用户显示其任务,对吗?因此,不要获取Project
s,而是通过TaskHandler
和所有这些东西。好吧,提供查询/存储库方法来获取端点所需的数据应该不会太难。您面临什么问题?@M.Prokhorov不,我想向用户展示的是他的项目。然后当他单击项目时,显示任务列表。单击任务列表显示任务。(我知道如何处理单击和请求)@Movsac,那么具体的问题是什么呢?将抓取定义为惰性,并确保序列化程序不会对其进行处理。如果您也展示了序列化代码的示例,则会更简单。这可能就是问题所在:您将内部模型(实体)直接暴露给外部世界(REST客户端)。您可能希望改为构建另一个模型,例如,使用仅表示该端点所需数据的数据传输对象(使用映射库(如mapstruct)移动数据)或通过提供自定义序列化/反序列化(Jackson实现这一点的一种方法可能是mixin——为每个端点提供具有不同注释的mixin)。
@RestController
public class HelloController {
@Autowired
private UserService userService;
@GetMapping("/")
public List<User> getAllData() {
// just runs a basic "from User" query
List<User> users = userService.findAll();
return users;
}
}