SpringBoot + Jpa 详细使用教程(企业开发使用总结)

SpringBoot + Jpa 实战教程

  • JPA 介绍
  • JPA 简单使用示例
  • JPA 实体类中相关注解说明
  • JPA 持久层关键字说明
  • 实战:JPA企业开发示例
    • 1. 实体继承基础通用属性
    • 2. 查询
      • 2.1 条件查询
      • 2.2 查询排序
      • 2.3 分页查询
      • 2.4 动态条件查询
      • 2.5 多表联查
      • 2.6 返回自定义Vo
    • 3. 修改和删除
  • 踩坑

JPA 介绍

JPA(Java Persistence API),对象关系映射(ORM)框架规范,是一种Java持久化规范。jpa可以通过实体类生成数据库的表,同时自带很多增删改查方法,大部分sql语句不需要我们自己写,配置完成后直接调用方法即可,很方便。

JPA 简单使用示例

1. pom.xml

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-webartifactId>
dependency>

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
 
<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
dependency>

2. application.properties配置

# 数据库连接配置
spring.datasource.url = jdbc:mysql://localhost:3306/manageserver?serverTimezone=Asia/Shanghai
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driver-class-name = com.mysql.cj.jdbc.Driver
# jpa配置
# 自动更新数据库表
spring.jpa.hibernate.ddl-auto=update
spring.jpa.hibernate.naming.physical-strategy=org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
# 是否在控制台显示Hibernate的sql
spring.jpa.show-sql = false

3. 创建实体类对象,用于映射数据库表

@Table(name="db_dictionary")
@Data
@Entity
public class DbDictionary implements Serializable {

    @Id
    @GenericGenerator(name = "faceset_generator", strategy = "uuid")
    @GeneratedValue(generator = "faceset_generator")
    @Column
    private String id;

    /**
     * 类型名称
     */
    @Size(max = 50)
    @Column
    @NotNull
    private String type;

    /**
     * 中文
     */
    @Column
    @NotNull
    private String name;

    /**
     * 代码
     */
    @Column
    @NotNull
    private String code;


    /**
     * 顺序
     */
    private Integer sort;

    /**
     * 描述信息
     */
    @Column
    private String remark;


    private static final long serialVersionUID = 1L;
}

4. 创建持久化接口DAO,继承JpaRepository,用于对数据库进行操作

@Repository
public interface DictionaryDao extends JpaRepository {
}

5. 至此,JPA基本配置已经完成,这里自带很多内置的增删改查方法,不用我们自己写sql语句,直接调用即可。

JPA 实体类中相关注解说明

  • @Entity:表明是一个实体类
  • @Table(name = "dict_info"):对应的数据表名,与@Entity注解一块使用,但是如果表名和实体类名相同的话,@Table可以省略
  • @GenericGenerator(name = "jpa-uuid", strategy = "uuid"):自定义hibernate主键生成策略
  • @Id:表示当前字段为主键
  • @GeneratedValue(generator = "jpa-uuid"):指定主键生成策略为uuid
  • @Column(name = "DICTNAME"):当实体类的属性与其映射的数据库表的列不同名时需要使用@Column 标注说明
  • @CreatedDate:创建时间
  • @LastModifiedDate:更新时间
  • @Temporal(TemporalType.TIMESTAMP):实体类会封装成完整的时间“yyyy-MM-dd hh:MM:ss”的 Date类型
  • @Transient:表示该属性并非一个到数据库表的字段的映射,ORM框架将忽略该属性

JPA 持久层关键字说明

JPA Data的使用模式已经帮我集成了日常一些关键字用法,通过查询可以直接使用!

关键字 方法命名 sql where字句
And findByNameAndPwd where name= ? and pwd =?
Or findByNameOrSex where name= ? or sex=?
Is,Equals findById,findByIdEquals where id= ?
Between findByIdBetween where id between ? and ?
LessThan findByIdLessThan where id < ?
LessThanEquals findByIdLessThanEquals where id <= ?
GreaterThan findByIdGreaterThan where id > ?
GreaterThanEquals findByIdGreaterThanEquals where id > = ?
After findByIdAfter where id > ?
Before findByIdBefore where id < ?
IsNull findByNameIsNull where name is null
isNotNull,NotNull findByNameNotNull where name is not null
Like findByNameLike where name like ?
NotLike findByNameNotLike where name not like ?
StartingWith findByNameStartingWith where name like ‘?%’
EndingWith findByNameEndingWith where name like ‘%?’
Containing findByNameContaining where name like ‘%?%’
OrderBy findByIdOrderByXDesc where id=? order by x desc
Not findByNameNot where name <> ?
In findByIdIn(Collection c) where id in (?)
NotIn findByIdNotIn(Collection c) where id not in (?)
True findByAaaTue where aaa = true
False findByAaaFalse where aaa = false
IgnoreCase findByNameIgnoreCase where UPPER(name)=UPPER(?)

实战:JPA企业开发示例

1. 实体继承基础通用属性

/**
 * 实体继承映射类基础 ,保存实体的通用属性
 *
 * @date: 2022-05-29
 * @author: Buckletime
 */
@Data
@Accessors(chain = true)
@MappedSuperclass   //实体继承映射
public abstract class BaseEntity implements Serializable {

    /**
     * 创建者
     */
    @Basic
    @Column(length = 50)
    private String creator;

    /**
     * 修改者
     */
    @Basic
    @Column(length = 50)
    private String modifier;

    /**
     * 创建时间
     */
    @Basic
    @Column(name = "create_time")
    @CreatedDate
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;

    /**
     * 修改时间
     */
    @Basic
    @Column(name = "update_time")
    @LastModifiedDate
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date updateTime;

}

2. 查询

2.1 条件查询

条件查询有两种方式,一是直接使用持久层提供的关键字,二是自己写查询SQL。

// 根据名称和性别查询用户
User findByNameAndSex(String name, String sex);
@Query(nativeQuery = true, value = "select * from user where name = :name and sex = :sex")
User findByNameAndSex(@Param("name") String name, @Param("sex") String sex);

2.2 查询排序

List<T> findAll(Sort sort);
//按创建时间倒序排列
Sort.by("createTime").descending()

2.3 分页查询

Page<T> findAll(Pageable pageable);
/*获取分页参数*/
public PageRequest getPageRequest() {
    return getPageRequest(Sort.unsorted());
}

/*获取分页和排序参数*/
public PageRequest getPageRequest(Sort sort) {
    ServletRequestAttributes attributes = getServletRequestAttributes();
    if (StringUtils.hasText(attributes.getRequest().getParameter("page")) && StringUtils.hasText(attributes.getRequest().getParameter("size"))) {
        int page = Integer.parseInt(attributes.getRequest().getParameter("page"));
        int size = Integer.parseInt(attributes.getRequest().getParameter("size"));
        return PageRequest.of(page, size, sort);
    }
    return PageRequest.of(Constants.zero, Constants.ten);
}

2.4 动态条件查询

动态条件查询Specification,DAO需要再继承JpaSpecificationExecutor接口

List<T> findAll(@Nullable Specification<T> spec);

Specification<ProjectionInfo> spec = (Specification<ProjectionInfo>) (root, query, cb) -> {
    List<Predicate> predicateList = new ArrayList<>();
    // 时间
    if (null != startTime && null != endTime) {
        predicateList.add(cb.between(root.get("createTime"), startTime, endTime));
    }
    // 数字
    if (searchDto.getCloud() != null) {
        predicateList.add(cb.le(root.<Integer>get("cloudPercent"), searchDto.getCloud()));
    }
    // 字符串
    if (searchDto.getName() != null) {
        predicateList.add(cb.equal(root.get("name"), searchDto.getName()));
    }
    // 列表
    if (StrUtil.isNotEmpty(searchDto.getSatellite())) {
        String[] satellites = searchDto.getSatellite().split(",");
        Expression<String> exp = root.<String>get("satellite");
        predicateList.add(exp.in(Arrays.asList(satellites)));
    }
    Predicate[] pre = new Predicate[predicateList.size()];
    pre = predicateList.toArray(pre);
    return query.where(pre).getRestriction();
};

2.5 多表联查

@Query(nativeQuery = true, value = "SELECT satellite, count(id), COALESCE(sum(file_size), 0) FROM t_mas_orbit_info" +
            " WHERE create_time BETWEEN :startTime AND :endTime " +
            " GROUP BY satellite")
List<Object[]> satelliteDataIncreased(@Param("startTime") Date startTime,
                                      @Param("endTime") Date endTime);

2.6 返回自定义Vo

@Query(value = "SELECT new cn.piesat.dispatch.model.vo.FileDataVO(p.id, p.fileName,p.stationCode,p.fileSize, p.fileDate, p.createTime, p.state, p.filePath,p.forwardTime) " +
            " FROM DbZxjProductInfoDTO p ")
List<FileDataVO> getFileList();

3. 修改和删除

进行修改和删除时,需要添加@Modifying@Transactional注解。

@Query(nativeQuery = true, value = "UPDATE db_order_info SET download_count = (SELECT download_count + 1) WHERE id = :orderId ")
@Modifying
@Transactional
int updateDownloadTimes(String orderId);
@Modifying
@Transactional
void deleteByName(String name);

踩坑

1.删除的方法上一定要加@Transactional和@Modifying注解
2.自定义删除方法的时候如果传的是基本类型或者包装类型一定要用 void deleteByxxx(String s) 而不是 void deleteAllByxxx(String s)。

因为deleteAllByxxx(String s)会被jpa识别为查询语句,只有传入参数是列表时才是用deleteAllByxxx(List s)

推荐使用原生sql,自带的delete或者deleteAll会先进行查询,然后在查询结果上面挨个执行删除,并不是一条sql执行完删除操作,所以还是建议自己写delete

你可能感兴趣的:(SpringBoot,spring,boot,java,jpa)