C#/C++ 透過ODBC連線OceanBase Oracle租戶

咸鱼翻身?發表於2024-05-07

概述

近期我們專案正處於將Oracle資料庫遷移到OceanBase Oracle租戶模式的階段。考慮到我們專案採用了C++和C#混合開發,並且使用了多種技術,因此存在多種資料庫連線方式。然而,針對C#連線OceanBase的案例相對較少,因此我特意記錄下這一過程。

開放資料庫互連(ODBC)是微軟公司開放服務結構(WOSA,Windows Open Services Architecture)中有關資料庫的一個組成部分,基本思想是為使用者提供簡單、標準、透明的資料庫連線的公共程式設計介面,開發廠商根據 ODBC 的標準去實現底層的驅動程式,這個驅動對使用者是透明的,並允許根據不同的 DBMS 採用不同的技術加以最佳化實現。

驅動下載

下載地址:https://www.oceanbase.com/softwarecenter-cloud

根據平臺型別選擇驅動。

驅動配置

開啟 ODBC 資料來源管理員:在 Windows 中,按下 Windows鍵 + R 開啟“執行”對話方塊,然後輸入 odbcad32 並按下 Enter 鍵,這將開啟 ODBC 資料來源管理員。

選擇系統的或使用者的資料來源:在 ODBC 資料來源管理員中,有兩個選項卡:使用者 DSN 和 系統 DSN。選擇一個適合你的選項,通常建議選擇 系統 DSN,因為它對所有使用者都可用。

新增一個新的資料來源:點選 新增 按鈕,然後在彈出的對話方塊中選擇 OceanBase ODBC 2.0 Driver 資料庫。

配置資料來源連線資訊:在配置 OceanBase 資料庫資料來源時,你需要提供以下資訊:

資料來源名稱(DSN):為你的資料來源指定一個唯一的名稱。這裡命名為OceanBase ODBC

描述:提供有關此資料來源的描述,以便識別它。

TNS 服務名稱:輸入你要連線的 Oracle 服務的 TNS 服務名稱。IP: XX.XX.XX.XX

使用者名稱和密碼:提供用於連線到 Oracle 資料庫的使用者名稱和密碼。

UserName: 使用者名稱@租戶名#叢集

測試連線:在完成配置後,你可以點選 測試連線 按鈕來驗證是否能夠成功連線到 OceanBase Oracle 資料庫。

注意:不透過DSN也可以連線

C++ 程式碼案例

#include <stdio.h>
#include <assert.h>
#include <windows.h>
#include <sql.h>
#include <sqlext.h>
#include <iostream>

void print_error(SQLSMALLINT HandleType, SQLHANDLE Handle) {
    SQLWCHAR SQLState[6];
    SQLINTEGER NativeError;
    SQLWCHAR SQLMessage[SQL_MAX_MESSAGE_LENGTH] = { 0 };
    SQLSMALLINT TextLengthPtr;

    SQLGetDiagRec(HandleType, Handle, 1, SQLState, &NativeError, SQLMessage, SQL_MAX_MESSAGE_LENGTH, &TextLengthPtr);
    std::wcerr << L"[" << SQLState << L"] (" << NativeError << L") " << SQLMessage << std::endl;
}

int main() {
    // Allocate environment handle
    SQLHANDLE henv;
    SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv);
    SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0);

    // Allocate connection handle
    SQLHANDLE hdbc;
    SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc);

    // Connection string

    //使用DSN
    SQLWCHAR* connectionString = (SQLWCHAR*)L"DSN=OceanBase ODBC;UID=使用者名稱@住戶名#叢集;PWD=密碼";

    //不使用DSN
    //SQLWCHAR* connectionString = (SQLWCHAR*)L"Driver={OceanBase ODBC 2.0 Driver};Server=xx.xx.xx.xx;Port=2883;Database=使用者名稱;User=使用者名稱@住戶名#叢集;Password=密碼;Option=3;";

    // Connect to the database
    SQLRETURN retcode = SQLDriverConnect(hdbc, NULL, connectionString, SQL_NTS, NULL, 0, NULL, SQL_DRIVER_NOPROMPT);
    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) {
        std::cerr << "Error connecting to database:" << std::endl;
        print_error(SQL_HANDLE_DBC, hdbc);
        return 1;
    }

    std::cout << "Connected to database successfully!" << std::endl;

    // Allocate statement handle
    SQLHANDLE hstmt;
    SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt);

    // Execute a query
    SQLWCHAR* query = (SQLWCHAR*)L"SELECT * FROM TIERS WHERE ROWNUM <= 1;";
    retcode = SQLExecDirect(hstmt, query, SQL_NTS);
    if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO) {
        std::cerr << "Error executing query:" << std::endl;
        print_error(SQL_HANDLE_STMT, hstmt);
        SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
        SQLDisconnect(hdbc);
        SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
        SQLFreeHandle(SQL_HANDLE_ENV, henv);
        return 1;
    }

    // Fetch and print results
    SQLCHAR name[256];
    SQLLEN nameLen;
    while (SQLFetch(hstmt) == SQL_SUCCESS) {
        SQLGetData(hstmt, 1, SQL_C_CHAR, name, sizeof(name), &nameLen);
        std::cout << "Name: " << name << std::endl;
    }

    // Cleanup
    SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    SQLDisconnect(hdbc);
    SQLFreeHandle(SQL_HANDLE_DBC, hdbc);
    SQLFreeHandle(SQL_HANDLE_ENV, henv);

    return 0;
}

C# 程式碼案例

using System;
using System.Data.Odbc;

namespace ConsoleApp
{
    internal class Program
    {
        static void Main(string[] args)
        {
            //使用DSN
            string connectionString = "DSN=OceanBase ODBC;Uid=使用者名稱@住戶名#叢集;Pwd=你的密碼;";


            //不使用DSN
            //string connectionString = "Driver={OceanBase ODBC 2.0 Driver};Server=xx.xx.xx.xx;Port=2883;Database=使用者名稱;User=使用者名稱@住戶名#叢集;;Password=密碼;Option=3;";
            using (OdbcConnection connection = new OdbcConnection(connectionString))
            {
                try
                {
                    connection.Open();
                    Console.WriteLine("Connected to Oracle database!");

                    // Perform database operations here

                    string query = "SELECT *FROM TIERS WHERE ROWNUM <= 1;";
                    using (OdbcCommand command = new OdbcCommand(query, connection))
                    {
                        using (OdbcDataReader reader = command.ExecuteReader())
                        {
                            while (reader.Read())
                            {
                                int id = reader.GetInt32(0); // 假設第一列是 ID
                                string name = reader.GetString(1); // 假設第二列是 Name
                                Console.WriteLine($"ID: {id}, Name: {name}");
                            }
                        }
                    }

                    connection.Close();
                }

        }
    }
}

NHibernate示例

安裝NHibernate

使用NuGet包管理器安裝NHibernate。你可以在Visual Studio中開啟NuGet包管理器控制檯,然後執行以下命令:

Install-Package NHibernate

這將自動下載並安裝NHibernate及其所有依賴項到你的專案中。

配置NHibernate

NHibernate.cfg.xml
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
    <session-factory>
        <property name="connection.driver_class">NHibernate.Driver.OdbcDriver</property>
        <!--<property name="connection.connection_string">DSN=OceanBase ODBC;Database=使用者名稱;Uid=使用者名稱@住戶名#叢集;Pwd=密碼;</property>-->
        <property name="connection.connection_string">Driver={OceanBase ODBC 2.0 Driver};Server=xx.xx.xx.xx;Port=2883;Database=使用者名稱;Uid=使用者名稱@住戶名#叢集;Pwd=密碼;</property>
        <property name="dialect">NHibernate.Dialect.Oracle10gDialect</property>
    </session-factory>
</hibernate-configuration>

配置對映類

public class TestEntity
{
    public virtual int Ident { get; set; }

    public virtual string Name { get; set; }
}

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
    <class name="ConsoleApp2.TestEntity, ConsoleApp2" table="TESTENTITY">
        <id name="Ident" column="IDENT" />
        <property name="Name" column="NAME" />
        <!-- 其他屬性對映... -->
    </class>
</hibernate-mapping>

查詢案例

using NHibernate.Cfg;
using System;
using System.IO;

class Program
{
    static void Main(string[] args)
    {
        string baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
        var cfg = new Configuration().Configure(Path.Combine(baseDirectory, "NHibernate.cfg.xml"));
        cfg.AddFile(Path.Combine(baseDirectory, "TestEntity.xml"));

        var sessionFactory = cfg.BuildSessionFactory();
        using (var session = sessionFactory.OpenSession())
        {
            var query = session.CreateQuery("FROM TestEntity")
                .SetMaxResults(10);

            var results = query.List();
        }
    }
}

相關文章