Spring boot整合JPA进行CRUD
前言
最近是在项目中使用到了Spring Data JPA来减少大量重复SQL语句的编写,能够感觉到的确是使用起来很方便效率也比较高。Spring Data JPA 能够简化数据访问层的实现,让工程师不必去写一些CRUD的接口和实现。Spring Data JPA 自动提供CRUD的实现,能够部分解放工程师们的工作量。
通过本篇博客可以实现使用JPA进行CRUD
系列博客
本博客的实现demo
环境配置
- 创建一个Maven项目并引入依赖
1.POM依赖
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <dependencies> <!--spring boot 启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--spring mvc--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--spring boot 开发工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!--spring boot 测试工具--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--jpa 启动器--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <!--mysql连接器--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
2.application.yml文件
server: port: 8099 spring: application: name: spring-data-jpa datasource: #mysq 驱动 driver-class-name: com.mysql.cj.jdbc.Driver #连接数据库的url中配置ip和数据库名称以及时区 url: jdbc:mysql://localhost:3306/spring_jpa?serverTimezone=Asia/Shanghai&characterEncoding=utf-8 username: root password: root jpa: hibernate: #更新或者创建数据库表结构 ddl-auto: update #控制台显示SQL show-sql: true
完整的项目结构
比较典型的MVC项目结构,在JPA里面将熟悉的dao层数据操作层用repository来命名
代码实现
实体类
目前有一个实体类,一个基础类(用于抽象出一些公共的字段)
基础类BaseEntity
import org.springframework.format.annotation.DateTimeFormat; import javax.persistence.Column; import javax.persistence.MappedSuperclass; import java.util.Date; /** * @author : [WangWei] * @version : [v1.0] * @className : BaseEntity * @description : [基础类] * @createTime : [2022/11/18 15:32] * @updateUser : [WangWei] * @updateTime : [2022/11/18 15:32] * @updateRemark : [描述说明本次修改内容] */ //@MappedSuperclass的类将不是一个完整的实体类,他将不会映射到数据库表,但是他的属性都将映射到其子类的数据库字段中。 @MappedSuperclass public class BaseEntity { //定义字段以及字段的类型和长度和是否允许为null @Column(name = "create_by",columnDefinition = "varchar(32) COMMENT '创建人'",nullable = false) private String createdBy; @Column(name = "created_id",columnDefinition = "varchar(32) COMMENT '创建人id'",nullable = false) private Long createdId; @Column(name = "create_time",nullable = false,columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; @Column(name = "updated_by",columnDefinition = "varchar(32) COMMENT '更新人'") private String updateBy; @Column(name = "updated_id",columnDefinition = "varchar(32) COMMENT '更新人id'") private Long updateId; 定义字段以及字段的类型并默认为当前时间,并当进行修改的时候更新时间为当前实现 @Column(name = "update_time",columnDefinition = "DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; @Column(name = "is_delete",columnDefinition = "tinyint(1) COMMENT '是否删除(0/1 未删除/删除)'") private int isDelete=0; @Column(name = "remark",columnDefinition = "varchar(64) COMMENT '备注'") private String remark; public String getCreatedBy() { return createdBy; } public void setCreatedBy(String createdBy) { this.createdBy = createdBy; } public Date getCreateTime() { return createTime; } public void setCreateTime(Date createTime) { this.createTime = createTime; } public String getUpdateBy() { return updateBy; } public void setUpdateBy(String updateBy) { this.updateBy = updateBy; } public Long getCreatedId() { return createdId; } public void setCreatedId(Long createdId) { this.createdId = createdId; } public Long getUpdateId() { return updateId; } public void setUpdateId(Long updateId) { this.updateId = updateId; } public Date getUpdateTime() { return updateTime; } public void setUpdateTime(Date updateTime) { this.updateTime = updateTime; } public int getIsDelete() { return isDelete; } public void setIsDelete(int isDelete) { this.isDelete = isDelete; } public String getRemark() { return remark; } public void setRemark(String remark) { this.remark = remark; } }
实体类UserEntity
import org.springframework.format.annotation.DateTimeFormat; import javax.persistence.*; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author : [WangWei] * @version : [v1.0] * @className : UserEntity * @description : [用户实体类] * @createTime : [2022/11/18 14:57] * @updateUser : [WangWei] * @updateTime : [2022/11/18 14:57] * @updateRemark : [描述说明本次修改内容] */ @Entity //声明类为实体类 @Table(name="jpa_user")//对应创建之后的表名 public class UserEntity extends BaseEntity{ @Id @Column(name = "user_code",columnDefinition = "bigint(20) COMMENT '学号'",nullable = false)//定义字段名和类型以及长度和备注,和是否允许为null private Long id; @Column(name="user_Name",nullable = false,columnDefinition = "varchar(32) COMMENT '用户名'") private String userName; @Column(name="pass_word",nullable = false,columnDefinition = "varchar(32) COMMENT '密码'") private String password; @Column(name="phone_Number",nullable = false,columnDefinition = "varchar(16) COMMENT '手机号'") private String phoneNumber; @Column(name="sex",columnDefinition = "varchar(2) COMMENT '性别'") private String sex; @Column(name="birthday",nullable = false,columnDefinition = "datetime COMMENT '生日日期'") @DateTimeFormat(pattern = "yyyy-MM-dd ") private Date birthday; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
启动类
此时已经可以直接运行启动类,启动程序时候在数据库中会直接生成相应的表。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SpringDataJpaApplication { public static void main(String[] args) { SpringApplication.run(SpringDataJpaApplication.class, args); } }
可以在mysql中查看,或者在Navicat上查看到已经创建的表
创建数据访问层
在repository中创建UserRepository接口继承JpaRepository接口,JpaRepository接口提供了一些的增删改查的方法。
JpaRepository接口
@NoRepositoryBean public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#findAll() */ @Override List<T> findAll(); /* * (non-Javadoc) * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort) */ @Override List<T> findAll(Sort sort); /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable) */ @Override List<T> findAllById(Iterable<ID> ids); /* * (non-Javadoc) * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable) */ @Override <S extends T> List<S> saveAll(Iterable<S> entities); /** * Flushes all pending changes to the database. */ void flush(); /** * Saves an entity and flushes changes instantly. * * @param entity * @return the saved entity */ <S extends T> S saveAndFlush(S entity); /** * Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear * the {@link javax.persistence.EntityManager} after the call. * * @param entities */ void deleteInBatch(Iterable<T> entities); /** * Deletes all entities in a batch call. */ void deleteAllInBatch(); /** * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is * implemented this is very likely to always return an instance and throw an * {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers * immediately. * * @param id must not be {@literal null}. * @return a reference to the entity with the given identifier. * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown. */ T getOne(ID id); /* * (non-Javadoc) * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example) */ @Override <S extends T> List<S> findAll(Example<S> example); /* * (non-Javadoc) * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort) */ @Override <S extends T> List<S> findAll(Example<S> example, Sort sort); }
UserRepository接口
import com.example.springdatajpa.entity.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; /** * @author : [WangWei] * @version : [v1.0] * @className : UserRepository * @description : [User数据访问接口] * @createTime : [2022/11/19 19:15] * @updateUser : [WangWei] * @updateTime : [2022/11/19 19:15] * @updateRemark : [描述说明本次修改内容] */ public interface UserRepository extends JpaRepository<UserEntity,Long> { }
JpaRepository<T, ID>T表示实体的类型,ID表示实体类中ID的类型。
使用Spring Data JPA 创建带条件的CRUD
由于JpaRepository<T, ID>接口只定义了一些较为简单的CRUD,但是对于一些带条件的CRUDJpaRepository并没有给出,但是我们可以在继承JpaRepository<T, ID>接口的接口中创建相应的方法。
import com.example.springdatajpa.entity.UserEntity; import org.springframework.data.jpa.repository.JpaRepository; /** * @author : [WangWei] * @version : [v1.0] * @className : UserRepository * @description : [描述说明该类的功能] * @createTime : [2022/11/19 19:15] * @updateUser : [WangWei] * @updateTime : [2022/11/19 19:15] * @updateRemark : [描述说明本次修改内容] */ public interface UserRepository extends JpaRepository<UserEntity,Long> { /* * @version V1.0 * Title: findUserEntitiesByPhoneNumberAndIsDelete * @author Wangwei * @description 根据手机号查询 * @createTime 2022/11/20 10:00 * @param [phoneNumber, isDelete] * @return com.example.springdatajpa.entity.UserEntity */ UserEntity findUserEntitiesByPhoneNumberAndIsDelete(String phoneNumber,int isDelete); }
创建相应的方法,先定义方法的返回值,在定义操作类型(find,delete,search)+By+条件
如果有需要可以参考Spring Data Jpa官网上Spring Data Jpa