unixODBC使用经验分享

本文分享了在项目中使用unixODBC的实践经验和技巧,包括源码编译、使用连接池、在日志中打印线程等内容。unixODBC在稳定性方面表现出色,为用户提供了一种高效、可靠的数据库访问解决方案。
部署运行你感兴趣的模型镜像

unixODBC(http://www.unixodbc.org)和iODBC(http://www.iodbc.org)是UNIX系统上两个开源的ODBC实现。关于二者的比较,有兴趣的朋友可以参考stackoverflow上的这篇帖子。我没有用过iODBC,所以不好评论孰优孰劣。但是从stackoverflow上关于两个项目的标签统计来看,应该是unixODBC用的更广泛一些。在距离上一版本发布两年以后,今年10月,unixODBC发布了2.3.2版本,基本上就是修正了一些bugs(其中有3个bug是我发现并提出修改意见的,偷笑),没有新的feature引入。我从2011年开始在项目中使用unixODBC,2012年中旬项目正式上线,到现在已经运行了1年半时间。总的来说unixODBC还是很稳定的,基本连个错误都没有。在这篇文章中,我把我使用unixODBC的一点经验分享出来,希望能给需要的朋友一些帮助。


(1)源码,编译和安装

在unixODBC的网站上提供了最新版本的源码下载,如果想下载之前的发布版本,可以访问这个网站:ftp://ftp.unixodbc.org/pub/unixODBC/。个人感觉,unixODBC的代码风格还是很清晰的,前后也比较一致(unixODBC里面也包含了一些其它开源的代码,像libltdl,而这些开源代码的风格和unixODBC的风格是不一致的)。只是有些函数有些太长了(像SQLConnect函数就有600多行),似乎不符合KISS(Keep It Small and Simple)原则。

编译unixODBC很简单:

./configure;

make;

make install

我的很多同事都说在Solaris环境下编译源代码是很痛苦的事情,但是编译unixODBC却总是一气呵成,连个错误都没有。

此外,由于默认编译unixODBC是优化的,所以我在实验室里使用时一般都是禁止优化的(./configure CFLAGS='-g -O0 '),这样debug时也比较方便,不会出现代码和函数对不上的问题。只有到了生产环境,才把优化打开。


(2)使用连接池

从2.0.0版本起,uinixODBC引入了连接池。unixODBC的项目负责人Nick Gorham这篇文章里详细介绍了连接池。引入连接池,可以使对数据库连接的使用更高效。下面我就对连接池的原理做个分析:

首先,uinixODBC引入两个全局变量:

/*
 * connection pooling stuff
 */

CPOOL *pool_head = NULL;
int pooling_enabled = 0;
其中pool_head指向连接池链表的首节点,而pooling_enabled则表示是否使用连接池。

其次,在SQLDisconnect函数中,可以看到:

/*
 * is it a pooled connection, or can it go back 
 */

if ( connection -> pooled_connection )
{
    __clean_stmt_from_dbc( connection );
    __clean_desc_from_dbc( connection );

    return_to_pool( connection );

    ......

    return function_return( SQL_HANDLE_DBC, connection, SQL_SUCCESS );
}
else if ( pooling_enabled && connection -> pooling_timeout > 0 ) 
{
    __clean_stmt_from_dbc( connection );
    __clean_desc_from_dbc( connection );

    return_to_pool( connection );

    ......

    return function_return( SQL_HANDLE_DBC, connection, SQL_SUCCESS );
}

如果使用了连接池的话,当断开连接时,连接是回到了连接池里,也就是return_to_pool这个函数。

最后,在SQLConnect函数中,可以看到:

if ( pooling_enabled && search_for_pool( connection, 
                                            server_name, name_length1,
                                            user_name, name_length2,
                                            authentication, name_length3,
                                            NULL, 0 ))
{
    ret_from_connect = SQL_SUCCESS;

    .....

    connection -> state = STATE_C4;

    return function_return( SQL_HANDLE_DBC, connection, ret_from_connect );
}

如果连接数据库时可以在连接池中找到可用的连接(search_for_pool),函数就直接返回,不用再做连接的操作了。


(3)在日志中打印线程

unixODBC的日志输出是通过dm_log_write函数:

if ( !log_info.program_name )
{
    uo_fprintf( fp, "[ODBC][%s]%s[%s][%d]%s\n", __get_pid((SQLCHAR*) tmp ), 
			tstamp_str,
            function_name, line, message );
}
else
{
    uo_fprintf( fp, "[%s][%s]%s[%s][%d]%s\n", log_info.program_name,
        __get_pid((SQLCHAR*) tmp ), 
		tstamp_str,
		function_name, line, message );
}

可以看到,日志输出包含进程名,时间戳,函数名,行号,和消息。但是现在的程序基本是多线程的,所以当有多个线程同时访问数据库时,从日志就很难区分开哪个线程到底做了什么,因此通常我会在日志中增加对线程的打印。因为我们的程序运行在Solaris系统,而在Solaris上,pthread_t类型是个整数,标示当前的线程号,所以下面的改动就可以增加对线程号的输出:

if ( !log_info.program_name )
{
    uo_fprintf( fp, "[ODBC][%s][%d]%s[%s][%d]%s\n", __get_pid((SQLCHAR*) tmp ), pthread_self(),
			tstamp_str,
            function_name, line, message );
}
else
{
    uo_fprintf( fp, "[%s][%s][%d]%s[%s][%d]%s\n", log_info.program_name,
        __get_pid((SQLCHAR*) tmp ), 
		pthread_self(),
		tstamp_str,
		function_name, line, message );
}

由于pthread_t类型在不同的系统定义不一样,所以如果同一份unixODBC代码需要运行在不同系统上,就需要实现定制化:

#ifdef __linux__
......
#endif

#ifdef __sun
......
#endif
关于pthread_t的打印,可以参考stackoverflow上的 这篇帖子

以上就是我使用unixODBC的一点经验分享,希望能给需要的朋友一点帮助。如果大家有其它好的经验,也希望能分享出来。

您可能感兴趣的与本文相关的镜像

Stable-Diffusion-3.5

Stable-Diffusion-3.5

图片生成
Stable-Diffusion

Stable Diffusion 3.5 (SD 3.5) 是由 Stability AI 推出的新一代文本到图像生成模型,相比 3.0 版本,它提升了图像质量、运行速度和硬件效率

### 如何在Unix系统中使用unixODBC静态库进行开发 #### 配置编译环境 为了能够在Unix系统上使用unixODBC静态库进行开发,首先需要确保已经正确安装了unixODBC及其开发文件。可以通过源码编译的方式安装带有静态库支持的unixODBC版本[^1]。 ```bash ./configure --enable-static=yes --prefix=/usr/local/unixodbc make && make install ``` 这会将unixODBC以及其静态库(`libodbc.a`)安装到指定目录下。 #### 编写应用程序代码 编写C/C++程序时,需包含必要的头文件并链接相应的静态库。下面是一个简单的例子来展示如何连接SQL Server数据库: ```c #include <stdio.h> #include <sql.h> #include <sqlext.h> int main() { SQLHENV hEnv; SQLHDBC hDbc; // 初始化环境句柄 if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv) != SQL_SUCCESS || SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0) != SQL_SUCCESS || SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc) != SQL_SUCCESS) { printf("Failed to initialize ODBC environment\n"); return -1; } // 连接到数据源 if (SQLConnect(hDbc, (SQLCHAR *)"DSN=mydsn", SQL_NTS, NULL, 0, NULL, 0) != SQL_SUCCESS) { printf("Could not connect to data source.\n"); SQLFreeHandle(SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_ENV, hEnv); return -1; } // 执行查询... // 清理资源 SQLDisconnect(hDbc); SQLFreeHandle(SQL_HANDLE_DBC, hDbc); SQLFreeHandle(SQL_HANDLE_ENV, hEnv); return 0; } ``` #### 编译与链接 当编译上述代码时,应指明gcc/g++查找静态库的位置,并显式地告诉它要链接哪些库。假设unixODBC被安装到了`/usr/local/unixodbc`: ```bash gcc -o myapp myapp.c \ -I/usr/local/unixodbc/include \ -L/usr/local/unixodbc/lib \ -lodbc -lodbcinst -static-libgcc ``` 这里的关键在于使用 `-L` 参数指向静态库所在的路径,而 `-l` 后跟的就是所需的库名(去掉前缀 `lib` 和后缀 `.a`)。另外加上 `-static-libgcc` 来强制静态链接GCC标准库[^2]。 #### 设置运行时环境变量 即使采用静态链接方式构建应用,某些情况下仍可能依赖于共享库中的符号解析或其他动态加载特性。因此建议设置适当的环境变量以便顺利运行程序: ```bash export LD_LIBRARY_PATH=/usr/local/unixodbc/lib:$LD_LIBRARY_PATH ``` 尽管对于完全静态化的二进制来说这不是绝对必需的操作,但在遇到问题时这样做有助于排除潜在的依赖关系错误[^3]。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值