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.测试效果

相关推荐
两点王爷1 小时前
Java读取csv文件内容,保存到sqlite数据库中
java·数据库·sqlite·csv
凡人的AI工具箱2 小时前
每天40分玩转Django:Django部署概述
开发语言·数据库·后端·python·django
2401_871213303 小时前
mysql之MHA
数据库·mysql
言之。3 小时前
【MySQL】事务
数据库·mysql
潇湘秦3 小时前
Oracle 11G还有新BUG?ORACLE 表空间迷案!
数据库·oracle
凡人的AI工具箱4 小时前
每天40分玩转Django:Django Email
数据库·人工智能·后端·python·django·sqlite
后端转全栈_小伵4 小时前
SQLite本地数据库的简介和适用场景——集成SpringBoot的图文说明
数据库·spring boot·后端·sqlite·学习方法
dbcat官方4 小时前
2.微服务灰度发布落地实践(agent实现)
微服务·云原生·架构
dengjiayue5 小时前
MySQL 性能瓶颈,为什么 MySQL 表的数据量不能太大?
数据库·mysql
m0_748232395 小时前
python3 Flask应用 使用 Flask-SQLAlchemy操作MySQL数据库
数据库·mysql·flask