JFinal使用技巧-MariaDB使用示例

MariaDB 和 MySQL 是兼容的,但它们是不同的数据库。然而,由于历史原因(MariaDB 是 MySQL 的一个分支),它们之间具有高度的兼容性。

对于MariaDB,有两种常见的JDBC驱动选择:

使用 MariaDB 官方提供的 JDBC 驱动,其驱动类为 org.mariadb.jdbc.Driver,JDBC URL 格式通常以 jdbc:mariadb:// 开头。

使用 MySQL 的 JDBC 驱动(即 MySQL Connector/J),其驱动类为 com.mysql.jdbc.Driver(旧版本)

或 com.mysql.cj.jdbc.Driver(新版本),JDBC URL 格式为 jdbc:mysql://。


虽然 MariaDB 和 MySQL 协议兼容,但为了获得更好的兼容性和支持 MariaDB 特有的功能,建议使用 MariaDB 官方驱动。

但是,如果你使用 MySQL 驱动来连接 MariaDB,在大多数情况下也是可以工作的,因为 MariaDB 设计为与 MySQL 兼容。

不过,可能存在一些细微的差异,尤其是在新版本中。


因此,建议根据你使用的数据库来选择驱动:

如果使用 MariaDB,优先使用 MariaDB 驱动。

如果使用 MySQL,则使用 MySQL 驱动。

image.png


代码示例:

版本对应关系
MariaDB 10.1+ 建议使用 mariadb-java-client 2.7+
最新版本推荐 3.0+
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>3.3.3</version>
</dependency>
//复制一个经典的 多库之动态管理数据库示例: 
public static void main(String[] args) {
    DruidPlugin druidPlugin = new DruidPlugin(
            "jdbc:mariadb://localhost:3307/information_schema",
            "root", "root").set(1, 1, 10);
    ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin);
    // 启动管理库
    druidPlugin.start();
    arp.start();

    String name = "test_1";
    // 建库
    Db.update("CREATE DATABASE " + name);

    // 启动业务库
    DruidPlugin druidPluginTest = new DruidPlugin("jdbc:mariadb://localhost:3307/" + name,
            "root", "root").set(1, 1, 10);
    ActiveRecordPlugin arpTest = new ActiveRecordPlugin(name, druidPluginTest);
    druidPluginTest.start();
    arpTest.start();
    // 建表
    DbPro testDb = Db.use(name);
    testDb.update(
            "CREATE TABLE `a` ( `id`  int NOT NULL AUTO_INCREMENT , `xx`  varchar(255) NULL , 
            PRIMARY KEY (`id`) ) ");
    // 写入数据
    testDb.update("INSERT INTO `a` (`xx`) VALUES ('xxxxx')");
    // 查询
    List<Record> list = testDb.find("SELECT * FROM `a` LIMIT 100");
    System.out.println(list.toString());

    druidPluginTest.stop();
    druidPlugin.stop();
}

image.png

image.png

PS:我本机有安装 MySQL 与 MariaDB 双数据库,所以 MariaDB 端口改为了3307

MariaDB的核心优势:

对比维度MariaDB 的优势体现
开源与社区更开放:由非营利的MariaDB基金会管理,承诺保持真正开源,社区驱动,开发更透明。
性能与扩展存储引擎更丰富:默认包含Aria、ColumnStore、MyRocks等,针对不同场景优化。
查询优化更强:优化器更先进,支持并行复制,显著提升主从同步速度。
功能特性功能更丰富:较早支持窗口函数、通用表表达式、WITH语句、INTERSECT/EXCEPT等。
动态列:允许在NoSQL风格的单行中存储键值对。
安全性权限更细化:支持更精细的权限控制,如基于表的列级权限。
默认更安全:安装后默认配置可能更严格。
兼容性与演进高度兼容:作为MySQL的“直接替代品”设计,数据和客户端协议兼容,迁移成本低。
创新更快:版本迭代迅速,能更快引入新特性。


PS:@zeroabc 反馈java.util.Date 使用习惯的问题。
因为MariaDB是严格遵守日期规则的,所以当Timestamp字段时,用Date对象,会丢失时分秒,需要使用java.sql.Timestamp对象。
喜欢使用BaseModel的用户,代码生成器需要配置一下:

// 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user",移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
generator.setRemovedTableNamePrefixes("t_");

// 还原默认的 java.sql.Timestamp
generator.addTypeMapping("java.sql.Timestamp", "java.sql.Timestamp");

// 生成
generator.generate();

在 .generate(); 前面进行addTypeMapping 设置一下。

以及防止 Record 用户,set的时候没有注意,可以再加一个防护,MariaDBDialect 入库的时候自动判断转换一下:

public class MariaDBDialect extends MysqlDialect {
    public MariaDBDialect() {
        this.modelBuilder = TimestampProcessedModelBuilder.me;
        this.recordBuilder = TimestampProcessedRecordBuilder.me;
    }

    private void handleValue(Map<String, Object> attrs) {
        attrs.forEach((k, v) -> {
            if (v instanceof java.util.Date && v.getClass() == java.util.Date.class){
                attrs.put(k, new java.sql.Timestamp(((java.util.Date) v).getTime()));
            }
        });
    }

    @Override
    public void forDbSave(String tableName, String[] pKeys, Record record, StringBuilder sql, List<Object> paras) {
        handleValue(record.toMap());
        super.forDbSave(tableName, pKeys, record, sql, paras);
    }

    @Override
    public void forDbUpdate(String tableName, String[] pKeys, Object[] ids, Record record, StringBuilder sql, List<Object> paras) {
        handleValue(record.toMap());
        super.forDbUpdate(tableName, pKeys, ids, record, sql, paras);
    }

    @Override
    public void forModelSave(Table table, Map<String, Object> attrs, StringBuilder sql, List<Object> paras) {
        handleValue(attrs);
        super.forModelSave(table, attrs, sql, paras);
    }

    @Override
    public void forModelUpdate(Table table, Map<String, Object> attrs, Set<String> modifyFlag, StringBuilder sql, List<Object> paras) {
        handleValue(attrs);
        super.forModelUpdate(table, attrs, modifyFlag, sql, paras);
    }
}

使用:

ActiveRecordPlugin arp = new ActiveRecordPlugin(。。。);
arp.setDialect(new MariaDBDialect());

PS:建议日期用时间戳一把梭,数字long解决。防止以后系统时间国际化后,各国时区处理麻烦的很,冬夏令时处理等问题直接跳过。


又水一篇~

评论区

JFinal

2025-12-06 00:22

实用,点赞收藏一波

zzutligang

2025-12-11 16:44

给杜总点赞。波总能在官方jfinal里增加一个MariaDB方言就完美了,虽然MariaDB兼容mysql。

jiangjian123

2025-12-20 11:52

可以用的

jiangjian123

2025-12-20 11:52

@jiangjian123 org.mariadb.jdbc.Driver

zeroabc

2025-12-28 13:48

杜总,不知道你有没有我这个情况,我用的jboot框架,然后不管是DruidPlugin还是HikariCpPlugin,保存Date对象时(数据库字段类型是datetime),时分秒会变成0-0-0(实际当然不是零时零分),改回mysql连接就没有问题,不知道是什么情况。方言是直接extent了jfinal的public class JbootMariadbDialect extends MysqlDialect implements JbootDialect

杜福忠

2025-12-28 15:11

@zeroabc Date 就是没有时分秒,保留时分秒的话要用Timestamp,或者是LocalDateTime对象。 Date 和 DateTime是不同的,MySQL老驱动是会保留,MariaDB是严格遵守规则。如果是做老项目兼容处理的话,可自建一个MariaDBDialect,覆写 Save、Update系列方法 e.getValue() 前判断一下Date类型转换为Timestamp就可以了。
我个人是不建议折腾Date类型,直接时间戳一把梭,前后端统一规则更方便。也没啥时区夏令时、冬令时的处理,麻烦的一批

zeroabc

2025-12-28 16:26

@杜福忠 这样,那是不是还得把ModelBase代码生成器的所有时间相关字段都改成DateTime?你们是这样处理?

杜福忠

2025-12-29 08:57

@zeroabc 我们时间戳一把梭,数字long啊,避免其他国家的用户因为冬夏令时回拨问题导致时间不一致的问题,前后交互上全程使用时间戳就可以了,计算时间冲突也方便

杜福忠

2025-12-29 11:07

@zeroabc 对了,如果需要ModelBase代码生成器的java.sql.Timestamp不被转为java.util.Date,要在生成器generator.generate(); 前面配置一下 generator.addTypeMapping("java.sql.Timestamp", "java.sql.Timestamp");
注意要移除generator.setTypeMapping(tm);那行demo代码,用默认的对象进行add覆盖即可

zeroabc

2025-12-29 14:15

@杜福忠 好的,感谢指教

热门分享

扫码入社