本文主要讲解 springData Jpa 入门相关知识, 了解JPA规范与Jpa的实现,搭建springboot+dpringdata jpa环境实现基础增删改操作,适合新手学习,老鸟绕道~

1. ORM 概论

ORM(Object-Relational Mapping)顾名思义就是表示对象关系映射。在面向对象的软件开发中,我们肯定是需要和数据库进行交互的,那么这里就存在一个问题如何将数据库中的表与我们代码中的对象映射起来尼,我们只要有一套程序能够做到建立对象与数据库的关联,操作对象就可以直接操作数据库数据,就可以说这套程序实现了ORM对象关系映射

简单的说:ORM就是建立实体类和数据库表之间的关系,从而达到操作实体类就相当于操作数据库表的目的。

目前市面上主流的ORM框架有Hibernate、Mybatis、Spring Data Jpa等,

  • 其中 Mybatis 框架是一个半自动的ORM框架,本身并不是完全面向对象的思想,但是得益于sql与代码的解耦,可以更灵活的操作sql与优化sql,但是同时也带有复杂的映射文件,在国内目前还是非常主流的。
  • Hibernate 是一款完全开源的优秀的全自动ORM框架,实现了对JDBC的轻量级封装,实现了JPA的一整套规范,它将数据库与POJO建立了映射关系,让开发人员实现了完全面向对象的操作数据库,框架帮我们自动生成sql

2. JPA

  • JPA 的全称是 Java Persistence API , 即 Java 持久化 API ,是 SUN 公司推出的一套基于ORM的规范,内部是由一系列的接口和抽象类构成。

  • JPA 通过 JDK 5.0 注解描述对象-关系表的映射关系,并将运行期的实体对象持久化到数据库中。

2.1 JPA优势

  1. 标准化

JPAJCP 组织发布的 Java EE 标准之一,因此任何声称符合 JPA 标准的框架都遵循同样的架构,提供相同的访问 API ,这保证了基于 JPA 开发的企业应用能够经过少量的修改就能够在不同的 JPA 框架下运行。

  1. 容器级特性的支持

JPA 框架中支持大数据集、事务、并发等容器级事务,这使得 JPA 超越了简单持久化框架的局限,在企业应用发挥更大的作用。

  1. 简单方便

    JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity 进行注释, JPA 的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成

  2. 查询能力

    JPA的查询语言是面向对象而非面向数据库的,它以面向对象的自然语法构造查询语句,可以看成是 Hibernate HQL 的等价物。 JPA 定义了独特的 JPQL(Java Persistence Query Language)JPQLEJB QL 的一种扩展,它是针对实体的一种查询语言,操作对象是实体,而不是关系数据库的表,而且能够支持批量更新和修改、 JOIN、GROUP BY、HAVING 等通常只有 SQL 才能够提供的高级查询特性,甚至还能够支持子查询。

  3. 高级特性

JPA 中能够支持面向对象的高级特性,如类之间的继承、多态和类之间的复杂关系,这样的支持能够让开发者最大限度的使用面向对象的模型设计企业应用,而不需要自行处理这些特性在关系数据库的持久化。

2.2 JPA与hibernate的关系

  • JPA规范本质上就是一种ORM规范,注意不是ORM框架——因为JPA并未提供ORM实现,它只是制订了一些规范,提供了一些编程的API接口,但具体实现则由服务厂商来提供实现。

  • JPA和Hibernate的关系就像JDBC和JDBC驱动的关系,JPA是规范,Hibernate除了作为ORM框架之外,它也是一种JPA实现。JPA怎么取代Hibernate呢?JDBC规范可以驱动底层数据库吗?答案是否定的,也就是说,如果使用JPA规范进行数据库操作,底层需要hibernate作为其实现类完成数据持久化工作。

3. Spring Data JPA

Spring Data JPASpring 基于 ORM 框架、 JPA 规范的基础上封装的一套 JPA 应用框架,可使开发者用极简的代码即可实现对数据库的访问和操作。它提供了包括增删改查等在内的常用功能,且易于扩展!学习并使用 Spring Data JPA 可以极大提高开发效率!

  • Spring Data JPA 让我们解脱了 DAO 层的操作,基本上所有 CRUD 都可以依赖于它来实现, 在实际的工作工程中,推荐使用 Spring Data JPA + ORM (如: hibernate )完成操作,这样在切换不同的ORM框架时提供了极大的方便,同时也使数据库层操作更加简单,方便解耦

3.1 JPA 、Hibernate 与Spring Data Jpa

  • JPA 是一套规范,内部是有接口和抽象类组成的。

  • hibernate 是一套成熟的ORM框架,而且 Hibernate 实现了 JPA 规范,所以也可以称 hibernateJPA 的一种实现方式,我们使用 JPAAPI 编程,意味着站在更高的角度上看待问题(面向接口编程)

  • Spring Data JPASpring 提供的一套对JPA操作更加高级的封装,是在 JPA 规范下的专门用来进行数据持久化的解决方案。

3.2 五分钟快速上手 Spring Data Jpa

3.2.1 构建开发环境

    1. 构建 springboot 脚手架构建初始环境,我们不要 web 模块,只需要 spring data jpamysql 即可

    1. 等待构建完成, spingboot 的强大在这里体现了,为我们快速构建了开箱即用的环境,我们在 application.yml 文件中添加我们需要的配置信息
spring:
datasource:
url: jdbc:mysql:///db?serverTimezone=GMT
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
jpa:
hibernate:
ddl-auto: update # 数据库没有表时自动构建,
database: mysql # 指定数据库类型
generate-ddl: true # 自动生成
show-sql: true # 现实sql到控制台
database-platform: org.hibernate.dialect.MySQL8Dialect # 数据库方言 DataBbase枚举内获取

3.2.2 进行增删改开发

    1. 创建映射实体类 DeptEntity , 这里用来 lombok 插件省去了 get/set 方法,对于 @Column 注解是可以放在 get 方法上的
@Entity
@Table(name = "dept", schema = "db", catalog = "")
@ToString
@Data
public class DeptEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "DEPTNO", nullable = false)
private int deptno; // name : 数据库中的列名 nullable : 是否为空 length:长度
@Column(name = "DNAME", nullable = true, length = 14)
private String dname; @Column(name = "LOC", nullable = true, length = 13)
private String loc; @Column(name = "flag", nullable = true)
private Integer flag; @Column(name = "type", nullable = true, length = 20)
private String type; }
    1. 编写完实体后,然后添加相应的 Dao 层接口,需要继承 JPA 的接口 JpaRepository , 代码如下:
public interface DeptRepository extends JpaRepository<DeptEntity,Integer> {

}

我们的 dao 层是一个接口,没有具体的实现,在继承的接口中已经定义了一些常用的方法供我们使用,后面详细介绍

    1. 编写测试类方法进行验证
@SpringBootTest
public class SpringJpaTest {
@Autowired
private DeptRepository deptRepository; @Test
public void jpaTest(){
List<DeptEntity> list = deptRepository.findAll();
System.out.println(list);
}
}
    1. 看到打印出查询结果
Hibernate: select deptentity0_.deptno as deptno1_0_, deptentity0_.dname as dname2_0_, deptentity0_.flag as flag3_0_, deptentity0_.loc as loc4_0_, deptentity0_.type as type5_0_ from dept deptentity0_
[DeptEntity(deptno=10, dname=张三, loc=NEW YORK, flag=10, type=真实类型), DeptEntity(deptno=20, dname=RESEARCH, loc=DALLAS, flag=20, type=11), DeptEntity(deptno=50, dname=zonghebu, loc=CHICAGO, flag=null, type=null), DeptEntity(deptno=60, dname=??, loc=123, flag=null, type=22), DeptEntity(deptno=61, dname=??, loc=123, flag=null, type=null), DeptEntity(deptno=62, dname=??, loc=123, flag=null, type=null), DeptEntity(deptno=72, dname=??, loc=123, flag=null, type=null)]

同时可以看到sql的语句,这是 Hibernate 帮我们生成的,总的来说 Spring Data Jpa 的实现是依赖了 HibernateJpa 规范的实现,

    1. 相应的添加与查询排序方法的测试全部如下:
 @Test
public void query(){
Sort deptno = Sort.by(Sort.Direction.DESC,"deptno");
List<DeptEntity> all = deptRepository.findAll(deptno);
System.out.println(all);
} @Test
public void insert(){
DeptEntity entity = new DeptEntity();
entity.setDname("质量控制部门");
entity.setFlag(1);
entity.setType("test");
//保存同时将保存结果返回
DeptEntity save = deptRepository.save(entity);
System.out.println(save);
}

增加方法打印:

Hibernate: insert into dept (dname, flag, loc, type) values (?, ?, ?, ?)

DeptEntity(deptno=73, dname=质量控制部门, loc=null, flag=1, type=test)

其他方法不再赘述都基本相似,这些方法都是继承自 JpaRepository 接口中

3.3 复杂查询的实现

3.3.1 接口已定义的方法

在父接口中定义了一套常用的查询, 相对比较简单,如下:

Optional<T> findById(ID id);
Iterable<T> findAllById(Iterable<ID> ids);
List<T> findAll(Sort sort);
List<T> findAllById(Iterable<ID> ids);

3.3.2 jpql的查询方式

  • jpql : jpa query language (jpq查询语言)

  • 特点:

    语法或关键字和sql语句类似

    查询的是类和类中的属性

  • 需要将JPQL语句配置到接口方法上

    1.特有的查询:需要在dao接口上配置方法

    2.在新添加的方法上,使用注解的形式配置jpql查询语句

    3.注解 : @Query

  • 代码实现如下:

在dao接口中自定义方法并添加注解

    /**
* 通过 deptno查询
* 使用@Query注解来编写jpql 语句 是面向对象的操作
* sql: select * from dept where deptno = ?
* jpql: select * from DeptEntity where deptno = ?1
*
* 在jpql中占位符好指定索引,与参数列表对应,从1开始
* @param id
* @return
*/
@Query(value=" from DeptEntity where deptno = ?1")
DeptEntity queryDept(Integer id); /**
* DML 操作, 需要加@Modifying 注解
* 在多个条件时要注意占位符下标的数字要和参数列表对应
* 需要注意,DML 语句需要事务配置,需要加 @Transactional 注解,一般在业务层,而不再数据层,
* @param name
* @param id
*/
@Query(value="update DeptEntity set dname=?1 where deptno=?2")
@Modifying
void updateName(String name,Integer id);
// JAVA

测试方法代码:

 @Test
public void queryDept(){
DeptEntity entity = deptRepository.queryDept(10);
System.out.println(entity);
} /**
* 这里需要加 @Transactional 注解来管理事务
*/
@Test
@Transactional
public void updateName(){
deptRepository.updateName("测试",10);
}

3.3.3 sql语句查询方式

  • 特有的查询:需要在dao接口上配置方法

  • 在新添加的方法上,使用注解的形式配置sql查询语句

  • 注解 :

@Query

value :jpql语句 | sql语句
nativeQuery :false(使用jpql查询) | true(使用本地查询:sql查询) 是否使用本地查询

示例代码:

dao接口代码:

 /**
* 需要添加 nativeQuery 参数来设置是都是sql查询, 默认是false ,是jpql查询
* @param num
* @return
*/
@Query(value="select * from dept where flag = ?",nativeQuery=true)
List<DeptEntity> queryList(Integer num);

测试代码:

@Test
public void nativeQuery(){
List<DeptEntity> list = deptRepository.queryList(10);
System.out.println(list);
}

3.3.4 方法名规则查询

  • 是对jpql查询,更加深入一层的封装

  • 我们只需要按照SpringDataJpa提供的方法名称规则定义方法,不需要再配置jpql语句,完成查询

  • 规则:

    • findBy开头: 代表查询

      对象中属性名称(首字母大写)

    • 含义:根据属性名称进行查询

接口代码:

    /**
* 方法名的约定:
* findBy : 查询
* 对象中的属性名(首字母大写) : 查询的条件
* Dname
* * 默认情况 : 使用 等于的方式查询
* 特殊的查询方式
*
* findAllByDname -- 根据名称查询
*
* 再springdataJpa的运行阶段
* 会根据方法名称进行解析 findBy from xxx(实体类)
* 属性名称 where dname =
*
* 1.findBy + 属性名称 (根据属性名称进行完成匹配的查询=)
* 2.findBy + 属性名称 + “查询方式(Like | isnull)”
* findAllByDnameLike
* 3.多条件查询
* findBy + 属性名 + “查询方式” + “多条件的连接符(and|or)” + 属性名 + “查询方式”
*/
List<DeptEntity> findAllByDname(String name); List<DeptEntity> findAllByDnameAndAndFlag(String name,Integer num); List<DeptEntity> findAllByDnameLike(String name);

测试代码省略

  • 主要的一些规则对应如下:

3.4 getOne,findOne以及findById的区别

这三个方法乍一看都是一样的功能,都是通过主键返回一个实体,但是再实际使用中还是有区别的,尤其在一对一的关系中我们如果直接用 getOne 查询,会出现 下面错误:

org.hibernate. LazyInitializationException: could not initialize proxy - no Session

下面我们简单说一下这三个方法:

  • getOne

getOne是懒加载,需要在 springboot 增加这个配置: spring.jpa.properties.hibernate.enable_lazy_load_no_trans=true ,yml中也是一样配置。但这种方式不太友好,建议不要使用。

每次初始化一个实体的关联就会创建一个临时的 session 来加载,每个临时的 session 都会获取一个临时的数据库连接,开启一个新的事物。这就导致对底层连接池压力很大,而且事物日志也会被每次 flush .

设想一下:假如我们查询了一个分页 list 每次查出1000条,这个实体有三个 lazy 关联对象, 那么,恭喜你,你至少需要创建 3000 个临时 session+connection+transaction .

getOne 来自 JpaReposiroty 接口,对于传入的标识则返回一个实体的引用;且取决于该方法的实现,可能会出现 EntityNotFoundException ,并会拒绝一些无效的标识;

  • findById

findById 来自 CrudRepository 接口,通过它的 id 返回一个实体;

findById返回一个Optional对象;

  • findOne

findOne 来自 QueryByExampleExecutor 接口, 返回一个通过 Example 匹配的实体或者 null

findOne返回一个Optional对象,可以实现动态查询

本文由AnonyStar 发布,可转载但需声明原文出处。

仰慕「优雅编码的艺术」 坚信熟能生巧,努力改变人生

欢迎关注微信公账号 :coder简码 获取更多优质文章

更多文章关注笔者博客 :IT简码

Spring Data Jpa 入门学习的更多相关文章

  1. spring data jpa入门学习

    本文主要介绍下spring data jpa,主要聊聊为何要使用它进行开发以及它的基本使用.本文主要是入门介绍,并在最后会留下完整的demo供读者进行下载,从而了解并且开始使用spring data ...

  2. Spring Data JPA入门及深入

    一:Spring Data JPA简介 Spring Data JPA 是 Spring 基于 ORM 框架.JPA 规范的基础上封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据库的访问 ...

  3. Spring Data JPA 入门Demo

    什么是JPA呢? 其实JPA可以说是一种规范,是java5.0之后提出来的用于持久化的一套规范:它不是任何一种ORM框架,在我看来,是现有ORM框架在这个规范下去实现持久层. 它的出现是为了简化现有的 ...

  4. Spring Data JPA入门

    1. Spring Data JPA是什么 它是Spring基于ORM框架.JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能, ...

  5. Spring Data JPA 入门篇

    Spring Data JPA是什么 它是Spring基于ORM框架(如hibernate,Mybatis等).JPA规范(Java Persistence API)封装的一套 JPA应用框架,可使开 ...

  6. Spring Data Jpa --- 入门

    一.概述 Spring Data是Spring下的一个子项目,用于简化数据库访问,并支持云服务的开源框架.Spring Data支持NoSQL和 关系数据存储,其主要目标是使得数据库的访问变得方便快捷 ...

  7. 【ORM框架】Spring Data JPA(一)-- 入门

    本文参考:spring Data JPA入门   [原创]纯干货,Spring-data-jpa详解,全方位介绍  Spring Data JPA系列教程--入门 一.Spring Data JPA介 ...

  8. Spring Data JPA 教程(翻译)

    写那些数据挖掘之类的博文 写的比较累了,现在翻译一下关于spring data jpa的文章,觉得轻松多了. 翻译正文: 你有木有注意到,使用Java持久化的API的数据访问代码包含了很多不必要的模式 ...

  9. 深入浅出学Spring Data JPA

    第一章:Spring Data JPA入门 Spring Data是什么 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架.其主要目标是使得对数据的访问变得方便快捷,并支持map ...

随机推荐

  1. Linux网络篇,ssh原理及应用

    一.对称加密与非对称加密 对称加密: 加密和解密的秘钥使用的是同一个.    非对称加密: 非对称加密算法需要两个密钥:公开密钥(publickey)和私有密钥:简称公钥和私钥 对称加密 对称加密的密 ...

  2. "文本加粗"组件:<b> —— 快应用组件库H-UI

     <import name="b" src="../Common/ui/h-ui/text/c_tag_b"></import> &l ...

  3. Python操作rabbitmq系列(三):多个接收端消费消息

    接着上一章.这一章,我们要将同一个消息发给多个客户端.这就是发布订阅模式.直接看代码: 发送端: import pikaimport sys connection = pika.BlockingCon ...

  4. Struts2-学习笔记系列(8)-异常处理

    后台抛出自定义异常 public String execute() throws Exception { if (getUser().equalsIgnoreCase("user" ...

  5. Mysql基础知识一

    1.数据库的定义 数据:描述事物符号记录.(包括数字.文字.图形.图像.声音.档案记录等)以记录形式统一的格式进行存储. 广义上的数据:出现在计算机内部的一切二进制数据流都为数据 狭义上的数据:只是数 ...

  6. 从CentOS 7.0升级到7.7版本

    我平时都在VirtualBox上装虚拟机,方法是导入ova镜像文件,比如导入从网上下载的CentOS7-base.ova,该ova为CentOS 7.0版本,而现在最新版本为7.7,为此进入系统后第一 ...

  7. 路径跟踪 PathMeasure的简单使用

    平时用path画一些简单的几何图形,呈现的时候也是已经绘制好的图形,想想,如果像动画一样看到它的绘制轨迹,是不是更酷?今天介绍的这个类PathMeasure就是干这个的,知道它的存在还是由于看了启舰写 ...

  8. 接口测试中实际发生的几个问题——python中token传递

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:AFKplayer PS:如有需要Python学习资料的小伙伴可以加点 ...

  9. .Net Core Send Email

    1.安装Nuget包MailKit,引用命名空间. using MailKit.Net.Smtp; using MimeKit; 注意:引用MailKit对应最新版本 2.定义收发地址和标题 Mime ...

  10. 快速从零开始安装Laravel5.2教程

    前面 本文默认你Win电脑什么都没装,也就是从零开始安装Laravel,并且环境都由我来指定分配哈! 环境 首先搭建运行环境,先到 PhpStudy官网 下载PhpStudy的Windows版本.然后 ...