1. 先别急着装库,确认你这套组合拳到底要打给谁
很多人拿到 Jeecg-boot 项目之后,第一反应是把官方文档里的 MySQL 配置一套,业务就能跑起来。但真到了生产环境,事情往往没这么简单。公司既有系统原本就是 Oracle,DBA 只给你开 Oracle 的库权限;或者项目验收要求数据库必须用某类商业数据库;又或者甲方直接说了,我们采购的就是 Oracle 11g,你看着办。这时候你就得把 Jeecg-boot 从默认的 MySQL 切到 Oracle 11g 上,这也是这篇"第二弹"存在的意义。
第一弹的基础部署已经把 Jeecg-boot 的前后端工程跑通,环境也理顺了。这一弹专门解决数据库这一层:从零装一个 Oracle 11g,建好表空间和用户,把 Jeecg-boot 的初始化 SQL 导进去,再把工程的数据库配置从 MySQL 换成 Oracle,最后启动、联调、排错,一路走到底。整个过程我会按"伸手党"的标准写,命令给你完整可复制,不让你自己去拼文档。
这篇内容适合这几类人看:公司要求必须用 Oracle 11g 的 Java 开发;准备把 Jeecg-boot 从开发环境往生产环境迁移的新手;以及那些被各种教程碎片搞得头大、想一口气把数据库部署链路跑通的人。文章默认操作系统是 CentOS 7 + Oracle 11g R2,这也是目前存量使用最多的组合。
1.1 这条链路上到底有哪几个环节
先把全链路拆开,心里有个地图,后面每一步才知道自己在干嘛。
- 系统准备:装依赖包、调内核参数、创建 oracle 账号、设置环境变量
- 安装 Oracle 软件:解压安装包、运行 runInstaller、执行 root 脚本
- 创建实例和监听:netca 配置监听、dbca 建库
- 数据库初始化:建表空间、建业务用户、导入 Jeecg-boot 的 Oracle 脚本
- 工程改造:pom.xml 加驱动、数据源配置切换、方言和分页调整
- 启动联调:后端跑起来、前端连上、处理各种兼容问题
这里面的坑主要集中在第三到第六步,尤其是第四步和第五步,数据库建好了但工程连不上、SQL 执行报错、分页查不出来,这些才是真正耗时间的地方。
1.2 版本组合怎么选才稳
我这次用的是 CentOS 7.6(64位)+ Oracle 11g R2(11.2.0.4)+ JDK 8 + Jeecg-boot 3.x 版本。这里要强调一个关键点:Oracle 11g R2 官方支持的操作系统里 CentOS 7 需要做一定兼容处理,但实际生产中使用的人非常多,稳定运行没问题。
JDK 版本和 Oracle 驱动的对应关系很容易搞混。JDK 8 建议用 ojdbc8,但 Oracle 11g 官方配套的是 ojdbc6,你可以在 pom 里引入 ojdbc8 也没问题。最稳的做法是用 ojdbc6 配 JDK 8,这个组合我在多个项目里都验证过。Oracle 12c 的 ojdbc8 驱动连 11g 实例也可以,但没必要,老老实实用 ojdbc6。
另外,如果你的 Jeecg-boot 版本比较老,初始化脚本的目录结构可能跟我说的有点差异,但整体思路不变。版本差异主要影响脚本文件名,后面我会专门讲怎么找正确的脚本。
2. 装 Oracle 11g 前,先把系统"底子"打好
这一步看着简单,但其实是最容易被跳过、后面疯狂返工的地方。Oracle 对操作系统参数的要求比 MySQL 严格得多,少了某些依赖包,图形界面直接起不来;内核参数没调,安装过程中会报各种莫名其妙的错误。
2.1 系统依赖包、内核参数与用户限制
先检查系统版本,确认是 64 位 CentOS:
cat /etc/redhat-release uname -r然后安装依赖包。Oracle 11g 官方要求一堆 compat 库,CentOS 7 上这些包有的在默认源里没有,需要先装 epel-release:
yum install -y epel-release yum install -y binutils compat-libcap1 compat-libstdc++-33 gcc gcc-c++ glibc \ glibc-devel libaio libaio-devel libgcc libstdc++ libstdc++-devel \ libXext libXtst libX11 libXau libXi make sysstat unixODBC unixODBC-devel这些包里有几个特别容易漏:compat-libstdc++-33和libaio-devel。漏了它们,安装时打不开 runInstaller 或报libclntsh.so找不到的情况很常见。
接下来调内核参数。编辑/etc/sysctl.conf,在末尾追加以下内容:
fs.aio-max-nr = 1048576 fs.file-max = 6815744 kernel.sem = 250 32000 100 128 kernel.shmmni = 4096 net.core.rmem_default = 262144 net.core.rmem_max = 4194304 net.core.wmem_default = 262144 net.core.wmem_max = 1048586 net.ipv4.ip_local_port_range = 9000 65500执行sysctl -p生效。这几个参数里面,kernel.sem影响力最大,不调的话后面 dbca 建库很可能卡死或报内存信号量错误。
再改用户资源限制。编辑/etc/security/limits.conf,追加:
oracle soft nproc 2047 oracle hard nproc 16384 oracle soft nofile 1024 oracle hard nofile 65536 oracle soft stack 10240顺带把 pam 配置也确认一下,/etc/pam.d/login里确保有session required pam_limits.so这一行。这一步容易被忽略,但缺少它nofile限制不会生效。
2.2 创建 oracle 专用账号
官方规范是创建两个组oinstall和dba,账号名就叫oracle。这个账号不是随便建着玩的,后面所有 Oracle 操作都必须用它执行,千万别拿 root 去跑安装程序。
groupadd oinstall groupadd dba useradd -g oinstall -G dba oracle passwd oracle mkdir -p /u01/app/oracle chown -R oracle:oinstall /u01/app/oracle chmod -R 775 /u01/app/oracle/u01这个路径就是后面 ORACLE_BASE,如果你磁盘规划不一样,可以改成别的位置,但前后必须保持一致。生产环境建议单独挂一块数据盘给/u01,避免系统盘空间被数据库文件占满。
2.3 环境变量别偷懒
切换到 oracle 用户,编辑~/.bash_profile:
su - oracle vi ~/.bash_profile追加:
export ORACLE_BASE=/u01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/11.2.0/dbhome_1 export ORACLE_SID=orcl export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin export LD_LIBRARY_PATH=$ORACLE_HOME/lib export NLS_LANG=AMERICAN_AMERICA.ZHS16GBKNLS_LANG这个变量建议一开始就设成ZHS16GBK,跟后续建库时的字符集保持一致。否则后面导入的 SQL 里有中文注释,很容易出现乱码入库的情况。
环境变量设置完成后,source ~/.bash_profile让它生效。到这里系统底子就算打好了。
3. 一步步把 Oracle 11g 装起来,含监听和实例
这个阶段是整个部署里最需要耐心的。如果你的服务器有图形桌面环境,可以走图形安装;但生产环境大多是纯命令行的 CentOS 服务器,所以下面我直接按命令行方式来写,这也是最贴近生产场景的操作。
3.1 解压安装包与命令行安装
Oracle 11g R2 的安装包一般叫这两个:
linux.x64_11gR2_database_1of2.ziplinux.x64_11gR2_database_2of2.zip
把两个 zip 放到/u01/install目录下,然后解压:
su - oracle cd /u01/install unzip linux.x64_11gR2_database_1of2.zip unzip linux.x64_11gR2_database_2of2.zip解压后会出现一个database目录,里面有runInstaller。命令行安装有两种方式:一种是准备 response 文件做完全静默安装,另一种是交互式但不开 X 窗口。
先看传统图形方式。如果你本地用 Xshell 或类似终端,可以配合 Xmanager 转发图形界面,在终端里设置 DISPLAY 后直接调出安装界面:
export DISPLAY=你的本机IP:0.0 cd /u01/install/database ./runInstaller如果你不想搞图形转发,建议用响应文件静默安装。Oracle 自带响应文件模板在database/response/db_install.rsp,复制一份后修改关键项:
cp database/response/db_install.rsp db_install_custom.rsp编辑db_install_custom.rsp,至少需要改这些内容:
oracle.install.option=INSTALL_DB_SWONLY ORACLE_HOSTNAME=你的主机名 UNIX_GROUP_NAME=oinstall INVENTORY_LOCATION=/u01/app/oraInventory SELECTED_LANGUAGES=en,zh_CN ORACLE_HOME=/u01/app/oracle/product/11.2.0/dbhome_1 ORACLE_BASE=/u01/app/oracle oracle.install.db.InstallEdition=EE oracle.install.db.DBA_GROUP=dba oracle.install.db.OPER_GROUP=dba oracle.install.db.config.starterdb.type=GENERAL_PURPOSE oracle.install.db.config.starterdb.globalDBName=orcl oracle.install.db.config.starterdb.SID=orcl oracle.install.db.config.starterdb.characterSet=ZHS16GBK oracle.install.db.config.starterdb.memoryLimit=800 oracle.install.db.config.starterdb.password.ALL=你的数据库密码这里有一个容易踩的坑:INVENTORY_LOCATION和ORACLE_BASE所在的目录必须保证 oracle 用户有写权限,否则安装一开始就报OUI-10086之类的问题。
然后执行安装:
cd /u01/install/database ./runInstaller -silent -responseFile /u01/install/db_install_custom.rsp安装脚本跑完后,会提示你"以 root 身份执行以下脚本",一般是两个:
su - root /u01/app/oraInventory/orainstRoot.sh /u01/app/oracle/product/11.2.0/dbhome_1/root.sh这两个脚本不执行,后面的 dbca 建库会出错。这是新手最容易漏的步骤。
3.2 配置监听器与创建实例
软件装好了,接下来要建实例。先配置监听器,用 netca 的静默模式最简单:
su - oracle netca /silent /responseFile /u01/app/oracle/product/11.2.0/dbhome_1/network/install/netca_typ.rsp执行完可以用lsnrctl status看看监听是否起来了。如果显示The command completed successfully,说明监听已运行。
创建实例用 dbca 静默模式。先规划实例名,这里统一用orcl,全局数据库名也叫orcl。一个大坑:字符集在这里要定好,后面基本改不了。我建议用ZHS16GBK,如果你确定要存多国语言数据,再考虑AL32UTF8。
dbca -silent -createDatabase \ -templateName General_Purpose.dbc \ -gdbname orcl -sid orcl \ -responseFile NO_VALUE \ -characterSet ZHS16GBK \ -sysPassword 你的密码 \ -systemPassword 你的密码 \ -datafileDestination /u01/app/oracle/oradata \ -recoveryAreaDestination /u01/app/oracle/flash_recovery_area \ -recoveryAreaSize 8192 \ -memoryPercentage 40这条命令跑起来需要几分钟到十几分钟不等,取决于机器配置。如果中间报内存不足或/tmp空间不足,检查一下kernel.sem是否生效、/tmp是否够大(至少 1GB 可用空间)。
3.3 安装后的基础验证
实例建好后,先用操作系统认证进入数据库验证:
sqlplus / as sysdba执行:
select status from v$instance; select name from v$database;能查到OPEN状态和数据库名ORCL,说明实例没问题。再确认监听能识别服务:
lsnrctl services看到orcl服务名,说明客户端可以通过 JDBC 连接了。到这里,Oracle 本身已经部署完成,接下来是给 Jeecg-boot 准备业务空间。
4. 建表空间、建用户、导入初始化 SQL,一步都不能省
Jeecg-boot 默认的数据库账号是root密码root之类,但实际生产环境绝对不能用默认账号。我们要建独立的表空间和用户,跟系统库隔离。
4.1 表空间怎么规划
先登录 sys:
sqlplus / as sysdba创建 Jeecg-boot 专用的表空间。表空间文件不要放在系统目录里,放到/u01/app/oracle/oradata/orcl下比较合理:
CREATE TABLESPACE JEECGBOOT DATAFILE '/u01/app/oracle/oradata/orcl/jeecgboot.dbf' SIZE 1024M AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED;这里SIZE 1024M是初始大小,AUTOEXTEND ON表示空间不够自动扩展。生产环境建议初始就给大一点,避免频繁扩展带来的性能抖动。
然后建临时表空间。Oracle 默认的 TEMP 表空间也能用,但隔离性不好,建议单独建一个:
CREATE TEMPORARY TABLESPACE JEECGBOOT_TEMP TEMPFILE '/u01/app/oracle/oradata/orcl/jeecgboot_temp.dbf' SIZE 512M AUTOEXTEND ON NEXT 100M MAXSIZE UNLIMITED;4.2 创建业务用户并授权
创建用户时,把默认表空间指向刚建的 JEECGBOOT,临时表空间指向 JEECGBOOT_TEMP:
CREATE USER jeecgboot IDENTIFIED BY 你的业务密码 DEFAULT TABLESPACE JEECGBOOT TEMPORARY TABLESPACE JEECGBOOT_TEMP; GRANT CONNECT, RESOURCE TO jeecgboot; GRANT UNLIMITED TABLESPACE TO jeecgboot;这里UNLIMITED TABLESPACE很重要,不授权的话,后面导入初始化脚本时一旦表空间配额用完就会报ORA-01536。
4.3 导入 Jeecg-boot 的 Oracle 初始化脚本
Jeecg-boot 项目的源码目录里通常会有一个db文件夹,里面放着各数据库的初始化脚本。MySQL 脚本文件名一般是jeecgboot-mysql.sql,Oracle 脚本一般叫jeecgboot-oracle.sql,也可能按版本分成多个脚本。它的位置一般在:
- 后端工程源码的
db/目录 - 如果你是从官方仓库下载的发布包,通常在
jeecg-boot/db/
在导入之前,先确认这个脚本是给 Oracle 用的,不要拿 MySQL 的脚本直接导入 Oracle。判断方式很简单:看里面的建表语句有没有反引号、有没有ENGINE=InnoDB、有没有AUTO_INCREMENT,有这些关键字的就是 MySQL 版。
用 jeecgboot 用户登录:
sqlplus jeecgboot/你的业务密码@localhost:1521/orcl然后执行脚本。脚本文件大,建议用@方式导入:
@/你的路径/jeecgboot-oracle.sql导入过程中如果报错,常见的有两类:
ORA-00900: invalid SQL statement:说明脚本里混了 MySQL 语法,需要改脚本ORA-01950:表空间配额不足,回到上一步加UNLIMITED TABLESPACE授权
导入完成后,验证一下表数量:
select count(*) from user_tables;Jeecg-boot 完整初始化后一般有几十到上百张表,如果你查出来数量明显不对,说明脚本执行中断过,需要排查具体报错点,而不是直接继续。
5. 把 Jeecg-boot 工程从 MySQL 切到 Oracle,配置就这么改
数据库这层准备好了,接下来是工程侧。很多人在这一步卡住,原因是对 Spring Boot 的数据源配置不熟悉,或者不知道 MyBatis 还需要单独设置数据库方言。
5.1 Maven 依赖:Oracle 驱动必须手动安装到本地仓库
Oracle 的 JDBC 驱动没有放在中央仓库,直接写进pom.xml是拉不下来的。你需要先把 ojdbc6 的 jar 包手动安装到 Maven 本地仓库。
先下载ojdbc6.jar(版本 11.2.0.3 或 11.2.0.4),然后执行:
mvn install:install-file \ -Dfile=ojdbc6.jar \ -DgroupId=com.oracle \ -DartifactId=ojdbc6 \ -Dversion=11.2.0.3 \ -Dpackaging=jar然后在后端工程的pom.xml里加上依赖:
<dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.3</version> </dependency>如果你用的是 Jeecg-boot 的微服务版本,记得在公共依赖模块加,而不是只加在某个微服务里。
5.2 数据源配置:application-dev.yml 的关键改动
Jeecg-boot 的配置通常分环境,开发环境是application-dev.yml,生产是application-prod.yml。找到数据源配置,把 MySQL 改成 Oracle:
spring: datasource: driver-class-name: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@你的数据库IP:1521:orcl username: jeecgboot password: 你的业务密码这里有几个容易犯迷糊的点:
jdbc:oracle:thin:@IP:1521/orcl和jdbc:oracle:thin:@IP:1521:orcl的区别- 前者是 SID 连接方式,后者是 SERVICE_NAME 连接方式。Oracle 11g 默认用 SID 方式连接,所以冒号后直接跟
orcl是没问题的。如果你用的是 12c+ 的 CDB/PDB,就得分清楚。
驱动类名一定不能写错,是oracle.jdbc.OracleDriver,不是oracle.jdbc.driver.OracleDriver。虽然两个在老版本里都能用,但新驱动推荐前者。
5.3 方言、分页与连接池参数
Jeecg-boot 使用了 Hibernate 的部分能力(比如代码生成器的 entity 映射),所以方言也要改。在 yml 里找到 jpa 配置,改成:
spring: jpa: database-platform: org.hibernate.dialect.Oracle10gDialect这里用Oracle10gDialect而不是OracleDialect,原因是 Oracle 11g 的 SQL 方言跟 10g 基本一致,而OracleDialect对应的是更老版本,某些新语法不兼容。
分页这部分坑更大。Jeecg-boot 用的 MyBatis-Plus,它默认的动态方言可能还是 MySQL。如果你用了官方的分页插件,需要在配置类里明确指定 Oracle 方言:
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.ORACLE));在 yml 中如果有一个mybatis-plus.global-config.db-config.dialect之类的配置项,直接改成oracle。
5.4 初始化脚本导入后还要处理兼容点
Jeecg-boot 的 Oracle 初始化脚本虽然官方是适配过的,但实际导入后还会有两个兼容问题需要手动处理。
第一个是序列问题。Oracle 没有 MySQL 的自增主键,Jeecg-boot 的 Oracle 脚本里会为相关表建序列和触发器,比如SEQ_SYS_USER这类。导入脚本后检查一下序列是否真的创建成功:
select sequence_name from user_sequences;如果某个表的序列缺失,写入时就会报主键冲突。处理办法是手动补序列,或者看脚本里是否漏掉了触发器。
第二个是时间字段的默认值。Oracle 的SYSDATE跟 MySQL 的NOW()行为类似,但有些表结构用了DEFAULT CURRENT_TIMESTAMP,这在 Oracle 里会报错。脚本如果是从 MySQL 版改的,你需要把这些默认值统一改成SYSDATE,否则执行 DML 时会出现 ORA-00932。
6. 启动、联调与排错:从"装好了"到"能跑通"的最后一段路
配置全部改完后,就开始启动验证。别指望一次就能顺利跑起来,数据库切换涉及的细节太多,我在多个项目里踩过的坑,基本都在下面这个流程里。
6.1 后端启动验证
执行 Jeecg-boot 的启动入口,观察日志。出现Started JeecgSystemApplication且没有异常堆栈,说明后端已经连接 Oracle 成功了。
但光启动成功还不够,需要实际测两个功能:
- 登录接口能不能通,验证 SQL 查询是否正常
- 列表分页查询能不能正常返回,验证分页方言是否生效
如果启动时报错,大概率是以下几种情况之一,我直接给排查路径。
6.2 高频报错清单与处理方式
| 报错信息 | 原因 | 解决办法 |
|---|---|---|
ClassNotFoundException: oracle.jdbc.OracleDriver | pom 里没有引入驱动,或本地仓库没有该 jar | 重新执行mvn install:install-file,并在 pom 中加入依赖 |
ORA-12541: TNS:no listener | 监听没启动,或端口不是 1521 | lsnrctl start启动监听,确认端口没被占 |
ORA-12514: TNS listener does not currently know of service requested | 连接串里的服务名不对 | 确认是 SIDorcl还是 SERVICE_NAME,保持连接串和实际一致 |
ORA-01017: invalid username/password | 用户名或密码错误 | 检查 yml 中的账号密码,用 sqlplus 手动验证 |
ORA-01034: ORACLE not available | 实例没启动 | sqlplus / as sysdba,执行startup |
BadSqlGrammarException | SQL 语法不兼容 MySQL | 检查 SQL 里是否还有反引号、NOW()、LIMIT等 MySQL 专用语法 |
NoSuchMethodError或方言报错 | Hibernate 方言版本不匹配 | 确认database-platform设置为Oracle10gDialect |
6.3 我踩过的几个特别隐蔽的细节
第一,Oracle 中对空字符串的处理和 MySQL 不同。MySQL 里''和NULL是两回事,但 Oracle 把空字符串当成NULL。这会导致某些查询逻辑跟原来不一样,比如WHERE user_name = ''在 Oracle 里查不出任何东西。如果业务代码里依赖了空字符串判断,建议全局梳理一遍。
第二,Oracle 默认字段名是大写的,而 MySQL 默认小写。MyBatis-Plus 的map-underscore-to-camel-case配置通常没问题,但如果手动写 SQL 用了SELECT *,返回的 Map 的 key 是大写的,这时 JSON 序列化后字段名看起来就和原来不同。最省事的办法是在查询 SQL 里显式写别名。
6.4 前端工程在这一环节要做的配合
Jeecg-boot 前端一般通过接口访问后端,数据库切换后前端通常不用改代码。但要确认后端的端口、接口前缀没变化,以及前端的代理配置是否指向了新的后端地址。如果用 Nginx 部署,检查 upstream 指向的是不是新启动的后端服务即可。
最后再分享两句实在话
我在实际部署中最深的体会是:Jeecg-boot 切 Oracle 并不难,难的是在切换之前把数据库和工程之间的兼容问题提前摸清楚。建议先在测试环境完整跑一遍从 Oracle 安装到工程启动的流程,记录下每一条报错和改动,再上生产。生产环境的 Oracle 安装建议让 DBA 参与,尤其是表空间规划和字符集选择这两个决定,一旦定下来后面就不太好改了。
另外,Oracle 11g 已经在运行的项目,后续要特别留意归档日志的增长,尤其是初始化脚本导入和频繁联调这个阶段,日志增长很快,磁盘很容易被打满。我当时在一次全量导入测试中,归档日志直接把数据盘写满了,差点导致数据库无法启动。所以每完成一个阶段,最好清理一下归档日志,或者设置自动删除策略。
这篇基础上的"第二弹"先把数据库这条腿立住,接下来你就可以安心往后端业务代码、权限配置、生产上线那些方向去折腾了。