Java: OracleHelper

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述: https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html ojdbc11
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 14:25
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracledemo
 * File      : DuOracleHelper.java
 * explain   : 学习  类
 **/

package Geovin.UtilitieDB;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.sql.Driver.*;
import java.util.HashMap;
import java.util.Map;
import java.sql.Connection;
import java.sql.DriverManager;

/**
 *geovindu,Geovin Du
 */
public class DuOracleHelper {

    /**
     * 命令类型枚举
     */
    public enum CommandType {
        TEXT, STORE_PROCEDURE
    }

    /**
     * 参数方向枚举
     */
    public enum ParameterDirection {
        IN, OUT
    }

    /**
     * 数据库参数类
     */
    public static class Parameter {
        public String name; // 注意:这个字段在简单查询中可能不需要,但保留用于存储过程
        public Object value;
        public ParameterDirection direction;
        public int type;

        /**
         * 新增三参数构造函数(用于简单查询)
         * @param value
         * @param direction
         * @param type
         */
        public Parameter(Object value, ParameterDirection direction, int type) {
            this.name = null; // 简单查询不需要参数名
            this.value = value;
            this.direction = direction;
            this.type = type;
        }

        /**
         * 保留原有的四参数构造函数(用于存储过程)
         * @param name
         * @param value
         * @param direction
         * @param type
         */
        public Parameter(String name, Object value, ParameterDirection direction, int type) {
            this.name = name;
            this.value = value;
            this.direction = direction;
            this.type = type;
        }
    }

    /**
     * 数据列类
     */
    public static class DataColumn {
        public String columnName;
        public Object value;

        public DataColumn(String columnName, Object value) {
            this.columnName = columnName;
            this.value = value;
        }

        @Override
        public String toString() {
            return "\"" + columnName + "\": " + (value == null ? "null" : "\"" + value.toString() + "\"");
        }
    }

    /**
     * 数据行类
     */
    public static class DataRow {
        private List<DataColumn> columns = new ArrayList<>();

        public void addColumn(DataColumn column) {
            columns.add(column);
        }

        public DataColumn getColumn(String columnName) {
            for (DataColumn column : columns) {
                if (column.columnName.equalsIgnoreCase(columnName)) {
                    return column;
                }
            }
            return null;
        }

        public List<DataColumn> getColumns() {
            return columns;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("{");
            for (int i = 0; i < columns.size(); i++) {
                sb.append(columns.get(i).toString());
                if (i < columns.size() - 1) {
                    sb.append(", ");
                }
            }
            sb.append("}");
            return sb.toString();
        }
    }

    /**
     * 数据表类
     */
    public static class DataTable {
        private List<DataRow> rows = new ArrayList<>();

        public void addRow(DataRow row) {
            rows.add(row);
        }

        public List<DataRow> getRows() {
            return rows;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < rows.size(); i++) {
                sb.append(rows.get(i).toString());
                if (i < rows.size() - 1) {
                    sb.append(",\n");
                }
            }
            sb.append("]");
            return sb.toString();
        }
    }

    /**
     * 数据集类
     */
    public static class DataSet {
        private List<DataTable> tables = new ArrayList<>();

        public void addTable(DataTable table) {
            tables.add(table);
        }

        public List<DataTable> getTables() {
            return tables;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder("{");
            for (int i = 0; i < tables.size(); i++) {
                sb.append("\"table").append(i).append("\": ").append(tables.get(i).toString());
                if (i < tables.size() - 1) {
                    sb.append(",\n");
                }
            }
            sb.append("}");
            return sb.toString();
        }
    }

    /**
     * 从JSON配置文件读取数据库连接信息
     * @param configFilePath 配置文件路径
     * @return 包含数据库连接信息的Map
     * @throws IOException 如果读取文件或解析JSON出错
     */
    public static Map<String, String> getConnectionInfo(String configFilePath) throws IOException {
        StringBuilder content = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new FileReader(configFilePath))) {
            String line;
            while ((line = reader.readLine()) != null) {
                content.append(line);
            }
        }

        // 解析JSON配置
        Map<String, String> config = new HashMap<>();

        // 简单解析,忽略JSON格式的复杂性
        String[] pairs = content.toString().replaceAll("[{}\"]", "").split(",");
        for (String pair : pairs) {
            String[] keyValue = pair.split(":");
            if (keyValue.length == 2) {
                config.put(keyValue[0].trim(), keyValue[1].trim());
            }
        }

        // 验证必要的配置项
        if (!config.containsKey("host") ||
                !config.containsKey("port") ||
                !config.containsKey("serviceName") ||
                !config.containsKey("user") ||
                !config.containsKey("password")) {
            throw new IOException("配置文件缺少必要的连接参数");
        }

        return config;
    }

    /**
     * 创建Oracle数据库连接
     * @param configFilePath 配置文件路径
     * @return Connection对象
     * @throws SQLException 如果连接数据库失败
     * @throws IOException 如果读取配置文件失败
     */
    public static Connection getConnection(String configFilePath) throws SQLException, IOException {
        Map<String, String> config = getConnectionInfo(configFilePath);

        try {
            // 加载Oracle驱动
            Class.forName("oracle.jdbc.OracleDriver");
        } catch (ClassNotFoundException e) {
            throw new SQLException("找不到Oracle JDBC驱动", e);
        }

        // 构建Oracle连接字符串
        String host = config.get("host");
        String port = config.get("port");
        String serviceName = config.get("serviceName");
        String user = config.get("user");
        String password = config.get("password");
        if (host == null || port == null || serviceName == null || user == null || password == null) {
            throw new IOException("配置文件缺少必要的连接参数");
        }
        // 构建连接URL  jdbc:oracle:thin:@//localhost:1521/TechnologyGame
        String url = String.format("jdbc:oracle:thin:@//%s:%s/%s",
                config.get("host"),
                config.get("port"),
                config.get("serviceName"));

        // 创建连接
        return DriverManager.getConnection(url, config.get("user"), config.get("password"));
    }

    /**
     * 执行查询并返回DataSet
     * @param configFilePath
     * @param commandType
     * @param commandText
     * @return
     * @throws Exception
     */
    public static DataSet executeDataSet(String configFilePath, CommandType commandType, String commandText) throws Exception {
        return executeDataSet(configFilePath, commandType, commandText, new Parameter[0]);
    }

    /**
     * 执行查询并返回DataSet,带参数
     * @param configFilePath
     * @param commandType
     * @param commandText
     * @param parameters
     * @return
     * @throws Exception
     */

    public static DataSet executeDataSet(String configFilePath, CommandType commandType, String commandText, Parameter... parameters) throws Exception {
        try (Connection conn = getConnection(configFilePath)) {
            return executeDataSet(conn, commandType, commandText, parameters);
        }
    }

    /**
     * 执行查询并返回DataSet
     * @param connection
     * @param commandType
     * @param commandText
     * @return
     * @throws Exception
     */
    public static DataSet executeDataSet(Connection connection, CommandType commandType, String commandText) throws Exception {
        return executeDataSet(connection, commandType, commandText, new Parameter[0]);
    }

    /**
     *  * 执行查询并返回DataSet,带参数
     * @param connection
     * @param commandType
     * @param commandText
     * @param parameters
     * @return
     * @throws Exception
     */
    public static DataSet executeDataSet(Connection connection, CommandType commandType, String commandText, Parameter... parameters) throws Exception {
        DataSet ds = new DataSet();
        System.out.println("开始执行查询: " + commandText);

        if (commandType == CommandType.TEXT) {
            try (PreparedStatement pstmt = connection.prepareStatement(commandText)) {
                // 设置参数
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    if (p.direction == ParameterDirection.IN) {
                        System.out.println("设置输入参数 " + (i + 1) + ": " + p.name + " = " + p.value);
                        pstmt.setObject(i + 1, p.value, p.type);
                    }
                }

                // 执行查询
                try (ResultSet rs = pstmt.executeQuery()) {
                    System.out.println("执行SQL查询成功,开始处理结果集");
                    DataTable dt = convertResultSetToDataTable(rs);
                    System.out.println("结果集转换为DataTable,包含 " + dt.getRows().size() + " 行");
                    ds.addTable(dt);
                }
            }
        } else if (commandType == CommandType.STORE_PROCEDURE) {
            StringBuilder paramPlaceholders = new StringBuilder();
            for (int i = 0; i < parameters.length; i++) {
                paramPlaceholders.append("?, ");
            }
            if (paramPlaceholders.length() > 0) {
                paramPlaceholders = new StringBuilder(" ( " + paramPlaceholders.substring(0, paramPlaceholders.length() - 2) + " ) ");
            }

            String sql = "{ call " + commandText + paramPlaceholders + " }";
            System.out.println("准备调用存储过程: " + sql);

            try (CallableStatement proc = connection.prepareCall(sql)) {
                // 设置参数
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    System.out.println("设置参数 " + (i + 1) + ": " + p.name + " (方向: " + p.direction + ", 类型: " + p.type + ")");

                    if (p.direction == ParameterDirection.IN) {
                        proc.setObject(i + 1, p.value, p.type);
                    } else if (p.direction == ParameterDirection.OUT) {
                        proc.registerOutParameter(i + 1, p.type);
                    }
                }

                // 执行存储过程
                System.out.println("开始执行存储过程...");
                boolean hasResultSet = proc.execute();
                System.out.println("存储过程执行完成,是否有结果集: " + hasResultSet);

                // 处理所有结果集
                int resultSetCount = 0;
                while (hasResultSet) {
                    try (ResultSet rs = proc.getResultSet()) {
                        System.out.println("处理结果集 #" + (resultSetCount + 1));
                        if (rs != null) {
                            DataTable dt = convertResultSetToDataTable(rs);
                            System.out.println("结果集 #" + (resultSetCount + 1) + " 包含 " + dt.getRows().size() + " 行");
                            ds.addTable(dt);
                            resultSetCount++;
                        } else {
                            System.out.println("结果集 #" + (resultSetCount + 1) + " 为空");
                        }
                    }
                    hasResultSet = proc.getMoreResults();
                    System.out.println("是否还有更多结果集: " + hasResultSet);
                }

                // 处理输出参数
                System.out.println("开始处理输出参数...");
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    if (p.direction == ParameterDirection.OUT) {
                        p.value = proc.getObject(i + 1);
                        System.out.println("输出参数 " + (i + 1) + " (" + p.name + ") 的值: " + p.value);

                        // 特殊处理 Oracle 游标
                        if (p.type == oracle.jdbc.OracleTypes.CURSOR) {
                            System.out.println("检测到游标参数,尝试获取结果集...");

                            // 使用 Oracle 特定的 API 获取游标
                            oracle.jdbc.OracleCallableStatement oracleProc = (oracle.jdbc.OracleCallableStatement) proc;
                            ResultSet rs = oracleProc.getCursor(i + 1);

                            if (rs != null) {
                                System.out.println("成功获取游标结果集,开始转换...");
                                DataTable dt = convertResultSetToDataTable(rs);
                                System.out.println("游标结果集包含 " + dt.getRows().size() + " 行");
                                ds.addTable(dt);
                                // 关闭结果集
                                rs.close();
                            } else {
                                System.out.println("游标结果集为空");
                            }
                        }
                    }
                }

                System.out.println("处理了 " + resultSetCount + " 个结果集和 " + parameters.length + " 个输出参数");
            }
        } else {
            throw new IllegalArgumentException("不支持的命令类型: " + commandType);
        }

        System.out.println("DataSet 包含 " + ds.getTables().size() + " 个表,总共 " +
                ds.getTables().stream().mapToInt(t -> t.getRows().size()).sum() + " 行数据");

        // 打印详细数据结构(调试用)
        if (ds.getTables().size() > 0) {
            System.out.println("第一个表的结构: " + ds.getTables().get(0));
        }

        return ds;
    }

    /**
     * 执行非查询命令
     * @param configFilePath
     * @param commandType
     * @param commandText
     * @throws Exception
     */
    public static void executeNonQuery(String configFilePath, CommandType commandType, String commandText) throws Exception {
        executeNonQuery(configFilePath, commandType, commandText, new Parameter[0]);
    }

    /**
     * 执行非查询命令,带参数
     * @param configFilePath
     * @param commandType
     * @param commandText
     * @param parameters
     * @throws Exception
     */
    public static void executeNonQuery(String configFilePath, CommandType commandType, String commandText, Parameter... parameters) throws Exception {
        try (Connection conn = getConnection(configFilePath)) {
            executeNonQuery(conn, commandType, commandText, parameters);
        }
    }

    /**
     * 执行非查询命令
     * @param connection
     * @param commandType
     * @param commandText
     * @throws Exception
     */
    public static void executeNonQuery(Connection connection, CommandType commandType, String commandText) throws Exception {
        executeNonQuery(connection, commandType, commandText, new Parameter[0]);
    }

    /**
     * 执行非查询命令,带参数
     * @param connection
     * @param commandType
     * @param commandText
     * @param parameters
     * @throws Exception
     */
    public static void executeNonQuery(Connection connection, CommandType commandType, String commandText, Parameter... parameters) throws Exception {
        if (commandType == CommandType.TEXT) {
            try (PreparedStatement pstmt = connection.prepareStatement(commandText)) {
                // 设置参数
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    if (p.direction == ParameterDirection.IN) {
                        pstmt.setObject(i + 1, p.value, p.type);
                    }
                }

                // 执行更新
                pstmt.executeUpdate();
            }
        } else if (commandType == CommandType.STORE_PROCEDURE) {
            StringBuilder paramPlaceholders = new StringBuilder();
            for (int i = 0; i < parameters.length; i++) {
                paramPlaceholders.append("?, ");
            }
            if (paramPlaceholders.length() > 0) {
                paramPlaceholders = new StringBuilder(" ( " + paramPlaceholders.substring(0, paramPlaceholders.length() - 2) + " ) ");
            }

            String sql = "{ call " + commandText + paramPlaceholders + " }";

            try (CallableStatement proc = connection.prepareCall(sql)) {
                // 设置参数
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    if (p.direction == ParameterDirection.IN) {
                        proc.setObject(i + 1, p.value, p.type);
                    } else if (p.direction == ParameterDirection.OUT) {
                        proc.registerOutParameter(i + 1, p.type);
                    }
                }

                // 执行存储过程
                proc.execute();

                // 处理输出参数
                for (int i = 0; i < parameters.length; i++) {
                    Parameter p = parameters[i];
                    if (p.direction == ParameterDirection.OUT) {
                        p.value = proc.getObject(i + 1);
                    }
                }
            }
        } else {
            throw new IllegalArgumentException("不支持的命令类型: " + commandType);
        }
    }

    /**
     * 将ResultSet转换为DataTable
     * @param rs
     * @return
     * @throws Exception
     */
    private static DataTable convertResultSetToDataTable(ResultSet rs) throws Exception {
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();

        DataTable dt = new DataTable();
        while (rs.next()) {
            DataRow dr = new DataRow();
            for (int i = 1; i <= columnCount; i++) {
                DataColumn dc = new DataColumn(rsmd.getColumnName(i), rs.getObject(i));
                dr.addColumn(dc);
            }
            dt.addRow(dr);
        }
        return dt;
    }
}
java 复制代码
/**
     *
     * @param schoolId
     * @return DataSet
     */
    @Override
    public DuOracleHelper.DataSet getSchoolByDataSet(String schoolId) {

        String sql = "SELECT * FROM School WHERE SchoolId = ?";
        try {

            // 示例1:执行SQL查询
            DuOracleHelper.DataSet resultSet = DuOracleHelper.executeDataSet(
                    "oraclecon.json",
                    DuOracleHelper.CommandType.TEXT,
                    sql,
                    new DuOracleHelper.Parameter(schoolId, DuOracleHelper.ParameterDirection.IN, Types.VARCHAR)
            );
            return resultSet;
        }
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

调用:

java 复制代码
 DuOracleHelper.DataSet resultSet =schoolBLL.getSchoolByDataSet("U0040");
                System.out.println(resultSet.toString());

项目结构:

相关推荐
追风少年浪子彦9 分钟前
mapstruct与lombok冲突原因及解决方案
java·spring boot·spring·spring cloud
why技术19 分钟前
也是出息了,业务代码里面也用上算法了。
java·后端·算法
她说人狗殊途29 分钟前
java.net.InetAddress
java·开发语言
天使day32 分钟前
Cursor的使用
java·开发语言·ai
咖啡进修指南41 分钟前
代理模式——Java
java·代理模式
Dxy12393102161 小时前
Python ExcelWriter详解:从基础到高级的完整指南
开发语言·python
JouJz2 小时前
设计模式之工厂模式:对象创建的智慧之道
java·jvm·设计模式
MZ_ZXD0012 小时前
flask校园学科竞赛管理系统-计算机毕业设计源码12876
java·spring boot·python·spring·django·flask·php
菜鸟特工0073 小时前
Oracle 数据库 Dblink
数据库·oracle