likes
comments
collection
share

Spring Data JPA 的基本使用

作者站长头像
站长
· 阅读数 18

1JPA 是什么

JPA(Java Persistence API)是 Sun 官方提出的 Java 持久化规范。它为 Java 开发人员提供了一种对象 / 关联映射工具来管理 Java 应用中的关系数据。它的出现主要是为了简化现有的持久化开发工作和整合 ORM 技术,结束现在 Hibernate、TopLink、JDO 等 ORM 框架各自为营的局面。

值得注意的是,JPA 是在充分吸收了现有的 Hibernate、TopLink、JDO 等 ORM 框架的基础上发展而来的,具有易于使用、伸缩性强等优点。从目前的开发社区的反应上看,JPA 受到了极大的支持和赞扬,其中就包括了 Spring 与 EJB 3.0 的开发团队。

JPA 是一套规范,不是一套产品,那么像 Hibernate、TopLink、JDO 它们是一套产品,如果说这些产品实现了这个 JPA 规范,那么我们就可以称他们为 JPA 的实现产品。

2 Spring Data JPA

Spring Data JPA 是 Spring 基于 ORM 框架、JPA 规范的基础上封装的一套 JPA 应用框架,可以让开发者用极简的代码即可实现对数据的访问和操作。它提供了包括增、删、改、查等在内的常用功能,且易于扩展,学习并使用 Spring Data JPA 可以极大提高开发效率。Spring Data JPA 其实就是 Spring 基于 Hibernate 之上构建的 JPA 使用解决方案,方便在 Spring Boot 项目中使用 JPA 技术。

Spring Data JPA 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它实现。

添加依赖

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

配置文件

spring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.jpa.properties.hibernate.hbm2ddl.auto=create
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
#SQL 输出
spring.jpa.show-sql=true
#format 一下 SQL 进行输出
spring.jpa.properties.hibernate.format_sql=true

hibernate.hbm2ddl.auto 参数的作用主要用于:自动创建、更新、验证数据库表结构,有四个值。

create:

每次加载 Hibernate 时都会删除上一次生成的表,然后根据 model 类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。

create-drop:

每次加载 Hibernate 时根据 model 类生成表,但是 sessionFactory 一关闭,表就自动删除。

update:

最常用的属性,第一次加载 Hibernate 时根据 model 类会自动建立起表的结构(前提是先建立好数据库),以后加载 Hibernate 时根据 model 类自动更新表结构,即使表结构改变了,但表中的行仍然存在,不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。

validate :

每次加载 Hibernate 时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。

其中:

dialect 主要是指定生成表名的存储引擎为 InnoDB show-sql 是否在日志中打印出自动生成的 SQL,方便调试的时候查看

实体类

import javax.persistence.*;

@Api("使用jpa 创建数据库 映射实体")
@Entity // 数据库表名默认与类名相同
@Data
@EqualsAndHashCode
@ToString
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(nullable = false,unique = true, length=32)
    private String userName;
    @Column(nullable = false)
    private String passWord;
    @Column(nullable = false, unique = false)
    private String email;
    @Column(nullable = true,unique = false)
    private String nickName;
    @Column(nullable = false)
    private String regTime;

    @Transient  //并非一个到数据库表的字段的映射,ORM 框架将忽略该属性。
    private String username;

    public Student(String userName, String passWord, String email, String nickName, String regTime) {
        this.userName = userName;
        this.passWord = passWord;
        this.email = email;
        this.nickName = nickName;
        this.regTime = regTime;
    }
}

实体类中的注解说明 @Entity(name=“EntityName”) 必须,用来标注一个数据库对应的实体,数据库中创建的表名默认和类名一致。其中,name 为可选,对应数据库中一个表,使用此注解标记 Pojo 是一个 JPA 实体。

@Table(name="",catalog="",schema="") 可选,用来标注一个数据库对应的实体,数据库中创建的表名默认和类名一致。通常和 @Entity 配合使用,只能标注在实体的 class 定义处,表示实体对应的数据库表的信息。

@Id 必须,@Id 定义了映射到数据库表的主键的属性,一个实体只能有一个属性被映射为主键。

@GeneratedValue(strategy=GenerationType,generator="") 可选,strategy: 表示主键生成策略,有 AUTO、INDENTITY、SEQUENCE 和 TABLE 4 种,分别表示让 ORM 框架自动选择,generator: 表示主键生成器的名称。

@Column(name = “user_code”, nullable = false, length=32) 可选,@Column 描述了数据库表中该字段的详细定义,这对于根据 JPA 注解生成数据库表结构的工具。name: 表示数据库表中该字段的名称,默认情形属性名称一致;nullable: 表示该字段是否允许为 null,默认为 true;unique: 表示该字段是否是唯一标识,默认为 false;length: 表示该字段的大小,仅对 String 类型的字段有效。

@Transient可选,@Transient 表示该属性并非一个到数据库表的字段的映射,ORM 框架将忽略该属性。

@Enumerated 可选,使用枚举的时候,我们希望数据库中存储的是枚举对应的 String 类型,而不是枚举的索引值,需要在属性上面添加 @Enumerated(EnumType.STRING) 注解。

dao层

创建的 Repository 只要继承 JpaRepository 就可以了。

JpaRepository 类中

@Repository
public interface StudentRepository extends JpaRepository<Student,Long> {
    public Student findByUserName(String userName);

    //自定义查询
    //根据名字查询,并且 emaile模糊查询
    List<Student> findByNickNameLikeOrEmailLike(String nickName, String email);
    List<Student> findByuserNameLike(String userName);
}

JpaRepository 方法中为我们默认提供了很多crud方法,以及查询方法

@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);
}

PagingAndSortingRepository 集成了CrudRepository接口 CrudRepository 接口为我们提供了很多的查询 删除 以及新增修改方法

public interface CrudRepository<T, ID> extends Repository<T, ID> {
    <S extends T> S save(S var1);

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

    Optional<T> findById(ID var1);

    boolean existsById(ID var1);

    Iterable<T> findAll();

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

    long count();

    void deleteById(ID var1);

    void delete(T var1);

    void deleteAll(Iterable<? extends T> var1);

    void deleteAll();
}

以及PagingAndSortingRepository , QueryByExampleExecutor 查询接口

public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
    Iterable<T> findAll(Sort var1);

    Page<T> findAll(Pageable var1);
}
public interface QueryByExampleExecutor<T> {
    <S extends T> Optional<S> findOne(Example<S> var1);

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

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

    <S extends T> Page<S> findAll(Example<S> var1, Pageable var2);

    <S extends T> long count(Example<S> var1);

    <S extends T> boolean exists(Example<S> var1);
}

当然这些查询方法在无法满足我的业务查询情况下,jpa为我们提供了自定义查询规则,我们只需要在接口中自定义查询即可。 但必须遵守一个自定义查询规则。

Spring Data JPA 可以根据接口方法名来实现数据库操作,主要的语法是 findXXBy、readAXXBy、queryXXBy、countXXBy、getXXBy 后面跟属性名称,利用这个功能仅需要在定义的 Repository 中添加对应的方法名即可,使用时 Spring Boot 会自动帮我们实现,示例如下。

如:

根据名字模糊查询或者 email模糊查询
List<Student> findByNickNameLikeOrEmailLike(String nickName, String email);
根据名字模糊查询
List<Student> findByuserNameLike(String userName);

当然删除也是一样,只要遵循Jpa命名规则即可,Jpa会在底层帮我们自动生成sql语句

修改、删除、统计也是类似语法:

Long deleteById(Long id);
Long countByUserName(String userName)

可以根据查询的条件不断地添加和拼接,Spring Boot 都可以正确解析和执行,其他使用示例可以参考下表。

具体的关键字,使用方法和生产成 SQL 如下表所示

KeywordSampleJPQL snippet
AndfindByLastnameAndFirstname… where x.lastname = ?1 and x.firstname = ?2
OrfindByLastnameOrFirstname… where x.lastname = ?1 or x.firstname = ?2
Is,EqualsfindByFirstnameIs,findByFirstnameEquals… where x.firstname = ?1
BetweenfindByStartDateBetween… where x.startDate between ?1 and ?2
LessThanfindByAgeLessThan… where x.age < ?1
LessThanEqualfindByAgeLessThanEqual… where x.age ⇐ ?1
GreaterThanfindByAgeGreaterThan… where x.age > ?1
GreaterThanEqualfindByAgeGreaterThanEqual… where x.age >= ?1
AfterfindByStartDateAfter… where x.startDate > ?1
BeforefindByStartDateBefore… where x.startDate < ?1
IsNullfindByAgeIsNull… where x.age is null
IsNotNull,NotNullfindByAge(Is)NotNull… where x.age not null
LikefindByFirstnameLike… where x.firstname like ?1
NotLikefindByFirstnameNotLike… where x.firstname not like ?1
StartingWithfindByFirstnameStartingWith… where x.firstname like ?1 (parameter bound with appended %)
EndingWithfindByFirstnameEndingWith… where x.firstname like ?1 (parameter bound with prepended %)
ContainingfindByFirstnameContaining… where x.firstname like ?1 (parameter bound wrapped in %)
OrderByfindByAgeOrderByLastnameDesc… where x.age = ?1 order by x.lastname desc
NotfindByLastnameNot… where x.lastname <> ?1
InfindByAgeIn(Collectionages)… where x.age in ?1
NotInfindByAgeNotIn(Collectionage)… where x.age not in ?1
TRUEfindByActiveTrue()… where x.active = true
FALSEfindByActiveFalse()… where x.active = false
IgnoreCasefindByFirstnameIgnoreCase… where UPPER(x.firstame) = UPPER(?1)

controller


@Api("api jpa测试返回  controller ")
@RestController
public class StudentController {

    @Autowired
    private StudentRepository studentRepository;

    @RequestMapping("test1")
    public void test1(){
        Student s1 = new Student("张三5", "123123", "123@qq.com","nickName1", LocalDate.now().toString());
        studentRepository.save(s1);

        List<Student> student = studentRepository.findByUserNameOrEmailLike("张", "3");
        System.out.println(student);


        s1 = new Student("张三6", "1231232222", "234@qq.com","nickName2", LocalDate.now().toString());
        studentRepository.save(s1);


        //studentRepository.deleteById(1L);
        s1 = new Student("张三7", "12312322221", "2345@qq.com","nickName3", LocalDate.now().toString());
        studentRepository.save(s1);


        List<Student> nic = studentRepository.findByNickNameLikeOrEmailLike("%nic%", "%3%");
        System.out.println("nic " + nic);

        List<Student> byuserNameLike = studentRepository.findByuserNameLike("%张%");
        System.out.println("byuserNameLike " + byuserNameLike);

    }
}

控制台打印结果

Hibernate: insert into student (email, nick_name, pass_word, reg_time, user_name) values (?, ?, ?, ?, ?)
2019-06-29 17:07:18.492  INFO 1256 --- [nio-8181-exec-1] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
Hibernate: select student0_.id as id1_0_, student0_.email as email2_0_, student0_.nick_name as nick_nam3_0_, student0_.pass_word as pass_wor4_0_, student0_.reg_time as reg_time5_0_, student0_.user_name as user_nam6_0_ from student student0_ where student0_.user_name=? or student0_.email like ?
[]
Hibernate: insert into student (email, nick_name, pass_word, reg_time, user_name) values (?, ?, ?, ?, ?)
Hibernate: insert into student (email, nick_name, pass_word, reg_time, user_name) values (?, ?, ?, ?, ?)
Hibernate: select student0_.id as id1_0_, student0_.email as email2_0_, student0_.nick_name as nick_nam3_0_, student0_.pass_word as pass_wor4_0_, student0_.reg_time as reg_time5_0_, student0_.user_name as user_nam6_0_ from student student0_ where student0_.nick_name like ? or student0_.email like ?
nic [Student(id=1, userName=张三5, passWord=123123, email=123@qq.com, nickName=nickName1, regTime=2019-06-29, username=张三5), Student(id=2, userName=张三6, passWord=1231232222, email=234@qq.com, nickName=nickName2, regTime=2019-06-29, username=张三6), Student(id=3, userName=张三7, passWord=12312322221, email=2345@qq.com, nickName=nickName3, regTime=2019-06-29, username=张三7)]
Hibernate: select student0_.id as id1_0_, student0_.email as email2_0_, student0_.nick_name as nick_nam3_0_, student0_.pass_word as pass_wor4_0_, student0_.reg_time as reg_time5_0_, student0_.user_name as user_nam6_0_ from student student0_ where student0_.user_name like ?
byuserNameLike [Student(id=1, userName=张三5, passWord=123123, email=123@qq.com, nickName=nickName1, regTime=2019-06-29, username=张三5), Student(id=2, userName=张三6, passWord=1231232222, email=234@qq.com, nickName=nickName2, regTime=2019-06-29, username=张三6), Student(id=3, userName=张三7, passWord=12312322221, email=2345@qq.com, nickName=nickName3, regTime=2019-06-29, username=张三7)]

数据库生成的表 Spring Data JPA 的基本使用

总结

使用Jpa可以大大大解决我们操作数据库,解放生产力,自动生成sql,自动建表等。 但也存在一个缺点,sql已经生成,我们无法对sql进行操作,无法进行sql调优。

单标crud效率贼高,但是多表查询,级联查询等操作就要用到 Jpa高级特性了,面对实际开发中的复杂业务就显得有点儿地效率了,这方面用orm框架 mybatis比较多。

转载自:https://juejin.cn/post/7231788630306816059
评论
请登录