Skip to content

spring-data-jpa

简介

JPA(Java Persistence API) 意即 Java 持久化 API,是 Sun 官方在 JDK5.0 后提出的 Java 持久化规范。JPA 的出现主要是为了简化持久层开发以及整合 ORM 技术。JPA 包括以下 3 方面的技术:

  1. ORM 映射元数据:支持 XML 和注解两种元数据的形式,元数据描述对象和表之间的映射关系
  2. API:操作实体对象来执行 CRUD 操作
  3. 查询语言:通过面向对象而非面向数据库的查询语言(JPQL)查询数据,避免程序的 SQL 语句紧密耦合

Spring Data JPA 极大的简化 JPA 的写法,可以在几乎不用写实现的情况下,实现对数据的访问和操作。除了 CRUD 外,还包括如分页、排序等一些常用的功能。它的核心概念包括:

  • Repository:最顶层的接口,是一个空的接口,目的是为了统一所有 Repository 的类型,且能让组件扫描的时候自动识别。
  • CrudRepository :是Repository的子接口,提供CRUD的功能
  • PagingAndSortingRepository:是CrudRepository的子接口,添加分页和排序的功能
  • JpaRepository:是PagingAndSortingRepository的子接口,增加了一些实用的功能,比如:批量操作等。
  • JpaSpecificationExecutor:用来做负责查询的接口
  • Specification:是Spring Data JPA提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可

Y9 主要使用了 Spring Boot + Spring Data Jpa 来做数据的 CRUD 等操作。具体 JpaRepository 提供的方法可查看:https://docs.spring.io/spring-data/jpa/docs/2.7.18/reference/html/#jpa.query-methods.query-creation

功能引用

Y9提供了两种JPA数据源配置模块

risenet-y9boot-starter-jpa-public

risenet-y9boot-starter-jpa-tenant

druid 是阿里巴巴开源平台上一个数据库连接池实现,它结合了 C3P0、DBCP、PROXOOL 等 DB 池的优点,同时加入了日志监控,可以很好的监控 DB 池连接和 SQL 的执行情况,可以说是针对监控而生的 DB 连接池,据说是目前最好的连接池。Y9 将数据连接池由 druid 来接管。其 druid 数据源属性配置参考如下所示:

(1)application.properties 配置:

需要排除DataSourceAutoConfiguration和HibernateJpaAutoConfiguration

properties
spring.autoconfigure.exclude[0]=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
spring.autoconfigure.exclude[1]=org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration

spring.data.jpa.repositories.bootstrap-mode=default
spring.data.jpa.repositories.enabled=false
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.mergeSql=true
spring.datasource.druid.filter.stat.slow-sql-millis=3000
spring.datasource.druid.filter.wall.config.drop-table-allow=false
spring.datasource.druid.filter.wall.enabled=true
spring.datasource.druid.stat-view-servlet.enabled=false
spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin
spring.datasource.druid.stat-view-servlet.reset-enable=false
spring.datasource.druid.stat-view-servlet.allow=127.0.0.1
spring.datasource.druid.web-stat-filter.enabled=false
spring.datasource.druid.web-stat-filter.url-pattern=/*
spring.datasource.druid.web-stat-filter.exclusions=*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/static/*
spring.jpa.generate-ddl=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.naming.implicit-strategy=org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
spring.jpa.open-in-view=false
spring.jpa.properties.hibernate.hbm2ddl.auto=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect
spring.jpa.properties.hibernate.jdbc.batch_size=100
spring.jpa.properties.hibernate.show_sql=true
yaml
spring:
    autoconfigure:
        exclude:
            - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
            - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
    data:
        jpa:
            repositories:
                bootstrap-mode: default
                enabled: false
    datasource:
        druid:
            filter:
                stat:
                    log-slow-sql: true
                    mergeSql: true
                    slow-sql-millis: 3000
                wall:
                    config:
                        drop-table-allow: false
                    enabled: true
            stat-view-servlet:
                enabled: false
                url-pattern: /druid/*
                login-username: admin
                login-password: admin
                reset-enable: false
                allow: 127.0.0.1
            web-stat-filter:
                enabled: false
                url-pattern: /*
                exclusions: '*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*,/static/*'
    jpa:
        generate-ddl: true
        database-platform: org.hibernate.dialect.MySQL8Dialect
        hibernate: 
            naming:
                implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        open-in-view: false
        properties:
            hibernate:
                hbm2ddl:
                    auto: none
                dialect: org.hibernate.dialect.MySQL8Dialect
                jdbc:
                    batch_size: 100
                show_sql: true

公共数据源的配置

引用与配置

(1)修改 pom.xml

将本公司的私服仓库地址添加到 pom.xml 文件中。

xml
<repositories>
    <repository>
        <id>y9-internet-repo</id>
        <url>https://svn.youshengyun.com:9900/nexus/repository/maven-public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <!-- <updatePolicy>always</updatePolicy> -->
            <!-- always,daily(default),interval:XXX,never -->
        </snapshots>
    </repository>
</repositories>

(2)将risenet-y9boot-starter-jpa-public 添加到 pom.xml 的依赖列表里.

xml
<dependency>
    <groupId>net.risesoft</groupId>
    <artifactId>risenet-y9boot-starter-jpa-public</artifactId>
     <version>[最新版本]</version>
</dependency>

(3)添加数据源属性配置,修改属性文件 application.properties

properties
spring.datasource.druid.y9-public.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.y9-public.url=jdbc:mysql://218.60.41.112:3306/y9_public?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false
spring.datasource.druid.y9-public.username=root
spring.datasource.druid.y9-public.password=Y9i-83204585
spring.datasource.druid.y9-public.initialSize=1
spring.datasource.druid.y9-public.maxActive=20
spring.datasource.druid.y9-public.maxPoolPreparedStatementPerConnectionSize=100
spring.datasource.druid.y9-public.maxWait=60000
spring.datasource.druid.y9-public.minEvictableIdleTimeMillis=300000
spring.datasource.druid.y9-public.minIdle=1
spring.datasource.druid.y9-public.poolPreparedStatements=true
spring.datasource.druid.y9-public.testOnBorrow=false
spring.datasource.druid.y9-public.testOnReturn=false
spring.datasource.druid.y9-public.testWhileIdle=true
spring.datasource.druid.y9-public.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.y9-public.useGlobalDataSourceStat=true
spring.datasource.druid.y9-public.validationQuery=SELECT 1 FROM DUAL
#设置实体类扫描位置
y9.feature.jpa.packagesToScanEntityPublic=net.risesoft.y9public.entity
y9.feature.jpa.packagesToScanRepositoryPublic=net.risesoft.y9public.repository
yaml
spring:
        datasource:
        druid:
            y9-public:
                driver-class-name: com.mysql.cj.jdbc.Driver
                url: jdbc:mysql://localhost:3306/y9_public?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false&allowPublicKeyRetrieval=true
                username: root
                password: 111111
                initialSize: 1
                maxActive: 20
                maxPoolPreparedStatementPerConnectionSize: 100
                maxWait: 60000
                minEvictableIdleTimeMillis: 300000
                minIdle: 1
                poolPreparedStatements: true
                testOnBorrow: false
                testOnReturn: false
                testWhileIdle: true
                timeBetweenEvictionRunsMillis: 60000
                useGlobalDataSourceStat: true
                validationQuery: SELECT 1 FROM DUAL
y9:
    feature:
        jpa:
            packagesToScanEntityPublic: net.risesoft.y9public.entity
            packagesToScanRepositoryPublic: net.risesoft.y9public.repository

使用说明

(1)创建数据源:y9PublicDS。

(2)创建 Entity 持久化操作的主要对象工厂 EntityManagerFactory:rsPublicEntityManagerFactory

(3)提供事务 PlatformTransactionManager:rsPublicTransactionManager

使用示例:

java
@Transactional(value = "rsPublicTransactionManager", readOnly = true)
public interface AppFolderRepository extends JpaRepository<AppFolder, String>, JpaSpecificationExecutor<AppFolder> {

}

(4)创建 JDBC 查询 JdbcTemplate Bean:jdbcTemplate4Public

使用示例:

java
@Autowired
@Qualifier("jdbcTemplate4Public")
private JdbcTemplate jdbcTemplate4Public;

@RequestMapping("/test")
public void test(HttpServletResponse response) {
	try {
		String sql = "select id from rs_common_tenant";
		List<String> tenantIDList = jdbcTemplate4Public.queryForList(sql, String.class);
		for (String tenantID : tenantIDList) {
			System.out.println(tenantID);
		}	
	} catch (IOException e) {
	
	}
}

租户数据源的配置

使用与配置

(1)修改 pom.xml

将本公司的私服仓库地址添加到 pom.xml 文件中。

xml
<repositories>
    <repository>
        <id>y9-internet-repo</id>
        <url>https://svn.youshengyun.com:9900/nexus/repository/maven-public/</url>
        <releases>
            <enabled>true</enabled>
        </releases>
        <snapshots>
            <enabled>true</enabled>
            <!-- <updatePolicy>always</updatePolicy> -->
            <!-- always,daily(default),interval:XXX,never -->
        </snapshots>
    </repository>
</repositories>

(2)将 risenet-y9boot-starter-jpa-tenant 添加到 pom.xml 的依赖列表里.

xml
<dependency>
    <groupId>net.risesoft</groupId>
    <artifactId>risenet-y9boot-starter-jpa-tenant</artifactId>
    <version>[最新版本]</version>
</dependency>

(3)多租户数据源的defaultDataSource通过属性spring.datasource.druid.tenantDefault指定,默认为spring.datasource.druid.y9Public,当然可以指定本应用自己的,比如spring.datasource.druid.flowable,修改属性文件application.properties如下:

properties
spring.datasource.druid.tenantDefault=spring.datasource.druid.flowable
spring.datasource.druid.flowable.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.flowable.url=jdbc:mysql://localhost:3306/y9_flowable?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false
spring.datasource.druid.flowable.username=root
spring.datasource.druid.flowable.password=111111
spring.datasource.druid.flowable.initialSize=1
spring.datasource.druid.flowable.maxActive=20
spring.datasource.druid.flowable.maxPoolPreparedStatementPerConnectionSize=100
spring.datasource.druid.flowable.maxWait=60000
spring.datasource.druid.flowable.minEvictableIdleTimeMillis=300000
spring.datasource.druid.flowable.minIdle=1
spring.datasource.druid.flowable.poolPreparedStatements=true
spring.datasource.druid.flowable.testOnBorrow=false
spring.datasource.druid.flowable.testOnReturn=false
spring.datasource.druid.flowable.testWhileIdle=true
spring.datasource.druid.flowable.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.flowable.useGlobalDataSourceStat=true
spring.datasource.druid.flowable.validationQuery=SELECT 1 FROM DUAL

#实体类扫描位置
y9.feature.jpa.packagesToScanEntityTenant=net.risesoft.entity
y9.feature.jpa.packagesToScanRepositoryTenant=net.risesoft.repository
yaml
spring:
    datasource:
        druid:
            tenantDefault: spring.datasource.druid.example
            example:
                driver-class-name: com.mysql.cj.jdbc.Driver
                url: jdbc:mysql://localhost:3306/y9_flowable?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false
                password: 111111
                username: root
                initialSize: 1
                maxActive: 20
                maxPoolPreparedStatementPerConnectionSize: 100
                maxWait: 60000
                minEvictableIdleTimeMillis: 300000
                minIdle: 1
                poolPreparedStatements: true
                testOnBorrow: false
                testOnReturn: false
                testWhileIdle: true
                timeBetweenEvictionRunsMillis: 60000
                useGlobalDataSourceStat: true
                validationQuery: SELECT 1 FROM DUAL
y9:
    feature:
        jpa:
            packagesToScanEntityTenant: net.risesoft.entity
            packagesToScanRepositoryTenant: net.risesoft.repository

使用说明

(1)创建数据源:y9PublicDS和defaultDataSource。

(2)创建 Entity 持久化操作的主要对象工厂 EntityManagerFactory:rsTenantEntityManagerFactory, entityManagerFactory

(3)提供事务 PlatformTransactionManager:rsTenantTransactionManager、transactionManager

使用示例:

java
@Transactional(value = "rsTenantTransactionManager", readOnly = true)
public interface AppItemRepository extends JpaRepository<AppItem, String>, JpaSpecificationExecutor<AppItem> {

}

(4)创建 JDBC 查询 JdbcTemplate Bean:jdbcTemplate4Tenant

使用示例:

java
@Autowired
@Qualifier("jdbcTemplate4Tenant")
private JdbcTemplate jdbcTemplate4Tenant;

@RequestMapping("/test")
public void test(HttpServletResponse response) {
	try {
		String sql = "select id from RC8_ORG_POSITION";
		List<String> positionIDs = jdbcTemplate4Tenant.queryForList(sql, String.class);
		for (String positionID : positionIDs) {
			System.out.println(positionID);
		}	
	} catch (IOException e) {
	
	}
}

数据库多租户数据源管理

提供数据源切换工具,可通过数据库轮询和 Kafka 监听两个方式监听数据源的变化,此外还提供 Liquibase 管理数据表结构的变化。

注:租户数据源的 Liquibase 管理管理需要配合数字底座的系统管理,先在数字底座生成系统才可使用。

引用与配置

(1)修改 pom.xml

<dependency>
    <groupId>net.risesoft</groupId>
    <artifactId>risenet-y9boot-starter-multi-tenant</artifactId>
    <version>[最新版本]</version>
</dependency>

(2)修改属性文件,其中

y9.feature.multi-tenant.event-source提供两个方式 kafka 和 db

properties
y9.feature.multi-tenant.event-source=db
yaml
y9:
    feature:
        multi-tenant:
            event-source: db

liquibase管理分公共库和租户库的初始化:

properties
y9.feature.liquibase.public-enabled=true
y9.feature.liquibase.tenant-enabled=true
yaml
y9:
    feature:
        liquibase:
            public-enabled: true
            tenant-enabled: true

约定目录结构如下:

liquibase-init

其中租户的 main.xml 示例如下:

xml
<?xml version="1.0" encoding="UTF-8"?>
<databaseChangeLog
        xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog
                      http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.9.xsd">

    <include file="liquibase/tenant/init.xml"/>
    <includeAll path="liquibase/tenant/release/"/>

</databaseChangeLog>

具体初始化和更新等操作可参考:liquibase官网

注:开启 liquibase 需要把把自动更新关闭,spring.jpa.properties.hibernate.hbm2ddl.auto=none

示例代码

码云地址:https://gitee.com/risesoft-y9/y9-core

该示例代码路径地址:https://gitee.com/risesoft-y9/y9-core/tree/main/y9-digitalbase-example/risenet-y9demo-data-jpa

Released under the GPL-3.0 License.