SpringBoot中JPA的学习

SpringBoot中JPA的学习

 

准备环境和项目配置

  写一下学习JPA的过程,主要是结合以前SpringBoot + Vue的项目和网上的博客学习一下。java

  首先,须要配置一下maven文件,有这么两个依赖:mysql

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

  而后是application中的配置问题,JPA有这么一些常见的参数:spring

  spring.jpa.show-sql 配置在日志中打印出执行的 SQL 语句信息。sql

  spring.jpa.hibernate.ddl-auto配置了实体类维护数据库表结构的具体行为,update表示当实体类的属性发生变化时,表结构跟着更新,也能够取值create,create表示启动的时候删除上一次生成的表,并根据实体类从新生成表,这个时候以前表中的数据就会被清空;还能够取值create-drop,这个表示启动时根据实体类生成表,可是当sessionFactory关闭的时候表会被删除;validate表示启动时验证明体类和数据表是否一致;none则什么都不作。数据库

  spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect 。在 SrpingBoot 2.0 版本中,Hibernate 建立数据表的时候,默认的数据库存储引擎选择的是 MyISAM (以前好像是 InnoDB,这点比较诡异)。这个参数是在建表的时候,将默认的存储引擎切换为 InnoDB 用的。json

  spring.jackson.serialization.indent_output=true表示格式化输出的json字符串,方便查看。segmentfault

 

定义数据实体类

  在这个项目里,数据实体类的定义方式大同小异:后端

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import javax.persistence.*; @Entity @Table(name = "book") @JsonIgnoreProperties({"handler","hibernateLazyInitializer"}) public class Book { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") int id; //把 category 对象的 id 属性做为 cid 进行了查询
 @ManyToOne @JoinColumn(name="cid") private Category category; String cover; String title; String author; String date; String press; String abs; public Category getCategory() { return category; } public void setCategory(Category category) { this.category = category; } public String getDate() { return date; } public void setDate(String date) { this.date = date; } ... }

  下面分别写一下这些注释的做用以及和其余部分关联:session

  @Entity 是一个必选的注解,声明这个类对应了一个数据库表。app

  @Table(name = "book") 是一个可选的注解。声明了数据库实体对应的表信息。包括表名称、索引信息等。这里声明这个实体类对应的表名是 book。若是没有指定,则表名和实体的名称保持一致。

  能够看一下对应的在MySQL中的数据表:

  

  其中8个属性分别表示序号、封面(存放图床的url或者本地的url地址)、标题、做者、出版日期、出版社、简介、表示类别的外键。

  @JsonIgnoreProperties由于是作先后端分离,而先后端数据交互用的是 json 格式。那么对象就会被转换为 json 数据。而本项目使用 jpa 来作实体类的持久化,jpa 默认会使用 hibernate,在 jpa 工做过程当中,就会创造代理类来继承该类 ,并添加 handler 和 hibernateLazyInitializer 这两个无须 json 化的属性,因此这里须要用 JsonIgnoreProperties 把这两个属性忽略掉。这里我看好多博主都没有写,在后面会对这个注解多作一些测试相关的内容。

  @Id表示该字段是一个id  

  @GeneratedValue注解存在的意义主要就是为一个实体生成一个惟一标识的主键、@GeneratedValue提供了主键的生成策略。@GeneratedValue注解有两个属性,分别是strategy和generator。generator属性的值是一个字符串,默认为"",其声明了主键生成器的名称。strategy属性提供四种值:1.AUTO主键由程序控制, 是默认选项 ,不设置就是这个;2.IDENTITY 主键由数据库生成, 采用数据库自增加, Oracle不支持这种方;3.SEQUENCE 经过数据库的序列产生主键, MYSQL不支持;4.Table提供特定的数据库产生主键, 该方式更有利于数据库的移植。须要注意的是不少博主将MySQL建表时设置自增属性,这里采用默认值表示自增。可是想运用到neo4j上可能要注意。

  @Column(length = 32) 用来声明实体属性的表字段的定义。默认的实体每一个属性都对应了表的一个字段。字段的名称默认和属性名称保持一致(并不必定相等)。字段的类型根据实体属性类型自动推断。这里主要是声明了字符字段的长度。若是不这么声明,则系统会采用 255 做为该字段的长度。这里的话我的感受原来博主的定义不够严谨,应该是:

@Column(length = 20) String date;

  @JoinColumn 注解的做用:用来指定与所操做实体或实体集合相关联的数据库表中的列字段。因为 @OneToOne(一对一)、@OneToMany(一对多)、@ManyToOne(多对一)、@ManyToMany(多对多) 等注解只能肯定实体之间几对几的关联关系,它们并不能指定与实体相对应的数据库表中的关联字段,所以,须要与 @JoinColumn 注解来配合使用。咱们也能够不写@JoinColumn,Hibernate会自动生成一张中间表来进行绑定,一般并不推荐让Hibernate自动去自动生成中间表,而是使用@JoinTable注解来指定中间表:  

  而后就是各个属性的get和set方法,注意下属性前面通常要加上private限制,可是这个博主没有加,不太规范这里。

 

实现持久层服务

public interface BookDAO extends JpaRepository<Book,Integer> { List<Book> findAllByCategory(Category category); /* 这个 findAllByTitleLikeOrAuthorLike,翻译过来就是“根据标题或做者进行模糊查询”, 参数是两个 String,分别对应标题或做者。 记住这个写法,我想固然的觉得是 findAllByTitleOrAuthorLike,只设置一个参数就行,结果瞎折腾了很久。 由于 DAO 里是两个参数,因此在 Service 里把同一个参数写了两遍。 用户在搜索时不管输入的是做者仍是书名,都会对两个字段进行匹配。 */ List<Book> findAllByTitleLikeOrAuthorLike(String keyword1, String keyword2); }

  声明BookDAO接口,继承JpaRepository,默认支持简单的 CRUD 操做,很是方便。  

  注意这里JpaRepository的第一个参数是刚刚定义的实体类,第二个参数是那个主键的类型,不少博客这里是有问题的。  

  而后能够放心的使用如下函数操做数据库:

<S extends T> S save(S entity); <S extends T> Iterable<S> saveAll(Iterable<S> entities);( Optional<T> findById(ID id); boolean existsById(ID id); Iterable<T> findAll(); Iterable<T> findAllById(Iterable<ID> ids); long count(); void deleteById(ID id); void delete(T entity); void deleteAll(Iterable<? extends T> entities); void deleteAll();
  关于这里JpaRepository的原理,能够参考这篇博客的内容:  
  
  这里写一下自定义JPA对应的函数名:
 
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 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 … where x.firstname not like ?1
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<age> ages)</age> … where x.age in ?1
NotIn findByAgeNotIn(Collection<age> age)</age> … 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)
相关文章
相关标签/搜索