Spring-Data-JPA 概述
基于JPA再封装的一套框架,底层还是使用第三方ORM框架,默认使用Hibernate
环境搭建
创建项目
引入依赖[配置pom.xml]
1 |
|
创建包
cn.itcast.service
cn.itcast.dao
cn.itcast.domain
创建applicationContext.xml
Spring整合Jpa就两步
1.由spring创建entityManagerFactory
2.使用标签jpa:repositories和spring进行整合
提示:该文件应该在java/main/resource目录下
注意修改数据库密码
1 |
|
快速入门
创建表cst_customer
提示:day01已经创建过了
1 | USE `jpa`; |
创建实体类Customer
1 | package cn.itcast.domain; |
通过注解配置映射关系
1 | package cn.itcast.domain; |
创建CustomerDao接口
1 | package cn.itcast.dao; |
编写测试类对接口进行测试
1 | package cn.itcast.dao; |
运行结果
可能出现的问题
问题1:javax.xml.bind.JAXBException
原因是使用的JDK1.9需要引入依赖
1 | <dependency> |
问题2:org.springframework.transaction.CannotCreateTransactionException
可能是applicationContext.xml中数据库账号密码配置错了
基本操作
增加
1 |
|
运行结果
删除
1 |
|
运行结果
修改
1 |
|
运行结果
查询
根据ID查询
1 |
|
运行结果
查询所有
1 |
|
运行结果
查询总记录数
1 |
|
运行结果
根据ID查询是否有记录
1 |
|
运行结果
findOne和getOne的区别
立刻查询findOne
1 |
|
运行结果
延迟查询 getOne
1 |
|
运行结果
区别
立刻查询:无论是否操作对象都会执行SQL
延迟查询:如果不操作对象不会执行SQL
使用JPQL语句操作数据库
好处
可以使用类似SQL的语句进行自定义查询
注意事项
需要注意的是查询的是实体类和属性,不是表名和字段
使用方式
CustomDao接口代码
在接口的方法上使用@Query注解
1 | /** |
测试代码
1 |
|
红线报错
from和?那里可能会报 from unexpected错误,不用理会,这是因为我们的JPQL语句书写不标准,当然也可以书写标准的HPQL语句,后续会讲
多占位符赋值(解决红线警告)
需求: 根据Id和姓名赋值
占位符的第一中写法
1 | "from Customer where custName=? and custId=?") (value = |
占位符的第二种写法
索引必须从1开始
?后面的数字表使用第几个形式参数的值
1 | "from Customer where custId=?2 and custName=?1 ") (value = |
占位符的第三种写法
1 | "from Customer where custId=:custId and custName=:custName ") (value = |
完全符合规范的姿势
1 | "select c from Customer c where c.custId=:custId and c.custName=:custName ") (value = |
根据客户名查询
接口
1 | "from Customer where custName = ?") (value = |
测试代码
1 |
|
运行结果
更新或者删除
CustomDao接口中的代码
1 |
|
测试代码
1 |
|
可能出现的问题
问题1:Not supported for DML operations
原因是因为接口上没有添加@Modifying 注解
问题2:Executing an update/delete query; nested exception is javax.persistence
原因是测试类没有开启事务,需要加@org.springframework.transaction.annotation.Transactional 注解
问题3:数据库没有更新成功
测试方法默认执行完后要事务回滚,修改为提交,在测试类添加@Rollback(false)注解
使用原生SQL操作数据库
使用原生SQL查询全部
接口代码
需要在@Query注解中指定属性navtiveQuery=true 表示使用的是原生SQL
这里SQL语句我没有写 select * … ,框架认为是不标准的写法要通过表的别名.*操作
1 | "select * from cst_customer ", nativeQuery = true) (value = |
###测试代码
1 |
|
运行结果
使用原生SQL模糊查询
接口代码
1 | /* |
测试代码
1 |
|
运行结果
使用原生SQL修改或删除
接口代码
1 | /** |
测试代码
1 |
|
运行结果
自定义简单查询
概述
自定义的简单查询就是根据方法名来自动生成 SQL,主要的语法是 findXXBy、readAXXBy、queryXXBy、countXXBy、getXXBy 后面跟属性名称:
1 | User findByUsername(String userName); |
也可以加一些关键字 And、Or:
1 | User findByUsernameOrAddress(String username, String address); |
修改、删除、统计也是类似语法:
1 | Long deleteById(Long id); |
基本上 SQL 体系中的关键词都可以使用,如 LIKE、IgnoreCase、OrderBy。
1 | List<User> findByAddressLike(String address); |
方法命名规范
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 |
… where x.age in ?1 |
NotIn | findByAgeNotIn(Collection |
… 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) |
##6.2基本查询
方法命名格式
属性名首字母要大写
查询一个实体类:findBy属性名1And属性名2
查询多个实体类:findAllBy属性名1And属性名2
接口代码
1 | /** |
测试代码
1 |
|
运行结果
模糊查询
方法命名格式
属性名首字母要大写
查询一个实体类:findBy属性名1And属性名2+Like
查询多个实体类:findAllBy属性名1And属性名2+Like
表数据
接口代码
1 | /** |
测试代码
1 |
|