2026/5/13 16:42:33
网站建设
项目流程
做百度网站优化多少钱,推荐几个做网站比较好的公司,十大免费文案网站,单页网站的优点将Forest应用的数据库从Derby迁移至MySQL
在现代Java企业级开发中#xff0c;选择合适的数据库是系统稳定运行的关键。许多教学或示例项目#xff08;如经典的 Forest 应用#xff09;出于便捷性考虑#xff0c;默认使用 Apache Derby 这类嵌入式数据库。然而#xff0c;…将Forest应用的数据库从Derby迁移至MySQL在现代Java企业级开发中选择合适的数据库是系统稳定运行的关键。许多教学或示例项目如经典的 Forest 应用出于便捷性考虑默认使用 Apache Derby 这类嵌入式数据库。然而一旦进入生产环境Derby 的并发处理能力弱、缺乏高可用支持、难以监控和备份等短板便暴露无遗。以 Forest 为例它是一个典型的 Java EE 示例应用常用于演示 JPA、Servlet 和 EJB 技术栈的整合。虽然基于 Derby 能快速启动并展示功能但若想将其部署为真实服务——比如作为后台管理系统原型或教学实训平台——就必须面对数据持久化的可维护性和扩展性问题。此时迁移到 MySQL 不仅是性能升级更是架构成熟度的一次跃迁。整个迁移过程并不复杂核心在于解耦“业务逻辑”与“数据存储”。得益于 Java EE 标准化的设计理念只要遵循 JDBC、JNDI 和 JPA 规范更换底层数据库只需调整配置和适配 SQL 语法无需重写代码。这种可移植性正是企业级框架的魅力所在。首先确保目标服务器上已安装并运行 MySQL 服务推荐 5.7 或以上版本。可以通过以下命令启动sudo systemctl start mysql接着登录 MySQL 控制台创建专用数据库和用户避免使用 root 账户直接连接应用提升安全性CREATE DATABASE forest CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER forestuserlocalhost IDENTIFIED BY your_secure_password; GRANT ALL PRIVILEGES ON forest.* TO forestuserlocalhost; FLUSH PRIVILEGES;⚠️ 实际部署时请务必使用强密码并根据网络环境决定是否开放forestuser%的远程访问权限。同时建议在防火墙层面限制 3306 端口的访问来源。接下来要修改的是web.xml文件中的数据源定义。Forest 使用 Java EE 容器管理的数据源机制因此我们只需替换原有的 Derby 配置为 MySQL 对应实现即可。定位到WEB-INF/web.xml中的data-source段落将其内容更新如下data-source namejava:global/ForestDataSource/name class-namecom.mysql.cj.jdbc.MysqlDataSource/class-name server-namelocalhost/server-name port-number3306/port-number database-nameforest/database-name userforestuser/user passwordyour_secure_password/password property nameuseSSL/name valuefalse/value /property property nameallowPublicKeyRetrieval/name valuetrue/value /property property nameserverTimezone/name valueUTC/value /property /data-source这里有几个关键点需要注意-class-name必须改为com.mysql.cj.jdbc.MysqlDataSource这是 MySQL Connector/J 提供的标准数据源类- 所有连接参数需准确填写尤其是主机名、端口和数据库名- 添加useSSLfalse是因为在大多数本地或内网环境中未配置 SSL如果启用了 TLS则应移除该属性并配置证书-allowPublicKeyRetrievaltrue允许驱动在无法通过安全方式获取公钥时进行明文传输适用于旧版认证插件- 设置serverTimezoneUTC可避免因时区不一致导致的时间字段错乱问题。完成修改后保存文件。仅仅更改配置还不够Java 应用必须能加载对应的 JDBC 驱动才能建立连接。由于 Forest 运行在 GlassFish 这类 Java EE 容器上我们需要将 MySQL 的 JDBC 驱动包即 MySQL Connector/J放入容器的共享类路径中。前往 MySQL 官方下载页 获取最新版本的 JAR 包例如mysql-connector-java-8.0.xx.jar然后将其复制到 GlassFish 的 domain lib 目录cp mysql-connector-java-8.0.xx.jar $GLASSFISH_HOME/domains/domain1/lib/随后重启应用服务器以加载新驱动asadmin restart-domain这一步至关重要——如果不重启即使配置正确容器也无法识别新的驱动类最终会抛出ClassNotFoundException: com.mysql.cj.jdbc.Driver错误。尽管 JPA 在理论上具备数据库无关性但在实际运行中仍需明确指定方言Dialect以便生成符合目标数据库特性的 SQL 语句。因此检查并更新META-INF/persistence.xml是必不可少的操作。找到persistence-unit配置段确保其引用了正确的全局数据源名称并显式设置 Hibernate 方言persistence-unit nameforestPU transaction-typeJTA jta-data-sourcejava:global/ForestDataSource/jta-data-source properties property namehibernate.dialect valueorg.hibernate.dialect.MySQL8Dialect/ property namehibernate.show_sql valuefalse/ property namehibernate.hbm2ddl.auto valueupdate/ /properties /persistence-unit其中-MySQL8Dialect适用于 MySQL 8.0若使用 5.7 可降级为MySQL57Dialect-hbm2ddl.autoupdate在首次迁移时非常有用它会自动根据实体类结构同步数据库表新增列、索引等但切记上线前应改为validate防止意外修改生产数据。原始 Forest 项目通常附带三组 SQL 初始化脚本drop.sql、create.sql和data.sql。这些脚本最初为 Derby 编写在迁移到 MySQL 时必须进行语法适配。删除脚本drop.sql为了安全起见先禁用外键检查再逐个删除表SET FOREIGN_KEY_CHECKS 0; DROP TABLE IF EXISTS person_groups; DROP TABLE IF EXISTS person; DROP TABLE IF EXISTS groups; DROP TABLE IF EXISTS order_detail; DROP TABLE IF EXISTS customer_order; DROP TABLE IF EXISTS order_status; DROP TABLE IF EXISTS product; DROP TABLE IF EXISTS category; SET FOREIGN_KEY_CHECKS 1;使用IF EXISTS可避免因表不存在而导致脚本中断适合重复执行场景。创建脚本create.sql这是改动最多的部分。以下是适配 MySQL 后的完整建表语句SET NAMES utf8mb4; SET time_zone 00:00; CREATE SCHEMA IF NOT EXISTS forest DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE forest; CREATE TABLE category ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(45) NOT NULL, tags VARCHAR(45) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE person ( id INT AUTO_INCREMENT PRIMARY KEY, firstname VARCHAR(50) NOT NULL, lastname VARCHAR(100) NOT NULL, email VARCHAR(45) NOT NULL UNIQUE, address VARCHAR(45) NOT NULL, city VARCHAR(45) NOT NULL, password VARCHAR(100), dtype VARCHAR(31) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE groups ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) NOT NULL, description VARCHAR(300) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE person_groups ( groups_id INT NOT NULL, email VARCHAR(45) NOT NULL, CONSTRAINT fk_person_groups_person FOREIGN KEY (email) REFERENCES person(email), CONSTRAINT fk_person_groups_groups FOREIGN KEY (groups_id) REFERENCES groups(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order_status ( id INT PRIMARY KEY, status VARCHAR(45) NOT NULL, description VARCHAR(200) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE customer_order ( id INT AUTO_INCREMENT PRIMARY KEY, amount FLOAT(52) NOT NULL, date_created TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, customer_id INT NOT NULL, status_id INT NOT NULL, CONSTRAINT fk_customer_order_order_status FOREIGN KEY (status_id) REFERENCES order_status(id), CONSTRAINT fk_customer_order_customer FOREIGN KEY (customer_id) REFERENCES person(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE product ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(45) NOT NULL, price DECIMAL(10,2) NOT NULL, description VARCHAR(145) NOT NULL, img VARCHAR(45), category_id INT NOT NULL, img_src LONGBLOB, CONSTRAINT fk_product_category FOREIGN KEY (category_id) REFERENCES category(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE order_detail ( order_id INT NOT NULL, product_id INT NOT NULL, qty INT NOT NULL, CONSTRAINT pk_order_product PRIMARY KEY (order_id, product_id), CONSTRAINT fk_order_detail_product FOREIGN KEY (product_id) REFERENCES product(id), CONSTRAINT fk_order_detail_order FOREIGN KEY (order_id) REFERENCES customer_order(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE INDEX idx_person_email ON person(email); CREATE INDEX idx_customer_order_status ON customer_order(status_id); CREATE INDEX idx_order_detail_pid ON order_detail(product_id);主要变更包括- 显式声明字符集为utf8mb4支持 emoji 和多语言- 所有表使用InnoDB引擎以支持事务和外键- 自增主键统一采用AUTO_INCREMENT- 图像字段由原来的BLOB升级为LONGBLOB适应更大文件- 外键约束命名规范化便于后期排查问题- 添加常用索引以优化查询性能。初始数据脚本data.sql此脚本基本保持不变只需注意两点1. 文件本身应以 UTF-8 编码保存防止中文乱码2. 密码字段继续使用MD5()函数加密与原设计一致。示例片段如下INSERT INTO category (name, tags) VALUES (Plants, Seeds, trees, flowers ...); INSERT INTO category (name, tags) VALUES (Food, Foods, healthy items ...); INSERT INTO person (firstname, lastname, email, address, city, password, dtype) VALUES (Robert, Exampler, robertexample.com, Example street, San Francisco, MD5(1234), Customer); INSERT INTO person (firstname, lastname, email, address, city, password, dtype) VALUES (Admin, Admin, adminexample.com, Example street, Belmont, MD5(admin), Administrator); INSERT INTO groups (name, description) VALUES (USERS, Users of the store); INSERT INTO groups (name, description) VALUES (ADMINS, Administrators of the store); INSERT INTO person_groups (groups_id, email) VALUES (1, robertexample.com); INSERT INTO person_groups (groups_id, email) VALUES (2, adminexample.com); INSERT INTO order_status (id, status, description) VALUES (1, Pending processing, ); INSERT INTO order_status (id, status, description) VALUES (2, Validating payment, ); -- 更多状态略...所有配置就绪后重新部署 WAR 包或重启应用服务器。打开浏览器访问首页重点验证以下几个方面页面是否正常加载是否存在 500 错误登录功能是否可用尝试用adminexample.com / admin登录后台数据是否成功初始化可通过命令行快速确认mysql -u forestuser -p -e USE forest; SELECT COUNT(*) FROM person;预期输出应类似---------- | COUNT(*) | ---------- | 4 | ----------如果数量正确且无异常日志说明迁移成功。当然过程中也可能遇到一些典型问题以下是常见故障及其解决方案问题现象可能原因解决方法ClassNotFoundException: com.mysql.cj.jdbc.Driver驱动未加载确认 JAR 是否放置于$domain/lib/并已重启服务器Access denied for user forestuserlocalhost认证失败检查用户名、密码及主机权限刷新权限表表创建失败或字符乱码字符集不匹配统一设置数据库、表、连接使用utf8mb4外键约束报错存储引擎非 InnoDB修改建表语句中的ENGINEInnoDB启动时报PersistenceException方言配置错误正确设置hibernate.dialect为对应版本此外建议开启 GlassFish 的日志记录功能查看server.log中的详细堆栈信息有助于精准定位问题根源。这次从 Derby 到 MySQL 的迁移看似只是换了数据库实则是一次小型架构演进。它不仅提升了系统的稳定性与并发能力更为后续引入连接池优化、读写分离、慢查询分析、数据备份恢复等运维手段铺平了道路。更重要的是整个过程充分体现了 Java EE 架构的灵活性通过标准接口隔离细节使得底层存储可以灵活替换。这种“一次编码多处部署”的特性正是企业级开发追求的核心价值之一。如果你正在学习 JPA 或准备将教学项目投入实际使用不妨动手实践这一迁移流程。你会发现真正掌握的不只是 SQL 语法差异而是如何在不同环境中构建健壮、可维护的应用系统。✅延伸建议在真实项目中应使用 Liquibase 或 Flyway 等数据库版本管理工具替代手工 SQL 脚本实现自动化迁移与回滚进一步提升交付效率与可靠性。