赞
踩
前言:一说JavaWeb,很多小伙伴都知道SSH,这个H代表的就是Hibernate框架,可是什么又是JPA呢?相信许多刚入门的小伙伴听说过但不是特别清楚,首先JPA的全称叫做Java Persistence API,JPA是一个基于O/R映射的标准规范,在这个规范中,JPA只定义标准规则,不提供实现,使用者则需要按照规范中定义的方式来使用。目前JPA的主要实现有Hibernate、EclipseLink、OpenJPA等,事实上,由于Hibernate在数据访问解决技术领域的霸主地位,JPA的标准基本是由Hibernate来主导的。另外,Spring框架为我们提供了Spring Data JPA,可以减少我们使用JPA时的代码量。
JPA的全称叫做Java Persistence API意即Java持久化API,是Sun官方在JDK5.0后提出的Java持久化规范(JSR 338,这些接口所在包为
javax.persistence
)。JPA是一个基于O/R映射的标准规范,在这个规范中,JPA只定义标准规则,不提供实现,使用者则需要按照规范中定义的方式来使用。目前JPA的主要实现有Hibernate、EclipseLink、OpenJPA等,事实上,由于Hibernate在数据访问解决技术领域的霸主地位,JPA的标准基本是由Hibernate来主导的。SpringBoot中的Spring Data JPA 实现默认就是Hibernate。
JPA的出现主要是为了简化持久层开发以及整合ORM技术,结束Hibernate、TopLink、JDO等ORM框架各自为营的局面。JPA是在吸收现有ORM框架的基础上发展而来,易于使用,伸缩性强。
(1) 总的来说,JPA包括以下3方面的技术:
ORM映射元数据:支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系
API: 操作实体对象来执行CRUD操作
查询语言: 通过面向对象而非面向数据库的查询语言(JPQL
)查询数据,避免程序的SQL语句紧密耦合
(2)ORM框架
ORM全英文名为Object-Relational Mapping:对象关系映射,简单来说为了不用JDBC那一套原始方法来操作数据库,ORM框架横空出世(mybatis、hibernate等等)。然而ORM框架出的太多了,百花齐放,琳琅满目,你一套标准我一套标准,要是想换一套框架实现项目,可能要从头再写。
Sun引入新的JPA ORM规范出于两个原因:
其一,简化现有Java EE和Java SE应用开发工作;
其二,Sun希望整合ORM技术,实现天下归一。
Spirng Data JPA 是Spring提供的一套简化JPA开发的框架,按照约定好的【方法命名规则】写dao层接口,就可以在不写接口实现的情况下,实现对数据库的访问和操作。同时提供了很多除了CRUD之外的功能,如分页、排序、复杂查询等等。Spring Data JPA 可以理解为 JPA 规范的再次封装抽象,底层还是使用了 Hibernate 的 JPA 技术实现。
Spring Data JPA是Spring Data家族的一部分,可以轻松实现基于JPA的存储库。 此模块处理对基于JPA的数据访问层的增强支持,它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
总的来说JPA是ORM规范,Hibernate、TopLink等是JPA规范的具体实现,这样的好处是开发者可以面向JPA规范进行持久层的开发,而底层的实现则是可以切换的。Spring Data Jpa则是在JPA之上添加另一层抽象(Repository层的实现),极大地简化持久层开发及ORM框架切换的成本。
使用 Spring Data JPA 访问数据,只需要数据访问层接口继承了JpaRepository接口(SpringDataJPA提供的简单数据操作接口)和JpaSpecificationExecutor(SpringDataJPA提供的复杂查询接口),SpringDataJPA就会为我们搞定单表的基本CRUD操作。
- DROP TABLE IF EXISTS `t_user`;
- CREATE TABLE `t_user` (
- `t_id` int(11) NOT NULL,
- `t_name` varchar(255) DEFAULT NULL,
- `t_age` int(11) DEFAULT NULL,
- `t_address` varchar(255) DEFAULT NULL,
- PRIMARY KEY (`t_id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
- ————————————————
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <!--JPA-->
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- </dependency>
-
- <!--数据库驱动-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>

今后我们修改application.properties文件配置为application.yml配置。yml配置文件比properties配置要更清晰更有层次感,可以很明了的看懂配置信息。
- server:
- port: 8088
-
- spring:
- datasource:
- url: jdbc:mysql://127.0.0.1:3306/shankeng?serverTimezone=UTC
- username: root
- password: root
- driver-class-name: com.mysql.cj.jdbc.Driver
- jpa:
- hibernate:
- ddl-auto: update
- naming:
- physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
- show-sql: true
根据数据库中的字段对应建立一个实体类UserEntity
- package com.hs.demo.entity;
-
- import javax.persistence.*;
- import java.io.Serializable;
-
- @Entity
- @Table(name="t_user")
- public class UserEntity implements Serializable {
- @Id
- @GeneratedValue
- @Column(name="t_id")
- private Long id;
- @Column(name="t_name")
- private String name;
- @Column(name="t_age")
- private int age;
- @Column(name="t_address")
- private String address;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public String getAddress() {
- return address;
- }
-
- public void setAddress(String address) {
- this.address = address;
- }
-
- public Long getId() {
-
- return id;
- }
-
- public void setId(Long id) {
- this.id = id;
- }
- }

既然实体类我们也已经创建完成了,那么接下来我们需要使用SpringDataJPA来完成数据库操作,我们新建UserJPA接口并且继承SpringDataJPA内的接口作为父类:
- package com.hs.demo.jpa;
-
- import com.hs.demo.entity.UserEntity;
- import org.springframework.data.jpa.repository.JpaRepository;
- import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
- import org.springframework.data.jpa.repository.Query;
- import javax.transaction.Transactional;
- import java.io.Serializable;
- import java.util.List;
-
- /**
- * JPA 提供了许多接口不用自己再去写底层封装了
- *
- * 按照命名规则来定义方法,即可以操作数据库了,如查询:findBy + 实体属性名, get + 实体类名 + By + 实体属性名,...
- * 还可以使用@Query注解,直接语句查询...
- *
- */
- public interface UserJPA extends JpaRepository<UserEntity, Long>, JpaSpecificationExecutor<UserEntity>, Serializable {
-
-
- //按名称查找所有用户
- List<UserEntity> findByName(String userName);
-
- //按姓名查找单个用户
- UserEntity getUserEntityByName(String userName);
-
- //按姓名查找单个用户 使用Query注解方式,默认是jpql语句对应实体类操作,如有需要加上nativeQuery=true来声明这是一个本地查询(sql查询)
- @Query("select u from UserEntity u where u.name = ?1")
- UserEntity findUserEntityByName(String userName);
-
- // //按姓名查找单个用户 使用原生SQL语句查询方式
- // @Query(value = "select * from t_user where t_name = ?1", nativeQuery = true)
- // UserEntity findUserEntityByName(String userName);
-
- //根据名称删除用户
- @Transactional
- void deleteByName(String userName);
-
- }

我们UserJPA继承了JpaRepository接口(SpringDataJPA提供的简单数据操作接口)、JpaSpecificationExecutor(SpringDataJPA提供的复杂查询接口)、Serializable(序列化接口)。我们并不需要做其他的任何操作了,因为SpringDataJPA会为我们搞定单表的基本CRUD操作。SpringDataJPA内部使用了类代理的方式让继承了它接口的子接口都以Spring管理的Bean的形式存在,也就是说我们可以直接使用@Autowired注解在spring管理bean使用。
注意事项
1、异步查询的时候,使用@ResponseBody注解将返回值写入到Http response body中,不然前端获取不到返回值。
2、删除的时候,删除方法要使用@Transactional返将该方法注入到事务中。
- package com.hs.demo.controller;
-
- import com.hs.demo.entity.UserEntity;
- import com.hs.demo.jpa.UserJPA;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.RestController;
- import java.util.List;
-
- @RestController
- @RequestMapping("/user")
- public class UserController {
-
- @Autowired
- private UserJPA userJPA;
-
- /**
- * 查询所有数据
- *
- * @return
- */
- @RequestMapping("/list")
- public List<UserEntity> list() {
- return userJPA.findAll();
- }
-
- @RequestMapping("/save")
- public UserEntity save(UserEntity entity) {
- return userJPA.save(entity);
- }
-
- @RequestMapping(value = "/delete", method = RequestMethod.GET)
- public List<UserEntity> delete(Long id) {
- userJPA.deleteById(id);
- return userJPA.findAll();
- }
-
- @RequestMapping("/find")
- //接收前端请求参数,普通方式-请求参数名和Controller方法的参数一致
- public UserEntity find(String name) {
- return userJPA.getUserEntityByName(name);
- }
-
- }

启动项目后,由于数据库中并无数据,直接访问127.0.0.1:8088/user/list显示为空,首先向数据库中插入数据,在浏览器中输入127.0.0.1:8088/user/save?name=admin&age=16&address=shanghai
效果如下图:
重复插入后,再次访问127.0.0.1:8088/user/list,效果如下图所示:
验证JPA的@Query方式,访问:http://127.0.0.1:8088/user/find?name=xmh
本篇博客介绍了如何使用Spring Boot JPA与MySQL进行数据交互,可以看到使用JPA可以大量减少Dao代码,大大提升开发效率。Spring Data JPA实现单表查询非常方便,还提供了方法命名规则定义方法的名称和@Query注解查询;当然这里只是简单的单表查询,接下来我会介绍JPA如何多表联合查询、动态条件查询和分页等等。
方法命名规则查询顾名思义就是根据方法的名字,就能创建查询。只需要按照Spring Data JPA提供的方法命名规则定义方法的名称,就可以完成查询工作。Spring Data JPA在程序执行的时候会根据方法名称进行解析,并自动生成SQL查询语句进行查询。
按照Spring Data JPA 定义的规则为:findBy + 实体属性名, get + 实体类名 + By + 实体属性名,...条件属性首字母需大写。
例如:
- List<User> findByUserName(String username);
-
- User findByUserNameAndPassword(String username,String password);
-
- Long countByUserName(String username);
-
- void deleteById(Long id);
按方法名解析的查询方法通常只适用于单表查询,且建议where条件参数不多于三条的情况下,返回值通常对应表的实体Bean或者实体类List类型。
参考链接:
Spring Data JPA提供的方法命名规则定义方法的名称
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。