项目结构

在这里插入图片描述
说明一下:
data 和 derby.log 是项目启动后自动创建的,不需要手动去创建

test-schema.sql

CREATE TABLE t_user
(
    id           BIGINT      NOT NULL PRIMARY KEY,
    username     VARCHAR(50) NOT NULL UNIQUE,
    email        VARCHAR(100),
    age          INTEGER
);

application.properties

spring.datasource.url=jdbc:derby://localhost:1527/data/myappdb;create=true;autoCommit=true
spring.datasource.driver-class-name=org.apache.derby.jdbc.ClientDriver
spring.datasource.username=
spring.datasource.password=
spring.sql.init.mode=never
mybatis-plus.mapper-locations=classpath*:/mapper/**/*.xml
mybatis-plus.type-aliases-package=com.example.demo.entity
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.global-config.db-config.db-type=derby

DerbyConfig

package com.example.config;

import org.apache.derby.drda.NetworkServerControl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;

import java.net.InetAddress;

@Configuration
public class DerbyConfig implements CommandLineRunner {

    @Value("${derby.mode:network}")
    private String derbyMode;

    @Override
    public void run(String... args) {
        if ("network".equalsIgnoreCase(derbyMode)) {
            startDerbyNetworkServer();
        }
    }

    private void startDerbyNetworkServer() {
        try {
            NetworkServerControl server = new NetworkServerControl(InetAddress.getByName("localhost"), 1527);
            server.start(null);
            System.out.println("✅ Derby Network Server started on localhost:1527");
            System.out.println("✅ Now both Application and IDEA can connect simultaneously");
        } catch (Exception e) {
            System.err.println("❌ Failed to start Derby Network Server: " + e.getMessage());
        }
    }
}

其余的文件

其余的文件 mapper service serviceImpl xml 等文件都是使用 mybaitsX 插件生成的

启动步骤

  1. 项目启动
  2. 连接 derby 数据库在这里插入图片描述
    注意!!!
    这里的版本要和 pom 文件里面的版本需要保持一致

在这里插入图片描述
3. 在 APP 里面执行 建表语句
在这里插入图片描述
4. 测试

@RestController
@RequestMapping("/derby")
public class DerbyController {

    @Autowired
    private TUserService tUserService;
    
    @RequestMapping("/test")
    public String test() {
        List<TUser> list = tUserService.list();
        return list.toString();
    }
    
    @RequestMapping("/insert")
    public String insert() {
        TUser tUser = new TUser();
        tUser.setUsername("setUsername");
        tUser.setEmail("setEmail");
        tUser.setAge(0);
        boolean save = tUserService.save(tUser);
        return save + "";
    }
}

特别说明

  1. derby 可以使用 嵌入式模式,也就是 embedded 模式 和 客户端模式,也就是 remote
  2. 如果使用 embedded 模式,只允许一个 jvm 线程连接,也就是说,我一边使用工具连接 derby 数据库,一边通过接口查询数据,会报错
  3. 而使用 remote 模式,则可以避免这种情况
  4. derby 想启动 remote 模式,需要手动开启,也就是写代码,就是上文我提供的 DerbyConfig 这个文件
  5. derby 是随项目启动而启动的,项目一关,工具就连不上了

思考

什么时候使用 derby 合适,什么时候使用 mysql 合适?

选择 Derby 还是 MySQL,主要取决于你的项目需求、规模和对数据库特性的要求。为了帮你快速把握,我用一个表格汇总它们的核心区别:

特性Apache DerbyMySQL
架构嵌入式 (亦可网络模式)客户端-服务器架构
管理零管理,开箱即用需安装、配置、维护
性能焦点嵌入式模式下读写快,资源占用低高并发、大数据量、复杂查询
扩展性弱,不适合分布式或大规模数据强,支持集群、分片、读写分离
SQL支持支持SQL标准支持SQL标准,并有大量扩展
主要场景嵌入式应用、桌面应用、移动应用、测试Web应用、企业应用、高并发系统、大型应用

🔍 Derby 就像一个轻便的工具箱,就在你的应用程序“内部”工作。它非常适合嵌入式轻量级的应用场景:

  • 嵌入式应用:需要将数据库和应用打包在一起,无需用户单独安装和配置数据库的场景,例如桌面软件、移动应用。
  • 开发与测试:希望快速搭建环境,避免复杂的数据库安装和配置,常用于单元测试或原型验证。
  • 小型或轻型应用:数据量不大(通常在GB级别以下),并发用户数很少(例如单用户或少量用户)的场景。
  • 需要零管理:应用场景要求简单的数据管理,且不希望投入精力进行数据库运维。

🌐 MySQL 则像一个强大的独立发电站,应用程序作为“客户端”通过网络连接到这个“服务器”。它擅长支持多用户、高并发、大数据量的场景:

  • Web应用程序:需要支持大量用户并发访问的网站、Web应用服务。
  • 企业级应用:需要处理大量数据和高并发请求,对性能、可靠性、可扩展性要求较高的关键业务系统,如CRM、ERP等。
  • 需要复杂功能:应用需要复杂的SQL查询、存储过程、触发器、视图、分布式事务等高级功能。
  • 高可用与扩展:系统需要高可用性保障(如主从复制、集群)、水平扩展(如分库分表)或大数据量(TB级别)处理能力。

💡 一些选择建议

  • 初学者或快速原型:可以从 Derby 入手,它能让你更专注于业务逻辑而非数据库管理。
  • 考虑未来变化:如果预计应用未来可能在用户量、数据量或复杂性方面显著增长,且你希望减少后续数据库迁移的工作量,那么即使初期规模较小,直接选择 MySQL 也可能是更省力的选择。
  • 混合使用:在大型项目中,有时也会混合使用。例如,主应用使用 MySQL,而每个客户端或某个特定模块使用内嵌的 Derby 处理本地数据。

Derby 支持 mysql 的语法么? 支持事务么?

Apache Derby 和 MySQL 虽然都是关系型数据库,但在 SQL 语法上存在一些差异。让我用一个表格来汇总它们的主要特性对比,以便你快速了解:

特性Apache DerbyMySQL
SQL标准支持支持 SQL92、部分 SQL99 和 SQL2003 特性支持 SQL 标准,并提供大量扩展(如 FROM_UNIXTIME, REPLACE
特定函数不支持 MySQL 特有函数(如 FROM_UNIXTIME),但提供类似功能的函数(如 TIMESTAMPADD 计算 Unix 时间戳)支持大量特有函数(如 FROM_UNIXTIME
分页语法不支持 LIMIT
• 10.4+:支持 ROW_NUMBER()
• 10.7+:支持 OFFSET/FETCH
支持 LIMITOFFSET
条件语句不支持存储过程或函数中的 IF 语句,但可使用 CASE 表达式或 MERGE 语句实现条件插入/更新支持 IF 语句(存储过程中)、IF() 函数、REPLACE 语句
事务支持完全支持 ACID 事务(原子性、一致性、隔离性、持久性)完全支持 ACID 事务
运行模式嵌入式(与应用同 JVM)、网络服务器模式客户端-服务器模式
适用场景嵌入式应用、单元测试、桌面应用Web 应用、高并发系统、大型应用

🧭 给开发者的建议

  • 在 Derby 中模拟 MySQL 函数:当需要在使用 Derby 进行测试或开发时模拟 MySQL 特有函数(如 FROM_UNIXTIME),可以:
    • 编写兼容层:创建自定义函数或使用 Derby 提供的其他函数(如 TIMESTAMPADD)来模拟实现。
    • 使用抽象层:在应用代码中利用 ORM(如 Hibernate)或自定义的 DAO 层来抽象 SQL 差异,避免直接编写依赖特定数据库的 SQL。
  • 处理条件插入/更新:在 Derby 中,需要实现“如果存在则更新,否则插入”的逻辑时,可以使用 MERGE 语句(Derby 支持),这是更符合 SQL 标准的方式。
  • 管理分页查询:根据你所使用的 Derby 版本,选择合适的分页方式:
    • Derby 10.7 及以上:使用标准的 OFFSET ... FETCH 子句。
    • Derby 10.4 至 10.6:使用 ROW_NUMBER() 函数配合子查询。
    • 更早版本或简单分页:考虑使用 JDBC 的 setMaxRows() 方法。

💎 总结

Derby 是一个轻量级、嵌入式、支持 ACID 事务的关系型数据库,非常适合嵌入式环境、单元测试和桌面应用。虽然它不完全支持 MySQL 的所有语法特性(尤其是某些特定函数和 LIMIT 子句),但其对 SQL 标准和事务的良好支持,使其在特定场景下是一个可靠的选择。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐