本文介绍了 OceanBase 数据库的 OB-ODBC 驱动和 MySQL 官方 MySQL-ODBC 驱动的使用说明和配置方法。
开放数据库互连(ODBC)是微软公司开放服务结构( WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,基本思想是为用户提供简单、标准、透明的数据库连接的公共编程接口,开发厂商根据 ODBC 的标准去实现底层的驱动程序,这个驱动对用户是透明的,并允许根据不同的 DBMS 采用不同的技术加以优化实现。
ODBC 主要由驱动程序和驱动程序管理器组成。驱动程序是一个用以支持 ODBC 函数调用的模块,每个驱动程序对应于相应的数据库,当应用程序从一个数据库系统移植到另一个时,只需更改应用程序中由 ODBC 管理程序设定的与相应数据库系统对应的别名即可。
建议使用 OceanBase 数据库的 OB-ODBC 驱动。
连接 MySQL 租户也可以使用 MySQL 官方 MySQL-ODBC 驱动。
连接 OceanBase 数据库的驱动程序管理器和驱动程序 OB-ODBC 均为 OceanBase 自研,通过该驱动可以连接访问 OceanBase 数据库。
Linux 下 OB-ODBC/MySQL-ODBC 连接 OceanBase 数据库的架构图如下所示。

连接环境配置
连接数据库前,需要配置连接环境,配置方法如下:
修改配置文件
odbc.ini,路径为/etc/odbc.ini,配置文件odbc.ini也可以放在除了/etc以外的其他目录,通过设置环境变量到相应的目录即可。[ODBC Data Sources] data_source_name = Name [Name] Driver=Oceanbase Description = MyODBC 5 Driver DSN SERVER = [OBProxy IP地址] PORT = [OBProxy 端口] USER = [用户名@租户名#集群名称] Password = [用户密码] Database = [数据库名] OPTION = 3 charset=UTF8配置
/etc/odbcinst.ini。[Oceanbase] Driver=/u01/mysql-odbc/lib/libmyodbc5a.so设置环境变量。
export ODBCSYSINI=/etc export ODBCINI=/etc/odbc.ini export LD_LIBRARY_PATH=/u01/mysql/lib:/usr/lib64:$LD_LIBRARY_PATH export PATH=$PATH:/u01/unix-odbc/bin配置完成后使用
odbcinst -j命令查看配置是否正确。返回结果如下所示:
unixODBC 2.3.7 DRIVERS............: /etc/odbcinst.ini SYSTEM DATA SOURCES: /etc/odbc.ini FILE DATA SOURCES..: /etc/ODBCDataSources USER DATA SOURCES..: /etc/odbc.ini SQLULEN Size.......: 8 SQLLEN Size........: 8 SQLSETPOSIROW Size.: 8
使用示例
以 OceanBase 数据库的 mysql 租户为测试环境,运行下述语句在数据库中创建一张示例表 TEST。
CREATE TABLE "TEST" ( "ID" NUMBER(38) NOT NULL, "NAME" VARCHAR2(32), CONSTRAINT "TEST_PK" PRIMARY KEY ("ID") ) COMPRESS FOR ARCHIVE REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 10编写连接数据库的驱动程序。
驱动程序的代码示例如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "sql.h" #include "sqlext.h" typedef struct tagODBCHandler { SQLHENV henv; SQLHDBC hdbc; SQLHSTMT hstmt; }ODBCHandler; int IS_SUCC(SQLRETURN retcode) { if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO) return 1; return 0; } void checkError(SQLRETURN retcode, const char* msg, ODBCHandler* handler) { SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; SQLINTEGER error; SQLSMALLINT len; SQLRETURN tmpcode; switch (retcode){ case SQL_SUCCESS: printf("%s retcode is SQLRETURN\n", msg); break; case SQL_SUCCESS_WITH_INFO: printf("%s retcode is SQL_SUCCESS_WITH_INFO\n", msg); break; case SQL_ERROR: printf("%s retcode is SQL_ERROR\n", msg); tmpcode = SQLError(handler->henv, handler->hdbc, handler->hstmt, sqlstate, &error, message, sizeof(message), &len); if (tmpcode != SQL_SUCCESS && tmpcode != SQL_SUCCESS_WITH_INFO) { printf("get sqlerror failed %d", tmpcode); } else { printf("error is %d, meeesage is %s, sqlstate is %s, len is %d\n", error, message, sqlstate, len); } break; case SQL_INVALID_HANDLE: printf("%s retcode is SQL_INVALID_HANDLE\n", msg); break; case SQL_STILL_EXECUTING: printf("%s retcode is SQL_STILL_EXECUTING\n", msg); break; case SQL_NO_DATA: printf("%s retcode is SQL_NO_DATA\n", msg); break; default: printf("%s retcode is UNKNOWN retcode\n", msg); break; } } int main(int argc, char** argv) { ODBCHandler handler; SQLRETURN retcode; #define MAX_NAME_LEN 255 SQLCHAR connOut[MAX_NAME_LEN+1]; SQLSMALLINT len; //Allocate environment handle retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &handler.henv); // Set the ODBC version environment attribute if (!IS_SUCC(retcode)) { checkError(retcode, "SQLAllocHandle", &handler); return -1; } retcode = SQLSetEnvAttr(handler.henv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3_80, 0); // Allocate connection handle if (!IS_SUCC(retcode)) { checkError(retcode, "SQLSetEnvAttr", &handler); return -1; } retcode = SQLAllocHandle(SQL_HANDLE_DBC, handler.henv, &handler.hdbc); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLAllocHandle", &handler); return -1; } // Set login timeout to 5 seconds SQLSetConnectAttr(handler.hdbc, SQL_LOGIN_TIMEOUT, (SQLPOINTER)5, 0); // Connect to data source retcode = SQLDriverConnect(handler.hdbc, NULL, (SQLCHAR*)"DSN=odbctest", SQL_NTS, connOut, MAX_NAME_LEN, &len,SQL_DRIVER_NOPROMPT); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLDriverConnect", &handler); return -1; } retcode = SQLAllocHandle(SQL_HANDLE_STMT, handler.hdbc, &handler.hstmt); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLAllocHandle", &handler); return -1; } { //insert retcode = SQLPrepare(handler.hstmt, (SQLCHAR*)"INSERT INTO test VALUES(?,'robin')", SQL_NTS); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLPrepare", &handler); return -1; } SQLINTEGER id = 2; retcode = SQLBindParameter(handler.hstmt, 1, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, &id, 0, NULL); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLBindParameter", &handler); return -1; } retcode = SQLExecute(handler.hstmt); if (!IS_SUCC(retcode)) { checkError(retcode, "SQLExecute", &handler); return -1; } } // clean handle SQLFreeHandle(SQL_HANDLE_STMT, handler.hstmt); SQLDisconnect(handler.hdbc); SQLFreeHandle(SQL_HANDLE_DBC, handler.hdbc); SQLFreeHandle(SQL_HANDLE_ENV, handler.henv); return 0; }编译并执行驱动程序。
GCC 编译时,使用
-I选项指定头文件,-L指定库文件目录,-l指定库名。示例语句如下所示:
gcc test.c -L/u01/unix-odbc/lib -lodbc -I/u01/unix-odbc/include -otest ./test检查结果:
obclient -hobproxy.oceanbase.abc.com -uhr@test0_5#obtest -p'hr' -P2883 obclient> select * from test; +----+-------+ | ID | NAME | +----+-------+ | 1 | jason | | 2 | robin | +----+-------+




