Spring Data JPA介绍
Spring Boot中支持的数据库交互方式多种多样,今天咱就来玩一下Spring Data JPA好了,因为其他的,咱也还不会呀!?!
JPA全称为Java Persistence API(Java持久层API),它是Sun公司在JavaEE 5中提出的Java持久化规范。它为Java开发人员提供了一种对象/关联映射工具,来管理Java应用中的关系数据,JPA吸取了目前Java持久化技术的优点,旨在规范、简化Java对象的持久化工作。很多ORM框架都是实现了JPA的规范,如:Hibernate、EclipseLink。
Spring Data JPA旨在通过减少实际需要的工作量来显著改善数据访问层的实现。它在JPA的基础上做了一些封装,可以轻松实现基于JPA的存储库。 此模块处理对基于JPA的数据访问层的增强支持。 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。
需要注意的是JPA统一了Java应用程序访问ORM框架的规范
JPA为我们提供了以下规范:
- ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
- JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发人员不用再写SQL了(只能说在一定程度上不用写SQL,实际情况可能还是会用一些SQL);
- JPQL查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合;
以上的定义引用自网络技术文章,我还在不断理解与学习中,我们先来Demo一个例子:
P.S.:本演示是基于上期文章创建的项目演进的:
集成Spring Data JPA
以连接Oracle为例(网上有很多Mysql的案例,除了配置不一样,其实使用差不多,有机会我们可以Demo Mysql、Mongo的案例)
在项目pom.xml中的dependencies节点加入以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc8</artifactId>
<version>12.2.0.1.0</version>
</dependency>
准备数据库配置
在src/main底下创建resources文件夹;
-
在resources文件夹内新建application.properties文件;
在application.properties文件内输入数据库的配置信息,如:
spring.datasource.url=jdbc:oracle:thin:@//xxdb-scan:xxxx/XXXX
spring.datasource.username=xxxx
spring.datasource.password=xxxxxxxx
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true
-
启动项目,验证数据库配置正确与否;
创建实体类entity
假设我们的数据库中有个表叫LEAD表(也叫lead表),我们想查询LEAD表中的数据;
- 创建entity包;
-
在entity包内创建实体类Lead.java;
- 编写实体类;
(LEAD 表有多个字段,我们本例只使用其中的2个字段,一个是lead_id, 一个是email;)
package com.mycompany.sample.entity;
import javax.persistence.*;
/**
* @author : dylanz
* @since : 06/30/2020
**/
@Entity
@Table(name = "LEAD")
public class Lead {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "lead_id")
private int leadId;
@Column(name = "email")
private String email;
public Lead() {
}
public Lead(Integer leadId, String email) {
this.leadId = leadId;
this.email = email;
}
public int getLeadId() {
return leadId;
}
public void setLeadId(int leadId) {
this.leadId = leadId;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
#@Table(name = "LEAD")这个非必需,当未提供时,说明本实体类的表名是实体类类名转换后的名字,如:
# 1.实体类名为Lead时,默认表名为:lead表;
# 2.实体类名为UserPermission时,默认表名为:user_permission表;
#@Column(name = "lead_id")中name为非必需,当未提供时,说明数据库的列名为对应成员变量转换后的名字,如:
# 1.当对应的成员变量为private int leadId; 时,默认数据库列名为lead_id;
# 2.当对应的成员变量为private int email; 时,默认数据库列名为email;
#可以看到,实体类和成员变量均为驼峰结构,而对应的表明和数据库列名为下划线结构;
#尽管如此,还是建议补全@Table和@Column;
#Spring Boot还有很多注解和属性,可以用于规范实体类及实体类的列,比如长度限制、数据类型限制等,
#这里不再详细介绍,毕竟我们本例的重点不是介绍这个。
创建repository
有了实体类之后,我们接下来要创建一个repository接口类,并在repository接口类内实现数据库交互,并且把交互结果映射到实体类Lead.java
- 创建repository包;
-
在repository包内创建repository接口类LeadRepository.java;
- 编写repository接口类;
package com.mycompany.sample.repository;
import com.mycompany.sample.entity.Lead;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import javax.transaction.Transactional;
/**
* @author : dylanz
* @since : 06/30/2020
**/
@Repository
public interface LeadRepository extends JpaRepository<Lead, Integer> {
@Query(value = "select l from Lead l where leadId=?1")
Lead getLeadByLeadId(Integer leadId);
@Query(value = "select lead_id,email from lead where lead_id=?1", nativeQuery = true)
Lead getLeadByLeadIdWithNativeQuery(Integer leadId);
@Modifying
@Query(value = "update lead set email=?1 where lead_id=?2", nativeQuery = true)
@Transactional
void updateLeadEmail(String email, Integer leadId);
}
#增、删、改的数据库交互,必须搭配@Modifying使用,并且建议也使用注解@Transactional来处理事务,
#即交互失败,Spring Boot会自动帮我们进行回滚。
创建service
repository创建完之后,我们就可以与数据库进行交互了,接下来我们写个service调用repository
- 创建service包;
-
创建service类;
- 编写service类;
package com.mycompany.sample.service;
import com.mycompany.sample.entity.Lead;
import com.mycompany.sample.repository.LeadRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author : dylanz
* @since : 06/30/2020
**/
@Service
public class LeadService {
@Autowired
private LeadRepository leadRepository;
public Lead getLead(Integer leadId) {
return leadRepository.getLeadByLeadId(leadId);
}
public Lead getLeadByLeadIdWithNativeQuery(Integer leadId) {
return leadRepository.getLeadByLeadIdWithNativeQuery(leadId);
}
public Lead updateEmail(com.mycompany.sample.domain.Lead lead) {
int leadId = lead.getLeadId();
String email = lead.getEmail();
leadRepository.updateLeadEmail(email, leadId);
Lead updatedLead = leadRepository.getLeadByLeadId(leadId);
if (updatedLead.getEmail() != null && !updatedLead.getEmail().equals(email)) {
throw new InternalError("Unable to update email for leadId: " + leadId + " with email: " + email);
}
return updatedLead;
}
}
开发带数据库交互功能的API
service开发完成后,我们要把该service暴露给客户端使用,于是就要创建API了
-
创建Controller;
- 编写Controller;
package com.mycompany.sample.controller;
import com.mycompany.sample.entity.Lead;
import com.mycompany.sample.service.LeadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author : dylanz
* @since : 06/30/2020
**/
@RestController
public class LeadController {
@Autowired
private LeadService leadService;
@GetMapping("/getLead/{leadId}")
@ResponseBody
public Lead getLead(@PathVariable Integer leadId) {
return leadService.getLead(leadId);
}
@GetMapping("/getLead")
@ResponseBody
public Lead getLeadById(@RequestParam("leadId") Integer leadId) {
return leadService.getLeadByLeadIdWithNativeQuery(leadId);
}
@PutMapping(value = "/updateLeadEmail")
@ResponseBody
public Lead updateLeadEmail(@RequestBody com.mycompany.sample.domain.Lead lead) {
return leadService.updateEmail(lead);
}
}
- 为了演示PUT请求,我还建了个updateLeadEmail API,并且引入lombok;
- pom.xml中dependencies节点内添加lombok依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
- 建立domain包;
- 编写Lead domain;
package com.mycompany.sample.domain;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Data;
import java.io.Serializable;
/**
* @author : dylanz
* @since : 06/30/2020
**/
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class Lead implements Serializable {
private static final long serialVersionUID = 1L;
private Integer leadId;
private String email;
}
运行Spring Boot项目,见证奇迹
调用Get API,返回执行结果:
http://127.0.0.1:8080/getLead?leadId=10xxxx46 或 http://127.0.0.1:8080/getLead/10xxxx46
调用Put API,返回执行结果:
- 同时项目log中,我们可以找到被执行的sql:
为了能看到sql,关键一步是src/main/resources/application.properties内的配置项:spring.jpa.show-sql=true
其中第一条SQL是非nativeQuery的,第二、三条SQL是nativeQuery的,nativeQuery的SQL就是我们平常写的sql,而非nativeQuery的SQL,是Spring Boot JPA帮我们生成的。
到此为止,我们已经完成了Spring Boot项目中采用Spring Boot JPA方式与数据库交互的实现!
码字不容易,点赞需积极
谢谢!!!