# SpringBoot Jdbc JPAJPA是`Java Persistence API`的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中基于模板Dao的实现,使得这些具体实体的Dao层已经变的很是“薄”,有一些具体实体的Dao实现可能彻底就是对模板Dao的简单代理,而且每每这样的实现类可能会出如今不少实体上。`Spring-data-jpa`的出现正可让这样一个已经很“薄”的数据访问层变成只是一层接口的编写方式JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下建立实体和建立Java 类同样简单,没有任何的约束和限制,只须要使用 `javax.persistence.Entity`进行注释,JPA的框架和接口也都很是简单,没有太多特别的规则和设计模式的要求,开发者能够很容易的掌握。JPA基于非侵入式原则设计,所以能够很容易的和其它框架或者容器集成。# JPA sql 语法 JPQL查询语法主要分为三类:* 查询用的 SELECT 语法* 更新用的 UPDATE 语法* 删除用的 DELETE 语法SELECT 语法结构由几个部份组成: SELECT 子句 FROM 字句 [WHERE 子句] [GROUP BY 子句] [HAVING 子句] [ORDER BY 子句]一个基本的 SELECT 语句以下所示: SELECT u.id, u.name FROM User u WHERE u.age > 10 AND u.age < 20其中`User u`是个路径表示`(path expression)`,路径表示有三种:范围变数(Range variable)路径表示、群集成员(Collection member)路径表示与关联导览(Association traversing)表示。User u是范围变数路径表示的一个例子,指定查询的实体为User与别名为u。一个群集成员路径表示用来指定物件中的群集成员,例如: SELECT u FROM User u, IN(u.emails) e WHERE e.address LIKE '%.%@openhome.cc'其中IN中指定的,就是群集成员路径表示,而>、<、AND、IN、LIKE等都是WHERE子句中条件表示式,简单列出一些条件表示式以下: 比较陈述 =、>、>=、<、<=、<> BETWEEN 陈述 [NOT BETWEEN LIKE 陈述 [NOT] LIKE IN 陈述 [NOT] IN NULL 陈述 IS [NOT] NULL EMPTY 陈述 IS [NOT] EMPTY EXISTS 陈述 [NOT] EXISTSLIKE中,能够用_表示比对单一字元,用%表示比对任意数目字元。 关联导览表示则提供SQL语法中JOIN的功能,包括了`INNER JOIN`、`LEFT OUTER JOIN`、`FETCH`等,如下为INNER JOIN的实际例子: SELECT u FROM User u INNER JOINu.emails e WHERE e.address LIKE '%.%@openhome.cc' JOIN关键字能够省略,上式等同於: SELECT u FROM User u JOINu.emails e WHERE e.address LIKE '%.%@openhome.cc' LEFT OUTER JOIN的OUTER关键字能够省略,一个例子以下: SELECT u FROM User u LEFT JOIN u.emails e WHERE e.address LIKE'%.%@openhome.cc' 在做INNER JOIN、LEFT OUTER JOIN能够加上FETCH关键字,以预先撷取相关资料,例如: SELECT u FROM User u LEFT JOIN FETCH u.emails e WHERE e.address LIKE'%.%@openhome.cc' SELECT中可使用汇集函式,例如: SELECT AVG(u.age) FROM User u SELECT中可使用建构表示,直接将一些资料封装为指定的物件,例如: SELECT NEW SomeObject(u.id, u.name, o.number) FROM User u JOIN Order o WHERE u.id = 1975 WHERE子句中可使用LENGTH()、LOWER()、UPPER()、SUBSTRING()等JPQL函式。 能够对查询结果使用ORDER BY进行排序: SELECT u FROM User u ORDER BY u.age ORDER预设是ASC昇幂排序,可以使用DESC降幂排序: SELECT u FROM User u ORDER BY u.age DESC 可同时指定两个以上的排序方式,例如先按照"age"降幂排序,若是"age"相同,则按照"name"昇幂排列: SELECT u FROM User u ORDER BY u.age DESC, u.name 能够配合GROUP BY子句,自动将指定的栏位依相同的内容群组,例如依栏位"sex"分组并做平均: SELECT u.sex, AVG(u.age) FROM User u GROUP BY u.sex GROUP BY一般搭配HAVING来使用,例如: SELECT u.sex, avg(u.age) FROM User u GROUP BY u.sex HAVING AVG(u.age) > 20 可使用UPDATE语法来更新资料,例如: UPDATE User u SET u.name='momor' WHERE u.name='bbb' 能够透过DELETE来删除资料,例如: DELETE User u WHERE u.name='bush'## 选择查询编辑 SELECT <select_expression> FROM <from_clause> [WHERE <conditional_expression>] [ORDER BY <order_by_clause>]## 聚合查询编辑 SELECT <select_expression> FROM <from_clause> [WHERE <conditional_expression>] [GROUP BY <group_by_clause>] [HAVING <conditional_expression>] [ORDER BY <order_by_clause>]## 更新查询编辑 UPDATE <entity name>[ [AS ] <identification variable>] SET <update_statement>{,<update_statement>}* [WHERE <conditional_expression>]## 删除查询编辑 DELETE FROM <entity name>[ [AS ] <identification variable>] [WHERE <conditional_expression>]# 项目引入继承自`JpaRepository`的接口就能完成数据访问Spring-data-jpa依赖于Hibernatejap 相关依赖, <!-- jpa --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>在`application.xml`中配置:数据库链接信息(如使用嵌入式数据库则不须要)、自动建立表结构的设置,例如使用mysql的状况以下: spring.datasource.url=jdbc:mysql://localhost:3306/test spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver # hibernate的配置属性,其主要做用是:自动建立、更新、验证数据库表结构 spring.jpa.properties.hibernate.hbm2ddl.auto=create-drop `spring.jpa.properties.hibernate.hbm2ddl.auto`是hibernate的配置属性,其主要做用是:自动建立、更新、验证数据库表结构。 该参数的几种配置以下: * `create`:每次加载hibernate时都会删除上一次的生成的表,而后根据你的model类再从新来生成新表,哪怕两次没有任何改变也要这样执行,这就是致使数据库表数据丢失的一个重要缘由。* `create-drop`:每次加载hibernate时根据model类生成表,可是sessionFactory一关闭,表就自动删除。* `update`:最经常使用的属性,第一次加载hibernate时根据model类会自动创建起表的结构(前提是先创建好数据库),之后加载hibernate时根据model类自动更新表结构,即便表结构改变了但表中的行仍然存在不会删除之前的行。要注意的是当部署到服务器后,表结构是不会被立刻创建起来的,是要等应用第一次运行起来后才会。* `validate`:每次加载hibernate时,验证建立数据库表结构,只会和数据库中的表进行比较,不会建立新表,可是会插入新值。 至此已经完成基础配置,若是您有在Spring下整合使用过它的话,相信你已经感觉到Spring Boot的便利之处:JPA的传统配置在persistence.xml文件中,可是这里咱们不须要。固然,最好在构建项目时候按照以前提过的最佳实践的工程结构来组织,这样以确保各类配置都能被框架扫描到。## 实体关联给实体添加`@Entity` 类注解,属性添加相应的注解`@Id`, `@GeneratedValue`, `@Column`等## 建立对应的接口实现对该实体的数据访问建立接口以`Repository`方式命名便于理解,接口继承自`JpaRepository` # JPA api文档https://docs.spring.io/spring-data/data-jpa/docs/current/api/## JPA 经过解析方法名建立查询 User findByName(String name) User findByNameAndAge(String name, Integer age) 上面分别实现了按name查询User实体和按name和age查询User实体,能够看到咱们这里没有任何类SQL语句就完成了两个条件查询方法| Keyword | Sample | JPQL snippet | | -------- | -----: | :----: || IsNotNull | findByAgeNotNull|... where x.age not null || Like | findByNameLike|... where x.name like ?1 || NotLike | findByNameNotLike | ... where x.name not like ?1 || StartingWith | findByNameStartingWith | ... where x.name like ?1(parameter bound with appended %) || EndingWith | findByNameEndingWith | ... where x.name like ?1(parameter bound with prepended %) || Containing | findByNameContaining | ... where x.name like ?1(parameter bound wrapped in %) || OrderBy | findByAgeOrderByName | ... where x.age = ?1 order by x.name desc || Not | findByNameNot | ... where x.name <> ?1 || In | findByAgeIn | ... where x.age in ?1 || NotIn | findByAgeNotIn | ... where x.age not in ?1 || True | findByActiveTrue | ... where x.avtive = true || Flase | findByActiveFalse | ... where x.active = false || And | findByNameAndAge | ... where x.name = ?1 and x.age = ?2 || Or | findByNameOrAge | ... where x.name = ?1 or x.age = ?2 || Between | findBtAgeBetween | ... where x.age between ?1 and ?2 || LessThan | findByAgeLessThan | ... where x.age < ?1 || GreaterThan | findByAgeGreaterThan | ... where x.age > ?1 || After/Before | ... | ... || IsNull | findByAgeIsNull | ... where x.age is null |## JpaRepository相关查询功能> a.Spring Data JPA框架在进行方法名解析时,会先把方法名多余的前缀截取掉,好比`find`、`findBy`、`read`、`readBy`、`get`、`getBy`,而后对剩下部分进行解析。> b.假如建立以下的查询:`findByUserDepUuid()`,框架在解析该方法时,首先剔除`findBy`,而后对剩下的属性进行解析,假设查询实体为Doc。1:先判断`userDepUuid` (根据POJO 规范,首字母变为小写)是否为查询实体的一个属性,若是是,则表示根据该属性进行查询;若是没有该属性,继续第二步;2:从右往左截取第一个大写字母开头的字符串此处为`Uuid`),而后检查剩下的字符串是否为查询实体的一个属性,若是是,则表示根据该属性进行查询;若是没有该属性,则重复第二步,继续从右往左截取;最后假设user为查询实体的一个属性;3:接着处理剩下部分(`DepUuid`),先判断user 所对应的类型是否有`depUuid`属性,若是有,则表示该方法最终是根据“ `Doc.user.depUuid`” 的取值进行查询;不然继续按照步骤2 的规则从右往左截取,最终表示根据“`Doc.user.dep.uuid`” 的值进行查询。4:可能会存在一种特殊状况,好比Doc包含一个`user` 的属性,也有一个`userDep` 属性,此时会存在混淆。能够明确在属性之间加上"_" 以显式表达意图,好比"`findByUser_DepUuid()`" 或者"`findByUserDep_uuid()`"> c.特殊的参数: 还能够直接在方法的参数上加入分页或排序的参数,好比:```Page<UserModel> findByName(String name, Pageable pageable);List<UserModel> findByName(String name, Sort sort);```> d.也可使用JPA的`NamedQueries`,方法以下:1:在实体类上使用`@NamedQuery`,示例以下:```@NamedQuery(name = "UserModel.findByAge",query = "select o from UserModelo where o.age >= ?1")```2:在本身实现的DAO的Repository接口里面定义一个同名的方法,示例以下:```public List<UserModel> findByAge(int age);```3:而后就可使用了,Spring会先找是否有同名的NamedQuery,若是有,那么就不会按照接口定义的方法来解析。> e.还可使用@Query来指定本地查询,只要设置`nativeQuery`为`true`,好比:```@Query(value="select * from tbl_user where name like %?1" ,nativeQuery=true)public List<UserModel> findByUuidOrAge(String name);```注意:当前版本的本地查询不支持翻页和动态的排序> f.使用命名化参数,使用`@Param`便可,好比:```@Query(value="select o from UserModel o where o.name like %:nn")public List<UserModel> findByUuidOrAge(@Param("nn") String name);```> g.一样支持更新类的Query语句,添加`@Modifying`便可,好比:```@Modifying@Query(value="update UserModel o set o.name=:newName where o.name like %:nn")public int findByUuidOrAge(@Param("nn") String name,@Param("newName") StringnewName);```注意: 1:方法的返回值应该是int,表示更新语句所影响的行数 2:在调用的地方必须加事务,没有事务不能正常执行> h.建立查询的顺序 Spring Data JPA 在为接口建立代理对象时,若是发现同时存在多种上述状况可用,它该优先采用哪一种策略呢? <jpa:repositories> 提供了`query-lookup-strategy `属性,用以指定查找的顺序。它有以下三个取值:1:`create-if-not-found`:若是方法经过@Query指定了查询语句,则使用该语句实现查询;若是没有,则查找是否认义了符合条件的命名查询,若是找到,则使用该命名查询;若是二者都没有找到,则经过解析方法名字来建立查询。这是`querylookup-strategy` 属性的默认值 2:`create`:经过解析方法名字来建立查询。即便有符合的命名查询,或者方法经过@Query指定的查询语句,都将会被忽略 3:`use-declared-query`:若是方法经过@Query指定了查询语句,则使用该语句实现查询;若是没有,则查找是否认义了符合条件的命名查询,若是找到,则使用该命名查询;若是二者都没有找到,则抛出异常## JPA 经过SQL查下提供经过使用`@Query` 注解来建立查询,您只须要编写JPQL语句,并经过相似“:name”来映射@Param指定的参数,就像例子中的第三个findUser函数同样在`@Query` 有个参数定义为是否实用实体JPA查询,或者纯SQL查询. `nativeQuery`