数据库支持
sz-admin 同时支持 MySQL 8.0+ 和 PostgreSQL 9.4+,建议 16+。数据库切换由两部分共同决定:
application.yml中的DB_TYPE,决定运行时加载哪个数据库连接配置。- Maven profile,决定构建产物中引入哪个数据库驱动模块。
IMPORTANT
DB_TYPE 与 Maven profile 必须保持一致。例如 DB_TYPE=postgresql 时,构建或 IDEA Maven Profile 也应选择 postgresql。
支持版本
| 数据库 | 最低版本 | 说明 |
|---|---|---|
| MySQL | 8.0.17 | 需要 JSON_OVERLAPS 函数以及多值索引支持。 |
| PostgreSQL | 9.4,建议 16+ | 需要数组操作符 && 以及 GIN 索引支持。 |
切换方式
第一步:修改 DB_TYPE
在 sz-service/sz-service-admin/src/main/resources/application.yml 中修改 DB_TYPE:
DB_TYPE: mysql # 可选:mysql | postgresql项目启动时会根据 DB_TYPE 自动加载对应数据库配置文件:
config/${spring.profiles.active}/${DB_TYPE}.yml例如:
| 当前 profile | DB_TYPE | 加载配置 |
|---|---|---|
| local | mysql | config/local/mysql.yml |
| local | postgresql | config/local/postgresql.yml |
| prod | mysql | config/prod/mysql.yml |
| prod | postgresql | config/prod/postgresql.yml |
第二步:选择 Maven profile
sz-service-admin 模块通过 Maven profile 控制数据库驱动模块:
| Profile | 作用 | 是否默认 |
|---|---|---|
mysql | 引入 sz-common-db-mysql | 是 |
postgresql | 引入 sz-common-db-postgresql | 否 |
默认不指定 profile 时使用 MySQL:
mvn -pl sz-service/sz-service-admin -am compile -DskipTests显式构建 MySQL 版本:
mvn -pl sz-service/sz-service-admin -am compile -DskipTests -Pmysql构建 PostgreSQL 版本:
mvn -pl sz-service/sz-service-admin -am compile -DskipTests -PpostgresqlWARNING
不要同时启用 mysql 和 postgresql。数据库驱动模块同一时间只应启用一个,否则可能出现驱动、类型处理器或方言注册冲突。
IDEA 本地开发
本地开发推荐也使用 Maven profile,不再通过注释或放开 pom.xml 依赖来切换数据库。
使用 MySQL
application.yml保持DB_TYPE: mysql。- IDEA Maven Profiles 不需要勾选任何数据库 profile,或只勾选
mysql。 - 刷新 Maven 后启动
AdminApplication。
使用 PostgreSQL
- 修改
application.yml:
DB_TYPE: postgresql- IDEA Maven Profiles 勾选
postgresql。 - 不要同时勾选
mysql。 - 刷新 Maven 后启动
AdminApplication。
生产部署
生产环境推荐显式指定数据库 profile,使构建产物和目标数据库清晰匹配。
MySQL:
mvn -pl sz-service/sz-service-admin -am package -DskipTests -PmysqlPostgreSQL:
mvn -pl sz-service/sz-service-admin -am package -DskipTests -Ppostgresql部署时还需要确认运行环境中的配置文件一致:
# MySQL 部署
DB_TYPE: mysql
# PostgreSQL 部署
DB_TYPE: postgresql对应连接信息分别维护在:
config/prod/mysql.yml
config/prod/postgresql.yml为什么使用 profile 切换驱动
数据库驱动和数据库方言属于构建期依赖。使用 Maven profile 的好处是:
- 本地和生产使用同一套切换方式,降低理解成本。
- 不需要用户修改
pom.xml正文,避免产生本地脏改动。 - 构建产物更明确,MySQL 版本只带 MySQL 模块,PostgreSQL 版本只带 PostgreSQL 模块。
- 与
DB_TYPE形成清晰分工:profile 管依赖,DB_TYPE管运行时配置。
配置文件说明
MySQL 配置
config/{profile}/mysql.yml:
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/sz_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true
username: your_username
password: your_password
hikari:
pool-name: HikariCP_MYSQL
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
liquibase:
change-log: classpath:db/changelog/changelog-master.xml
enabled: true
database-change-log-lock-table: databasechangeloglock
database-change-log-table: databasechangelogPostgreSQL 配置
config/{profile}/postgresql.yml:
spring:
datasource:
driver-class-name: org.postgresql.Driver
url: jdbc:postgresql://127.0.0.1:5432/sz_admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: your_username
password: your_password
hikari:
pool-name: HikariCP_PG
minimum-idle: 5
idle-timeout: 600000
maximum-pool-size: 10
auto-commit: true
max-lifetime: 1800000
connection-timeout: 30000
connection-test-query: SELECT 1
liquibase:
change-log: classpath:db/changelog/changelog-master.xml
enabled: true
database-change-log-lock-table: databasechangeloglock
database-change-log-table: databasechangelog类型差异对照
两种数据库在字段类型上存在差异。Liquibase 脚本通过 <property> 变量统一处理通用差异,业务代码通常无感知。
| 用途 | MySQL | PostgreSQL | Liquibase 变量 |
|---|---|---|---|
| 布尔标识,T/F | CHAR(1) | VARCHAR(1) | ${bool.type} |
| 时间字段 | DATETIME | TIMESTAMP | ${datetime.type} |
| 大文本 | MEDIUMTEXT | TEXT | 按目标库分别处理 |
| 部门范围字段 | JSON | BIGINT[] | 按目标库分别处理 |
| 标识符包裹 | 反引号 | 双引号 | 方言层自动处理 |
dept_scope 字段说明
dept_scope 是数据权限的核心字段,用于记录数据创建者所属部门 ID 集合。由于 MySQL 和 PostgreSQL 的数组存储机制不同,该字段在两种数据库中的类型和查询方式也不同。
| 方面 | MySQL | PostgreSQL |
|---|---|---|
| 字段类型 | JSON,如 [16, 17] | BIGINT[],如 {16,17} |
| 部门过滤 SQL | JSON_OVERLAPS(dept_scope, '[16,17]') | dept_scope && ARRAY[16,17]::BIGINT[] |
| 推荐索引 | 多值索引 | USING GIN (dept_scope) |
| Java 映射 | LongListTypeHandler | LongListTypeHandler |
业务实体中统一使用:
@Column(typeHandler = LongListTypeHandler.class)
private List<Long> deptScope;数据权限方言自动激活
框架根据 JDBC 驱动名自动注册对应的数据权限方言:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
-> 激活 MysqlPermissionDialect
spring.datasource.driver-class-name=org.postgresql.Driver
-> 激活 PostgresqlPermissionDialect两个方言都继承自 AbstractPermissionDialect,统一数据权限流程,只在 SQL 片段上做差异化处理。
| 抽象方法 | MySQL 实现 | PostgreSQL 实现 |
|---|---|---|
buildUserUnitDeptSql | EXISTS 子查询,反引号标识符 | EXISTS 子查询,双引号标识符 |
buildDeptUnitSql | JSON_OVERLAPS(dept_scope, '[...]') | dept_scope && ARRAY[...]::BIGINT[] |
buildAllowAdminViewSql | EXISTS + 反引号 | EXISTS + 双引号 |
buildExcludeAdminSql | NOT EXISTS + 反引号 | NOT EXISTS + 双引号 |
buildUserListSql | 反引号包裹字段并拼接 IN | 双引号包裹字段并拼接 IN |
新增业务表时的注意事项
新增业务表时,先确认该模块是否需要同时兼容 MySQL 和 PostgreSQL。
- 如果项目已经固定使用 MySQL,只需要按 MySQL 类型编写脚本,例如
dept_scope=JSON,大文本使用MEDIUMTEXT。 - 如果项目已经固定使用 PostgreSQL,只需要按 PostgreSQL 类型编写脚本,例如
dept_scope=BIGINT[],大文本使用TEXT。 - 如果模块需要同时兼容 MySQL 和 PostgreSQL,类型差异无法通过变量统一时,应分别编写两个
changeSet,并通过dbms属性区分。
示例:
<!-- MySQL 版本:dept_scope 使用 JSON,大文本使用 MEDIUMTEXT -->
<changeSet id="demo-struct-your-table-202605100838" author="sz" dbms="mysql">
<preConditions onFail="MARK_RAN">
<not><tableExists tableName="your_table"/></not>
</preConditions>
<createTable tableName="your_table">
<column name="del_flag" type="${bool.type}" defaultValue="F"/>
<column name="create_time" type="${datetime.type}"/>
<column name="dept_scope" type="JSON" remarks="部门范围"/>
<column name="content" type="MEDIUMTEXT" remarks="内容"/>
</createTable>
</changeSet>
<!-- PostgreSQL 版本:dept_scope 使用 BIGINT[],大文本使用 TEXT -->
<changeSet id="demo-struct-your-table-pg-202605100838" author="sz" dbms="postgresql">
<preConditions onFail="MARK_RAN">
<not><tableExists tableName="your_table"/></not>
</preConditions>
<createTable tableName="your_table">
<column name="del_flag" type="${bool.type}" defaultValue="F"/>
<column name="create_time" type="${datetime.type}"/>
<column name="dept_scope" type="BIGINT[]" remarks="部门范围"/>
<column name="content" type="TEXT" remarks="内容"/>
</createTable>
</changeSet>NOTE
bool.type 和 datetime.type 这类通用差异可以通过 <property> 变量统一处理,单个 changeSet 即可兼容两种数据库。dept_scope、大文本等无法统一的差异,才需要按数据库拆分 changeSet。
更多 Liquibase 编写规则请参考 Liquibase 使用说明。
