Spring Boot+JPA增删改查实例

本文使用spring boot配合JPA实现增删改查。并介绍orphanRemoval属性,使用该属性对子类实体进行增删操作。

阅读本文您需要掌握以下前提知识:

  • Spring Boot基础知识
  • Hibernates-JPA基础知识
  • Java基础知识

什么是orphanRemoval,百度了下发现没有非常准确且简单的定义。

orphanRemoval:当子类实体不再与父类实体关联时即删除该实体。

即,当你从父实体的相应集合中删除了该子类实体时,它会被物理删除,而非只在内存中删除。

以下为实例,模拟了评论以及点赞操作:
为了让大家更加直观,先上项目结构图:
在这里插入图片描述
AddCommentRequestBean.java : 插入评论的request bean
AddCommentLikeRequestBean.java : 点赞的request bean
CrudCommentController.java : 添删评论或点赞的接口类
CrudCommentControllerImpl.java : 添删评论或点赞的实现类
Comment.java : 评论信息实体类
CommentLike.java : 点赞信息实体类
CommentLikePK.java : 点赞信息的联合主键

本例中的父类为评论信息,子类为点赞信息,关系图如下:
在这里插入图片描述

先从实体类看起:
Comment.java
可见评论信息包含点赞信息,关系为OneToMany。并设置了orphanRemoval=true。因此将某子类实体从父类中的commentLike中移除时,其就会被物理删除。添加和移除可见本类的addCommentLike以及removeCommentLike的两个方法。用的是Set集合类的add()以及remove()方法。

package com.example.demo.entity;

import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.validation.constraints.Size;

@Entity( name="Comment" )
@Table( name = "tb_comment_info" )
@NamedQuery(name = "Comment.findAll", query = "SELECT c FROM Comment c")
public class Comment {

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "comment_id",columnDefinition = "BIGINT UNSIGNED")
    private Long commentId;
	
	@Size( max = 200 )
	@Column( name = "comment_body" )
	private String commentBody;
	
	@OneToMany(mappedBy = "comment", fetch = FetchType.EAGER, orphanRemoval = true, cascade = { CascadeType.PERSIST } )
	private Set<CommentLike> commentLike;

	
	public Long getCommentId() {
		return commentId;
	}

	public void setCommentId(Long commentId) {
		this.commentId = commentId;
	}

	public String getCommentBody() {
		return commentBody;
	}

	public void setCommentBody(String commentBody) {
		this.commentBody = commentBody;
	}

	public Set<CommentLike> getCommentLike() {
		return commentLike;
	}

	public void setCommentLike(Set<CommentLike> commentLike) {
		this.commentLike = commentLike;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((commentId == null) ? 0 : commentId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Comment other = (Comment) obj;
		if (commentId == null) {
			if (other.commentId != null)
				return false;
		} else if (!commentId.equals(other.commentId))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Comment [commentId=" + commentId + ", commentBody=" + commentBody + "]";
	}

	public CommentLike addCommentLike( CommentLike commentLike ) {	
		this.getCommentLike().add( commentLike );
		commentLike.setComment( null );
		return commentLike;	
	}
	
	public CommentLike removeCommentLike( CommentLike commentLike ) {	
		this.getCommentLike().remove( commentLike );
		commentLike.setComment( null );
		return commentLike;	
	}
	
}

CommentLike.java

package com.example.demo.entity;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity( name="CommentLike" )
@Table( name = "tb_comment_like_info" )
@NamedQuery(name = "CommentLike.findAll", query = "SELECT c FROM CommentLike c")
public class CommentLike {

	@EmbeddedId
	private CommentLikePK id;

    @ManyToOne
    @JoinColumns({
    				@JoinColumn(name = "comment_id",referencedColumnName = "comment_id",insertable = false, updatable = false)
    			})
    private Comment comment;
    
	public CommentLikePK getId() {
		return id;
	}

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

	public Comment getComment() {
		return comment;
	}

	public void setComment(Comment comment) {
		this.comment = comment;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CommentLike other = (CommentLike) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "CommentLike [id=" + id + "]";
	}

}

点赞实体类的联合主键
CommentLikePK.java

package com.example.demo.entity;

import java.io.Serializable;

import javax.persistence.Column;

public class CommentLikePK implements Serializable{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Column(name = "comment_id",columnDefinition = "BIGINT UNSIGNED")
    private Long commentId;
	
	@Column(name = "user_id",columnDefinition = "BIGINT UNSIGNED")
    private Long userId;

	public Long getCommentId() {
		return commentId;
	}

	public void setCommentId(Long commentId) {
		this.commentId = commentId;
	}

	public Long getUserId() {
		return userId;
	}

	public void setUserId(Long userId) {
		this.userId = userId;
	}

	public static long getSerialversionuid() {
		return serialVersionUID;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((commentId == null) ? 0 : commentId.hashCode());
		result = prime * result + ((userId == null) ? 0 : userId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		CommentLikePK other = (CommentLikePK) obj;
		if (commentId == null) {
			if (other.commentId != null)
				return false;
		} else if (!commentId.equals(other.commentId))
			return false;
		if (userId == null) {
			if (other.userId != null)
				return false;
		} else if (!userId.equals(other.userId))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "CommentLikePK [commentId=" + commentId + ", userId=" + userId + "]";
	}

}

再来看两个request bean
AddCommentRequestBean.java
添加评论时,评论不得为空

package com.example.demo.bean;

import javax.validation.constraints.NotBlank;
import lombok.Data;

@Data
public class AddCommentRequestBean {

	@NotBlank
	private String commentBody;
	
}

AddCommentLikeRequestBean.java
调用点赞接口时,评论编号以及用户ID不得为空。

package com.example.demo.bean;

import javax.validation.constraints.NotBlank;

import lombok.Data;

@Data
public class AddCommentLikeRequestBean {

	@NotBlank
	private Long commentId;
	
	@NotBlank
	private Long userId;
	
}

增删评论以及点赞信息的接口类

CrudCommentController.java

package com.example.demo.controller;

import javax.validation.Valid;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.bean.AddCommentLikeRequestBean;
import com.example.demo.bean.AddCommentRequestBean;

@RestController
@RequestMapping("/restapi/comment")
public interface CrudCommentController {

	@PostMapping("/add")
	public ResponseEntity<?> addComment( @Valid @RequestBody AddCommentRequestBean addCommentRequestBean );
	
	@PostMapping("/remove/{commentId}")
	public ResponseEntity<?> removeComment( @PathVariable(name="commentId", required = true ) Long commentId );
	
	@PostMapping("/like")
	public ResponseEntity<?> addCommentLike( @Valid @RequestBody AddCommentLikeRequestBean addCommentLikeRequestBean );
	
	@PostMapping("/dislike")
	public ResponseEntity<?> removeCommentLike( @Valid @RequestBody AddCommentLikeRequestBean addCommentLikeRequestBean );
	
}

增删评论以及点赞信息的实现类

CrudCommentControllerImpl.java

package com.example.demo.controllerimpl;

import javax.transaction.Transactional;
import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import com.example.demo.bean.AddCommentLikeRequestBean;
import com.example.demo.bean.AddCommentRequestBean;
import com.example.demo.controller.CrudCommentController;
import com.example.demo.entity.Comment;
import com.example.demo.entity.CommentLike;
import com.example.demo.entity.CommentLikePK;
import com.example.demo.repository.CommentRepository;

@Component
@Transactional
public class CrudCommentControllerImpl implements CrudCommentController {

	@Autowired
	private CommentRepository commentRepository;
	
	@Override
	public ResponseEntity<?> addComment(@Valid AddCommentRequestBean addCommentRequestBean) {
		// TODO Auto-generated method stub
		
		// 生成新的评论
		Comment comment = new Comment();
		// 设置评论内容
		comment.setCommentBody( addCommentRequestBean.getCommentBody() );
		// 使用仓库存储
		commentRepository.save( comment );
		
		return new ResponseEntity<>("成功添加评论",HttpStatus.OK);
	}

	@Override
	public ResponseEntity<?> removeComment( Long commentId ) {
		// TODO Auto-generated method stub
		
		// 使用仓库根据评论ID删除评论
		commentRepository.deleteById( commentId );
		
		return new ResponseEntity<>("成功删除评论",HttpStatus.OK);
	}

	@Override
	public ResponseEntity<?> addCommentLike(@Valid AddCommentLikeRequestBean addCommentLikeRequestBean) {
		// TODO Auto-generated method stub
		
		// 如果评论不存在则报错,存在则获取该实体
		Comment comment = commentRepository.findById( addCommentLikeRequestBean.getCommentId() )
				                           .orElseThrow(()-> new RuntimeException("该评论不存在"));
		
		// 生成点赞信息的联合主键
		CommentLikePK commentPK = new CommentLikePK();
		commentPK.setCommentId( addCommentLikeRequestBean.getCommentId() );
		commentPK.setUserId( addCommentLikeRequestBean.getUserId() );
		
		// 生成点赞信息,并设置主键
		CommentLike commentLike = new CommentLike();
		commentLike.setId( commentPK );
		
		// 当子类实体中没有该用户的点赞信息时插入
		// 注意equals和hashCode是否正确,如不正确contains执行结果会错误
		if( !comment.getCommentLike().contains( commentLike ) ) {
			comment.addCommentLike( commentLike );
		}
		
		return new ResponseEntity<>("成功点赞",HttpStatus.OK);
	}

	@Override
	public ResponseEntity<?> removeCommentLike(@Valid AddCommentLikeRequestBean addCommentLikeRequestBean) {
		// TODO Auto-generated method stub

		Comment comment = commentRepository.findById( addCommentLikeRequestBean.getCommentId() )
                						   .orElseThrow(()-> new RuntimeException("该评论不存在"));
		
		// 生成点赞信息的联合主键
		CommentLikePK commentPK = new CommentLikePK();
		commentPK.setCommentId( addCommentLikeRequestBean.getCommentId() );
		commentPK.setUserId( addCommentLikeRequestBean.getUserId() );
		
		CommentLike commentLike = new CommentLike();
		commentLike.setId( commentPK );
		
		// 当子类实体中有当前用户的点赞信息时删除该点赞信息
		// 注意equals和hashCode是否正确,如不正确contains执行结果会错误
		if( comment.getCommentLike().contains( commentLike ) ) {
			comment.removeCommentLike( commentLike );
			return new ResponseEntity<>("成功取消点赞",HttpStatus.OK);
			
		}else {
			// do nothing
			return new ResponseEntity<>("已取消点赞",HttpStatus.OK);
		}
	}

}

YML文件

server:
  port: 8083
  tomcat:
    uri-encoding: UTF-8
spring: 
  application: 
    name: demo
  mvc: 
    static-path-pattern: static/**
  thymeleaf:
    prefix: classpath:/templates/
    suffix: .html
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    #本例使用mysql,如使用其他DB请自行切换
    url: jdbc:mysql://localhost/test_database?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&allowPublicKeyRetrieval=true
    #注意此处切换为自己的账号密码
    username: 
    password: 
  jpa:
    #为当前线程配置EntityManager
    open-in-view: false
    #自动执行DDL
    generate-ddl: true
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL5InnoDBDialect
        ddl-auto: update

POM

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.3.1.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
		<dependency>
		    <groupId>javax.validation</groupId>
		    <artifactId>validation-api</artifactId>
		    <version>2.0.1.Final</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<scope>runtime</scope>
		</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>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

使用PostMan测试

起始状态,两个表皆为空
在这里插入图片描述

调用CrudCommentController的addComment()方法添加评论
在这里插入图片描述
确认评论数据是否被添加
在这里插入图片描述

再调用CrudCommentController的addCommentLike()方法为该评论添加点赞信息。
在这里插入图片描述
再次查看点赞表数据,点赞信息被添加。
在这里插入图片描述

再调用CrudCommentController的removeCommentLike()方法移除该点赞信息。

在这里插入图片描述

最后调用CrudCommentController的removeComment()来移除刚刚添加的评论。
在这里插入图片描述

展开阅读全文

Git 实用技巧

11-24
这几年越来越多的开发团队使用了Git,掌握Git的使用已经越来越重要,已经是一个开发者必备的一项技能;但很多人在刚开始学习Git的时候会遇到很多疑问,比如之前使用过SVN的开发者想不通Git提交代码为什么需要先commit然后再去push,而不是一条命令一次性搞定; 更多的开发者对Git已经入门,不过在遇到一些代码冲突、需要恢复Git代码时候就不知所措,这个时候哪些对 Git掌握得比较好的少数人,就像团队中的神一样,在队友遇到 Git 相关的问题的时候用各种流利的操作来帮助队友于水火。 我去年刚加入新团队,发现一些同事对Git的常规操作没太大问题,但对Git的理解还是比较生疏,比如说分支和分支之间的关联关系、合并代码时候的冲突解决、提交代码前未拉取新代码导致冲突问题的处理等,我在协助处理这些问题的时候也记录各种问题的解决办法,希望整理后通过教程帮助到更多对Git操作进阶的开发者。 本期教程学习方法分为“掌握基础——稳步进阶——熟悉协作”三个层次。从掌握基础的 Git的推送和拉取开始,以案进行演示,分析每一个步骤的操作方式和原理,从理解Git 工具的操作到学会代码存储结构、演示不同场景下Git遇到问题的不同处理方案。循序渐进让同学们掌握Git工具在团队协作中的整体协作流程。 在教程中会通过大量案进行分析,案会模拟在工作中遇到的问题,从最基础的代码提交和拉取、代码冲突解决、代码仓库的数据维护、Git服务端搭建等。为了让同学们容易理解,对Git简单易懂,文章中详细记录了详细的操作步骤,提供大量演示截图和解析。在教程的最后部分,会从提升团队整体效率的角度对Git工具进行讲解,包括规范操作、Gitlab的搭建、钩子事件的应用等。 为了让同学们可以利用碎片化时间来灵活学习,在教程文章中大程度降低了上下文的依赖,让大家可以在工作之余进行学习与实战,并同时掌握里面涉及的Git不常见操作的相关知识,理解Git工具在工作遇到的问题解决思路和方法,相信一定会对大家的前端技能进阶大有帮助。
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值