第九章: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(?)

 

识别二维码关注个人微信公众号

本章完结,待续,欢迎转载!
 
本文说明:该文章属于原创,如需转载,请标明文章转载来源!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值