springbootSpring Boot全家桶

Spring Boot数据库交互之Spring Data JPA

2020-06-30  本文已影响0人  狄仁杰666

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为我们提供了以下规范:

  1. ORM映射元数据:JPA支持XML和注解两种元数据的形式,元数据描述对象和表之间的映射关系,框架据此将实体对象持久化到数据库表中;
  2. JPA 的API:用来操作实体对象,执行CRUD操作,框架在后台替我们完成所有的事情,开发人员不用再写SQL了(只能说在一定程度上不用写SQL,实际情况可能还是会用一些SQL);
  3. JPQL查询语言:通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句紧密耦合;

以上的定义引用自网络技术文章,我还在不断理解与学习中,我们先来Demo一个例子:

P.S.:本演示是基于上期文章创建的项目演进的:

5分钟入手Spring Boot

集成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>

准备数据库配置

  1. 在src/main底下创建resources文件夹;

  2. 在resources文件夹内新建application.properties文件;


    resources
  3. 在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
  1. 启动项目,验证数据库配置正确与否;


    启动项目 1
    启动项目 2

创建实体类entity
假设我们的数据库中有个表叫LEAD表(也叫lead表),我们想查询LEAD表中的数据;

  1. 创建entity包;
  2. 在entity包内创建实体类Lead.java;


    实体类
  3. 编写实体类;
    (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

  1. 创建repository包;
  2. 在repository包内创建repository接口类LeadRepository.java;


    repository接口类
  3. 编写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

  1. 创建service包;
  2. 创建service类;


    service类
  3. 编写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了

  1. 创建Controller;


    Controller
  2. 编写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);
    }
}
  1. 为了演示PUT请求,我还建了个updateLeadEmail API,并且引入lombok;
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>
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=10xxxx46http://127.0.0.1:8080/getLead/10xxxx46

API交互结果 1
API交互结果 2

调用Put API,返回执行结果:

API交互结果 3
  1. 同时项目log中,我们可以找到被执行的sql:
    为了能看到sql,关键一步是src/main/resources/application.properties内的配置项:spring.jpa.show-sql=true
    后台log

其中第一条SQL是非nativeQuery的,第二、三条SQL是nativeQuery的,nativeQuery的SQL就是我们平常写的sql,而非nativeQuery的SQL,是Spring Boot JPA帮我们生成的。

到此为止,我们已经完成了Spring Boot项目中采用Spring Boot JPA方式与数据库交互的实现!

码字不容易,点赞需积极

谢谢!!!

上一篇下一篇

猜你喜欢

热点阅读