第九章:SpringBoot2.3.0 JPA+Mysql案例,並提供hibernate_sequence不存在解決方案

一)JPA簡介

Java Persistence API是一種標準技術,可讓您將對象“映射”到關係數據庫。

目前Hibernate是最流行的JPA實現之一。

 

優點:JPA在新增、修改、刪除操作支持非常好。大大減少了數據庫SQL的編寫。

缺點:JPA在查詢方面支持不太友好,主要是體現在多表連接查詢上,所以複雜的查詢可以用EntityManager方式。

 

實體類加載方式

傳統上,JPA“實體”類在persistence.xml文件中指定。在Spring Boot中,此文件不是必需的,而是使用“實體掃描”。默認情況下,將搜索主配置類(用@EnableAutoConfiguration或註釋的一個@SpringBootApplication)下的所有軟件包。

也可以使用@EntityScan註釋來自定義實體掃描位置。

 

二)JPA+Mysql案例

第一步:先在Mysql數據庫創建一個表,並設置主鍵自動增長

腳本如下:

CREATE TABLE `tab_employee` (
  `emp_id` int(11) UNSIGNED AUTO_INCREMENT,
  `emp_name` varchar(100) DEFAULT NULL,
  `emp_no` varchar(100) DEFAULT NULL,
  `create_date` date DEFAULT NULL,
  PRIMARY KEY (`emp_id`)
);

select * from tab_employee;

 

第二步:創建一個maven項目,並在pom.xml中引入SpringBoot的Jar,JPA的Jar,Mysql的Jar

pom.xml內容如下:

<?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>

    <groupId>com.oysept</groupId>
    <artifactId>jpa_springboot</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.0.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

 

SpringBoot啓動類:

package com.oysept;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JpaApplication {
    public static void main(String[] args) {
        SpringApplication.run(JpaApplication.class, args);
    }
}

項目結構圖如下:

 

第三步:創建一個application.yml配置文件,指定啓動端口和Mysql數據庫配置

注:Mysql8.0版本以上的數據庫,連接的配置有點變化,比如url後指定時區和數據庫編碼方式等。

server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/oysept?serverTimezone=GMT&useUnicode=true&characterEncoding=utf8
    username: root
    password: root
    driver-class-name: com.mysql.cj.jdbc.Driver

  jpa:
    show-sql: true

 

第四步:創建一個JPA實體類

@Entity:標識了該註解了的類,被認爲是一個典型的實體類。

@Table:標識實體類映射的數據庫表信息,name屬性,表示數據庫中的表名。

@Column:標識實體類映射的數據庫表字段信息,name屬性,表示數據庫表中的字段名。

@Id:標識一個唯一ID,常用於數據庫表主鍵字段。

@GeneratedValue:標識數據庫主鍵字段生成策略。

    TABLE:使用一個特定的數據庫表來保存主鍵。

    SEQUENCE:根據底層數據庫的序列來生成主鍵,條件是數據庫支持序列、Mysql好像不支持該方式。

    IDENTITY:主鍵由數據庫自動生成(主要是自動增長型)。

    AUTO:主鍵由程序控制,會自動匹配主鍵生成策略。

package com.oysept.bean;

import javax.persistence.*;
import java.util.Date;

/**
 * 員工表
 * @Table中的name屬性,表示數據庫中的表名
 * @Column中的name屬性,表示數據庫表中的字段名
 * @author ouyangjun
 */
@Entity
@Table(name = "TAB_EMPLOYEE")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "emp_id")
    private Long empId;

    @Column(name = "emp_name")
    private String empName;

    @Column(name = "emp_no")
    private String empNO;

    @Column(name = "create_date")
    private Date createDate;

    public Long getEmpId() {return empId;}
    public void setEmpId(Long empId) {this.empId = empId;}

    public String getEmpName() {return empName;}
    public void setEmpName(String empName) {this.empName = empName;}

    public String getEmpNO() {return empNO;}
    public void setEmpNO(String empNO) {this.empNO = empNO;}

    public Date getCreateDate() {return createDate;}
    public void setCreateDate(Date createDate) {this.createDate = createDate;}
}

 

第五步:創建一個UserRepository工具類,並繼承JpaRepository接口。

JPA的功能一般是從RepositoryCrudRepository接口擴展,JpaRepository接口是其子類。

並且JPA有一套自己的方法名稱命名方式,如需自定義實現,可以通過@Query註解進行擴展。

package com.oysept.repository;

import com.oysept.bean.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface UserRepository extends JpaRepository<User, Integer> {

    /**
     * jpa自帶分頁查詢
     * @param pageable
     * @return
     */
    Page<User> findAll(Pageable pageable);

    /**
     * 根據用戶ID查詢一條數據,jpa有一定的查詢規則,以一些通用前綴開頭,比如findBy、find、get等
     * 如果不想用這種默認規則,需要在接口上添加@Query主鍵,自定義實現數據查詢,如下面一個接口
     * @param empId
     * @return
     */
    User findByEmpId(Long empId);

    /**
     * jpa支持對象查詢,簡稱HQL,也支持原生sql查詢
     * @return
     */
    @Query("select u from User u")
    List<User> listUser();

    // 原生sql方式查詢
    @Query(value = "select emp_id as empId, emp_name as empName, emp_no as empNO, create_date as createDate from tab_employee",
        nativeQuery = true)
    List<User> listEmployee();
}

 

第六步:創建一個UserController控制器工具類,用於測試JPA接口

先創建一個空殼子,然後再一步步添加測試接口。

package com.oysept.controller;

import com.oysept.bean.User;
import com.oysept.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

@RestController
public class JpaController {

    @Autowired
    private UserRepository userRepository;
    
}

 

方法1、新增User信息

// 新增user訪問地址: http://localhost:8080/jpa/insertUser
@RequestMapping(value="/jpa/insertUser")
public User insertUser() {
    User user = new User();
    user.setEmpName("aaaa");
    user.setEmpNO("bbbb");
    user.setCreateDate(new Date());
    return userRepository.save(user);
}

 

方法2、批量新增User信息

// 批量新增User訪問地址: http://localhost:8080/jpa/batchInsertUser
@RequestMapping(value="/jpa/batchInsertUser")
public List<User> batchInsertUser() {
    User user = null;
    List<User> list = new ArrayList<User>();
    for (int i=0; i<10; i++) {
        user = new User();
        user.setEmpName("aaaa");
        user.setEmpNO("bbbb");
        user.setCreateDate(new Date());
        list.add(user);
    }
    List<User> userList = userRepository.saveAll(list);
    return userList;
}

 

方法3、JPA自帶分頁,查詢全部用戶信息。

/**
 * JPA自帶分頁,查詢全部用戶信息
 * 訪問地址: http://localhost:8080/jpa/findAll
 */
@RequestMapping(value="/jpa/findAll")
public Page<User> findAll() {
    Pageable pageable = Pageable.unpaged();
    Page<User> page = userRepository.findAll(pageable);
    return page;
}

// 自定義方式獲取全部User信息, 訪問地址: http://localhost:8080/jpa/listUser
@RequestMapping(value="/jpa/listUser")
public List<User> listUser() {
    List<User> list = userRepository.listUser();
    return list;
}

 

方法4、根據ID查詢User數據

// 根據ID查詢User數據,訪問地址: http://localhost:8080/jpa/findByEmpId
@RequestMapping(value="/jpa/findByEmpId")
public User findByEmpId() {
    Long empId = 1L; // ID
    User user = userRepository.findByEmpId(empId);
    return user;
}

 

三)Table 'hibernate_sequence' doesn't exist解決方案

方案一:在application.ymlapplication.properties增加以下配置:

spring.jpa.properties.hibernate.hbm2ddl.auto=update

這個hibernate.hbm2ddl.auto參數的作用主要用於:自動創建、更新、驗證數據庫表結構。

有四個值:

create: 每次加載 hibernate 時都會刪除上一次的生成的表,然後根據你的 model 類再重新來生成新表,哪怕兩次沒有任何改變也要這樣執行,這就是導致數據庫表數據丟失的一個重要原因。

create-drop :每次加載 hibernate 時根據 model 類生成表,但是 sessionFactory 一關閉,表就自動刪除。

update:最常用的屬性,第一次加載 hibernate 時根據 model 類會自動建立起表的結構(前提是先建立好數據庫),以後加載 hibernate 時根據 model 類自動更新表結構,即使表結構改變了但表中的行仍然存在不會刪除以前的行。要注意的是當部署到服務器後,表結構是不會被馬上建立起來的,是要等 應用第一次運行起來後纔會。

validate :每次加載 hibernate 時,驗證創建數據庫表結構,只會和數據庫中的表進行比較,不會創建新表,但是會插入新值。

 

實體類配置如下:

@Id
@GeneratedValue
private Long empId;

 

方案二:直接在實體類中指定主鍵生成策略

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long empId;

 

四)JPA Repository方法名稱命名規則

方法名稱命名規則:findBy(關鍵字)+屬性名稱(屬性名稱的首字母大寫)+查詢條件(首字母大寫)

關鍵字

方法名

sql where 子句

And

findByNameAndPwd

where name= ? and pwd =?

Or

findByNameOrSex

where name= ? or sex=?

Is,Equal

findById,findByIdEquals

where id= ?

Between

findByIdBetween

where id between ? and ?

LessThan

findByIdLessThan

where id < ?

LessThanEqual

findByIdLessThanEquals

where id <= ?

GreaterThan

findByIdGreaterThan

where id > ?

GreaterThanEqual

findByIdGreaterThanEquals

where id > = ?

After

findByIdAfter

where id > ?

Before

findByIdBefore

where id < ?

IsNull

findByNameIsNull

where name is null

isNotNull,Not

findByNameNotNull

where name is not Null null

Like

findByNameLike

where name like ?

NotLike

findByNameNotLike

where name not like ?

StartingWith

findByNameStartingWith

where name like ‘?%’

EndingWith

findByNameEndingWith

where name like ‘%?’

Containing

findByNameContaining

where name like ‘%?%’

OrderBy

findByIdOrderByXDesc

where id=? order by x desc

Not

findByNameNot

where name <> ?

In

findByIdIn(Collection<?> c)

where id in (?)

NotIn

findByIdNotIn(Collection<?> c)

where id not in (?)

True

findByAaaTue

where aaa = true

False

findByAaaFalse

where aaa = false

IgnoreCase

findByNameIgnoreCase

where UPPER(name)=UPPER(?)

 

識別二維碼關注個人微信公衆號

本章完結,待續,歡迎轉載!
 
本文說明:該文章屬於原創,如需轉載,請標明文章轉載來源!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章