springcloud微服务搭建多数据源(mysql,oracle,postgres,等等)管理模块,支持通过注解方式切换不同类型的数据库

1.背景

同一套微服务管理系统,业务完全一样,但不同的客户可能要求使用自己熟悉的数据库,比如,mysql,oracle,postgres,还有一些国产数据库。如果能够将数据库模块独立出来,兼容各家的数据库操作,在发布系统之前,只需要通过注解切换到定制的数据库类型,那么就会方便很多。

2.实现方案

完整项目文件结构;

2.1.单体项目运行,未注册到nacos

新建多数据源管理模块,并在application.yml里面配置不同数据库的信息;

java 复制代码
# Tomcat
server:
  port: 9305

# Spring
spring:
  application:
    # 应用名称
    name: sharetek-multi-datasource
  profiles:
    # 环境配置
    active: @profiles.active@

--- # nacos 配置
spring:
  cloud:
    nacos:
      # nacos 服务地址
      server-addr: @nacos.server@
      discovery:
        # 注册组
        group: @nacos.discovery.group@
        namespace: ${spring.profiles.active}
        cluster-name: xa
      config:
        # 配置组
        group: @nacos.config.group@
        namespace: ${spring.profiles.active}
  config:
    import:
      - optional:nacos:application-common.yml
      - optional:nacos:datasource.yml
      - optional:nacos:${spring.application.name}.yml

  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    # 数据源
    mysql:
      type: ${spring.datasource.type}
      driver-class-name: com.mysql.cj.jdbc.Driver
      jdbc-url: jdbc:mysql://localhost:3306/sharetek-demodb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
      username: xxx
      password: xxx
    oracle:
      type: ${spring.datasource.type}
      driverClassName: oracle.jdbc.OracleDriver
      url: jdbc:oracle:thin:@//localhost:1521/XE
      username: xxx
      password: xxx
      hikari:
        connectionTestQuery: SELECT 1 FROM DUAL
#    postgres:
#      type: ${spring.datasource.type}
#      driverClassName: org.postgresql.Driver
#      url: ${datasource.system-postgres.url}
#      username: ${datasource.system-postgres.username}
#      password: ${datasource.system-postgres.password}

启动类,

pom.xml配置内容如下,(有些依赖是其他系统模块的,主要是加入数据库驱动等依赖)

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.sharetek</groupId>
        <artifactId>sharetek-visual</artifactId>
        <version>${revision}</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sharetek-multi-datasource</artifactId>

    <description>
        sharetek-multi-datasource 多数据源管理
    </description>

    <dependencies>
        <dependency>
            <groupId>org.sharetek</groupId>
            <artifactId>sharetek-common-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

        <!-- 数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!-- sharetek Common Log -->
        <dependency>
            <groupId>org.sharetek</groupId>
            <artifactId>sharetek-common-log</artifactId>
        </dependency>

        <!-- Mysql Connector -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <!-- Oracle -->
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
        </dependency>
        <!-- PostgreSql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <!-- SqlServer -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

以mysql为例,读取mysql数据库配置信息,(dml时会用到,如果未来使用代码生成功能,用mybatisplus操作数据库,此处可以不需要,包括MysqlHelper.java等)

java 复制代码
package org.sharetek.multids.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author tjm
 * @title MysqlProperties
 * @date 2024/4/26 13:27
 * @description mysql数据库配置信息
 */
@Data
@Component
@ConfigurationProperties(prefix = "spring.datasource.mysql")
public class MysqlProperties {

    private String jdbcUrl;

    private String userName;

    private String passWord;

    private String driverClassName;

}
复制代码
多数据源配置类DataSourceConfig.class,用来读取application.yml里面配置的各种数据库信息,在容器中生成DataSource对象;
java 复制代码
package org.sharetek.multids.config;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

/**
 * @author junlintianxia
 * @title DataSourceConfig
 * @date 2024/4/26 10:59
 * @description 多数据源配置类
 */
@Configuration
public class DataSourceConfig {

    /**
     * mysql数据源
     *
     * @Param: []
     * @Return: javax.sql.DataSource
     * @Author: junlintianxia
     * @Date: 2024/4/26 11:19
     */
    @Bean
    @ConfigurationProperties("spring.datasource.mysql")
    DataSource dataSourceMysql() {
        return DataSourceBuilder.create().build();
    }

    /**
     * oracle数据源
     *
     * @Param: []
     * @Return: javax.sql.DataSource
     * @Author: junlintianxia
     * @Date: 2024/4/26 11:19
     */
    @Bean
    @ConfigurationProperties("spring.datasource.oracle")
    DataSource dataSourceOracle() {
        return DataSourceBuilder.create().build();
    }

//    /**
//     * postgresql数据源
//     *
//     * @Param: []
//     * @Return: javax.sql.DataSource
//     * @Author: junlintianxia
//     * @Date: 2024/4/26 11:19
//     */
//    @Bean
//    @ConfigurationProperties("spring.datasource.postgresql")
//    DataSource dataSourcePostgresql() {
//        return DruidDataSourceBuilder.create().build();
//    }

}

JdbcTemplate配置类JdbcTemplateConfig.class,用DataSource生成JdbcTemplate对象,用于ddl相关操作;

java 复制代码
package org.sharetek.multids.config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * @author junlintianxia
 * @title JdbcTemplateConfig
 * @date 2024/4/25 17:24
 * @description JdbcTemplate配置类
 */
@Configuration
public class JdbcTemplateConfig {

    /**
     * mysql数据源
     *
     * @Param: [dataSource]
     * @Return: org.springframework.jdbc.core.JdbcTemplate
     * @Author: junlintianxia
     * @Date: 2024/4/26 11:25
     */
    @Bean
    JdbcTemplate getJdbcTemplateMysql(@Qualifier("dataSourceMysql") DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }

    /**
     * oracle数据源
     *
     * @Param: [dataSource]
     * @Return: org.springframework.jdbc.core.JdbcTemplate
     * @Author: junlintianxia
     * @Date: 2024/4/26 11:25
     */
    @Bean
    JdbcTemplate getJdbcTemplateOracle(@Qualifier("dataSourceOracle") DataSource dataSource)
    {
        return new JdbcTemplate(dataSource);
    }

//    /**
//     * postgresql数据源
//     *
//     * @Param: [dataSource]
//     * @Return: org.springframework.jdbc.core.JdbcTemplate
//     * @Author: junlintianxia
//     * @Date: 2024/4/26 11:25
//     */
//    @Bean
//    JdbcTemplate getJdbcTemplatePostgresql(@Qualifier("dataSourcePostgresql") DataSource dataSource)
//    {
//        return new JdbcTemplate(dataSource);
//    }


}

MySQL的crud工具类如下,

java 复制代码
package org.sharetek.multids.utils;

import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
//import org.sharetek.multids.config.MysqlProperties;
import org.sharetek.multids.config.MysqlProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author tjm
 * @title MysqlUtils
 * @date 2024/4/25 14:20
 * @description mysql操作类,包括增删改查
 */
@Slf4j
@Component
public class MysqlHelper {

    //定义数据库的连接
    private Connection connection;

    //定义sql语句的执行对象
    private PreparedStatement pStatement;

    //定义查询返回的结果集合
    private ResultSet resultset;

    private static final String SQL = "SELECT * FROM ";     // 数据库操作

    @Autowired
    private MysqlProperties mysqlProperties;

    @PostConstruct
    public void init() {
        try {
            Class.forName(mysqlProperties.getDriverClassName()); //注册驱动
            connection = DriverManager.getConnection(mysqlProperties.getJdbcUrl(), mysqlProperties.getUserName(), mysqlProperties.getPassWord()); //定义连接
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    /**
     * 对数据库的增/删/改
     *
     * @Param: [sql, params]
     * @Return: boolean
     * @Author: tjm
     * @Date: 2024/4/25 14:30
     */
    public boolean addDeleteModify(String sql, List<Object> params) throws SQLException {
        int result = -1;//设置为
        pStatement = connection.prepareStatement(sql);  //填充占位符
        int index = 1; //从第一个开始添加
        if (params != null && !params.isEmpty()) {
            for (int i = 0; i < params.size(); i++) {
                pStatement.setObject(index++, params.get(i));//填充占位符
            }
        }
        result = pStatement.executeUpdate();    //执行成功将返回大于0的数
        return result > 0 ? true : false;
    }

    /**
     * 查询单条记录
     *
     * @Param: [sql: sql语句, params: 占位符]
     * @Return: java.util.Map<java.lang.String, java.lang.Object>
     * @Author: tjm
     * @Date: 2024/4/25 14:32
     */
    public Map<String, Object> getSimpleResult(String sql, List<Object> params) throws SQLException {
        Map<String, Object> map = new HashMap<>();
        int index = 1;  //从1开始设置占位符
        pStatement = connection.prepareStatement(sql);
        // 判断参数是否为空
        if (params != null && !params.isEmpty()) {
            // 循环填充占位符
            for (int i = 0; i < params.size(); i++) {
                pStatement.setObject((i+1), params.get(i));
            }
        }
        resultset = pStatement.executeQuery();
        // 将查询结果封装到map集合
        ResultSetMetaData metaDate = resultset.getMetaData();   //获取resultSet列的信息
        int columnLength = metaDate.getColumnCount();   //获得列的长度
        while (resultset.next()) {
            for (int i = 0; i < columnLength; i++) {
                String metaDateKey = metaDate.getColumnName(i + 1); //获得列名
                Object resultsetValue = resultset.getObject(metaDateKey);   //通过列名获得值
                if (resultsetValue == null) {
                    resultsetValue = "";    //转成String类型
                }
                //添加到map集合(以上代码是为了将从数据库返回的值转换成map的key和value)
                map.put(metaDateKey, resultsetValue);
            }
            break;
        }
        return map;
    }

    /**
     * 查询多条记录
     *
     * @Param: [sql: sql语句, params: 占位符]
     * @Return: java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @Author: tjm
     * @Date: 2024/4/25 14:35
     */
    public List<Map<String, Object>> getMultipleResult(String sql, List<Object> params) throws SQLException {
        List<Map<String, Object>> list = new ArrayList<>();
        //填充占位符
        int index = 1;
        pStatement = connection.prepareStatement(sql);
        if (params != null && !params.isEmpty()) {
            for (int i = 0; i < params.size(); i++) {
                pStatement.setObject(index++, params.get(i));
            }
        }
        //执行SQL语句
        resultset = pStatement.executeQuery();
        //封装resultset成map类型
        ResultSetMetaData metaDate = resultset.getMetaData();//获取列信息,交给metaDate
        int columnLength = metaDate.getColumnCount();
        while (resultset.next()) {
            Map<String, Object> map = new HashMap<>();
            for (int i = 0; i < columnLength; i++) {
                // 获取列名
                String metaDateKey = metaDate.getColumnName(i + 1);
                Object resultsetValue = resultset.getObject(metaDateKey);
                if (resultsetValue == null) {
                    resultsetValue = "";
                }
                map.put(metaDateKey, resultsetValue);
            }
            list.add(map);
        }
        return list;
    }

    /**
     * 应用反射机制返回单条记录
     *
     * @Param: [sql: sql语句, params: 占位符, javabean,会执行javabean类里面的toString方法]
     * @Return: T 泛型
     * @Author: tjm
     * @Date: 2024/4/25 14:38
     */
    public <T> T getSimpleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception {
        T result = null;
        int index = 1;
        pStatement = connection.prepareStatement(sql);
        if (ObjectUtil.isNotEmpty(params)) {
            for (int i = 0; i < params.size(); i++) {
                pStatement.setObject(index++, params.get(i));
            }
        }
        resultset = pStatement.executeQuery(sql);
        //封装resultset
        ResultSetMetaData metaData = resultset.getMetaData();//获得列的信息
        int columnLength = metaData.getColumnCount();//获得列的长度
        while (resultset.next())//循环取值
        {
            result = javabean.newInstance();//通过反射机制创建一个实例
            for (int i = 0; i < columnLength; i++) {
                String metaDateKey = metaData.getColumnName(i + 1);
                Object resultsetValue = resultset.getObject(metaDateKey);
                if (resultsetValue == null) {
                    resultsetValue = "";
                }
                //获取列的属性,无论是公有。保护还是私有,都可以获取
                Field field = javabean.getDeclaredField(metaDateKey);
                field.setAccessible(true);//打开javabean的访问private权限
                field.set(result, resultsetValue);//给javabean对应的字段赋值
            }
        }
        return result;
    }

    /**
     * 通过反射机制访问数据库,并返回多条记录
     *
     * @Param: [sql: sql语句, params: 占位符,Javabean,会执行javabean类里面的toString方法]
     * @Return: java.util.List<T>
     * @Author: tjm
     * @Date: 2024/4/25 14:52
     */
    public <T> List<T> getMultipleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception {
        List<T> list = new ArrayList<T>();
        int index = 1;
        pStatement = connection.prepareStatement(sql);
        if (params != null && !params.isEmpty()) {
            for (int i = 0; i < params.size(); i++) {
                pStatement.setObject(index, params.get(i));
            }
        }
        resultset = pStatement.executeQuery(sql);
        //封装resultset
        ResultSetMetaData metaData = resultset.getMetaData();//取出列的信息
        int columnLength = metaData.getColumnCount();//获取列数
        while (resultset.next()) {
            T tResult = javabean.newInstance();//通过反射机制创建一个对象
            for (int i = 0; i < columnLength; i++) {
                String metaDataKey = metaData.getColumnName(i + 1);
                Object resultsetValue = resultset.getObject(metaDataKey);
                if (resultsetValue == null) {
                    resultsetValue = "";
                }
                Field field = javabean.getDeclaredField(metaDataKey);
                field.setAccessible(true);
                field.set(tResult, resultsetValue);
            }
            list.add(tResult);
        }
        return list;
    }

    /**
     * 获取数据库下的所有表名
     *
     * @Param: []
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/25 15:00
     */
    public List<String> getTableNames() {
        List<String> tableNames = new ArrayList<>();
        ResultSet rs = null;
        try {
            //获取数据库的元数据
            DatabaseMetaData db = connection.getMetaData();
            //从元数据中获取到所有的表名
            rs = db.getTables(null, null, null, new String[]{"TABLE"});
            while (rs.next()) {
                tableNames.add(rs.getString(3));
            }
        } catch (SQLException e) {
            log.error("getTableNames failure", e);
        } finally {
            try {
                rs.close();
                closeConnection();
            } catch (SQLException e) {
                log.error("close ResultSet failure", e);
            }
        }
        return tableNames;
    }

    /**
     * 获取表中所有字段名称
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/25 15:01
     */
    public List<String> getColumnNames(String tableName) {
        List<String> columnNames = new ArrayList<>();
        PreparedStatement pStemt = null;
        String tableSql = SQL + tableName;
        try {
            pStemt = connection.prepareStatement(tableSql);
            //结果集元数据
            ResultSetMetaData rsmd = pStemt.getMetaData();
            //表列数
            int size = rsmd.getColumnCount();
            for (int i = 0; i < size; i++) {
                columnNames.add(rsmd.getColumnName(i + 1));
            }
        } catch (SQLException e) {
            log.error("getColumnNames failure", e);
        } finally {
            if (pStemt != null) {
                try {
                    pStemt.close();
                    closeConnection();
                } catch (SQLException e) {
                    log.error("getColumnNames close pstem and connection failure", e);
                }
            }
        }
        return columnNames;
    }

    /**
     * 获取表中所有字段类型
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/25 15:02
     */
    public List<String> getColumnTypes(String tableName) {
        List<String> columnTypes = new ArrayList<>();
        PreparedStatement pStemt = null;
        String tableSql = SQL + tableName;
        try {
            pStemt = connection.prepareStatement(tableSql);
            //结果集元数据
            ResultSetMetaData rsmd = pStemt.getMetaData();
            //表列数
            int size = rsmd.getColumnCount();
            for (int i = 0; i < size; i++) {
                columnTypes.add(rsmd.getColumnTypeName(i + 1));
            }
        } catch (SQLException e) {
            log.error("getColumnTypes failure", e);
        } finally {
            if (pStemt != null) {
                try {
                    pStemt.close();
                    closeConnection();
                } catch (SQLException e) {
                    log.error("getColumnTypes close pstem and connection failure", e);
                }
            }
        }
        return columnTypes;
    }

    /**
     * 获取表中所有字段的注释
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/25 15:02
     */
    public List<String> getColumnComments(String tableName) {
        List<String> columnTypes = new ArrayList<>();
        PreparedStatement pStemt = null;
        String tableSql = SQL + tableName;
        List<String> columnComments = new ArrayList<>();//列名注释集合
        ResultSet rs = null;
        try {
            pStemt = connection.prepareStatement(tableSql);
            rs = pStemt.executeQuery("show full columns from " + tableName);
            while (rs.next()) {
                columnComments.add(rs.getString("Comment"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            if (rs != null) {
                try {
                    rs.close();
                    closeConnection();
                } catch (SQLException e) {
                    log.error("getColumnComments close ResultSet and connection failure", e);
                }
            }
        }
        return columnComments;
    }

    /**
     * 获取当前数据库下的所有表名称
     *
     * @Param: []
     * @Return: java.util.List
     * @Author: tjm
     * @Date: 2024/4/25 15:04
     */
    public List getAllTableName() throws Exception {
        List tables = new ArrayList();
        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery("SHOW TABLES ");
        while (rs.next()) {
            String tableName = rs.getString(1);
            tables.add(tableName);
        }
        rs.close();
        stmt.close();
        closeConnection();
        return tables;
    }

    /**
     * 根据表名获得建表sql语句(批量)
     *
     * @Param: [tableNames]
     * @Return: java.util.Map
     * @Author: tjm
     * @Date: 2024/4/25 15:05
     */
    public Map<String, String> getCreateSqlByTableNameBatch(List<String> tableNames) throws Exception {
        Map<String, String> map = new HashMap<>();
        Statement stmt = connection.createStatement();
        for (int i = 0; i < tableNames.size(); i++) {
            String table = tableNames.get(i);
            ResultSet rs = stmt.executeQuery("SHOW CREATE TABLE " + table);
            if (rs != null && rs.next()) {
                String createDDL = rs.getString(2);
                String comment = parse(createDDL);
                map.put(table, comment);
            }
            rs.close();
        }
        stmt.close();
        closeConnection();
        return map;
    }

    /**
     * 根据表名获得所有字段名及注释
     *
     * @Param: [tableName]
     * @Return: void
     * @Author: tjm
     * @Date: 2024/4/25 15:07
     */
    public Map<String, String> getColumnCommentByTableName(String tableName) throws Exception {
        Map<String, String> map = new HashMap();
        Statement stmt = connection.createStatement();
        ResultSet rs = stmt.executeQuery("show full columns from " + tableName);
        if (rs != null && rs.next()) {
            map.put(rs.getString("Field"), rs.getString("Comment"));
        }
        rs.close();
        stmt.close();
        closeConnection();
        return map;
    }

    /**
     * 返回注释信息
     *
     * @Param: [all]
     * @Return: java.lang.String
     * @Author: tjm
     * @Date: 2024/4/25 15:04
     */
    public static String parse(String all) {
        String comment = null;
        int index = all.indexOf("COMMENT='");
        if (index < 0) {
            return "";
        }
        comment = all.substring(index + 9);
        comment = comment.substring(0, comment.length() - 1);
        return comment;
    }

    /**
     * 关闭连接(注意在finally里面执行以下方法)
     *
     * @Param: []
     * @Return: void
     * @Author: tjm
     * @Date: 2024/4/25 14:54
     */
    public void closeConnection() {
        if (resultset != null) {
            try {
                resultset.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                resultset = null;
            }
        }
        if (pStatement != null) {
            try {
                pStatement.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                pStatement = null;
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                connection = null;
            }
        }
    }

}

mysql库ddl工具类MysqlUtils.class,用于对表格结构的操作;

java 复制代码
package org.sharetek.multids.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.sharetek.multids.domain.AttributeItemEntity;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static org.sharetek.common.core.constant.MultiDbConstants.TABLE_PREFIX;

/**
 * @author junlintianxia
 * @title MysqlUtils
 * @date 2024/4/25 10:54
 * @description mysql 工具类
 */
@Slf4j
@Component
public class MysqlUtils {

    private JdbcTemplate jdbcTemplate;

    public MysqlUtils(@Qualifier("getJdbcTemplateMysql") JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    /**
     * 创建数据库
     *
     * @Param: [dbName]
     * @Return: void
     * @Author: junlintianxia
     * @Date: 2024/4/25 11:12
     */
    public void createDatabase(String dbName) {
        String query = "CREATE DATABASE IF NOT EXISTS " + dbName;
        jdbcTemplate.execute(query);
    }

    /**
     * 删除数据库
     *
     * @Param: [dbName]
     * @Return: void
     * @Author: junlintianxia
     * @Date: 2024/4/25 11:12
     */
    public void dropDatabase(String dbName) {
        String query = "DROP DATABASE IF EXISTS " + dbName;
        jdbcTemplate.execute(query);
    }

    /**
     * 创建表
     *
     * @Param: [id, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:21
     */
    public boolean createTable(String definedName, List<AttributeItemEntity> columns) {
        return doCreateTable(TABLE_PREFIX + definedName, columns);
    }

    /**
     * 批量删除表
     *
     * @Param: [tableNames]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:22
     */
    @Transactional(rollbackFor = Throwable.class)
    public boolean dropTables(List<String> tableNames) {
        return dropTable(tableNames);
    }

    /**
     * 添加字段
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:22
     */
    public boolean addColumns(String tableName, List<AttributeItemEntity> columns) {
        return doAddColumns(tableName, columns);
    }

    /**
     * 修改字段名称
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:23
     */
    public boolean updateColumns(String tableName, List<AttributeItemEntity> columns) {
        return doUpdateColumns(tableName, columns);
    }

    /**
     * 删除字段
     *
     * @Param: [id, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:24
     */
    public boolean dropColumns(Long id, List<AttributeItemEntity> columns) {
        return dropColumns(TABLE_PREFIX + id, columns);
    }

    /**
     * 获取列类型
     *
     * @Param: [type, length]
     * @Return: java.lang.String
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:39
     */
    private String columnType(String type, Integer length) {
        if ("varchar".equalsIgnoreCase(type)) {
            if (ObjectUtil.isEmpty(length) || length == 0) {
                length = 255;
            }
            return type + "(" + length + ")";
        }
        return type;
    }

    /**
     * 创建表(详细)
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:26
     */
    private boolean doCreateTable(String tableName, List<AttributeItemEntity> columns) {
        StringBuffer sb = new StringBuffer();
        sb.append("CREATE TABLE IF NOT EXISTS `" + tableName + "` (\n");
        sb.append("`id` bigint NOT NULL COMMENT '主键',\n");
        columns.forEach(e -> {
            sb.append("`" + e.getName() + "` " + columnType(e.getType(), e.getLength()) + " " + isNullSql(e.getEnableNull()) + " " + isDefaultSql(e.getDefaultValue()) + " COMMENT '" + e.getComment() + "',\n");
            if (e.getIsUnique()) {
                sb.append("UNIQUE KEY " + "uniq_" + e.getName() + " (`" + e.getName() + "`),\n");
            }
        });
        sb.append("`create_time` DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间', \n");
        sb.append("PRIMARY KEY (`id`) \n");
        sb.append(");\n");
        return execute(sb);
    }

    /**
     * 添加字段(详细)
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:33
     */
    private boolean doAddColumns(String tableName, List<AttributeItemEntity> columns) {
        StringBuffer sb = new StringBuffer();
        columns.forEach(e -> {
            sb.append("ALTER TABLE `" + tableName + "`  ADD COLUMN " + e.getName() + " " + columnType(e.getType(), e.getLength()) + " "
                + isNullSql(e.getEnableNull()) + " " + isDefaultSql(e.getDefaultValue()) + " COMMENT '" + e.getComment() + "';\n");
        });
        return execute(sb);
    }

    /**
     * 修改字段(详细),只能改名称
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:34
     */
    private boolean doUpdateColumns(String tableName, List<AttributeItemEntity> columns) {
        StringBuffer sb = new StringBuffer();
        columns.forEach(e -> {
            if (StrUtil.isNotEmpty(e.getNewName()) && !e.getName().equalsIgnoreCase(e.getNewName())) {
                sb.append("ALTER TABLE `" + tableName + "` RENAME COLUMN " + e.getName() + " TO " + e.getNewName() + ";\n");
            }
        });
        return execute(sb);
    }

    /**
     * 删除字段(详细)
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:34
     */
    private boolean dropColumns(String tableName, List<AttributeItemEntity> columns) {
        StringBuffer sb = new StringBuffer();
        columns.forEach(e -> {
            sb.append("ALTER TABLE `" + tableName + "`  DROP COLUMN \"" + e.getName() + "\";\n");
        });
        return execute(sb);
    }

    /**
     * 批量删除表(详细)
     *
     * @Param: [tableNames]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:34
     */
    private boolean dropTable(List<String> tableNames) {
        StringBuffer sb = new StringBuffer();
        tableNames.forEach(tableName -> {
            sb.append("DROP TABLE IF EXISTS `" + tableName + "`;");
        });
        return execute(sb);
    }

    /**
     * 获取所有表名称
     *
     * @Param: []
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:21
     */
    public List<String> tableNames() {
        List<String> tableNames = new ArrayList<>();
        try {
            Connection getConnection = jdbcTemplate.getDataSource().getConnection();
            DatabaseMetaData metaData = getConnection.getMetaData();
            ResultSet rs = metaData.getTables(getConnection.getCatalog(), null, null, new String[]{"TABLE"});
            while (rs.next()) {
                String tableName = rs.getString("TABLE_NAME");
                tableNames.add(tableName);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return tableNames;
    }

    /**
     * 执行sql
     *
     * @Param: [sb]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:35
     */
    private boolean execute(StringBuffer sb) {
        try {
            jdbcTemplate.execute(sb.toString());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 是否可为空
     *
     * @Param: [boo]
     * @Return: java.lang.String
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:35
     */
    private String isNullSql(Boolean boo) {
        if (boo) {
            return "NULL";
        }
        return "NOT NULL";
    }

    /**
     * 是否有默认值
     *
     * @Param: [obj]
     * @Return: java.lang.String
     * @Author: junlintianxia
     * @Date: 2024/4/25 13:35
     */
    private String isDefaultSql(Object obj) {
        if (ObjectUtil.isNotEmpty(obj)) {
            if (obj instanceof String) {
                return "DEFAULT '" + obj + "'";
            }
            return "DEFAULT " + obj;
        }
        return "";
    }

    /**
     * 获取所有表名
     *
     * @Param: []
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/25 11:11
     */
    public List<String> getAllTableNames() {
        String query = "SHOW TABLES;";
        List<String> tableNames = new ArrayList<>();
        jdbcTemplate.query(query, rs -> {
            while (rs.next()) {
                tableNames.add(rs.getString(1));
            }
        });
        return tableNames;
    }

    /**
     * 获取表数据
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.util.Map < java.lang.String, java.lang.Object>>
     * @Author: junlintianxia
     * @Date: 2024/4/25 11:11
     */
    public List<Map<String, Object>> getTableData(String tableName) {
        String query = "SELECT * FROM " + tableName + ";";
        return jdbcTemplate.queryForList(query);
    }


}
复制代码
数据源DML接口IDmlService.class,数据的增删改查,所有数据源通用;
java 复制代码
package org.sharetek.multids.service;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @author tjm
 * @title IDmlService
 * @date 2024/4/29 10:58
 * @description 数据源DML接口
 */
public interface IDmlService {

    /**
     * 对数据库的增/删/改
     *
     * @Param: [sql, params]
     * @Return: boolean
     * @Author: tjm
     * @Date: 2024/4/29 11:16
     */
    public boolean addDeleteModify(String sql, List<Object> params) throws SQLException;

    /**
     * 查询单条记录
     *
     * @Param: [sql, params]
     * @Return: T
     * @Author: tjm
     * @Date: 2024/4/29 11:16
     */
    Map<String, Object> getSimpleResult(String sql, List<Object> params) throws SQLException;

    /**
     * 查询多条记录
     *
     * @Param: [sql, params]
     * @Return: java.util.List<T>
     * @Author: tjm
     * @Date: 2024/4/29 11:17
     */
    public List<Map<String, Object>> getMultipleResult(String sql, List<Object> params) throws SQLException;

    /**
     * 应用反射机制返回单条记录
     *
     * @Param: [sql, params, javabean]
     * @Return: T
     * @Author: tjm
     * @Date: 2024/4/29 11:17
     */
    public <T> T getSimpleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception;

    /**
     * 通过反射机制访问数据库,并返回多条记录
     *
     * @Param: [sql, params, javabean]
     * @Return: java.util.List<T>
     * @Author: tjm
     * @Date: 2024/4/29 11:17
     */
    public <T> List<T> getMultipleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception;

    /**
     * 获取数据库下的所有表名
     *
     * @Param: []
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/29 11:18
     */
    public List<String> getTableNames();

    /**
     * 获取表下的所有列名
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/29 11:18
     */
    public List<String> getColumnNames(String tableName);

    /**
     * 获取表中所有字段类型
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/29 11:19
     */
    public List<String> getColumnTypes(String tableName);

    /**
     * 获取表中所有字段的注释
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/29 11:19
     */
    public List<String> getColumnComments(String tableName);

    /**
     * 根据表名获得建表sql语句(批量)
     *
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: tjm
     * @Date: 2024/4/29 11:19
     */
    public Map<String, String> getCreateSqlByTableNameBatch(List<String> tableNames) throws Exception;

    /**
     * 根据表名获得所有字段名及注释
     *
     * @Param: [tableName]
     * @Return: void
     * @Author: tjm
     * @Date: 2024/4/29 11:29
     */
    public Map<String, String> getColumnCommentByTableName(String tableName) throws Exception;



}

数据源DDL接口IDdlService.class,多数据库表结构的相关操作,所有数据源通用;

java 复制代码
package org.sharetek.multids.service;

import org.sharetek.multids.domain.AttributeItemEntity;

import java.util.List;

/**
 * @author junlintianxia
 * @title IDdlService
 * @date 2024/4/25 15:25
 * @description 数据源DDL接口
 */
public interface IDdlService {

    /**
     * 创建数据库
     *
     * @Param: [dbName]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:21
     */
    public boolean createDatabase(String dbName);

    /**
     * 删除数据库
     *
     * @Param: [dbName]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:21
     */
    public void dropDatabase(String dbName);

    /**
     * 创建表
     *
     * @Param: [definedName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:21
     */
    public boolean createTable(String definedName, List<AttributeItemEntity> columns);

    /**
     * 删除表
     *
     * @Param: [tableNames]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:22
     */
    public boolean dropTables(List<String> tableNames);

    /**
     * 添加列
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:22
     */
    public boolean addColumns(String tableName, List<AttributeItemEntity> columns);

    /**
     * 修改列
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:22
     */
    public boolean updateColumns(String tableName, List<AttributeItemEntity> columns);

}

mysql库ddl操作service层实现类,对表结构的处理;

java 复制代码
package org.sharetek.multids.service.impl.mysql;

import lombok.RequiredArgsConstructor;
import org.sharetek.multids.domain.AttributeItemEntity;
import org.sharetek.multids.service.IDdlService;
import org.sharetek.multids.utils.MysqlUtils;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * @author junlintianxia
 * @title MysqlDdlServiceImpl
 * @date 2024/4/25 15:25
 * @description mysql数据库DDL服务实现类
 */
@Service
@RequiredArgsConstructor
public class MysqlDdlServiceImpl implements IDdlService {

    private final MysqlUtils mysqlUtils;

    @Override
    public boolean createDatabase(String dbName) {
        try {
            mysqlUtils.createDatabase(dbName);
            return true;
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public void dropDatabase(String dbName) {

    }

    /**
     * 创建表
     *
     * @Param: [definedName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/29 17:45
     */
    @Override
    public boolean createTable(String definedName, List<AttributeItemEntity> columns) {
        return mysqlUtils.createTable(definedName, columns);
    }

    /**
     * 删除表
     *
     * @Param: [tableNames]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/29 17:45
     */
    @Override
    public boolean dropTables(List<String> tableNames) {
        return mysqlUtils.dropTables(tableNames);
    }

    /**
     * 添加列
     *
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/29 17:46
     */
    @Override
    public boolean addColumns(String tableName, List<AttributeItemEntity> columns) {
        return mysqlUtils.addColumns(tableName, columns);
    }

    /**
     * 修改列
     *
     * @param tableName
     * @param columns
     * @Param: [tableName, columns]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/28 17:22
     */
    @Override
    public boolean updateColumns(String tableName, List<AttributeItemEntity> columns) {
        return mysqlUtils.updateColumns(tableName, columns);
    }
}

mysql库dml操作service层实现类MysqlDmlServiceImpl.class;

java 复制代码
package org.sharetek.multids.service.impl.mysql;

import lombok.RequiredArgsConstructor;
import org.sharetek.multids.service.IDmlService;
import org.sharetek.multids.utils.MysqlHelper;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @author junlintianxia
 * @title MysqlDmlServiceImpl
 * @date 2024/4/29 11:37
 * @description mysql数据库DML服务实现类
 */
@Service
@RequiredArgsConstructor
public class MysqlDmlServiceImpl implements IDmlService {

    private final MysqlHelper mysqlHelper;

    /**
     * 对数据库的增/删/改
     *
     * @param sql
     * @param params
     * @Param: [sql, params]
     * @Return: boolean
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:16
     */
    @Override
    public boolean addDeleteModify(String sql, List<Object> params) throws SQLException {
        return mysqlHelper.addDeleteModify(sql, params);
    }

    /**
     * 查询单条记录
     *
     * @param sql
     * @param params
     * @Param: [sql, params]
     * @Return: T
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:16
     */
    @Override
    public Map<String, Object> getSimpleResult(String sql, List<Object> params) throws SQLException {
        return mysqlHelper.getSimpleResult(sql, params);
    }

    /**
     * 查询多条记录
     *
     * @param sql
     * @param params
     * @Param: [sql, params]
     * @Return: java.util.List<T>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:17
     */
    @Override
    public List<Map<String, Object>> getMultipleResult(String sql, List<Object> params) throws SQLException {
        return mysqlHelper.getMultipleResult(sql, params);
    }

    /**
     * 应用反射机制返回单条记录
     *
     * @param sql
     * @param params
     * @param javabean
     * @Param: [sql, params, javabean]
     * @Return: T
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:17
     */
    @Override
    public <T> T getSimpleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception {
        return mysqlHelper.getSimpleResult_Ref(sql, params, javabean);
    }

    /**
     * 通过反射机制访问数据库,并返回多条记录
     *
     * @param sql
     * @param params
     * @param javabean
     * @Param: [sql, params, javabean]
     * @Return: java.util.List<T>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:17
     */
    @Override
    public <T> List<T> getMultipleResult_Ref(String sql, List<Object> params, Class<T> javabean) throws Exception {
        return mysqlHelper.getMultipleResult_Ref(sql, params, javabean);
    }

    /**
     * 获取数据库下的所有表名
     *
     * @Param: []
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:18
     */
    @Override
    public List<String> getTableNames() {
        return mysqlHelper.getTableNames();
    }

    /**
     * 获取表下的所有列名
     *
     * @param tableName
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:18
     */
    @Override
    public List<String> getColumnNames(String tableName) {
        return mysqlHelper.getColumnNames(tableName);
    }

    /**
     * 获取表中所有字段类型
     *
     * @param tableName
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:19
     */
    @Override
    public List<String> getColumnTypes(String tableName) {
        return mysqlHelper.getColumnTypes(tableName);
    }

    /**
     * 获取表中所有字段的注释
     *
     * @param tableName
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:19
     */
    @Override
    public List<String> getColumnComments(String tableName) {
        return mysqlHelper.getColumnComments(tableName);
    }

    /**
     * 根据表名获得建表sql语句(批量)
     *
     * @param tableNames
     * @Param: [tableName]
     * @Return: java.util.List<java.lang.String>
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:19
     */
    @Override
    public Map<String, String> getCreateSqlByTableNameBatch(List<String> tableNames) throws Exception {
        return mysqlHelper.getCreateSqlByTableNameBatch(tableNames);
    }

    /**
     * 根据表名获得所有字段名及注释
     *
     * @param tableName
     * @Param: [tableName]
     * @Return: void
     * @Author: junlintianxia
     * @Date: 2024/4/29 11:29
     */
    @Override
    public Map<String, String> getColumnCommentByTableName(String tableName) throws Exception {
        return mysqlHelper.getColumnCommentByTableName(tableName);
    }

}
java 复制代码
package org.sharetek.multids.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author junlintianxia
 * @title AttributeItemEntity
 * @date 2024/4/25 11:48
 * @description 数据库表的field实体
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AttributeItemEntity {

    public AttributeItemEntity(String name, String type, String comment, Integer length, Boolean enableNull, Boolean isUnique) {
        this.name = name;
        this.type = type;
        this.comment = comment;
        this.length = length;
        this.enableNull = enableNull;
        this.isUnique = isUnique;
    }

    // 当前名称
    private String name;

    // 新名称
    private String newName;

    // 类型
    private String type;

    // 注释
    private String comment;

    // 默认值
    private String defaultValue = "";

    // 长度
    private Integer length = 32;

    // 是否允许为空
    private Boolean enableNull = true;

    // 别名
    private String alias;

    // 是否唯一
    private Boolean isUnique = false;

}

用户操作入口DDLController.class,表结构相关操作,

java 复制代码
package org.sharetek.multids.controller;

import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotEmpty;
import org.sharetek.common.log.annotation.Log;
import org.sharetek.common.log.enums.BusinessType;
import org.sharetek.multids.domain.AttributeItemEntity;
import org.sharetek.multids.service.IDdlService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.List;


/**
 * ddl控制器
 *
 * @Param:
 * @Return:
 * @Author: junlintianxia
 * @Date: 2024/4/25 15:42
 */
@Validated
@RestController
@RequestMapping("/ddl")
public class DDLController {

    @Resource(name = "mysqlDdlServiceImpl")
    private IDdlService ddlService;

    /**
     * 新建数据库
     */
    @Log(title = "新建数据库", businessType = BusinessType.INSERT)
    @PostMapping(value = "/addDB")
    public boolean addDB(String dbName) {
        return ddlService.createDatabase(dbName);
    }

    /**
     * 新建表
     */
    @Log(title = "新建表", businessType = BusinessType.INSERT)
    @PostMapping(value = "/addTable")
//    public boolean addTable(String tableName, List<AttributeItemEntity> columns) {
    public boolean addTable() {
        String definedName = "student2";
        List<AttributeItemEntity> columns = new ArrayList<>();

        AttributeItemEntity column = new AttributeItemEntity();
        column.setName("stuNo");
        column.setType("VARCHAR");
        column.setLength(11);
        column.setDefaultValue("");
        column.setEnableNull(true);
        column.setComment("学号");
        columns.add(column);

        return ddlService.createTable(definedName, columns);
    }

    /**
     * 删除表(批量)
     */
    @Log(title = "删除表", businessType = BusinessType.DELETE)
    @DeleteMapping("/delTables/{tableNames}")
    public boolean delTables(@NotEmpty(message = "表名称不能为空")
                          @PathVariable String[] tableNames) {
        return ddlService.dropTables(List.of(tableNames));
    }

    /**
     * 添加列(批量)
     */
    @Log(title = "添加列", businessType = BusinessType.INSERT)
    @PostMapping("/addColumns/{tableName}")
//    public boolean addColumns(@PathVariable String tableName, @RequestBody List<AttributeItemEntity> columns) {
    public boolean addColumns() {
        String tableName = "table_student";
        List<AttributeItemEntity> columns = new ArrayList<>();
        columns.add(new AttributeItemEntity("stuName", "VARCHAR", "姓名", 32, true, false));

        return ddlService.addColumns(tableName, columns);
    }

    /**
     * 修改列名
     */
    @Log(title = "修改列名", businessType = BusinessType.UPDATE)
    @PutMapping("/updateColumns/{tableName}")
//    public boolean updateColumns(@PathVariable String tableName, @RequestBody List<AttributeItemEntity> columns) {
    public boolean updateColumns() {
        String tableName = "table_student";
        List<AttributeItemEntity> columns = new ArrayList<>();
        AttributeItemEntity column = new AttributeItemEntity();
        column.setName("stuName");
        column.setNewName("stuName2");
        columns.add(column);

        return ddlService.updateColumns(tableName, columns);
    }


}

用户crud操作控制器入口,DMLController.class,所有数据源通用;

java 复制代码
package org.sharetek.multids.controller;

import cn.hutool.core.date.DateTime;
import jakarta.annotation.Resource;
import org.sharetek.common.log.annotation.Log;
import org.sharetek.common.log.enums.BusinessType;
import org.sharetek.multids.service.IDmlService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * @author junlintianxia
 * @title DMLController
 * @date 2024/4/29 10:54
 * @description dml控制器
 */
@Validated
@RestController
@RequestMapping("/dml")
public class DMLController {

    @Resource(name = "mysqlDmlServiceImpl")
    private IDmlService dmlService;

    /**
     * 对数据库的增/删/改
     */
    @Log(title = "对数据库的增/删/改", businessType = BusinessType.OTHER)
    @PostMapping(value = "/addDeleteModify")
//    public boolean addDeleteModify(String sql, List<Object> params) throws SQLException {
    public boolean addDeleteModify() throws SQLException {
        // test
        String sql = "insert into table_student(id,stuNo,addr,create_time) values(?,?,?,?)";
        List<Object> params = List.of(1, "no001", "xi'an", new DateTime());
        return dmlService.addDeleteModify(sql, params);
    }

    /**
     * 查询单条记录
     */
    @Log(title = "查询单条记录", businessType = BusinessType.QUERY)
    @GetMapping(value = "/getSimpleResult")
//    public Map<String, Object> getSimpleResult(String sql, List<Object> params) throws SQLException {
    public Map<String, Object> getSimpleResult() throws SQLException {
        // test 查询
        String sql = "select * from table_student where id = ?";
        List<Object> params = List.of(1L);
        return dmlService.getSimpleResult(sql, params);
    }

    /**
     * 查询多条记录
     */
    @Log(title = "查询多条记录", businessType = BusinessType.QUERY)
    @GetMapping(value = "/getMultipleResult")
//    public List<Map<String, Object>> getMultipleResult(String sql, List<Object> params) throws SQLException {
    public List<Map<String, Object>> getMultipleResult() throws SQLException {
        // test 查询
        String sql = "select * from table_student where addr = ?";
        List<Object> params = List.of("xi'an");
        return dmlService.getMultipleResult(sql, params);
    }





}

2.2.微服务方案,数据库配置信息通过nacos读取

pom.xml补充如下,

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.sharetek</groupId>
        <artifactId>sharetek-visual</artifactId>
        <version>${revision}</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>sharetek-multi-datasource</artifactId>

    <description>
        sharetek-multi-datasource 多数据源管理
    </description>

    <dependencies>
        <!-- SpringCloud Alibaba Nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!-- SpringCloud Alibaba Nacos Config -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.sharetek</groupId>
            <artifactId>sharetek-common-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>

        <!-- 数据库连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.16</version>
        </dependency>

        <!-- sharetek Common Log -->
        <dependency>
            <groupId>org.sharetek</groupId>
            <artifactId>sharetek-common-log</artifactId>
        </dependency>

        <!-- Mysql Connector -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <!-- Oracle -->
        <dependency>
            <groupId>com.oracle.database.jdbc</groupId>
            <artifactId>ojdbc8</artifactId>
        </dependency>
        <!-- PostgreSql -->
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
        </dependency>
        <!-- SqlServer -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

</project>

在application.yml中注释掉数据库配置信息,

XML 复制代码
# Tomcat
server:
  port: 9305

# Spring
spring:
  application:
    # 应用名称
    name: sharetek-multi-datasource
  profiles:
    # 环境配置
    active: @profiles.active@

--- # nacos 配置
spring:
  cloud:
    nacos:
      # nacos 服务地址
      server-addr: @nacos.server@
      discovery:
        # 注册组
        group: @nacos.discovery.group@
        namespace: ${spring.profiles.active}
        cluster-name: xa
      config:
        # 配置组
        group: @nacos.config.group@
        namespace: ${spring.profiles.active}
  config:
    import:
      - optional:nacos:application-common.yml
      - optional:nacos:datasource.yml
      - optional:nacos:${spring.application.name}.yml

#  datasource:
#    type: com.zaxxer.hikari.HikariDataSource
#    # 数据源
#    mysql:
#      type: ${spring.datasource.type}
#      driver-class-name: com.mysql.cj.jdbc.Driver
#      jdbc-url: jdbc:mysql://localhost:3306/sharetek-demodb?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
#      username: xxx
#      password: xxx
#    oracle:
#      type: ${spring.datasource.type}
#      driverClassName: oracle.jdbc.OracleDriver
#      url: jdbc:oracle:thin:@//localhost:1521/XE
#      username: xxx
#      password: xxx
#      hikari:
#        connectionTestQuery: SELECT 1 FROM DUAL
#    postgres:
#      type: ${spring.datasource.type}
#      driverClassName: org.postgresql.Driver
#      url: ${datasource.system-postgres.url}
#      username: ${datasource.system-postgres.username}
#      password: ${datasource.system-postgres.password}

如果启动项目时,提示NullPointException,如下,

解决方法如下,

3.测试效果

相关推荐
Leon-Ning Liu6 小时前
Oracle数据库常用视图:dba_datapump_jobs
数据库·oracle·dba
数据库生产实战6 小时前
Oracle 19C RAC下TRUNCATE TABLE的REUSE STORAGE选项作用和风险浅析!
数据库·oracle
小猪咪piggy7 小时前
【微服务】(4) 负载均衡
微服务·云原生·架构
小白银子7 小时前
零基础从头教学Linux(Day 60)
linux·数据库·mysql·oracle
瀚高PG实验室7 小时前
数据库安全配置指导
服务器·数据库·瀚高数据库
憋问我,我也不会7 小时前
MYSQL 命令
数据库·mysql
24K老游8 小时前
postgres15 flink cdc同步测试
数据库
无泡汽水9 小时前
MySQL入门练习50题
数据库·mysql
JIngJaneIL9 小时前
助农惠农服务平台|助农服务系统|基于SprinBoot+vue的助农服务系统(源码+数据库+文档)
java·前端·数据库·vue.js·论文·毕设·助农惠农服务平台
云外天ノ☼9 小时前
待办事项全栈实现:Vue3 + Node.js (Koa) + MySQL深度整合,构建生产级任务管理系统的技术实践
前端·数据库·vue.js·mysql·vue3·koa·jwt认证