上一篇介绍了Spring JdbcTemplate
的使用,对比原始的JDBC
而言,它更加的简洁。但随着表的增加,重复的CRUD工作让我们苦不堪言,这时候Spring Data Jpa
的作用就体现出来了…..
[TOC]
JPA
JPA 是 Java Persistence API 的简称,中文名 Java持久层API,是JDK 5.0注解或XML描述对象-关系表
的映射关系,并将运行期的实体对象持久化到数据库中。
Sun引入新的 JPA ORM 规范出于两个原因:其一,简化现有 Java EE 和 Java SE 应用开发工作;其二,Sun希望整合 ORM 技术,实现天下归一。
Sun公司在JDK1.5的时候,吸收了Hibernate、TopLink等 ORM框架 的优点,提出了Java持久化规范:JPA;Hibernate在3.2的时候提供了JPA的实现,其余的JPA的供应商还有诸如OpenJPA、Toplink等;
SpringDataJPA
Spring Data JPA 是在JPA规范的基础下提供了Repository层的 实现,但是使用哪一款 ORM 需要你自己去决定;相比我们更为熟悉的Hibernate和MyBatis,Spring Data JPA 可以看做更高层次的抽象。
优点
- 丰富的API,简单操作无需编写额外的代码
- 丰富的SQL日志输出
缺点
- 学习成本较大,需要学习
HQL
,如:@Query(value="from LogToIndex group by elkIndex")
- 配置复杂,虽然
SpringBoot
简化的大量的配置,但关系映射多表查询配置依旧不容易 - 性能较差,对比
JdbcTemplate
、Mybatis
等ORM框架,它的性能无异于是最差的
环境/版本一览:
- 开发工具:Intellij IDEA 2018.2.2
- springboot: 2.0.5.RELEASE
- jdk:1.8.0_171
- maven:3.3.9
1、搭建
2、pom.xml
1 | <!-- spring-data-jpa 携带 jdbc, jdbc 携带 HikariCP --> |
3、application.yml
1 | spring: |
JPA 配置 ddl-auto 几种属性
- create: 每次运行程序时,都会重新创建表,故而数据会丢失
- create-drop: 每次运行程序时会先创建表结构,然后待程序结束时清空表
- upadte: 每次运行程序,没有表时会创建表,如果对象发生改变会更新表结构,原有数据不会清空,只会更新(推荐使用)
- validate: 运行程序会校验数据与数据库的字段类型是否相同,字段不同会报错
4、sql
由于上面我们采用的是spring.jpa.hibernate.ddl-auto=update
方式,因此这里可以跳过手动建表的操作
5、entity
1 | package com.fatal.entity; |
6、dto
1 | package com.fatal.dto; |
7、utils
1 | package com.fatal.convert; |
8、repository
1 | package com.fatal.mapper; |
注:if(:username != '', u.username LIKE CONCAT('%', :username, '%'), 1=1)
中判断!=
后面不能用 null
,否则不起作用。
9、Test
1 | package com.fatal; |
测试
前三个就贴出来了。
数据库
1、测试分页查询
2、测试分页查询(内容替换)
3、测试自定义分页查询sql
4、测试动态拼装sql加模糊查询
笔记
1、GenerationType
1 | public enum GenerationType { |
- TABLE:使用一个特定的数据库表格来保存主键。
- SEQUENCE:根据底层数据库的序列来生成主键,条件是数据库支持序列。
- IDENTITY:主键由数据库自动生成(主要是自动增长型)
- AUTO:主键由程序控制。
2、JpaRepository 中的 T getOne(ID id)
这个方法使用要特别注意
,查询结果自带懒加载效果的。
如果你在测试类中调用这个方法,那么你讲会遇到下面的错误 No Session
org.hibernate.LazyInitializationException: could not initialize proxy [com.fatal.entity.Goods#1] - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:169)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:309)
at org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor.intercept(ByteBuddyInterceptor.java:45)
at org.hibernate.proxy.ProxyConfiguration$InterceptorDispatcher.intercept(ProxyConfiguration.java:95)
at com.fatal.entity.Goods$HibernateProxy$yA5wHloO.toString(Unknown Source)
at java.lang.String.valueOf(String.java:2994)
at java.io.PrintStream.println(PrintStream.java:821)
at com.fatal.repository.GoodsRepositoryTest.findByIdTest(GoodsRepositoryTest.java:37)
即便你在application.yml
中加了
1 | # 注册OpenEntityManagerInViewInterceptor。在整个请求处理过程中将JPA EntityManager绑定到线程。 |
也无济于事。因为 junit 根本不需要加载拦截器(这只是我的猜想,因为 junit 不需要web,那需要拦截器干嘛)
参考资料
一起来学SpringBoot | 第六篇:整合SpringDataJpa
总结
SpringBoot
的知识已经有前辈在我们之前探索了。比较喜欢的博主有:唐亚峰 | Battcn、方志朋的专栏、程序猿DD、纯洁的微笑。对这门技术感兴趣的可以去他们的博客逛逛。谢谢他们的分享~~
以上文章是我用来学习的Demo
,都是基于 SpringBoot2.x
版本。
源码地址: https://github.com/ynfatal/springboot2-learning/tree/master/chapter6