SpringBoot项目中使用Jpa(SpringDataJpa)

SpringBoot项目中使用Jpa(SpringDataJpa)

前言

  • JPA是 Java Persistence API 的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关 系,并将运行期的实体对象持久化到数据库中。
  • 在ORM框架中,Hibernate是一支很大的部队,使用很广泛,也很方便,能力也很强,同时Hibernate也是和JPA整 合的比较良好,我们可以认为JPA是标准,实际上也是,JPA几乎都是接口,实现都是Hibernate在做,宏观上面看,在 JPA的统一之下Hibernate很良好的运行。
  • 我们都知道Spring的强劲,到目前为止,企业级应用Spring几乎是无所不能,无所不在,已经是实际上的标准了, 企业级应用不使用Spring的几乎没有。而Spring整合第三方框架的能力又很强,他要做的不仅仅是个最早的IOC容器这 么简单一回事,目前Spring涉及的方面太广,主要是体目前和第三方工具的整合上。而在与第三方整合这方面,Spring 希望把持久化这块内容也拿下。于是就有了Spring-data-**这一系列包。包括,Spring-data-jpa,Spring-data- template,Spring-data-mongodb,Spring-data-redis,还有个民间产品,mybatis-spring,和前面类似,这是和 mybatis整合的第三方包,这些都是干的持久化工具干的事儿。
  • 这里介绍Spring-data-jpa,表明与Jpa的整合
  • SpringData

:实则SpringData就是Spring提供了一个操作数据的框架。而SpringData JPA只是SpringData框架下的一个基于JPA标准操作数据的模块,总得包括以下:

    • ORM映射:支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系
    • API:操作实体对象来执行CRUD操作
    • 查询语言:通过面向对象而非面向数据库的查询语言(JPQL)查询数据,避免程序的SQL语句紧密耦合
  • SpringDataJPA

:基于JPA的标准数据进行操作。简化操作持久层的代码。只需要编写接口就可以。

  • 后面博主会陆续写出Jpa的关联关系和增删改查以及连表查询操作,欢迎关注

什么是Spring Data Jpa

Spring Data Jpa是Spring Data家族的一部分,Spring Data JPA相对于Java EE中的JPA,配置更简单,以轻量级的方式实现了部分在 EJB 容器环境下才具有的功能,将 EntityManager 的创建与销毁、事务管理等代码抽取出来,并由其统一管理,并且极大的简化了数据库访问层的代码。 Spring Data包含众多子项目除了JPA还有Spring Data MongoDB等等


SpringJpa 的运行原理

  1. SpringJPA 的全称是 Spring Data JPA 。其中JPA是 Java Persistence API 的缩写(Java持久化API),是SUN公司推出的一套接口,一套标准,Hibernate是一个具体的ORM的持久层框架(类似于Mybatis框架)实现了JPA接口 。
  2. Spring Data 是Spring开发团队提供的一套标准API和不同持久层整合技术实现。Spring Data 的出现就是为了简化、统一持久层的各种实现技术API。 (注:Spring Data 在项目里以 spring-data-commons 这个jar存在 )
  3. Spring Data JPA 既实现了 Spring Data 接口又实现了JPA接口,也是为了简化持久层的开发。 (注:Spring Data JPA 在项目里以 spring-data-jpa 这个jar存在

SpringJpa 优点

  1. 提供统一的接口,可避免我们再次重复的编写基础的DAO类;
  2. 遵循JPA规范,同时也提供了灵活的数据访问方式;
  3. 通过方法名即可自动生成HQL语句;
  4. 通过接口自动注入实现类,实现超级简单。

Spring Data JPAMyBatis 对比

Spring Data JPAMyBatis 对比,实际上就是 HibernateMyBatis 的对比,具体如下:

从基本概念和框架目标上看,两个框架差别还是很大的。 hibernate是一个自动化更强、更高级的框架,毕竟在java代码层面上,省去了绝大部分sql编写,取而代之的是 用面向对象的方式操作关系型数据库的数据。 MyBatis则是一个能够灵活编写sql语句,并将sql的入参和查询结果映射成POJOs的一个持久层框架。所以,从表 面上看,hibernate能方便、自动化更强,而MyBatis 在Sql语句编写方面则更灵活自由。

注:至于这两个框架用哪一个,可以根据自己的掌握情况或者使用场景进行选择。我个人推荐使用Spring Data JPA,由于的确很简单,符合灵敏开发要求。


SpringBoot 引入 SpringDataJpa 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

在yml文件配置如下,按需索取

spring:
  datasource:
    url:  jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&allowMultiQueries=true&useSSL=false
    username: root
    password: root
  jpa:
    database: mysql
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    show-sql: true
    hibernate:
      ddl-auto: update # 一般使用update
        # create: 每次运行程序时,都会重新创建表,故而数据会丢失
        # create-drop: 每次运行程序时会先创建表结构,然后待程序结束时清空表
        # upadte: 每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)
        # validate: 运行程序会校验数据与数据库的字段类型是否一样,字段不同会报错
        # none: 禁用DDL处理

这里贴出来博主的一些配置:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.jmccms</groupId>
    <artifactId>Jmccms</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Jmccms</name>
    <url>https://repo.spring.io/milestone</url>
    <description>CYJ:ChenYongJia 服务提供者Jmccms</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!-- 项目属性配置信息 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <!--引入spring-boot  2.1.1.RELEASE ,SpringCloud的版本为 Greenwich.M3-->
        <spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
        <mysql-connector>5.1.39</mysql-connector>
        <junit-version>4.12</junit-version>
        <druid>1.0.18</druid>
        <!--<activiti.version>6.0.0</activiti.version>-->
    </properties>

    <dependencies>

        <!-- 引入web依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- 引入AOP -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <!--<dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.9.3</version>
        </dependency>-->

        <!-- SpringCloud Eureka 注册中心依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- SpringCloud Hystrix 微服务容错监控组件:断路器,依赖隔离,服务降级,服务监控 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

        <!-- 权限控制Spring-Oauth2.0的认证模式依赖暂时不用,由于一些注解和API从spring security5.0中移除,所以需要导入下面的依赖包 -->
        <!-- spring-cloud-starter-oauth2 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <!-- SpringCloud Feign 依赖 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!-- Spring Boot JPA 依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <!-- 引入test测试依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- Junit 单元测试 依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

        <!-- 引入redis数据库依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <!-- 引入jdbc链接依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- 引入security权限依赖模块 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- 引入Thymeleaf模板 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <!-- 引入mysql链接依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql-connector}</version>
        </dependency>

        <!-- 引入 Lombok 依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- Spring Boot devtools 热部署 依赖 -->
        <!--<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
        </dependency>-->

        <!-- alibaba的fastjson工具 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>

        <!-- 引入Gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>

        <!-- 阿里开源EXCEL -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>easyexcel</artifactId>
            <version>1.1.2-beta5</version>
        </dependency>

        <!--<dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>-->

        <!-- 用于字符串工具类 -->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <!--<version>3.8.1</version>-->
            <version>3.6</version>
            <scope>provided</scope>
        </dependency>

        <!-- 使用httpclient获取天气信息 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.8</version>
        </dependency>

        <!-- 引入工作流 -->
        <!--<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-basic</artifactId>
            <version>${activiti.version}</version>
        </dependency>-->

        <!--<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-actuator</artifactId>
            <version>${activiti.version}</version>
        </dependency>-->

        <!--<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-rest</artifactId>
            <version>${activiti.version}</version>
        </dependency>-->

        <!-- 整合swagger2 -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- 整合swagger-ui -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- eu协助类 -->
        <dependency>
            <groupId>eu.bitwalker</groupId>
            <artifactId>UserAgentUtils</artifactId>
            <version>1.21</version>
        </dependency>

    </dependencies>

    <!-- SpringCloud 所有子项目 版本聚焦管理.MS:统一所有SpringCloud依赖项目的版本 依赖 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <!-- SpringBoot 2.1.X 以上版本这样配置 -->
                <version>${spring-cloud.version}</version>
                <!-- <version>Dalston.RC1</version> -->
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <!-- SpringBoot 项目打jar包的Maven插件 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <!-- SpringBoot项目打包jar名称 -->
        <finalName>jmccms</finalName>
    </build>

    <!-- SpringCloud 官方远程仓库.MS:部分本地仓库和镜像仓库没有SpringCloud子项目依赖。 -->
    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

</project>

使用 Spring Data Jpa 增删改查(当然一般都和 lombok 结合使用)

第一步先创建你的数据库和配置文件保持一致,Jpa将自动帮你建表

package com.jmccms.entity;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
import org.springframework.format.annotation.DateTimeFormat;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * @Description: 用户类
 * @BelongsProject: Jmccms
 * @BelongsPackage: com.jmccms.entity
 * @Author: ChenYongJia
 * @CreateTime: 2019-05-02 15:32
 * @Email chen87647213@163.com
 */
@Getter
@Setter
@AllArgsConstructor // 自动所有参数的构造方法方法
@NoArgsConstructor // 自动无参的构造方法方法
@Builder
@Entity
@Table(name = "jmccms_user")
public class User implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @OrderBy
    @Column(columnDefinition = "bigint(19) unsigned  COMMENT '用户id'")
    private Long userId;
    @Column(columnDefinition = "varchar(64) NOT NULL COMMENT '用户名称'  ")
    private String userName;
    @Column(columnDefinition = "varchar(100) NOT NULL COMMENT '用户密码'  ")
    private String userPassWord;
    @Column(columnDefinition = "datetime COMMENT '用户创建时间' ")
    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")    //日期格式化为中国的时区 东8区
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    //接受::字符串日期需要格式化为日期类型
    private Date userCreateTime;
    @Column(columnDefinition = "datetime COMMENT '用户最后一次登录时间' ")
    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")    //日期格式化为中国的时区 东8区
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    //接受::字符串日期需要格式化为日期类型
    private Date userLastLoginTime;
    @Column(columnDefinition = "timestamp COMMENT '最后一次修改时间'", nullable = false, updatable = false, insertable = false)
    @JsonFormat(locale="zh", timezone="GMT+8", pattern="yyyy-MM-dd HH:mm:ss")    //日期格式化为中国的时区 东8区
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")    //接受::字符串日期需要格式化为日期类型
    private Timestamp userLastUpdateTime;
    @Column(columnDefinition = "varchar(64) NOT NULL COMMENT '创建人'  ")
    private String userFounder;
    @Column(columnDefinition = "varchar(64) COMMENT '修改人'  ")
    private String userUpdateMan;

    @JsonIgnore
    @ManyToMany(fetch = FetchType.EAGER) // 指定多对多关系
    @Cascade(value = { CascadeType.ALL }) // 设置级联关系
    @JoinTable(name = "jmccms_user_role", // 指定第三张中间表名称
            joinColumns = { @JoinColumn(name = "user_id") }, // 本表主键userId与第三张中间表user_role_tb的外键user_role_tb_user_id对应
            inverseJoinColumns = { @JoinColumn(name = "role_id") }) // 多对多关系另一张表与第三张中间表表的外键的对应关系
    @NotFound(action = NotFoundAction.IGNORE) // NotFound : 意思是找不到引用的外键数据时忽略,NotFound默认是exception
    private Set<Role> rolesSet = new HashSet<>();// 用户所拥有的角色集合

}

  • 建立数据库访问层
    • 使用 Spring Data JPA 建立数据库十分简单,只需要定义一个继承了 JpaRepository 的接口,下面是博主项目的一个类,可以参照
package com.jmccms.dao;

import com.jmccms.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import javax.transaction.Transactional;
import java.util.List;

/**
 * @Description: 用户接口
 * @BelongsProject: Jmccms
 * @BelongsPackage: com.jmccms.dao
 * @Author: ChenYongJia
 * @CreateTime: 2019-05-02 18:05
 * @Email chen87647213@163.com
 */
public interface UserRepository extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> {

    /**
     * 根据用户名和密码查询用户
     * @return
     */
    User findByUserNameAndUserPassWord(String userName, String userPassWord);

    /**
     * 根据用户名查询用户
     * @return
     */
    User findByUserName(String userName);

    /**
     * 根据用户id查询用户信息
     * @param userId
     * @return
     */
    User findByUserId(Long userId);

    /**
     * 批量删除用户信息
     *
     * @param userList
     * @return
     */
    @Query(value = "DELETE FROM jmccms_user WHERE user_id IN (:userList)", nativeQuery = true)
    @Modifying
    @Transactional
    Integer deleteUser(@Param(value = "userList") List<String> userList);

    /**
     * 根据ID查询用户角色
     *
     * @param userId
     * @return
     */
    @Query(value = "SELECT role_id FROM jmccms_user_role WHERE 1=1 AND user_id=:usersId ", nativeQuery = true)
    List<Long> getUserRole(@Param(value = "usersId") Long userId);

}
  • 继承了 JpaRepository 就相当于有了下面的数据访问操作方法,这些都是 Spring Data Jpa 封装好的。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.data.jpa.repository;

import java.util.List;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    List<T> findAll();

    List<T> findAll(Sort var1);

    List<T> findAllById(Iterable<ID> var1);

    <S extends T> List<S> saveAll(Iterable<S> var1);

    void flush();

    <S extends T> S saveAndFlush(S var1);

    void deleteInBatch(Iterable<T> var1);

    void deleteAllInBatch();

    T getOne(ID var1);

    <S extends T> List<S> findAll(Example<S> var1);

    <S extends T> List<S> findAll(Example<S> var1, Sort var2);
}

支持的关键字、示例及JPQL片段如下表所示:

Keyword

Sample

JPQL Snippet

And

findByLastnameAndFirstname

… where x.lastname = ?1 and x.firstname = ?2

Or

findByLastnameOrFirstname

… where x.lastname = ?1 or x.firstname = ?2

Is,Equals

indByFirstname,findByFirstnameIs,findByFirstnameEquals

… where x.firstname = ?1

Between

findByStartDateBetween

… where x.startDate between ?1 and ?2

LessThan

findByAgeLessThan

… where x.age < ?1

LessThanEqual

findByAgeLessThanEqual

… where x.age <= ?1

GreaterThan

findByAgeGreaterThan

… where x.age > ?1

GreaterThanEqual

findByAgeGreaterThanEqual

… where x.age >= ?1

After

findByStartDateAfter

… where x.startDate > ?1

Before

findByStartDateBefore

… where x.startDate < ?1

IsNull

findByAgeIsNull

… where x.age is null

IsNotNull,NotNull

findByAge(Is)NotNull

… where x.age not null

Like

findByFirstnameLike

… where x.firstname like ?1

NotLike

findByFirstnameNotLike

… findByFirstnameNotLike

StartingWith

findByFirstnameStartingWith

… where x.firstname like ?1 (parameter bound with appended %)

EndingWith

findByFirstnameEndingWith

… where x.firstname like ?1 (parameter bound with prepended %)

Containing

findByFirstnameContaining

… where x.firstname like ?1 (parameter bound wrapped in %)

OrderBy

findByAgeOrderByLastnameDesc

… where x.age = ?1 order by x.lastname desc

Not

findByLastnameNot

… where x.lastname <> ?1

In

findByAgeIn(Collection ages)

… where x.age in ?1

NotIn

findByAgeNotIn(Collection ages)

… where x.age not in ?1

True

findByActiveTrue()

… where x.active = true

False

findByActiveFalse()

… where x.active = false

IgnoreCase

findByFirstnameIgnoreCase

… where UPPER(x.firstame) = UPPER(?1)

#头条创作挑战赛#

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容