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


    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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

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

    @Repository
    public interface DictionaryDao extends JpaRepository {
    }
    
    • 1
    • 2
    • 3

    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字句
    AndfindByNameAndPwdwhere name= ? and pwd =?
    OrfindByNameOrSexwhere name= ? or sex=?
    Is,EqualsfindById,findByIdEqualswhere id= ?
    BetweenfindByIdBetweenwhere id between ? and ?
    LessThanfindByIdLessThanwhere id < ?
    LessThanEqualsfindByIdLessThanEqualswhere id <= ?
    GreaterThanfindByIdGreaterThanwhere id > ?
    GreaterThanEqualsfindByIdGreaterThanEqualswhere id > = ?
    AfterfindByIdAfterwhere id > ?
    BeforefindByIdBeforewhere id < ?
    IsNullfindByNameIsNullwhere name is null
    isNotNull,NotNullfindByNameNotNullwhere name is not null
    LikefindByNameLikewhere name like ?
    NotLikefindByNameNotLikewhere name not like ?
    StartingWithfindByNameStartingWithwhere name like ‘?%’
    EndingWithfindByNameEndingWithwhere name like ‘%?’
    ContainingfindByNameContainingwhere name like ‘%?%’
    OrderByfindByIdOrderByXDescwhere id=? order by x desc
    NotfindByNameNotwhere name <> ?
    InfindByIdIn(Collection c)where id in (?)
    NotInfindByIdNotIn(Collection c)where id not in (?)
    TruefindByAaaTuewhere aaa = true
    FalsefindByAaaFalsewhere aaa = false
    IgnoreCasefindByNameIgnoreCasewhere 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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    2. 查询

    2.1 条件查询

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

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

    2.2 查询排序

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

    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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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();
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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();
    
    • 1
    • 2
    • 3

    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);
    
    • 1
    • 2
    • 3
    • 4
    @Modifying
    @Transactional
    void deleteByName(String name);
    
    • 1
    • 2
    • 3

    踩坑

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

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

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

  • 相关阅读:
    c#、wpf开发中页面在win10下被缩放125%引起页面错乱的解决办法。
    BPMN是什么
    nero platinum刻录光盘简要教程(文章末尾有教程链接)
    WooCommerce数据库解释:它是如何工作的以及在哪里可以找到数据
    GPT-5: 超越人类语言的模型,你还不了解一下?
    多元共进|科技促进艺术发展,助力文化传承
    Linux引入中saltstack介绍与使用
    基于偏二叉树SVM多分类算法的应用层DDoS检测方法
    cad怎么转换成pdf格式黑白?
    (vue)数组对象去重
  • 原文地址:https://blog.csdn.net/weixin_45698637/article/details/124327479