Spring Boot:整合Spring Data JPA

綜合概述

JPA是Java Persistence API的簡稱,是一套Sun官方提出的Java持久化規範。其設計目標主要是爲了簡化現有的持久化開發工做和整合ORM技術,它爲Java開發人員提供了一種ORM工具來管理Java應用中的關係數據。 簡而言之,JPA提供了使用面向對象的方式操做數據庫的功能。JPA充分吸取了現有Hibernate,TopLink,JDO等ORM框架的優點,具備易於使用、伸縮性強等優勢。html

Spring Data JPA是Spring基於Spring Data框架對於JPA規範的一套具體實現方案,使用Spring Data JPA能夠極大地簡化JPA 的寫法,幾乎能夠在不寫具體實現的狀況下完成對數據庫的操做,而且除了基礎的CRUD操做外,Spring Data JPA還提供了諸如分頁和排序等經常使用功能的實現方案。合理的使用Spring Data JPA能夠極大的提升咱們的平常開發效率和有效的下降項目開發成本。java

實現案例

接下來,咱們就經過實際案例來說解Spring Data JPA的整合,以及提供JPA相關操做的一些示例。mysql

生成項目模板

爲方便咱們初始化項目,Spring Boot給咱們提供一個項目模板生成網站。git

1.  打開瀏覽器,訪問:https://start.spring.io/web

2.  根據頁面提示,選擇構建工具,開發語言,項目信息等。spring

3.  點擊 Generate the project,生成項目模板,生成以後會將壓縮包下載到本地。sql

4.  使用IDE導入項目,我這裏使用Eclipse,經過導入Maven項目的方式導入。數據庫

 

添加相關依賴

清理掉不須要的測試類及測試依賴,添加 Maven 相關依賴,這裏須要添加上WEB和Swagger和JPA的依賴,Swagger的添加是爲了方便接口測試。apache

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.louis.springboot</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- web -->
        <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
        <!-- swagger -->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>
        <!-- jpa -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
        <!-- 打包時拷貝MyBatis的映射文件 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/sqlmap/*.xml</include>
                </includes>
                <filtering>false</filtering>
            </resource>
            <resource>  
                <directory>src/main/resources</directory>  
                    <includes> 
                        <include>**/*.*</include>  
                    </includes> 
                    <filtering>true</filtering>  
            </resource> 
        </resources>
    </build>

</project>

添加相關配置

1.添加數據源配置api

將application.properties文件更名爲application.yml ,並在其中添加MySQL數據源鏈接信息。

注意:

這裏須要首先建立一個MySQL數據庫,並輸入本身的用戶名和密碼。這裏的數據庫是springboot。

另外,若是你使用的是MySQL 5.x及之前版本,驅動配置driverClassName是com.mysql.jdbc.Driver。

application.yml 

server:
  port: 8080
spring:
  datasource:
    driverClassName: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&zeroDateTimeBehavior=convertToNull&autoReconnect=true&characterEncoding=utf-8
    username: root
    password: 123456
  jpa:
    show-sql: true # 默認false,在日誌裏顯示執行的sql語句
    database: mysql
    hibernate.ddl-auto: update #指定爲update,每次啓動項目檢測表結構有變化的時候會新增字段,表不存在時會新建,若是指定create,則每次啓動項目都會清空數據並刪除表,再新建
    properties.hibernate.dialect: org.hibernate.dialect.MySQL5Dialect
    database-platform: org.hibernate.dialect.MySQL5Dialect
    hibernate:
      naming:
        implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl #指定jpa的自動錶生成策略,駝峯自動映射爲下劃線格式
        #physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl

2. 添加swagger 配置

添加一個swagger 配置類,在工程下新建 config 包並添加一個 SwaggerConfig 配置類。

SwaggerConfig.java

複製代碼
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.any())
                .paths(PathSelectors.any()).build();
    }

    private ApiInfo apiInfo(){
        return new ApiInfoBuilder()
                .title("SpringBoot API Doc")
                .description("This is a restful api document of Spring Boot.")
                .version("1.0")
                .build();
    }

}

編寫業務代碼

首先,編寫一個實體類,並添加相關注解,具體註解說明參見代碼。

SysUser.java

package com.louis.springboot.demo.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;

@Entity    // @Entity: 實體類, 必須
// @Table: 對應數據庫中的表, 必須, name=表名, Indexes是聲明表裏的索引, columnList是索引的列, 同時聲明此索引列是否惟一, 默認false
@Table(name = "sys_user", indexes = {@Index(name = "id", columnList = "id", unique = true), @Index(name = "name", columnList = "name", unique = true)})
public class SysUser {
    
    @Id // @Id: 指明id列, 必須
    @GeneratedValue(strategy = GenerationType.IDENTITY) // @GeneratedValue: 代表是否自動生成, 必須, strategy也是必寫, 指明主鍵生成策略, 默認是Oracle
    private Long id;
  
    @Column(name = "name", nullable = false) // @Column: 對應數據庫列名,可選, nullable 是否能夠爲空, 默認true
    private String name; 

    private String password;

    private String email;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

}

而後,編寫一個SysUserDao並繼承JpaRepository,由此咱們已經繼承了大部分可用的CURD操做,針對基礎操做,DAO徹底不用寫任何方法。

SysUserDao.java

package com.louis.springboot.demo.dao;

import java.io.Serializable;

import org.springframework.data.jpa.repository.JpaRepository;

import com.louis.springboot.demo.model.SysUser;

public interface SysUserDao extends JpaRepository<SysUser, Long>, Serializable {
    
}

使用Spring Data JPA,能夠經過兩種方式使用 JPA 進行數據持久化。

方式一:使用Spring Data JPA 提供的接口默認實現,如上面咱們的DAO實現。

方式二:自定義符合Spring Data JPA規則的查詢方法,由框架將其自動解析爲SQL。

Spring Data JPA提供了一些實現了基本的數據庫操做的接口類,這些接口和類的關係以下。

其中CrudRepository是頂層CURD接口,提供了一些簡單的增刪查改功能,接口定義以下。

CrudRepository.java

package org.springframework.data.repository;

import java.util.Optional;

/**
 * Interface for generic CRUD operations on a repository for a specific type.
 * @author Oliver Gierke
 * @author Eberhard Wolff
 */
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {

    /**
     * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
     * entity instance completely.
     *
     * @param entity must not be {@literal null}.
     * @return the saved entity will never be {@literal null}.
     */
    <S extends T> S save(S entity);

    /**
     * Saves all given entities.
     *
     * @param entities must not be {@literal null}.
     * @return the saved entities will never be {@literal null}.
     * @throws IllegalArgumentException in case the given entity is {@literal null}.
     */
    <S extends T> Iterable<S> saveAll(Iterable<S> entities);

    /**
     * Retrieves an entity by its id.
     *
     * @param id must not be {@literal null}.
     * @return the entity with the given id or {@literal Optional#empty()} if none found
     * @throws IllegalArgumentException if {@code id} is {@literal null}.
     */
    Optional<T> findById(ID id);

    /**
     * Returns whether an entity with the given id exists.
     *
     * @param id must not be {@literal null}.
     * @return {@literal true} if an entity with the given id exists, {@literal false} otherwise.
     * @throws IllegalArgumentException if {@code id} is {@literal null}.
     */
    boolean existsById(ID id);

    /**
     * Returns all instances of the type.
     *
     * @return all entities
     */
    Iterable<T> findAll();

    /**
     * Returns all instances of the type with the given IDs.
     *
     * @param ids
     * @return
     */
    Iterable<T> findAllById(Iterable<ID> ids);

    /**
     * Returns the number of entities available.
     *
     * @return the number of entities
     */
    long count();

    /**
     * Deletes the entity with the given id.
     *
     * @param id must not be {@literal null}.
     * @throws IllegalArgumentException in case the given {@code id} is {@literal null}
     */
    void deleteById(ID id);

    /**
     * Deletes a given entity.
     *
     * @param entity
     * @throws IllegalArgumentException in case the given entity is {@literal null}.
     */
    void delete(T entity);

    /**
     * Deletes the given entities.
     *
     * @param entities
     * @throws IllegalArgumentException in case the given {@link Iterable} is {@literal null}.
     */
    void deleteAll(Iterable<? extends T> entities);

    /**
     * Deletes all entities managed by the repository.
     */
    void deleteAll();
}

PagingAndSortingRepository在繼承了CrudRepository基礎上實現了排序和分頁的方法。

PagingAndSortingRepository.java

package org.springframework.data.repository;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

/**
 * Extension of {@link CrudRepository} to provide additional methods to retrieve entities using the pagination and
 * sorting abstraction.
 *
 * @author Oliver Gierke
 * @see Sort
 * @see Pageable
 * @see Page
 */
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {

    /**
     * Returns all entities sorted by the given options.
     *
     * @param sort
     * @return all entities sorted by the given options
     */
    Iterable<T> findAll(Sort sort);

    /**
     * Returns a {@link Page} of entities meeting the paging restriction provided in the {@code Pageable} object.
     *
     * @param pageable
     * @return a page of entities
     */
    Page<T> findAll(Pageable pageable);
}

JpaRepository又在繼承PagingAndSortingRepository的基礎上,同時繼承了QueryByExampleExecutor接口,使其擁有了匹配指定樣例查詢的能力。 

JpaRepository.java

package org.springframework.data.jpa.repository;

import java.util.List;
import javax.persistence.EntityManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.QueryByExampleExecutor;

/**
 * JPA specific extension of {@link org.springframework.data.repository.Repository}.
 *
 * @author Oliver Gierke
 * @author Christoph Strobl
 * @author Mark Paluch
 */
@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#findAll()
     */
    List<T> findAll();

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.PagingAndSortingRepository#findAll(org.springframework.data.domain.Sort)
     */
    List<T> findAll(Sort sort);

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#findAll(java.lang.Iterable)
     */
    List<T> findAllById(Iterable<ID> ids);

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.CrudRepository#save(java.lang.Iterable)
     */
    <S extends T> List<S> saveAll(Iterable<S> entities);

    /**
     * Flushes all pending changes to the database.
     */
    void flush();

    /**
     * Saves an entity and flushes changes instantly.
     *
     * @param entity
     * @return the saved entity
     */
    <S extends T> S saveAndFlush(S entity);

    /**
     * Deletes the given entities in a batch which means it will create a single {@link Query}. Assume that we will clear
     * the {@link javax.persistence.EntityManager} after the call.
     *
     * @param entities
     */
    void deleteInBatch(Iterable<T> entities);

    /**
     * Deletes all entities in a batch call.
     */
    void deleteAllInBatch();

    /**
     * Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is
     * implemented this is very likely to always return an instance and throw an
     * {@link javax.persistence.EntityNotFoundException} on first access. Some of them will reject invalid identifiers
     * immediately.
     *
     * @param id must not be {@literal null}.
     * @return a reference to the entity with the given identifier.
     * @see EntityManager#getReference(Class, Object) for details on when an exception is thrown.
     */
    T getOne(ID id);

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
     */
    @Override
    <S extends T> List<S> findAll(Example<S> example);

    /*
     * (non-Javadoc)
     * @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
     */
    @Override
    <S extends T> List<S> findAll(Example<S> example, Sort sort);
}

上面由於咱們的SysUserDao直接繼承了JpaRepository,因此上述全部的接口SysUserDao都是能夠直接使用的,固然,除了能夠直接使用默認提供的基礎接口外,Spring Data JPA還容許咱們自定義查詢方法,對於符合如下命名規則的方法,Spring Data JPA可以根據其方法名爲其自動生成SQL,除了使用示例中的 find 關鍵字,還支持的關鍵字有:query、get、read、count、delete等。 

只要按照如下命名規範的定義的方法,Spring Data JPA都可以幫咱們自動生成SQL,無需本身實現。

接着編寫一個服務接口,添加用戶保存、刪除、查詢所有和分頁查詢的方法。

SysUserService.java

package com.louis.springboot.demo.service;
import java.util.List;
import com.louis.springboot.demo.model.SysUser;
import com.louis.springboot.demo.util.PageQuery;

public interface SysUserService {

    /**
     * 保存用戶
     * @param user
     */
    public void save(SysUser user);
    
    /**
     * 刪除用戶
     * @param id
     */
    public void delete(SysUser user);
    
    /**
     * 查詢所有用戶
     * @return
     */
    public List<SysUser> findAll();
    
    /**
     * 查詢分頁數據
     * @return
     */
    public Object findPage(PageQuery pageQuery);

}

繼續編寫服務實現類並調用DAO實現相應功能,如下DAO方法都是繼承而來的,除此以後,JPA還提供了大量的API可用。

SysUserServiceImpl.java

package com.louis.springboot.demo.service.impl;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import com.louis.springboot.demo.dao.SysUserDao;
import com.louis.springboot.demo.model.SysUser;
import com.louis.springboot.demo.service.SysUserService;
import com.louis.springboot.demo.util.PageQuery;

@Service
public class SysUserServiceImpl implements SysUserService {
    
    @Autowired
    private SysUserDao sysUserDao;

    @Override
    public void save(SysUser user) {
        sysUserDao.save(user);
    }

    @Override
    public void delete(SysUser user) {
        sysUserDao.delete(user);
    }

    @Override
    public List<SysUser> findAll() {
        return sysUserDao.findAll();
    }

    @Override
    public Object findPage(PageQuery pageQuery) {
        return sysUserDao.findAll(PageRequest.of(pageQuery.getPage(), pageQuery.getSize()));
    }

}

接着編寫一個用戶控制器,調用服務接口實現對應功能。

SysUserController.java

package com.louis.springboot.demo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.louis.springboot.demo.model.SysUser;
import com.louis.springboot.demo.service.SysUserService;
import com.louis.springboot.demo.util.PageQuery;

@RestController
@RequestMapping("user")
public class SysUserController {

    @Autowired
    private SysUserService sysUserService;
    
    @PostMapping(value="/save")
    public Object save(@RequestBody SysUser user) {
        sysUserService.save(user);
        return 1;
    }
    
    @PostMapping(value="/delete")
    public Object delete(@RequestBody SysUser user) {
        sysUserService.delete(user);
        return 1;
    }
    
    @GetMapping(value="/findAll")
    public Object findAll() {
        return sysUserService.findAll();
    }
    
    @PostMapping(value="/findPage")
    public Object findPage(@RequestBody PageQuery pageQuery) {
        return sysUserService.findPage(pageQuery);
    }
    
}

上面對分頁請求進行了簡單的封裝,主要包含查詢頁碼和每頁數量兩個屬性。

PageQuery.java

package com.louis.springboot.demo.util;

public class PageQuery {

    private int page;
    private int size;
    
    public int getPage() {
        return page;
    }
    public void setPage(int page) {
        this.page = page;
    }
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }
    
}

編譯測試運行

1.  右鍵項目 -> Run as -> Maven install,開始執行Maven構建,第一次會下載Maven依賴,可能須要點時間,若是出現以下信息,就說明項目編譯打包成功了。

2.  打開數據庫,建立一個springboot數據庫,而後右鍵文件 DemoApplication.java -> Run as -> Java Application,開始啓動應用,若是一開始數據庫沒有對應的表,在應用啓動時會建立,咱們能夠經過控制檯查看到對應的SQL語句。

3.  打開瀏覽器,訪問:http://localhost:8080/swagger-ui.html,進入swagger接口文檔界面。

4.  首先訪問findAll接口,此時並無數據,因此返回結果爲空。

而後調用save接口,分別插入如下三條數據。

{
  
  "id": 1,
  "name": "111",
  "email": "111@qq.com",
  "password": "111"
}
{
  
  "id": 2,
  "name": "222",
  "email": "222@qq.com",
  "password": "222"
}
{
  
  "id": 3,
  "name": "333",
  "email": "333@qq.com",
  "password": "333"
}

接着回來繼續調用findAll接口,能夠看到咱們已經成功的插入了三條數據。

接着測試分頁查詢接口findPage,輸入{ "page": 0, "size": 2 },標識查詢第一頁,每頁顯示兩條記錄,下面返回正確的分頁查詢數據。

最後咱們測試一下刪除接口delete,刪除掉id爲1的數據,再次調用findAll接口,咱們發現目標記錄已經成功被刪除。

 

參考資料

項目主頁:https://spring.io/projects/spring-data-jpa

參考文檔:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/

網上資料:http://www.360doc.com/content/17/0801/09/16915_675758662.shtml

網上資料:https://www.ibm.com/developerworks/cn/opensource/os-cn-spring-jpa/index.html

相關導航

Spring Boot 系列教程目錄導航

Spring Boot:快速入門教程

Spring Boot:整合Swagger文檔

Spring Boot:整合MyBatis框架

Spring Boot:實現MyBatis分頁

源碼下載

碼雲:https://gitee.com/liuge1988/spring-boot-demo.git


做者:朝雨憶輕塵
出處:https://www.cnblogs.com/xifengxiaoma/ 
版權全部,歡迎轉載,轉載請註明原文做者及出處。

相關文章
相關標籤/搜索