当前位置: 首页>后端>正文

java动态数据源(多种数据库)中自定义表(实体)的创建及增查删改实现

我正在做一个开源的低代码平台:https://gitee.com/IElwin/ezlcp-java,了解代代码平台的都知道,会有自定义数据源、自定义表(实体)、自定义表单、自定义报表等功能。

关于自定义数据源,如果只支持一种数据库的话,开发起来就会容易些。目前很多平台是支持多种数据库的,如:MySQLOraclePostgreSQLSQL Server,还有的会支持国产的数据库,如:达梦人大金仓等。

如果表结构是固定的,我们可以使用MyBatisHibernateORM工具类库来操作表;但是需求中表结构是用户自定义的,可能随时变动,使用ORM工具就不适合了。那怎么实现这些用户自定义动态表的创建、修改表结构、查询、插入等操作呢?接下来比较一下各实现方案:

方法一:使用JdbcTemplate全手写SQL

当然直接用jdbc来实现也是可以的,但用spring的JdbcTemplate会更优雅一些,可以少写一些代码。我看过一个产品的源码就是用这种方式来实现的。使用的是策略设计模式,定义一个数据操作的接口,每一种数据库就写一个实现该接口的操作类。当进行数据库操作时,会根据DruidDataSource数据源的getDbType方法来获取数据库类型,找到相应的操作类Bean,再执行相应的方法。这是最基本也是最灵活的方案,但是会有很多代码量,也需要花大量的时间来测试。之前用过的那个产品在MySQL数据库下运行正常,切换到Oracle数据源时一大堆问题出现。我就想有没有这方面开源组件,节省开发时间和测试时间。

方法二:使用AnyLine

AnyLine是国内的开源java组件,官网地址:http://doc.anyline.org/,它底层的实现方式类似于第一种方法。使用时,如果要支持某一种数据,就引用该数据库的相关的Jar包,官方文档中写的支持多种数据库,还有些国产数据库也支持。完全开源免费的,也可以切换数据源,所以我就试用了一下,测试主要代码如下:

        service.setDataSource(dsName);
        Table table = service.metadata().table(null, null, tableName);
        if (null != table) {
            service.ddl().drop(table);
        }
        table = new Table(tableName);
        table.setComment("测试创建的表");
        table.addColumn("id", "varchar(64)").setPrimaryKey(true).setComment("主键");
        table.addColumn("name", "varchar(50)").setComment("姓名");
        table.addColumn("age", "int").setComment("年龄");
        table.addColumn("create_time", "datetime").setComment("创建时间");
        table.addColumn("create_by", "varchar(64)").setComment("创建人");
        service.ddl().create(table);
        //插入数据
        DataRow row = new DataRow();
        row.put("id","101");
        row.put("name","张三");
        String now= DateUtils.getTime();
        row.put("age",60);
        row.put("create_time",now);
        service.insert(tableName, row);
        //查询数据
        DataSet set = service.querys(tableName);
        service.setDefaultDataSource();

pom.xml文件相关内容如下:

     <!-- 每一种数据库要引用一个类库,还要引入该数据库的jdbc驱动程序 -->
        <dependency>
            <groupId>org.anyline</groupId>
            <artifactId>anyline-data-jdbc-postgresql</artifactId>
            <version>8.6.3-20230625</version>
        </dependency>
        <dependency>
            <groupId>org.anyline</groupId>
            <artifactId>anyline-data-jdbc-oracle</artifactId>
            <version>8.6.3-20230625</version>
        </dependency>
       <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.6.0</version>
        </dependency>
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
            <version>23.2.0.0</version>
        </dependency>

就是先切换到指定的数据源,然后创建表,插入一条数据,再查询该表,最后切换回默认数据源。日期类型在MySQL数据库下,直接传new Date() 或者时间字符串都是可以的;但切换到PostgreSQL两种类型值都会报错了。说明AnyLine也不是很稳定,还需要测试以及对某种数据库特殊处理才可以。

方法三: 使用jDialects

jDialects项目地址:https://gitee.com/drinkjava2/jdialects,也是国内的免费开源组件,并不是很出名,但非常轻量极。官方的介绍:jDialects是一个Java数据库方言工具,支持80多种数据库方言,具有分页、函数变换、类型变换、DDL生成、JPA注解解析等功能,它通常与JDBC工具组合使用。
pom.xml引入:

<dependency>
    <groupId>com.github.drinkjava2</groupId>
    <artifactId>jdialects</artifactId>
    <version>5.0.13.jre8</version>
</dependency>

因为这个类库只负责生成SQL,至于SQL的执行还是需要引入相关的JDBC驱动程序的。测试代码如下:

        var ds = DruidUtils.getDataSource(dsId);
        var template = new JdbcTemplate(ds);
        TableModel t = new TableModel(tableName);
        t.comment("测试创建的表");
        t.column("id").VARCHAR(64).pkey().comment("主键");
        t.column("name").VARCHAR(50).comment("姓名");
        t.column("age").INTEGER().comment("年龄");
        t.column("create_time").TIMESTAMP().comment("创建时间");
        t.column("create_by").VARCHAR(64).comment("创建人");
        Dialect dialect = Dialect.guessDialect(ds);
        String[] ddlArray = dialect.toDropAndCreateDDL(t);
        for (String ddl : ddlArray) {
            template.execute(ddl);
        }
        String now = DateUtils.getTime();
        String sql = "insert into " + tableName + " (id,name,age,create_time) values('101','李明',18,'" + now + "')";
        template.execute(sql);

        sql = "select * from " + tableName;
        JsonResult result = JsonResult.getSuccessResult("common.handleSuccess");
        var data = template.queryForList(sql);

测试了MySQLPostgreSQL两种数据库都是可以正常运行的,所以就决定是你了。

方法四: 使用jOOQ

jOOQ官网:https://www.jooq.org/,看了教程觉得用起来很简单的;但是它是一个商用软件,虽然也有开源版本。开源版本只支持MySQLPostgreSQL还有一些小众数据库,而且只支持特定的版本(比如MySQL只支持8.0.31版,其他旧版本不支持),觉得开源版本太鸡肋,决定放弃试用。如果你不在乎钱的话可以使用,商业版也可以免费试用30天。

总结

最终的决定采用的方案是:先定义统一的操作接口(方法一、二中都有接口),然后建立一个默认的实现类(调用jDialects,应该可以兼容大多数常用的数据库);对于jDialects未实现的或者出错的数据库,再新建一个实现类(可继承默认实现类)来处理。


https://www.xamrdz.com/backend/3w21939166.html

相关文章: