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提供的一个查询规范,要做复杂的查询,只需围绕这个规范来设置查询条件即可

数字底座主要使用了 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-publicrisenet-y9boot-starter-jpa-tenantrisenet-y9boot-starter-jpa-dedicated,基于 spring-data-jpa,用 druid 来做数据源连接池管理。

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

druid 关于监控、防 SQL 注入等配置可以根据自己的需求配置,参考如下所示:

yaml
spring:
    datasource:
        druid:
            filter:
                stat:
                    log-slow-sql: true
                    mergeSql: true
                    slow-sql-millis: 3000
                    enabled: true
                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/*'
properties
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.stat.enabled=true
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/*

功能引用

使用时需排除 DataSourceAutoConfigurationHibernateJpaAutoConfiguration,避免默认的自动配置影响自定义 starter 的配置。

公共数据源

starter 的自动配置类创建了以下 Bean:

  • 数据源:y9PublicDS。
  • Entity 持久化操作的主要对象工厂 EntityManagerFactory:rsPublicEntityManagerFactory
  • 事务管理器 PlatformTransactionManager:rsPublicTransactionManager
  • JdbcTemplate Bean:jdbcTemplate4Public

可通过 y9.feature.jpa.packagesToScanEntityPublic 配置 Entity 的扫描路径, y9.feature.jpa.packagesToScanRepositoryPublic 配置 Repository 的扫描路径。

添加依赖

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

xml

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

如需使用 SNAPSHOT 版本,且 maven 没有 POM 继承链至数字底座的 y9-digitalbase-parent 则还需将有生的私服仓库地址添加到 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>

由于 Starter 使用 AspectJ 模式(即 mode = AdviceMode.ASPECTJ)启用事务,AspectJ 模式内部方法调用也能事务生效且性能更好,需要在项目中添加 AspectJ 依赖和插件方能使相关事务注解生效:

  • 引入 aspectj 依赖包。
xml

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
</dependencies>
  • 在 plugins 中引入 aspectj-maven-plugin
xml

<build>
    <plugins>
        <plugin>
            <groupId>dev.aspectj</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

上方依赖、插件没有版本及配置是因为 maven 的 POM 继承链至了数字底座的 y9-digitalbase-parent

如果新建项目没有对应的继承则需在 pom.xml 中添加一下相关属性及依赖:

xml

<properties>
    <java.version>11</java.version>
    <aspectj.version>1.9.20.1</aspectj.version>
    <aspectj-maven-plugin.version>1.13.1</aspectj-maven-plugin.version>
</properties>
<build>
<plugins>
    <plugin>
        <!--<groupId>com.nickwongdev</groupId>-->
        <groupId>dev.aspectj</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>${aspectj-maven-plugin.version}</version>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjtools</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <id>weave-classes</id>
                <phase>process-classes</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
                <configuration>
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
            <execution>
                <id>weave-test-classes</id>
                <phase>process-test-classes</phase>
                <goals>
                    <goal>test-compile</goal>
                </goals>
                <configuration>
                    <testSources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/test-classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
        </executions>
        <configuration>
            <verbose>true</verbose>
            <forceAjcCompile>true</forceAjcCompile>
            <aspectLibraries>
                <aspectLibrary>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                </aspectLibrary>
            </aspectLibraries>
            <complianceLevel>${java.version}</complianceLevel>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>UTF-8</encoding>
            <showWeaveInfo>true</showWeaveInfo>
        </configuration>
    </plugin>
</plugins>
</build>

修改配置文件

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
    autoconfigure:
        exclude:
            - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
            - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
    data:
        jpa:
            repositories:
                bootstrap-mode: default
                enabled: false
    jpa:
        generate-ddl: true
        show-sql: true
        open-in-view: false
        database-platform: org.hibernate.dialect.MySQL8Dialect
        hibernate: 
            ddl-auto: none
            naming:
                implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        properties:
            hibernate:
                jdbc:
                    batch_size: 100
y9:
    feature:
        jpa:
            packagesToScanEntityPublic: net.risesoft.y9public.entity
            packagesToScanRepositoryPublic: net.risesoft.y9public.repository
properties
spring.datasource.druid.y9-public.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.y9-public.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
spring.datasource.druid.y9-public.username=root
spring.datasource.druid.y9-public.password=111111
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
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.data.jpa.repositories.bootstrap-mode=default
spring.data.jpa.repositories.enabled=false
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=none
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.properties.hibernate.jdbc.batch_size=100
y9.feature.jpa.packagesToScanEntityPublic=net.risesoft.y9public.entity
y9.feature.jpa.packagesToScanRepositoryPublic=net.risesoft.y9public.repository

示例代码

java

@Transactional(value = "rsPublicTransactionManager", readOnly = true)
public interface AppFolderServiceImpl implements AppFolderService {

}
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) {

    }
}

租户数据源

多租户的数据源由 Y9LoginPersonHolder.getTenantId() (即当前登录用户的租户 id)决定 ,对于该值为空的情况则会使用租户的默认数据源,对于已经集成单点登录的后端项目,该值会自动设置,无需担心。

starter 的自动配置类创建了以下 Bean:

  • 数据源:y9PublicDS 和 defaultDataSource。
  • 创建 Entity 持久化操作的主要对象工厂 EntityManagerFactory:rsTenantEntityManagerFactory, entityManagerFactory
  • 事务管理器 PlatformTransactionManager:rsTenantTransactionManager、transactionManager
  • JdbcTemplate Bean:jdbcTemplate4Tenant

可通过 y9.feature.jpa.packagesToScanEntityTenant 配置 Entity 的扫描路径, y9.feature.jpa.packagesToScanRepositoryTenant 配置 Repository 的扫描路径。

添加依赖

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

xml

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

如需使用 SNAPSHOT 版本,且 maven 没有 POM 继承链至数字底座的 y9-digitalbase-parent 则还需将有生的私服仓库地址添加到 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>

由于 Starter 使用 AspectJ 模式(即 mode = AdviceMode.ASPECTJ)启用事务,AspectJ 模式内部方法调用也能事务生效且性能更好,需要在项目中添加 AspectJ 依赖和插件方能使相关事务注解生效:

  • 引入 aspectj 依赖包。
xml

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
</dependencies>
  • 在 plugins 中引入 aspectj-maven-plugin
xml

<build>
    <plugins>
        <plugin>
            <groupId>dev.aspectj</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

上方依赖、插件没有版本及配置是因为 maven 的 POM 继承链至了数字底座的 y9-digitalbase-parent

如果新建项目没有对应的继承则需在 pom.xml 中添加一下相关属性及依赖:

xml

<properties>
    <java.version>11</java.version>
    <aspectj.version>1.9.20.1</aspectj.version>
    <aspectj-maven-plugin.version>1.13.1</aspectj-maven-plugin.version>
</properties>
<build>
<plugins>
    <plugin>
        <!--<groupId>com.nickwongdev</groupId>-->
        <groupId>dev.aspectj</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>${aspectj-maven-plugin.version}</version>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjtools</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <id>weave-classes</id>
                <phase>process-classes</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
                <configuration>
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
            <execution>
                <id>weave-test-classes</id>
                <phase>process-test-classes</phase>
                <goals>
                    <goal>test-compile</goal>
                </goals>
                <configuration>
                    <testSources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/test-classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
        </executions>
        <configuration>
            <verbose>true</verbose>
            <forceAjcCompile>true</forceAjcCompile>
            <aspectLibraries>
                <aspectLibrary>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                </aspectLibrary>
            </aspectLibraries>
            <complianceLevel>${java.version}</complianceLevel>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>UTF-8</encoding>
            <showWeaveInfo>true</showWeaveInfo>
        </configuration>
    </plugin>
</plugins>
</build>

修改配置文件

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

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
    autoconfigure:
        exclude:
            - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
            - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
    data:
        jpa:
            repositories:
                bootstrap-mode: default
                enabled: false
    jpa:
        generate-ddl: true
        show-sql: true
        open-in-view: false
        database-platform: org.hibernate.dialect.MySQL8Dialect
        hibernate: 
            ddl-auto: none
            naming:
                implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        properties:
            hibernate:
                jdbc:
                    batch_size: 100
y9:
    feature:
        jpa:
            packagesToScanEntityTenant: net.risesoft.entity
            packagesToScanRepositoryTenant: net.risesoft.repository
properties
spring.datasource.druid.tenantDefault=spring.datasource.druid.example
spring.datasource.druid.example.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.example.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.example.password=111111
spring.datasource.druid.example.username=root
spring.datasource.druid.example.initialSize=1
spring.datasource.druid.example.maxActive=20
spring.datasource.druid.example.maxPoolPreparedStatementPerConnectionSize=100
spring.datasource.druid.example.maxWait=60000
spring.datasource.druid.example.minEvictableIdleTimeMillis=300000
spring.datasource.druid.example.minIdle=1
spring.datasource.druid.example.poolPreparedStatements=true
spring.datasource.druid.example.testOnBorrow=false
spring.datasource.druid.example.testOnReturn=false
spring.datasource.druid.example.testWhileIdle=true
spring.datasource.druid.example.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.example.useGlobalDataSourceStat=true
spring.datasource.druid.example.validationQuery=SELECT 1 FROM DUAL
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
spring.data.jpa.repositories.bootstrap-mode=default
spring.data.jpa.repositories.enabled=false
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=none
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.properties.hibernate.jdbc.batch_size=100
y9.feature.jpa.packagesToScanEntityTenant=net.risesoft.entity
y9.feature.jpa.packagesToScanRepositoryTenant=net.risesoft.repository

示例代码

java

@Transactional(value = "rsTenantTransactionManager", readOnly = true)
public interface AppItemServiceImpl implements AppItemService {

}
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) {

    }
}

专用数据源

starter 的自动配置类创建了以下 Bean:

  • 创建数据源:y9DedicatedDS。
  • 创建Entity持久化操作的主要对象工厂 EntityManagerFactory:rsDedicatedEntityManagerFactory
  • 提供事务PlatformTransactionManager:rsDedicatedTransactionManager
  • 创建 JDBC 查询 JdbcTemplate Bean:jdbcTemplate4Dedicated

可通过 y9.feature.jpa.packagesToScanEntityDedicated 配置 Entity 的扫描路径, y9.feature.jpa.packagesToScanRepositoryDedicated 配置 Repository 的扫描路径。

添加依赖

risenet-y9boot-starter-jpa-dedicated 添加到pom.xml的依赖列表里.

xml

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

如需使用 SNAPSHOT 版本,且 maven 没有 POM 继承链至数字底座的 y9-digitalbase-parent 则还需将有生的私服仓库地址添加到 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>

由于 Starter 使用 AspectJ 模式(即 mode = AdviceMode.ASPECTJ)启用事务,AspectJ 模式内部方法调用也能事务生效且性能更好,需要在项目中添加 AspectJ 依赖和插件方能使相关事务注解生效:

  • 引入 aspectj 依赖包。
xml

<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
    </dependency>
</dependencies>
  • 在 plugins 中引入 aspectj-maven-plugin
xml

<build>
    <plugins>
        <plugin>
            <groupId>dev.aspectj</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

上方依赖、插件没有版本及配置是因为 maven 的 POM 继承链至了数字底座的 y9-digitalbase-parent

如果新建项目没有对应的继承则需在 pom.xml 中添加一下相关属性及依赖:

xml

<properties>
    <java.version>11</java.version>
    <aspectj.version>1.9.20.1</aspectj.version>
    <aspectj-maven-plugin.version>1.13.1</aspectj-maven-plugin.version>
</properties>
<build>
<plugins>
    <plugin>
        <!--<groupId>com.nickwongdev</groupId>-->
        <groupId>dev.aspectj</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>${aspectj-maven-plugin.version}</version>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjtools</artifactId>
                <version>${aspectj.version}</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <id>weave-classes</id>
                <phase>process-classes</phase>
                <goals>
                    <goal>compile</goal>
                </goals>
                <configuration>
                    <sources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
            <execution>
                <id>weave-test-classes</id>
                <phase>process-test-classes</phase>
                <goals>
                    <goal>test-compile</goal>
                </goals>
                <configuration>
                    <testSources/>
                    <weaveDirectories>
                        <weaveDirectory>${project.build.directory}/test-classes</weaveDirectory>
                    </weaveDirectories>
                </configuration>
            </execution>
        </executions>
        <configuration>
            <verbose>true</verbose>
            <forceAjcCompile>true</forceAjcCompile>
            <aspectLibraries>
                <aspectLibrary>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                </aspectLibrary>
            </aspectLibraries>
            <complianceLevel>${java.version}</complianceLevel>
            <source>${java.version}</source>
            <target>${java.version}</target>
            <encoding>UTF-8</encoding>
            <showWeaveInfo>true</showWeaveInfo>
        </configuration>
    </plugin>
</plugins>
</build>

risenet-y9boot-starter-jpa-dedicated 组件用于不是多租户,但又需要定义自己的数据源的场景,比如 risecloud 工程,首先定义 spring.application.name,比如 spring.application.name=risecloud,那么就要在 spring.datasource.druid.risecloud 前缀下定义数据源,修改属性文件,如下所示:

修改配置文件

yaml
spring:
    application:
        name: risecloud
    datasource:
        druid:
            risecloud:
                driver-class-name: com.mysql.cj.jdbc.Driver
                initialSize: 1
                maxActive: 20
                maxPoolPreparedStatementPerConnectionSize: 100
                maxWait: 60000
                minEvictableIdleTimeMillis: 300000
                minIdle: 1
                password: 111111
                poolPreparedStatements: true
                testOnBorrow: false
                testOnReturn: false
                testWhileIdle: true
                timeBetweenEvictionRunsMillis: 60000
                url: jdbc:mysql://127.0.0.1:3306/risecloud?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false
                useGlobalDataSourceStat: true
                username: root
                validationQuery: SELECT 1 FROM DUAL
    jpa:
        generate-ddl: true
        show-sql: true
        open-in-view: false
        database-platform: org.hibernate.dialect.MySQL8Dialect
        hibernate:
            ddl-auto: none
            naming:
                implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyHbmImpl
                physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
        properties:
            hibernate:
                jdbc:
                    batch_size: 100
y9:
    feature:
        jpa:
            packagesToScanEntityDedicated: net.risesoft.y9dedicated.entity
            packagesToScanRepositoryDedicated: net.risesoft.y9dedicated.repository
properties
spring.application.name=risecloud
spring.datasource.druid.risecloud.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.druid.risecloud.initialSize=1
spring.datasource.druid.risecloud.maxActive=20
spring.datasource.druid.risecloud.maxPoolPreparedStatementPerConnectionSize=100
spring.datasource.druid.risecloud.maxWait=60000
spring.datasource.druid.risecloud.minEvictableIdleTimeMillis=300000
spring.datasource.druid.risecloud.minIdle=1
spring.datasource.druid.risecloud.password=111111
spring.datasource.druid.risecloud.poolPreparedStatements=true
spring.datasource.druid.risecloud.testOnBorrow=false
spring.datasource.druid.risecloud.testOnReturn=false
spring.datasource.druid.risecloud.testWhileIdle=true
spring.datasource.druid.risecloud.timeBetweenEvictionRunsMillis=60000
spring.datasource.druid.risecloud.url=jdbc:mysql://127.0.0.1:3306/risecloud?serverTimezone=GMT%2B8&nullCatalogMeansCurrent=true&useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true&useCompression=true&useSSL=false
spring.datasource.druid.risecloud.useGlobalDataSourceStat=true
spring.datasource.druid.risecloud.username=root
spring.datasource.druid.risecloud.validationQuery=SELECT 1 FROM DUAL
spring.jpa.generate-ddl=true
spring.jpa.show-sql=true
spring.jpa.open-in-view=false
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect
spring.jpa.hibernate.ddl-auto=none
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.properties.hibernate.jdbc.batch_size=100
y9.feature.jpa.packagesToScanEntityDedicated=net.risesoft.y9dedicated.entity
y9.feature.jpa.packagesToScanRepositoryDedicated=net.risesoft.y9dedicated.repository

示例代码

java

@Transactional(value = "rsDedicatedTransactionManager")
public interface AskServiceImpl implements AskService {
}
java

@Autowired
@Qualifier("jdbcTemplate4Dedicated")
private JdbcTemplate jdbcTemplate4Dedicated;

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

    }
}

示例项目

示例项目地址:https://gitee.com/risesoft-y9/y9-core/tree/main/y9-digitalbase-example/risenet-y9demo-data-jpa

Released under the GPL-3.0 License.