6.2 Spring Boot集成jpa

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 6.2 Spring Boot集成jpaJava持久化API(JPA,Java Persistence API)是一个将对象映射为关系数据库的标准技术。

6.2 Spring Boot集成jpa

Java持久化API(JPA,Java Persistence API)是一个将对象映射为关系数据库的标准技术。JPA通过注解或XML描述ORM(Object Relationship Mapping,对象-关系表的映射关系),并将运行期的实体对象持久化到数据库中。

其中,SQL(结构化查询语言, Structured Query Language),是持久化操作中很重要的一个方面,通过面向对象而非面向数据库的查询语言查询数据,避免程序的SQL语句的紧耦合。

JPA的主要目标之一就是提供更加简单的编程模型:在JPA框架下创建实体和创建Java 类一样简单,没有任何的约束和限制,只需要使用 javax.persistence.Entity进行注解。

JPA的框架和接口也都非常简单,没有太多特别的规则和设计模式的要求,开发者可以很容易的掌握。

JPA基于非侵入式原则设计,因此可以很容易的和其它框架或者容器集成。

在SpringBoot中,如果我们想使用JPA作为数据库ORM层,很简单,我们只需要添加spring-boot-starter-data-jpa依赖即可:

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

spring-boot-starter-data-jpa提供了以下关键依赖:

  • Hibernate - 一个非常流行的JPA实现。
  • Spring Data JPA - 让实现基于JPA的repositories更容易。
  • Spring ORMs - Spring框架的ORM。

详细的依赖树如下

在SpringBoot中,模块依赖图如下:

当然,还有数据源的一些配置:

#mysql
spring.datasource.url = jdbc:mysql://localhost:3306/teda?useUnicode=true&characterEncoding=UTF8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.max-active=0
spring.datasource.max-idle=0
spring.datasource.min-idle=0
spring.datasource.max-wait=10000
spring.datasource.max-wait-millis=31536000

# Specify the DBMS
spring.jpa.database = MYSQL
# Show or not log for each sql query
spring.jpa.show-sql = true
# Hibernate ddl auto (create, create-drop, update)
spring.jpa.hibernate.ddl-auto = update
# Naming strategy
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
# stripped before adding them to the entity manager)
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

在实体类上使用@NamedQuery

我们可以直接在实体类上,定义查询方法。代码示例:

package com.steda.entity

import java.util.Date
import javax.persistence._

import scala.beans.BeanProperty

@Entity
@NamedQuery(name = "findByState",
  query = "select t from TedaCase t where t.state = ?1")
class TedaCase {
  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @BeanProperty
  var id: Long = _
  @BeanProperty
  var name: String = _
  ...
}

然后,我们继承CrudRepository接口之后,定义一个同名的方法findByState,就可以直接用这个方法了,它会执行我们定义好的查询语句并返回结果。代码示例:

package com.steda.dao


import com.steda.entity.TedaCase
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.CrudRepository

trait TedaCaseDao extends CrudRepository[TedaCase, java.lang.Long] {
  def findByState(state: Integer): java.util.List[TedaCase]
  ...
}


同样的,如果我们想定义多条NamedQuery,也是可以的。代码示例如下:

@NamedQueries({ 
        @NamedQuery(name="findAllUser",query="select u from User u"), 
        @NamedQuery(name="findUserWithId",query="select u from User u WHERE u.id = ?1"), 
        @NamedQuery(name="findUserWithName",query="select u from User u WHERE u.name = :name") 
         
}) 

其背后的方法的生成自动生成原理,是由类org.hibernate.jpa.spi.AbstractEntityManagerImpl来完成的。实质思想就是通过注解在运行时动态生成对应的查询方法,实现了元编程。

在接口方法上使用@Query

指定了nativeQuery = true,即使用原生的sql语句查询。使用原生的sql语句, 根据数据库的不同,在sql的语法或结构方面可能有所区别。举例如下:

@Query(value="select * from param_json_template order by id desc",nativeQuery = true)

默认false。我们可以使用java对象作为表名来查询。但是要注意,就不能使用原生sql的select * from ,要使用java字段名。举例如下:

@Query(value="select  id,paramObject,paramJsonTemplateStr  from ParamJsonTemplate p where p.paramObject like %:paramObject% order by p.id desc")

如果我们想指定参数名,可以通过@Param(value = "paramObject") 来指定方法变量名,然后在查询语句中,使用:paramObject来使用该变量。
举例如下:

@Query(value="select  id,paramObject,paramJsonTemplateStr  from ParamJsonTemplate p where p.paramObject like %:paramObject% order by p.id desc")
  def findByParamObject(@Param(value = "paramObject") paramObject:String): java.util.List[ParamJsonTemplate]

完整实例代码:

package com.steda.dao

import org.springframework.data.repository.CrudRepository
import com.steda.entity.ParamJsonTemplate
import org.springframework.data.jpa.repository.Query
import org.springframework.data.repository.query.Param

trait ParamJsonTemplateDao extends CrudRepository[ParamJsonTemplate, java.lang.Long] {


  @Query(value="select * from param_json_template order by id desc",nativeQuery = true)
  def findAll(): java.util.List[ParamJsonTemplate]


  @Query(value="select  id,paramObject,paramJsonTemplateStr  from ParamJsonTemplate p where p.paramObject like %:paramObject% order by p.id desc")
  def findByParamObject(@Param(value = "paramObject") paramObject:String): java.util.List[ParamJsonTemplate]

  def save(p: ParamJsonTemplate): ParamJsonTemplate

}

JpaRepository 创建查询的顺序

Spring Data JPA 在为接口创建代理对象时,可以利用创建方法进行查询,也可以利用@Query注释进行查询,那么如果在命名规范的方法上使用了@Query,那spring data jpa是执行我们定义的语句进行查询,还是按照规范的方法进行查询呢?它该优先采用哪种策略呢?

QueryLookupStrategy定义了3个属性key,用以指定查找的顺序。它有如下三个取值:

1:create-if-not-found:如果方法通过@Query指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则通过解析方法名字来创建查询。这是 query-lookup-strategy 属性的默认值。

2:create:通过解析方法名字来创建查询。即使有符合的命名查询,或者方法通过 @Query指定的查询语句,都将会被忽略

3:use-declared-query:如果方法通过@Query指定了查询语句,则使用该语句实现查询;如果没有,则查找是否定义了符合条件的命名查询,如果找到,则使用该命名查询;如果两者都没有找到,则抛出异常。

Spring Data JPA 在org.springframework.data.repository.query.QueryLookupStrategy中定义了如下策略枚举值:

CREATE, USE_DECLARED_QUERY, CREATE_IF_NOT_FOUND

其源码如下:

/*
 * Copyright 2008-2010 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springframework.data.repository.query;

import java.lang.reflect.Method;
import java.util.Locale;

import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.util.StringUtils;

/**
 * Strategy interface for which way to lookup {@link RepositoryQuery}s.
 * 
 * @author Oliver Gierke
 */
public interface QueryLookupStrategy {

    public static enum Key {

        CREATE, USE_DECLARED_QUERY, CREATE_IF_NOT_FOUND;

        /**
         * Returns a strategy key from the given XML value.
         * 
         * @param xml
         * @return a strategy key from the given XML value
         */
        public static Key create(String xml) {

            if (!StringUtils.hasText(xml)) {
                return null;
            }

            return valueOf(xml.toUpperCase(Locale.US).replace("-", "_"));
        }
    }

    /**
     * Resolves a {@link RepositoryQuery} from the given {@link QueryMethod} that can be executed afterwards.
     * 
     * @param method
     * @param metadata
     * @param namedQueries
     * @return
     */
    RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries);
}

具体的实现逻辑,在org.springframework.data.jpa.repository.query.JpaQueryLookupStrategy中。其关键方法如下:


    /**
     * Creates a {@link QueryLookupStrategy} for the given {@link EntityManager} and {@link Key}.
     * 
     * @param em must not be {@literal null}.
     * @param key may be {@literal null}.
     * @param extractor must not be {@literal null}.
     * @param evaluationContextProvider must not be {@literal null}.
     * @return
     */
    public static QueryLookupStrategy create(EntityManager em, Key key, QueryExtractor extractor,
            EvaluationContextProvider evaluationContextProvider) {

        Assert.notNull(em, "EntityManager must not be null!");
        Assert.notNull(extractor, "QueryExtractor must not be null!");
        Assert.notNull(evaluationContextProvider, "EvaluationContextProvider must not be null!");

        switch (key != null ? key : Key.CREATE_IF_NOT_FOUND) {
            case CREATE:
                return new CreateQueryLookupStrategy(em, extractor);
            case USE_DECLARED_QUERY:
                return new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider);
            case CREATE_IF_NOT_FOUND:
                return new CreateIfNotFoundQueryLookupStrategy(em, extractor, new CreateQueryLookupStrategy(em, extractor),
                        new DeclaredQueryLookupStrategy(em, extractor, evaluationContextProvider));
            default:
                throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key));
        }
    }


从这句switch (key != null ? key : Key.CREATE_IF_NOT_FOUND),我们可以看出默认值是CREATE_IF_NOT_FOUND。

小结

本章示例工程源代码:

https://github.com/EasySpringBoot/teda

参考资料:
1.http://docs.jboss.org/hibernate/orm/5.2/quickstart/html_single/
2.https://spring.io/guides/gs/accessing-data-jpa/
3.http://baike.baidu.com/item/JPA

相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
7天前
|
NoSQL Java 关系型数据库
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
本文介绍在 Spring Boot 中集成 Redis 的方法。Redis 是一种支持多种数据结构的非关系型数据库(NoSQL),具备高并发、高性能和灵活扩展的特点,适用于缓存、实时数据分析等场景。其数据以键值对形式存储,支持字符串、哈希、列表、集合等类型。通过将 Redis 与 Mysql 集群结合使用,可实现数据同步,提升系统稳定性。例如,在网站架构中优先从 Redis 获取数据,故障时回退至 Mysql,确保服务不中断。
45 0
微服务——SpringBoot使用归纳——Spring Boot 中集成Redis——Redis 介绍
|
7天前
|
JSON Java API
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的使用
本文详细介绍了Swagger2的使用方法,包括在Spring Boot项目中的配置与应用。重点讲解了Swagger2中常用的注解,如实体类上的`@ApiModel`和`@ApiModelProperty`,Controller类上的`@Api`、`@ApiOperation`以及参数上的`@ApiParam`等。通过示例代码展示了如何为实体类和接口添加注解,并在页面上生成在线接口文档,实现接口测试。最后总结了Swagger的优势及其在项目开发中的重要性,提供了课程源代码下载链接供学习参考。
51 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的使用
|
7天前
|
缓存 Java API
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
本文介绍了在Spring Boot中配置Swagger2的方法。通过创建一个配置类,添加`@Configuration`和`@EnableSwagger2`注解,使用Docket对象定义API文档的详细信息,包括标题、描述、版本和包路径等。配置完成后,访问`localhost:8080/swagger-ui.html`即可查看接口文档。文中还提示了可能因浏览器缓存导致的问题及解决方法。
47 0
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的配置
|
7天前
|
安全 Java Apache
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 身份和权限认证
本文介绍了 Apache Shiro 的身份认证与权限认证机制。在身份认证部分,分析了 Shiro 的认证流程,包括应用程序调用 `Subject.login(token)` 方法、SecurityManager 接管认证以及通过 Realm 进行具体的安全验证。权限认证部分阐述了权限(permission)、角色(role)和用户(user)三者的关系,其中用户可拥有多个角色,角色则对应不同的权限组合,例如普通用户仅能查看或添加信息,而管理员可执行所有操作。
40 0
|
7天前
|
安全 Java 数据安全/隐私保护
微服务——SpringBoot使用归纳——Spring Boot中集成 Shiro——Shiro 三大核心组件
本课程介绍如何在Spring Boot中集成Shiro框架,主要讲解Shiro的认证与授权功能。Shiro是一个简单易用的Java安全框架,用于认证、授权、加密和会话管理等。其核心组件包括Subject(认证主体)、SecurityManager(安全管理员)和Realm(域)。Subject负责身份认证,包含Principals(身份)和Credentials(凭证);SecurityManager是架构核心,协调内部组件运作;Realm则是连接Shiro与应用数据的桥梁,用于访问用户账户及权限信息。通过学习,您将掌握Shiro的基本原理及其在项目中的应用。
41 0
|
7天前
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于 xml 的整合
本教程介绍了基于XML的MyBatis整合方式。首先在`application.yml`中配置XML路径,如`classpath:mapper/*.xml`,然后创建`UserMapper.xml`文件定义SQL映射,包括`resultMap`和查询语句。通过设置`namespace`关联Mapper接口,实现如`getUserByName`的方法。Controller层调用Service完成测试,访问`/getUserByName/{name}`即可返回用户信息。为简化Mapper扫描,推荐在Spring Boot启动类用`@MapperScan`注解指定包路径避免逐个添加`@Mapper`
29 0
|
7天前
|
前端开发 Java 数据库
微服务——SpringBoot使用归纳——Spring Boot集成Thymeleaf模板引擎——Thymeleaf 介绍
本课介绍Spring Boot集成Thymeleaf模板引擎。Thymeleaf是一款现代服务器端Java模板引擎,支持Web和独立环境,可实现自然模板开发,便于团队协作。与传统JSP不同,Thymeleaf模板可以直接在浏览器中打开,方便前端人员查看静态原型。通过在HTML标签中添加扩展属性(如`th:text`),Thymeleaf能够在服务运行时动态替换内容,展示数据库中的数据,同时兼容静态页面展示,为开发带来灵活性和便利性。
34 0
|
7天前
|
Java Maven 微服务
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档——Swagger2 的 maven 依赖
在项目中使用Swagger2工具时,需导入Maven依赖。尽管官方最高版本为2.8.0,但其展示效果不够理想且稳定性欠佳。实际开发中常用2.2.2版本,因其稳定且界面友好。以下是围绕2.2.2版本的Maven依赖配置,包括`springfox-swagger2`和`springfox-swagger-ui`两个模块。
29 0
|
7天前
|
前端开发 Java API
微服务——SpringBoot使用归纳——Spring Boot集成 Swagger2 展现在线接口文档—— Swagger 简介
第6课介绍了在Spring Boot中集成Swagger2以展示在线接口文档的方法。随着前后端分离架构的发展,API文档成为连接前端与后端开发的重要纽带。然而,代码更新频繁导致文档难以同步维护,Swagger2解决了这一问题。通过Swagger,在线API文档不仅方便了接口调用方查看和测试,还支持开发者实时测试接口数据。本文使用Swagger 2.2.2版本,讲解如何在Spring Boot项目中导入并配置Swagger2工具,从而高效管理接口文档。
41 0
|
7天前
|
消息中间件 存储 Java
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装
本教程介绍ActiveMQ的安装与基本使用。首先从官网下载apache-activemq-5.15.3版本,解压后即可完成安装,非常便捷。启动时进入解压目录下的bin文件夹,根据系统选择win32或win64,运行activemq.bat启动服务。通过浏览器访问`http://127.0.0.1:8161/admin/`可进入管理界面,默认用户名密码为admin/admin。ActiveMQ支持两种消息模式:点对点(Queue)和发布/订阅(Topic)。前者确保每条消息仅被一个消费者消费,后者允许多个消费者同时接收相同消息。
38 0
微服务——SpringBoot使用归纳——Spring Boot中集成ActiveMQ——ActiveMQ安装

热门文章

最新文章