SpringBoot整合JPA(六)
二八佳人体似酥,腰间仗剑斩愚夫。虽然不见人头落,暗里教君骨髓枯。
上一章简单介绍了SpringBoot整合JdbcTemplate(五),如果没有看过,请观看上一章
日常生活中,我们并不使用 JdbcTemplate, 而是使用 JPA和MyBatis,MyBatis-Plus. 这一章节,我们讲解一下, JPA的相关操作。
一. SpringBoot 整合 JPA前期准备
按照老蝴蝶以前讲解的方式,采用Maven 构建SpringBoot项目。
一.一 pom.xml 添加依赖
<!--引入MySql的驱动-->
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId>
</dependency>
<!--引入springboot与jpa整合的依赖-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
一.二 application.yml 添加JPA的配置
# 引入 数据库的相关配置
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/springboot?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=UTF-8&useSSL=falseusername: rootpassword: abc123# JPA的相关配置jpa:# 设置数据库平台database-platform: org.hibernate.dialect.MySQLDialect# 设置数据库database: mysql# 是否展示SQL语句show-sql: truehibernate:# 持久化规则是 updateddl-auto: updatenaming:# 物理命名策略类的全限定名称physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
一.三 创建 User 表
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (`id` int(11) NOT NULL AUTO_INCREMENT,`name` varchar(15) DEFAULT NULL,`sex` varchar(20) DEFAULT NULL,`age` int(6) DEFAULT NULL,`description` varchar(50) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=18 DEFAULT CHARSET=utf8;
二. 整合JPA应用
SpringBoot整合JPA时,需要创建相应的 实体类,工厂接口。
工厂接口有 Crud接口,有 PagingAndSorting,有 Jpa接口,也有 Specification 动态查询接口。
每一种接口,都有其特殊的功能。
二.一 创建 POJO 类和业务类
在 pojo 包下,创建 User.java 类
@Data
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "user")
@Entity
public class User implements Serializable {/*** @param id id编号* @param name 姓名* @param sex 性别* @param age 年龄* @param description 描述*/@Id//指定生成策略@GeneratedValue(strategy=GenerationType.IDENTITY)private Integer id;@Column(name = "name")private String name;@Column(name="sex")private String sex;@Column(name="age")private Integer age;@Column(name="description")private String description;
}
在 service包下,创建相应的接口和实现类
public interface UserService {}
@Service
public class UserServiceImpl implements UserService {}
二.二 Crud 工厂接口
二.二.一 接口的相关定义
org.springframework.data.repository.CrudRepository
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {}
方法签名 | 方法解释 |
---|---|
<S extends T> S save(S entity); | 插入或者更新一个对象 |
<S extends T> Iterable<S> saveAll(Iterable<S> entities); | 插入或者更新多个对象,批量操作 |
Optional findById(ID id); | 根据id 查询对象 |
boolean existsById(ID id); | 是否存在此id的记录 |
Iterable findAll(); | 查询所有的记录 |
Iterable findAllById(Iterable ids); | 根据id集合查询相关的记录 |
long count(); | 统计数目 |
void deleteById(ID id); | 根据id进行删除 |
void delete(T entity); | 根据实体对象进行删除 |
void deleteAll(Iterable<? extends T> entities); | 根据实体对象集合进行删除,批量操作 |
void deleteAll(); | 删除所有的记录 |
二.二.二. Crud 接口实现
在 repository 包下,创建 UserCrudRepository 接口。
public interface UserCrudRepository extends CrudRepository<User,Integer> {}
二.二.三 Crud 测试
在 test测试目录下,创建对应的测试类和测试方法,进行测试。
@SpringBootTest
@Log4j2
public class CrudRepositoryTests {@Autowiredprivate UserService userService;
}
二.二.三.一 插入 save 方法
测试方法:
@Testpublic void addTest(){//1. 构建对象User user=new User();user.setName("欢欢");user.setAge(22);user.setSex("女");user.setDescription("一个非常可爱的女孩纸");//2. 添加方法userService.addUser(user);log.info("添加成功,{}",user);}
省略接口方法,其对应的实现方法
添加Crud接口注入
@Autowired
private UserCrudRepository userCrudRepository;
@Overridepublic void addUser(User user) {userCrudRepository.save(user);}
控制台打印输出:
二.二.三.二 更新 save 方法
测试方法
@Testpublic void updateTest(){//1. 构建对象User user=new User();user.setId(1); //id不存在,会添加user.setName("欢欢");user.setDescription("岳泽霖最好的朋友");//2. 修改方法userService.updateUser(user);log.info("修改成功,{}",user);}
接口实现方法
@Overridepublic void updateUser(User user) {userCrudRepository.save(user);}
控制台打印输出
先查询,发现有,就更新,如果没有的话,就插入。
二.二.三.三 删除 delete 方法
测试方法
@Testpublic void deleteTest(){userService.deleteUser(1);}
接口实现方法
@Overridepublic void deleteUser(Integer id) {userCrudRepository.deleteById(id);}
数据库里面,没有此条数据了。
二.二.三.四 批量更新数据 saveAll
重新执行一下, save() 方法,插入一条数据, id=2.
测试方法:
@Testpublic void batchAddTest(){//1. 构建对象User user=new User();user.setName("小欢欢");user.setAge(22);user.setSex("女");user.setDescription("一个小坏蛋");User user1=new User();user1.setName("小泽霖");user1.setAge(25);user1.setSex("男");user1.setDescription("一个大坏蛋");//这是修改的操作,id=2已经存在这条记录了。User user2=new User();user2.setName("岳泽霖");user2.setId(2);user2.setAge(25);user2.setSex("男性");user2.setDescription("一个快乐的程序员");//2. 放置到集合里面List<User> userList=new ArrayList<>();userList.add(user);userList.add(user1);userList.add(user2);userService.batchAddUser(userList);}
接口实现方法:
@Overridepublic void batchAddUser(List<User> userList) {userCrudRepository.saveAll(userList);}
会插入前两条,更新第三条记录。
二.二.三.五 根据id 进行查询 findById
@Testpublic void findByIdTest(){User user=userService.findById(3);log.info(user);}
接口实现方法
@Overridepublic User findById(Integer id) {Optional<User> optional= userCrudRepository.findById(id);if(optional.isPresent()){return optional.get();}return null;}
二.二.三.六 查询所有的数据 findAll
@Testpublic void findAllTest(){List<User> userList=userService.findAll();userList.forEach(n->log.info(n));}
接口实现方法
@Overridepublic List<User> findAll() {Iterable<User> iterator= userCrudRepository.findAll();List<User> userList=new ArrayList<>();//将 Iterable 转换成 listiterator.forEach(n->userList.add(n));return userList;}
二.二.三.七 根据id集合进行查询 findAllById
@Testpublic void findByIdsTest(){List<Integer> ids= Arrays.asList(3,4,6);List<User> userList=userService.findAllByIds(ids);userList.forEach(n->log.info(n));}
接口实现方法
@Overridepublic List<User> findAllByIds(List<Integer> ids) {Iterable<User> iterator= userCrudRepository.findAllById(ids);List<User> userList=new ArrayList<>();iterator.forEach(n->userList.add(n));return userList;}
二.二.三.八 查询数目 count
@Testpublic void countTest(){Long count=userService.count();log.info("总数目{}",count);}
接口实现方法
@Overridepublic Long count() {return userCrudRepository.count();}
这就是 Crud仓库接口的基本用法。
二.三 PagingAndSorting 工厂接口
二.三.一 接口的相关定义
org.springframework.data.repository.PagingAndSortingRepository
分页和排序的接口,继承了 Crud的接口。
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {Iterable<T> findAll(Sort sort);Page<T> findAll(Pageable pageable);
}
方法签名 | 方法解释 |
---|---|
Iterable findAll(Sort sort); | 排序 |
Page findAll(Pageable pageable); | 分页 |
二.三.二 PagingAndSorting 接口实现
在 repository 包下,创建 UserPagingAndSortingRepository 接口
public interface UserPagingAndSortingRepository extends PagingAndSortingRepository<User,Integer> {}
二.三.三 PagingAndSorting 测试
在 test目录下,创建 PagingAndSortingRepositoryTests 测试类和测试方法。
多添加几条数据,好便于分页和排序。
二.三.三.一 排序,按照性别和年龄
@Autowiredprivate UserPagingAndSortingRepository userPagingAndSortingRepository;@Testpublic void sortTest(){List<User> userList=userService.findAllOrderBySexAndAge();userList.forEach(n->log.info(n));}
业务接口方法
@Overridepublic List<User> findAllOrderBySexAndAge() {Sort.Order sort1= Sort.Order.desc("sex");Sort.Order sort2 = Sort.Order.asc("age");Sort sort=Sort.by(sort1,sort2);Iterable<User> userIterable=userPagingAndSortingRepository.findAll(sort);List<User> userList=new ArrayList<>();userIterable.forEach(n->userList.add(n));return userList;}
二.三.三.二 排序并分页
@Testpublic void pageTest(){Page<User> page=userService.pageAll();log.info("总页数:{}",page.getTotalPages());log.info("总的数目:{}",page.getTotalElements());log.info("当前页数:{}",page.getNumber()+1);log.info("当前页的数目:{}",page.getNumberOfElements());List<User> userList= page.getContent();userList.forEach(n->log.info(n));}
业务接口方法
@Overridepublic Page<User> pageAll() {Sort sort=Sort.by(Sort.Direction.DESC,"id");// 默认从0开始的Pageable pageable= PageRequest.of(2-1, 4, sort);Page<User> userPage=userPagingAndSortingRepository.findAll(pageable);return userPage;}
这就是 PageAndSorting仓库接口的基本用法。
二.四 JpaRepository 工厂接口
二.四.一接口的相关定义
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {}
继承了分页,还有一个查询的接口。
方法签名 | 方法解释 |
---|---|
List findAll(); | 查询所有,返回对象集合 |
List findAll(Sort sort); | 查询所有,可排序,返回对象集合 |
List findAllById(Iterable ids); | 根据id集合,查询所有的记录,返回对象集合 |
<S extends T> List*lt;S> saveAll(Iterable<S> entities); | 批量保存数据 |
void flush(); | 刷新缓存 |
S saveAndFlush(S entity); | 保存并刷新 |
void deleteInBatch(Iterable entities); | 根据对象集合 |
void deleteAllInBatch(); | 批量删除所有 |
T getOne(ID id); | 根据id查询当前对象,如果没有的话,返回null |
<S extends T> List<S> findAll(Example<S> example); | 根据条件,查询数据,返回对象集合 |
<S extends T> List<S> findAll(Example<S> example, Sort sort); | 根据条件,支持排序,查询数据,返回对象集合 |
二.四.二 Jpa 接口实现
在repository包下,创建 UserJpaRepository 接口。 通常使用的是这个Jpa的接口,会在这接口内添加相应的接口定义。
当接口的方法名称定义符合相应的规范的时候,不用写相应的实现,Jpa会帮我们自动匹配生成相应的sql语句。
public interface UserJpaRepository extends JpaRepository<User,Integer> {}
二.四.三 JPA测试
在test目录下,创建JpaRepositoryTests 进行测试。
二.四.三.一 查询全部
@Testpublic void findAllTest(){List<User> userList=userService.jpaFindAll();userList.forEach(n->log.info(n));}
业务方法
@Autowiredprivate UserJpaRepository userJpaRepository;@Overridepublic List<User> jpaFindAll() {return userJpaRepository.findAll();}
不用往 UserJpaRepository 添加方法。
二.四.三.二 Example 查询 (通常不用)
测试方法
@Testpublic void findByExampleTest(){User user=new User();user.setName("泽霖");user.setAge(25);user.setSex("男");//1.创建匹配器ExampleMatcher exampleMatcher=ExampleMatcher.matching().withMatcher("sex",matcher -> matcher.contains()).withMatcher("age",matcher -> matcher.exact()).withMatcher("name",matcher ->matcher.contains());//2. 生成Example 对象Example example=Example.of(user,exampleMatcher);//3. 进行查询List<User>userList=userService.findByExample(example);userList.forEach(n->log.info(n));}
业务实现接口
@Overridepublic List<User> findByExample(Example example) {return userJpaRepository.findAll(example);}
不用往 UserJpaRepository 添加方法。
二.四.三.三 根据名称进行查询
@Testpublic void findByNameTest(){List<User> userList=userService.findByName("小欢欢");userList.forEach(n->log.info(n));}
业务方法
@Overridepublic List<User> findByName(String name) {return userJpaRepository.findByName(name);}
需要往 UserJpaRepository 里面添加方法,需要符合一定的规则
List<User> findByName(String name);
二.四.三.四 根据性别和年龄
@Testpublic void findBySexAndAgeTest(){List<User> userList=userService.findBySexAndAge("男",25);userList.forEach(n->log.info(n));}
业务方法
@Overridepublic List<User> findBySexAndAge(String sex, Integer age) {return userJpaRepository.findBySexAndAge(sex,age);}
需要往 UserJpaRepository 里面添加方法,需要符合一定的规则
List<User> findBySexAndAge(String sex, Integer age);
二.四.三.五 根据性别查询,年龄排序
@Testpublic void findAllOrderByTest(){List<User> userList=userService.findBySexOrderByAge("女");userList.forEach(n->log.info(n));}
业务方法
@Overridepublic List<User> findBySexOrderByAge(String sex) {return userJpaRepository.findBySexOrderByAgeDesc(sex);}
需要往 UserJpaRepository 里面添加方法,需要符合一定的规则
List<User> findBySexOrderByAgeDesc(String sex);
二.四.三.六 使用原始SQL进行查询部分字段
@Testpublic void findQueryNameTest(){List<Map<String,Object>> userMapList=userService.findQueryByName("小欢欢");for(Map<String,Object> map:userMapList){log.info("id是:{},name是{}",map.get("id"),map.get("name"));}}
业务方法
@Overridepublic List<Map<String,Object>> findQueryByName(String name) {return userJpaRepository.findQueryByName(name);}
需要往 UserJpaRepository 里面添加方法,需要符合一定的规则
@Query(value="select id as id,name as name from user where name=:name",nativeQuery = true)List<Map<String,Object>> findQueryByName(@Param("name") String name);
二.四.三.七 使用原始SQL进行查询全部字段
@Testpublic void findQueryNameTest(){List<Map<String,Object>> userMapList=userService.findQueryByName("小欢欢");for(Map<String,Object> map:userMapList){log.info("id是:{},name是{}",map.get("id"),map.get("name"));}}
业务方法
@Overridepublic List<User> jpaFindAllSql(String name) {return userJpaRepository.findAllSql(name);}
需要往 UserJpaRepository 里面添加方法,需要符合一定的规则
@Query(value="select * from user where name=:name",nativeQuery = true)List<User> findAllSql(@Param("name")String name);
这就是 jpa的一些基本的用法。
二.五 JpaSpecificationExecutor 动态查询接口
二.五.一 接口的相关定义
public interface JpaSpecificationExecutor<T> {}
方法签名 | 方法解释 |
---|---|
Optional findOne(@Nullable Specification spec); | 根据条件,查询最多只有一条记录 |
List findAll(@Nullable Specification spec); | 根据条件,查询多条记录 |
Page findAll(@Nullable Specification spec, Pageable pageable); | 根据条件,分页查询,可包含排序 |
List findAll(@Nullable Specification spec, Sort sort); | 根据条件,排序查询 |
long count(@Nullable Specification spec); | 查询数目 |
二.五.二. JpaSpecificationExecutor实现
通常都是与 JpaRepository 一起使用的。
public interface UserSpecificationRepository extends JpaRepository<User, Integer>,JpaSpecificationExecutor<User>{}
二.五.三 Specification 动态查询测试
@Testpublic void nameAndSexAndDescTest(){User user=new User();user.setName("小欢欢1");user.setSex("女");user.setAge(27);user.setDescription("小坏蛋");List<User> userList=userService.findByNameSexAndDesc(user);userList.forEach(n->log.info(n));}
业务接口方法
@Overridepublic List<User> findByNameSexAndDesc(User user) {//1. 根据条件创建 Specification 对象信息Specification<User> specification=new Specification<User>(){@Overridepublic Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {//1. 用于接收封装的查询对象List<Predicate> predicateList = new ArrayList<>();if(user!=null){//1.如果name 不为空的话,对name 进行精确匹配if(!StringUtils.isEmpty(user.getName())){Predicate namePredicate = criteriaBuilder.equal(root.get("name"), user.getName());predicateList.add(namePredicate);}//2.如果sex 不为空的话,也是精确匹配if(!StringUtils.isEmpty(user.getSex())){Predicate sexPredicate=criteriaBuilder.equal(root.get("sex"),user.getSex());predicateList.add(sexPredicate);}//3.如果age不为空的话,就是 < 匹配if(!StringUtils.isEmpty(user.getAge())){Predicate agePreDicate=criteriaBuilder.lt(root.get("age"),user.getAge());predicateList.add(agePreDicate);}//4. 如果description 不为空的话,进行模糊匹配if(!StringUtils.isEmpty(user.getDescription())){Predicate descPredicate=criteriaBuilder.like(root.get("description"),"%"+user.getDescription()+"%");predicateList.add(descPredicate);}}return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));}};//传入条件,也可以传入分页信息。这儿就不举例分页了。return userSpecificationRepository.findAll(specification);}
如果将 user条件的属性全部去掉,是一种sql查询,sex去掉,又是一种sql查询,会根据属性的不同,动态的处理。
动态查询,也可以传入分页和排序的相关信息。
这个非常重要,需要重点掌握一下。
本章节的代码放置在 github 上:
https://github.com/yuejianli/springboot/tree/develop/Jpa
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!
SpringBoot整合JPA(六)相关推荐
- (二)SpringBoot 整合 JPA
一.JPA简介 JPA(java persistence api)并不是一个框架,而是一组规范.Hibernate.TopLink.OpenJPA都实现了JPA规范,不过Hinernate最成功).所 ...
- Springboot整合JPA多数据源(Oracle+Mysql)
Springboot整合JPA多数据源 1. Maven 2. 基本配置 2.1 DataSource 3. 多数据源配置 3.1 JpaConfigOracle 3.2 JpaConfigMysql ...
- Springboot整合JPA
文章目录 JPA技术 常用注解 Springboot整合JPA 1.引入JPA依赖 2.配置 3.启动类 4.实体类 5.定义接口和数据库交互(dao) 6.JPA中使用原生态的SQL语句 7.Tes ...
- springboot整合JPA+MYSQL+queryDSL数据增删改查
Spring Boot Jpa 是 Spring 基于 ORM 框架.Jpa 规范的基础上封装的一套 Jpa 应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常 ...
- SpringBoot整合JPA 数据库自动增加字段问题记录
Spring整合JPA启动的时候忽然发现,数据增加了两个字段,我当时就很纳闷了,我自己写的有实体有字段,并且跟数据一致,为什么要给我增加两个字段哪? 我的实体如下: 启动的时候就变成这样了 然后就找度 ...
- springboot整合jpa+h2
JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中. JPA的主要目标之一 ...
- 【idea】Springboot整合jpa
第一步快速搭建springboot项目:在你建立的工程下创建 Module 选择Spring initializr创建. 第二步:修改包名.项目名.web项目打成war包.在Type处选择: Mave ...
- java版spring cloud+spring boot+redis社交电子商务平台(四)SpringBoot 整合JPA
java b2b2c电子商务社交平台源码请加企鹅求求:一零三八七七四六二六.JPA全称Java Persistence API.JPA通过JDK 5.0注解或XML描述对象-关系表的映射关系,并将运行 ...
- springboot整合jpa之连接MySql实现crud
整体思路:搭建springboot一定要注意版本问题,各个jar包之间是否兼容.搭建可以从上往下进行,是一个从Controller层和Service层-->Dao层的一个过程. 1.添加mave ...
- 七十三、SpringBoot整合Jpa
@Author:Runsen 来源:尚硅谷 下面建议读者学习尚硅谷的B站的SpringBoot视频,我是学雷丰阳视频入门的. 具体链接如下:B站尚硅谷SpringBoot教程 这里需要注意的是:jpa ...
最新文章
- 从源码分析DEARGUI之add_slider_float-4和add_slider_int-4
- java文件复制速度_java中文件复制得速度测试
- 【PhotoScan精品教程】任务一:新建工程、导入照片、设置坐标系、导入控制点(POS)、自由空三
- 【入门5】字符串(今天刷洛谷了嘛)
- pb string 接收dll按值返回_JavaScript 是如何工作的:JavaScript 的共享传递和按值传递...
- SpringBoot项目集成Mybatis Plus(三)分页插件
- Java中url传递中文参数取值乱码的解决方法
- ionic Toggle(开关控件)
- requestIdleCallback函数
- jqGrid获取数据库数据的方式
- java json 多余属性,fastjson支持JSON字符串解析到指定类型的JavaBean时的多余属性么?...
- 从ISO 文件制作U盘启动盘.
- Hadoop组件及功能
- 元器件的温度特性(电容、电感、晶振等)
- 实战1 - 空气质量数据的校准
- 电驴提示“该内容尚未提供权利证明,无法提供下载”之解决办法
- c语言比率分布 函数 rate(m),R语言中统计分布和模拟_R语言培训
- monaco-editor(code编辑器插件)使用及常用配置与方法
- python周末吃什么_中午不知道吃什么,用Python爬取美团外卖评论帮你选餐
- 5分钟学会如何制样(XPS测试)