SpringBoot集成JPA及基本使用

前言

在讲解SpringBoot集成JPA之前,先简单了解一下几个概念,JDBC、ORM、JPA以及Spring Data JPA。

1.1 JDBC

JDBC(Java DataBase Connectivity),是java连接数据库操作的原生接口API,为开发者访问数据库提供标准的接口。各数据库厂商依照JDBC规范,实现规范中的接口,实现数据库的连接。Java开发者使用同样的访问代码,配置不同的Driver、url以及账号,即可实现不同数据库厂家的数据库连接。

当数据库连接之后,通过拼接SQL语句,发送到数据库,达到对数据库中数据的操作。

缺点:

1)业务代码耦合SQL字符串拼接语句,维护比较麻烦;

2)不符合Java面向对象的编程思想;

1.2 ORM

对象-关系映射(Object-Relational Mapping,简称ORM),是一种描述对象与关系数据库之间映射的规范,采用面向对象编程的思想,操作数据库。

在Java中,ORM就是将Java类与DB中的Table表进行映射,代码中对相关Java类的操作,关联到数据库后,即体现为DB中关联的Table表的操作。

1.3 JPA

JPA是Java Persistence API的简称,中文名Java持久层API,是JDK5.x版本引入的。JPA的宗旨是为POJO提供持久化标准规范。

JAP采用ORM对象关系映射,以Java面向对象的编程思想,在javax.persistence包下提供对实体对象的CRUD操作,将开发者从繁琐的JDBC和SQL代码中解脱出来。

1.4 Spring Data JPA

Spring Data JPA是Spring提供的一套简化JPA开发的框架,按照约定好的方法名命规则写DAO层接口,可以在不写接口实现的情况下,实现对数据库中Table的操作,同时提供了除CRUD操作之外的许多功能,如分页、复杂查询等。

SpringBoot集成Spring Data JPA

2.1 引入依赖

在SpringBoot项目的pom.xml中引入相关依赖。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- 参数校验 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <!-- JPA是针对数据库的操作,需要引入对应的数据库 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
            <version>2.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
            <scope>compile</scope>
        </dependency>

2.2 参数配置

在application.yml中配置数据库连接信息。

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowMultiQueries=true
    username: root
    password: 123456
    druid:
      stat-view-servlet:
        login-username: druid
        login-password: 123456
        url-pattern: /druid/*
        enabled: true
      filters: stat,wall
      web-stat-filter:
        url-pattern: /
        enabled: true
        exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*'
      filter:
        wall:
          config: #支持单个事物多条sql语句执行
            multi-statement-allow: true
            none-base-statement-allow: true
          enabled: true
  jpa:
    hibernate:
      naming:
        #Java代码实体字段命名与数据库表结构字段之间的名称映射策略
        #当没有使用@Table和@Column注解时,implicit-strategy配置项才会被使用,当对象模型中已经指定时,
        #implicit-strategy并不会起作用。
        #implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
        #physical-strategy一定会被应用,与对象模型中是否显式地指定列名或者已经被隐式决定无关,
        #SpringPhysicalNamingStrategy:表名,字段为小写,当有大写字母的时候会添加下划线分隔符号,默认值。
        #PhysicalNamingStrategyStandardImpl:直接映射,不会做过多的处理,会禁止将驼峰转为下划线
        #physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
    # 用于指定 Session 是否在视图渲染完成后自动关闭,默认为false,意味着在视图渲染完成后,session会自动关闭
    open-in-view: false
    # 控制是否打印运行时的SQL语句与参数信息
    show-sql: true

说明:spring.jpa.open-in-view通常设置为false,即当视图渲染完成后,Session自动关闭。Spring使用AOP(面向切面编程思想)管理事务,在方法调用前和调用后插入事务处理逻辑。如果open-in-view设置为true时,由于Session保持打开状态,可能导致事务的隔离性问题。另外,在多线程环境中,如果多个线程共享同一个Session,并且该Session的open-in-view设置为true,也可能导致事务的隔离性问题。

2.3 添加数据库表实体类Entity

package com.jingai.jpa.dao.entity;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

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

@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
@JsonIgnoreProperties(value = { "hibernateLazyInitializer"})
@Table(name = "tb_product")
public class ProductEntity {

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

    private String name;

    private String deliveryNo;

    private String customer;

    private String securityCode;

    private Date createTime;

    private Date validateTime;

    private int validateNum;

}

说明:如果数据库访问时报com.fasterxml.jackson.databind.exc.InvalidDefinitionException异常,是因为在转化成json的时候,fasterxml.jackson将对象转换为json报错,发现有字段值为null。底层的hibernate会给被管理的Entity加入一个hibernateLazyInitializer属性,

jsonplugin会把hibernateLazyInitializer也拿出来操作,并读取里面一个不能被反射操作的属性就产生了这个异常。

2.4 添加Repository

继承JpaRepository接口,自动提供了基本的CRUD、分页、批量保存接口。

package com.jingai.jpa.dao;

import com.jingai.jpa.dao.entity.ProductEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface ProductRepository extends JpaRepository<ProductEntity, Long> {

    List<ProductEntity> findByPidBetween(long startPid, long endPid);

    @Query("from ProductEntity where name like ?1")
    List<ProductEntity> searchByName(String name);

}

在Repository接口中,除了JpaRepository自动提供的接口以外,可以自定义接口。

1)通过Spring Data JPA的命名规范,直接定义接口,无需写Sql语句;

2)使用自定义的SQL语句;

2.5 添加Service

package com.jingai.jpa.service;

import com.jingai.jpa.dao.entity.ProductEntity;

import java.util.List;

public interface ProductService {

    ProductEntity save(ProductEntity entity);

    ProductEntity getById(long id);

    List<ProductEntity> findByPidBetween(long start, long end);

    List<ProductEntity> searchByName(String name);

    int batchSave(List<ProductEntity> list)

}

2.6 添加Service实现类

在Service实现类中,引入Repository对象,对数据库表进行操作。在此处,不仅可以使用ProductRepository中定义的searchByName和findByIdBetween(),而且还可以访问save、getById以及saveAll,这些是在JpaRespository中提供的实现。

package com.jingai.jpa.service.impl;

import com.jingai.jpa.dao.ProductRepository;
import com.jingai.jpa.dao.entity.ProductEntity;
import com.jingai.jpa.service.ProductService;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;

@Service
public class ProductServiceImpl implements ProductService {

    @Resource
    private ProductRepository productRepository;

    @Override
    public ProductEntity save(ProductEntity entity) {
        return productRepository.save(entity);
    }

    @Override
    public ProductEntity getById(long id) {
        return productRepository.getById(id);
    }

    @Override
    public List<ProductEntity> findByPidBetween(long startPid, long endPid) {
        return productRepository.findByPidBetween(startPid, endPid);
    }

    @Override
    public List<ProductEntity> searchByName(String name) {
        return productRepository.searchByName("%" + name + "%");
    }

    @Override
    public int batchSave(List<ProductEntity> list) {
        return productRepository.saveAll(list).size();
    }

}

2.7 添加Controller

package com.jingai.jpa.controller;

import com.jingai.jpa.dao.entity.ProductEntity;
import com.jingai.jpa.service.ProductService;
import com.jingai.jpa.util.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.persistence.EntityNotFoundException;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.util.Map;

@Slf4j
@Validated
@RestController
@RequestMapping("product")
public class ProductController {

    @Resource
    private ProductService productService;

    @GetMapping("get")
    public Map<String, Object> get(@NotNull(message = "id不能为空") @Min(value = 1, message = "id无效") Long id) {
        ProductEntity entity = productService.getById(id);
        try {
            if (entity == null || !StringUtils.hasText(entity.getSecurityCode())) {
                log.info(String.format("id为%d的记录不存在", id));
            }
        } catch(EntityNotFoundException e) {
            return ResponseUtil.fail(String.format("id为%d的记录不存在", id));
        }
        return ResponseUtil.success(entity);
    }

}

在Controller类中引入Service,访问Service的提供的接口,实现对数据库的操作。其他接口的访问也是使用类似的方法,此处就不在贴代码了。

说明:@Validated、@NotNull、@Min为参数校验,详见:Spring validation参数校验基本使用_spring validate 参数-CSDN博客

Repository方法命名规则

规则:findBy(关键字)+ 属性名称(属性名称的首字母大写)+ 查询条件(首字母大写)

方法名词命名规范表

关键字      示例 SQL表达式
And findByCol1AndCol2(val1, val2) where col1 = ?1 and col2 = ?2
Or findByCol1OrCol2(val1, val2) where col1 = ?1 or col2 = ?2
Is、Equals findByColumn(val)、
findByColumnIs(val)、
findByColumnEquals(val)
where column = ?1
Between findByColBetween(val1, val2) where col between ?1 and ?2
LessThan、Before findByColLessThan(val)、
findByColBefore(val)
where col < ?1
LessThanEqual findByColLessThanEqual(val) whre col <= ?1
GreaterThan、After findByColGreaterThan(val)、
findByColAfter(val)
where col > ?1
GreaterThanEqual findByColGreaterThanEqual(val) where col >= ?1
IsNull findByColIsNull() where col is null
IsNotNull、NotNull findByColIsNotNull()、
findByColNotNull()
where col is not null
Like findByColLike(val) where col like ?1
NotLike findByColNotLike(val) where col not like ?1
StartingWith findByColStartingWith(val) where col like ?1
(参数增加前缀%)
EndingWith findByColEndingWith(val) where col like ?1
(参数增加后缀%)
Containing findByColContaining(val) where col likt ?1
(参数被%包裹)
OrderBy findByCol1OrderByCol2Asc(val) where col1 = ?1 order by col2 asc
Not findByColNot where col <> ?1
In findByColIn(Collection<?> val) where col in ?1
NotIn findByColNotIn(Collection<?> val) where col not in ?1
True findByColTrue() where col = true
False findByColFalse() where col = false
IgnoreCase findByColIgnoreCase(val) where upper(col) = upper(?1)

小结

限于篇幅,SpringBoot集成Spring Data JPA及基本使用就分享到这里。

关于本篇内容你有什么自己的想法或独到见解,欢迎在评论区一起交流探讨下吧。

相关推荐

  1. SpringBoot集成JPA基本使用

    2024-04-25 10:08:02       18 阅读
  2. Springboot集成JPA多Hibernate数据源

    2024-04-25 10:08:02       33 阅读
  3. Elasticsearch8搭建Springboot集成使用

    2024-04-25 10:08:02       17 阅读
  4. SpringBoot 3.2.1中使用JPA报错

    2024-04-25 10:08:02       38 阅读
  5. SpringBoot 整合 JPA:实战指南

    2024-04-25 10:08:02       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-04-25 10:08:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-04-25 10:08:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-04-25 10:08:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-04-25 10:08:02       18 阅读

热门阅读

  1. 直接扩频通信系统的Matlab实现

    2024-04-25 10:08:02       14 阅读
  2. pandas数据分析综合练习50题 - 地区房价分析

    2024-04-25 10:08:02       50 阅读
  3. NLP(7)--Embedding、池化、丢弃层

    2024-04-25 10:08:02       23 阅读
  4. 检查现有的remote repo 并换新的remote repo

    2024-04-25 10:08:02       31 阅读
  5. npm详解:Node.js的包管理器

    2024-04-25 10:08:02       17 阅读
  6. Linux 解压报错

    2024-04-25 10:08:02       12 阅读
  7. Kafka:分布式流处理平台的深度解析

    2024-04-25 10:08:02       14 阅读
  8. 【打工日常】解决docker对镜像pull的很慢的问题

    2024-04-25 10:08:02       15 阅读