Oracle的学习心得和知识总结(三十一)| ODBC开放式数据库连接概述及应用程序开发

news2025/1/20 13:31:20

注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下:

1、参考书籍:《Oracle Database SQL Language Reference》
2、参考书籍:《PostgreSQL中文手册》
3、EDB Postgres Advanced Server User Guides,点击前往
4、PostgreSQL数据库仓库链接,点击前往
5、PostgreSQL中文社区,点击前往
6、Microsoft 开放式数据库连接 (ODBC),点击前往
7、ODBC 程序员参考,点击前往
8、ODBC 概述,点击前往


1、本文内容全部来源于开源社区 GitHub和以上博主的贡献,本文也免费开源(可能会存在问题,评论区等待大佬们的指正)
2、本文目的:开源共享 抛砖引玉 一起学习
3、本文不提供任何资源 不存在任何交易 与任何组织和机构无关
4、大家可以根据需要自行 复制粘贴以及作为其他个人用途,但是不允许转载 不允许商用 (写作不易,还请见谅 💖)


ODBC开放式数据库连接概述

  • 文章快速说明索引
  • 开放式数据库连接
  • 如何开发应用程序
    • 建立 ODBC DSN
    • 编写 ODBC 程序
    • 编写 OCI 程序



文章快速说明索引

学习目标:

目的:接下来这段时间我想做一些兼容Oracle数据库Real Application Testing (即:RAT)上的一些功能开发,本专栏这里主要是学习以及介绍Oracle数据库功能的使用场景、原理说明和注意事项等,基于PostgreSQL数据库的功能开发等之后 由新博客进行介绍和分享!


学习内容:(详见目录)

1、ODBC开放式数据库连接概述


学习时间:

2023年12月17日 14:07:20


学习产出:

1、ODBC开放式数据库连接概述
2、CSDN 技术博客 1篇


注:下面我们所有的学习环境是Centos7+PostgreSQL16.1+Oracle19c+MySQL5.7

postgres=# select version();
                                                 version                                                 
---------------------------------------------------------------------------------------------------------
 PostgreSQL 16.1 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-15), 64-bit
(1 row)

postgres=#

#-----------------------------------------------------------------------------#

SQL> select * from v$version; 

BANNER									    BANNER_FULL 								BANNER_LEGACY									CON_ID
--------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- ----------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production		     0
									    Version 19.3.0.0.0


SQL>
#-----------------------------------------------------------------------------#

mysql> select version();
+-----------+
| version() |
+-----------+
| 5.7.19    |
+-----------+
1 row in set (0.06 sec)

mysql>

开放式数据库连接

开放式数据库连接 (ODBC) 是一种广泛接受的应用程序编程接口 (API),适用于数据库访问。其基于 Open Group 和 ISO/IEC 的数据库 API 调用级别接口 (CLI) 规范,并使用结构化查询语言 (SQL) 作为其数据库访问语言。

ODBC 旨在实现最大的互操作性,即单个应用程序能够使用相同的源代码访问不同的数据库管理系统 (DBMS)。数据库应用程序会在 ODBC 接口中调用函数,这些函数在特定于数据库的模块(称为“驱动程序”)中实现。驱动程序的使用将应用程序与特定于数据库的调用隔离,就像打印机驱动程序将字处理程序与特定于打印机的命令隔离一样。由于驱动程序在运行时加载,因此用户需要添加新驱动程序才能访问新的 DBMS;无需重新编译或重新链接应用程序。

ODBC 是为客户应用程序访问关系数据库时提供的一个标准的接口,对于不同的数据库,ODBC 提供了统一的 API,使应用程序调用提供的 API 来访问任何提供了 ODBC 驱动程序的数据库:

  • 应用程序(Application,即对应下图的客户程序):应用程序本身不直接与数据库打交道,主要负责处理并调用ODBC函数,发送对数据库的SQL请求及获取结果
  • 驱动程序管理器(Driver Manager,即对应下图的 ODBC 驱动管理程序):驱动程序管理器是一个带有输入程序的动态链接库(DLL),主要目的是加载驱动程序,处理ODBC调用的初始化调用,提供ODBC调用的参数有效性和序列有效性
  • 驱动程序(Driver,即对应下图的 ODBC 驱动程序):驱动程序是一个完成ODBC函数调用并与数据库相互影响的DLL,这些驱动程序可以处理对于特定的数据的数据库访问请求。对于应用驱动程序管理器送来的命令,驱动程序再进行解释形成自己的数据库所能理解的命令。驱动程序将处理所有的数据库访问请求,对于应用程序来讲不需要关注所使用的是本地数据库还是网络数据库

在这里插入图片描述


总结一下,ODBC 体系结构有四个主要组成部分:

  1. 应用程序:执行处理并调用 ODBC 函数来提交 SQL 语句并检索结果
  2. 驱动程序管理器:代表应用程序加载和卸载驱动程序。 处理 ODBC 函数调用或将其传递给驱动程序
  3. 驱动程序:处理 ODBC 函数调用,将 SQL 请求提交到特定数据源,并将结果返回到应用程序。 如有必要,驱动程序会修改应用程序的请求,以便该请求符合关联的 DBMS 支持的语法
  4. 数据源:由用户想要访问的数据及其关联的操作系统、DBMS 和用于访问 DBMS 的网络平台(如果有)组成

如何开发应用程序

一个ODBC应用程序的编写,通常步骤如下所示:

在这里插入图片描述

任何应用程序都不太可能完全按此顺序调用所有这些函数。但是,大多数应用程序使用这些步骤的一些变体。下图显示了基本的应用程序步骤:

在这里插入图片描述

简单解释一下,例如:

  1. 步骤 1:连接数据源
  2. 步骤 2:初始化应用程序
  3. 步骤 3:生成并执行 SQL 语句
  4. 步骤 4a:提取结果;步骤 4b:提取行计数
  5. 步骤 5:提交事务
  6. 步骤 6:从数据源断开连接

建立 ODBC DSN

DSN(Data Source Name)是用于指定ODBC与相关的驱动程序相对应的一个入口,所有DSN的信息由系统进行管理。一般来讲当应用程序要使用ODBC访问数据库时,就需要指定一个DSN以便于连接到一个指定的ODBC驱动程序。


下面列出了 ODBC Driver for SQL Server 中提供的连接字符串和 DSN 的关键字以及 SQLSetConnectAttr 和 SQLGetConnectAttr 的连接属性:

  • 受支持的 DSN/连接字符串关键字和连接属性

我们这里以连接oracle数据库为例,编写一个odbc应用测试程序。作为服务端的Oracle数据库 机器1如下:

[oracle@dbserver ~]$ ifconfig 
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 192.168.1.14  netmask 255.255.255.0  broadcast 192.168.1.255
        inet6 2409:8a71:abc:ed70:250:56ff:fe2b:6b00  prefixlen 64  scopeid 0x0<global>
        inet6 fe80::250:56ff:fe2b:6b00  prefixlen 64  scopeid 0x20<link>
        ether 00:50:56:2b:6b:00  txqueuelen 1000  (Ethernet)
        RX packets 3711  bytes 2060244 (1.9 MiB)
        RX errors 0  dropped 5  overruns 0  frame 0
        TX packets 1374  bytes 168460 (164.5 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 415  bytes 64588 (63.0 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 415  bytes 64588 (63.0 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

virbr0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 192.168.122.1  netmask 255.255.255.0  broadcast 192.168.122.255
        ether 52:54:00:3b:26:0a  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

[oracle@dbserver ~]$
[oracle@dbserver ~]$ sqlplus / as sysdba

SQL*Plus: Release 19.0.0.0.0 - Production on Tue Dec 19 09:57:49 2023
Version 19.3.0.0.0

Copyright (c) 1982, 2019, Oracle.  All rights reserved.

Connected to an idle instance.

SQL> startup;
ORACLE instance started.

Total System Global Area 1157624440 bytes
Fixed Size		    9134712 bytes
Variable Size		  352321536 bytes
Database Buffers	  788529152 bytes
Redo Buffers		    7639040 bytes
Database mounted.
Database opened.
SQL> 
SQL> select * from v$version;

BANNER									    BANNER_FULL 								BANNER_LEGACY	  CON_ID
--------------------------------------------------------------------------- --------------------------------------------------------------------------- --------------------------------------------------------------------------- ----------
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	    Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production	Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production		     0
									    Version 19.3.0.0.0


SQL>

机器2(CentOS8)配置ODBC连接oracle,步骤如下:

一、安装oracle客户端及oracle ODBC驱动程序(这里一定要注意别下错了,32位还是64位)

// 下载oracle客户端包:

https://www.oracle.com/cn/database/technologies/instant-client/linux-x86-64-downloads.html
https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm

https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm

https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm

https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm

https://download.oracle.com/otn_software/linux/instantclient/1921000/oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm

提前安装相关依赖,如下:

[postgres@localhost:~/odbcloc]$ sudo yum install libaio*
...
[postgres@localhost:~/odbcloc]$ sudo yum install libnsl*
...
[postgres@localhost:~/odbcloc]$ sudo yum install libaio.so.1* -y
...
[postgres@localhost:~/odbcloc]$ sudo yum install libnsl.so.1* -y
...
[root@localhost odbc]# ll
total 54924
-rw-rw-r--. 1 postgres postgres 53832016 Dec 19 00:17 oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   614204 Dec 19 00:17 oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   246728 Dec 19 00:17 oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   703388 Dec 19 00:17 oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm
-rw-rw-r--. 1 postgres postgres   837556 Dec 19 00:17 oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm
[root@localhost odbc]#
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle-instantclient19.21-basic-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle-instantclient19.21-sqlplus################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle-instantclient19.21-devel-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle-instantclient19.21-tools-1################################# [100%]
[root@localhost odbc]# 
[root@localhost odbc]# rpm -ivh oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm 
Verifying...                          ################################# [100%]
Preparing...                          ################################# [100%]
Updating / installing...
   1:oracle-instantclient19.21-odbc-19################################# [100%]
[root@localhost odbc]#

执行如下命令查看rpm安装后,生成文件及安装路径:

[root@localhost odbc]# rpm -qpl oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm 
/usr/lib/oracle
/usr/lib/oracle/19.21
/usr/lib/oracle/19.21/client64
/usr/lib/oracle/19.21/client64/bin
/usr/lib/oracle/19.21/client64/bin/odbc_update_ini.sh
/usr/lib/oracle/19.21/client64/lib
/usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
/usr/share/oracle
/usr/share/oracle/19.21
/usr/share/oracle/19.21/client64
/usr/share/oracle/19.21/client64/doc
/usr/share/oracle/19.21/client64/doc/ODBC_LICENSE
/usr/share/oracle/19.21/client64/doc/ODBC_README
[root@localhost odbc]# 

配置环境变量,如下:

[root@localhost odbcloc]# vim /etc/profile
...
#根据实际安装路径配置
 export ORACLE_HOME=/usr/lib/oracle/19.21/client64
 export TNS_ADMIN=/usr/lib/oracle/19.21/client64/network/admin
 export LD_LIBRARY_PATH=/usr/lib/oracle/19.21/client64/lib
 export ORACLE_SID=orcl
 export PATH=$ORACLE_HOME:$PATH
 export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin

source /etc/profile 使其生效

配置监听配置文件,如下:

[postgres@localhost:~/odbc]$ sudo mkdir -p /usr/lib/oracle/19.21/client64/network/admin
[sudo] password for postgres: 
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ cd /usr/lib/oracle/19.21/client64/network/admin/
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ vim tnsnames.ora 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ sudo vim tnsnames.ora 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ 
[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$ cat tnsnames.ora 
ORCL =
(DESCRIPTION =
  (ADDRESS_LIST =
     (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.14)(PORT = 1521))
  )
  (CONNECT_DATA =
    (SERVICE_NAME = ORCL)
  )
)

[postgres@localhost:/usr/lib/oracle/19.21/client64/network/admin]$

二、安装 unixODBC 驱动程序管理器,如下:

[root@localhost admin]# yum install unixODBC unixODBC-devel -y
...

若是选择源码编译安装,则获取 unixODBC-2.3.1.tar.gz。 可以从 http://www.unixodbc.org 获取 unixODBC-2.3.1.tar.gz放到/usr/local下,然后运行下述命令:

注:如果自定义其他安装目录,需要配置环境变量,否则使用时可能会出现找不到库的问题

tar zxvf unixODBC-2.3.1.tar.gz
cd unixODBC-2.3.1 
./configure --prefix=/usr/local/unixODBC-2.3.1 --includedir=/usr/include 
--libdir=/usr/lib -bindir=/usr/bin --sysconfdir=/etc
make
make install

三、安装之后运行odbcinst -j,如下:

[postgres@localhost:~]$ odbcinst -j
unixODBC 2.3.7
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /home/postgres/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
[postgres@localhost:~]$

根据odbcinst -j 显示的路径,配置 odbcinst.iniodbc.ini 文件

[postgres@localhost:~]$ sudo vim /etc/odbcinst.ini
[postgres@localhost:~]$ 
[postgres@localhost:~]$ cat /etc/odbcinst.ini
# Example driver definitions

# Driver from the postgresql-odbc package
# Setup from the unixODBC package
[PostgreSQL]
Description	= ODBC for PostgreSQL
Driver		= /usr/lib/psqlodbcw.so
Setup		= /usr/lib/libodbcpsqlS.so
Driver64	= /usr/lib64/psqlodbcw.so
Setup64		= /usr/lib64/libodbcpsqlS.so
FileUsage	= 1

[ORACLE]
Description = ODBC for Oracle
Driver      = /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
FileUsage   = 1

[postgres@localhost:~]$

[postgres@localhost:~]$ ls /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
/usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
[postgres@localhost:~]$ 
[postgres@localhost:~]$ ldd /usr/lib/oracle/19.21/client64/lib/libsqora.so.19.1
	linux-vdso.so.1 (0x00007ffc2750b000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007f0dec769000)
	libm.so.6 => /lib64/libm.so.6 (0x00007f0dec3e7000)
	libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f0dec1c7000)
	libnsl.so.1 => /lib64/libnsl.so.1 (0x00007f0debfae000)
	librt.so.1 => /lib64/librt.so.1 (0x00007f0debda6000)
	libaio.so.1 => /lib64/libaio.so.1 (0x00007f0debba3000)
	libresolv.so.2 => /lib64/libresolv.so.2 (0x00007f0deb98b000)
	libclntsh.so.19.1 => /usr/lib/oracle/19.21/client64/lib/libclntsh.so.19.1 (0x00007f0de777c000)
	libclntshcore.so.19.1 => /usr/lib/oracle/19.21/client64/lib/libclntshcore.so.19.1 (0x00007f0de71d7000)
	libodbcinst.so.2 => /lib64/libodbcinst.so.2 (0x00007f0de6fc1000)
	libc.so.6 => /lib64/libc.so.6 (0x00007f0de6bfc000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f0decc27000)
	libnnz19.so => /usr/lib/oracle/19.21/client64/lib/libnnz19.so (0x00007f0de6583000)
	libltdl.so.7 => /lib64/libltdl.so.7 (0x00007f0de6379000)
[postgres@localhost:~]$

在机器2上先行验证一下,如下:

[postgres@localhost:~]$ sqlplus c##oracle/123456@192.168.1.14:1521/orcl

SQL*Plus: Release 19.0.0.0.0 - Production on Mon Dec 18 18:54:13 2023
Version 19.20.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Mon Dec 18 2023 18:53:33 -08:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> show user;         
USER is "C##ORACLE"
SQL> 
SQL> Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[postgres@localhost:~]$

[postgres@localhost:~]$ sudo vim /etc/odbc.ini
[postgres@localhost:~]$ 
[postgres@localhost:~]$ cat /etc/odbc.ini
[pg]
Description = Test to pg
Driver = PostgreSQL
Database = postgres
Servername = 127.0.0.1
UserName = postgres
Password = 1
Port = 5432
ReadOnly = 0
ConnSettings = set client_encoding to UTF8

[oracle_test]
driver = ORACLE
server = 192.168.1.14
port = 1521
ServerName = orcl
UserID = c##oracle
password = 123456

[postgres@localhost:~]$

连接测试

[postgres@localhost:~]$ isql -v oracle_test
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+
SQL> create table t_a(id int, name varchar(64));
SQLRowCount returns -1
SQL> insert into t_a values(1, 'a');
SQLRowCount returns 1
SQL> insert into t_a values(2, 'b');
SQLRowCount returns 1
SQL> insert into t_a values(3, 'c');
SQLRowCount returns 1
SQL> insert into t_a values(4, 'd');
SQLRowCount returns 1
SQL> insert into t_a values(5, 'jj');
SQLRowCount returns 1
SQL> select * from t_a;
+-----------------------------------------+-----------------------------------------------------------------+
| ID                                      | NAME                                                            |
+-----------------------------------------+-----------------------------------------------------------------+
| 1                                       | a                                                               |
| 2                                       | b                                                               |
| 3                                       | c                                                               |
| 4                                       | d                                                               |
| 5                                       | jj                                                              |
+-----------------------------------------+-----------------------------------------------------------------+
SQLRowCount returns -1
5 rows fetched
SQL>

编写 ODBC 程序

#include <stdio.h>
#include <sqlext.h>

int main() {
    SQLHENV env; // ODBC环境句柄
    SQLHDBC dbc; // ODBC连接句柄
    SQLRETURN ret;

    // Step 1: 初始化环境
    ret = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);
    ret = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*)SQL_OV_ODBC3, SQL_IS_INTEGER);

    // Step 2: 分配连接句柄
    ret = SQLAllocHandle(SQL_HANDLE_DBC, env, &dbc);

    // Step 3: 建立连接
    ret = SQLDriverConnect(dbc, NULL,
                           (SQLCHAR*)"DRIVER={Oracle};SERVER=<server>;DATABASE=<database>;UID=<username>;PWD=<password>;",
                           SQL_NTS, NULL, 0, NULL, SQL_DRIVER_COMPLETE);

    if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
        printf("Connected to Oracle.\n");

        // Step 4: 执行SQL查询
        SQLHSTMT stmt; // SQL语句句柄
        ret = SQLAllocHandle(SQL_HANDLE_STMT, dbc, &stmt);

        ret = SQLExecDirect(stmt, (SQLCHAR*)"SELECT * FROM my_table", SQL_NTS);

        if (ret == SQL_SUCCESS || ret == SQL_SUCCESS_WITH_INFO) {
            // 处理结果集
            // ...
            printf("SQL executed successfully.\n");
        } else {
            // 处理错误
            // ...
            printf("SQL execution failed.\n");
        }

        // Step 5: 释放语句句柄
        ret = SQLFreeHandle(SQL_HANDLE_STMT, stmt);
    } else {
        // 处理连接失败
        // ...
        printf("Failed to connect to Oracle.\n");
    }

    // Step 6: 断开连接
    ret = SQLDisconnect(dbc);

    // Step 7: 释放连接句柄
    ret = SQLFreeHandle(SQL_HANDLE_DBC, dbc);

    // Step 8: 释放环境句柄
    ret = SQLFreeHandle(SQL_HANDLE_ENV, env);

    return 0;
}

要编译以上的代码,首先需要确保已经安装了ODBC驱动和相关的开发库。接下来,可以使用gcc或其他支持C编译的工具进行编译。例如,使用gcc命令编译该代码:

gcc -o odbc_demo odbc_demo.c -lodbc
gcc -o odbc_demo odbc_demo.c -L/odbc库的路径 -lodbc
#可通过下面的命令查找odbc库的路径
sudo find / -name "libodbc*"

其中,odbc_demo为输出的可执行文件名,odbc_demo.c为上述代码保存的文件名。-lodbc用于链接ODBC库。请注意,编译时可能需要配置包含路径和连接选项,具体取决于所使用的操作系统和ODBC驱动程序。


下面是一个示例,源码odbctest.c如下:

#include <stdio.h>

#include <sql.h>
#include <sqlext.h>

static void
test_SQLConnect()
{
	SQLRETURN ret;
    SQLHENV env;
    SQLHDBC conn;
    HSTMT hstmt = SQL_NULL_HSTMT;
    SQLSMALLINT sdwNative;
	SQLINTEGER swMsgLen;
	char buffer[256];
	char message[1000];

	SQLCHAR *dsn = (SQLCHAR *) "oracle_test";
    //CHAR* queryStr="create table t_odbc(id int);";

	SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &env);

	SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void *) SQL_OV_ODBC3, 0);

	SQLAllocHandle(SQL_HANDLE_DBC, env, &conn);

	printf("Connecting with SQLConnect...\n");

	ret = SQLConnect(conn, dsn, SQL_NTS, NULL, 0, NULL, 0);
	if (SQL_SUCCEEDED(ret)) {
		printf("connected success!\n");
	} else {
		printf("SQLConnect failed.\n");
		return;
	}

    ret = SQLSetConnectAttr(conn,
						   SQL_ATTR_AUTOCOMMIT,
						   (SQLPOINTER)SQL_AUTOCOMMIT_OFF,
						   SQL_IS_UINTEGER);
	if (SQL_SUCCEEDED(ret)) {
		printf("set autommit off success!\n");
	} else {
		printf("set autommit failed.\n");
		return;
	}

    ret = SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);

    ret = SQLExecDirect(hstmt, (SQLCHAR *)"create table t_odbc(id int)", SQL_NTS);
    if (SQL_SUCCEEDED(ret)) {
		printf("create table success!\n");
	}
    else {
		printf("create table failed.\n");
		return;
	}

    ret = SQLExecDirect(hstmt, (SQLCHAR *) "INSERT INTO t_odbc VALUES (10000)", SQL_NTS);
	if (SQL_SUCCEEDED(ret)) {
		printf("insert table success!\n");
	}
    else {
		printf("insert table failed.\n");
		return;
	}

    SQLEndTran(SQL_HANDLE_DBC, conn, SQL_COMMIT);
    if (SQL_SUCCEEDED(ret)) {
		printf("SQLEndTran success!\n");
	}
    else {
		printf("SQLEndTran failed.\n");
		return;
	}

    ret = SQLFreeHandle(SQL_HANDLE_STMT, hstmt);
    if (SQL_SUCCEEDED(ret)) {
		printf("SQLFreeHandle success!\n");
	}
    else {
		printf("SQLFreeHandle failed.\n");
		return;
	}

    ret = SQLDisconnect(conn);
	if (SQL_SUCCEEDED(ret)) {
		printf("SQLDisconnect success!\n");
	}
    else {
        printf("SQLDisconnect failed.\n");
        SQLError(env, conn, hstmt, buffer, &swMsgLen,
		message, 256, &sdwNative);
		printf("%s\n%s\n", buffer, message);
		return;
	}

	ret = SQLFreeHandle(SQL_HANDLE_DBC, conn);
	if (!SQL_SUCCEEDED(ret))
	{
		printf("SQLFreeHandle failed\n");
		return;
	}
	conn = NULL;

	ret = SQLFreeHandle(SQL_HANDLE_ENV, env);
	if (!SQL_SUCCEEDED(ret))
	{
		printf("SQLFreeHandle failed\n");
		return;
	}
	env = NULL;
}


int main(int argc, char **argv)
{
	test_SQLConnect();
	return 0;
}

通过以下命令进行编译,第一条命令用于将UnixODBC驱动库安装在系统路径下,第二条命令可用于源码编译安装时,将UnixODBC安装在自定义路径下,可找到对应的odbc动态库路径,通过-L指定库的路径,-I指定所需头文件的路径等等

gcc -o odbctest odbctest.c -lodbc -g -O0
gcc -o odbctest odbctest.c -L/usr/lib64/ -lodbc

执行可执行程序

[postgres@localhost:~/odbc]$ vim odbctest.c
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ gcc -o odbctest odbctest.c -lodbc -g -O0
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ls
odbctest                                                  oracle-instantclient19.21-odbc-19.21.0.0.0-1.x86_64.rpm
odbctest.c                                                oracle-instantclient19.21-sqlplus-19.21.0.0.0-1.x86_64.rpm
oracle-instantclient19.21-basic-19.21.0.0.0-1.x86_64.rpm  oracle-instantclient19.21-tools-19.21.0.0.0-1.x86_64.rpm
oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ./odbctest 
Connecting with SQLConnect...
connected success!
set autommit off success!
create table success!
insert table success!
SQLEndTran success!
SQLFreeHandle success!
SQLDisconnect success!
[postgres@localhost:~/odbc]$

编写 OCI 程序

oci应用程序的编写步骤和odbc流程一致,只是调用的接口不同,示例 如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "oci.h" //引用OCI接口的头文件,因此编译时需要指定该头文件的路径
 
/*user name and password*/
static text* username=(text *)"c##oracle";
static text* password=(text *)"123456";
static text* oracle=(text *)"192.168.1.14/orcl";
 
/* Define SQL statements to be used in program. */
static text* SQL=(text *)"insert into t_oci(id1, id2) values (:1, :2)";
 
/*handle define*/
static OCIEnv             *p_env;                                        //OCI environment handle
static OCIError         *p_err;                                        //OCI error handle
static OCISvcCtx        *p_svc;                                        //OCI service context handel
static OCIServer        *p_ser;                                        //OCI server handle
static OCISession        *p_usr;                                        //OCI user session handle
static OCIStmt            *p_sql;                                        //OCI statement handle
static OCIDefine        *p_dfn = (OCIDefine *)NULL;            //OCI define handle
static OCIBind            *p_bnd = (OCIBind *)NULL;                //OCI bind handle
 
/*create OCI environment*/
int create_env()
{
    int swResult;            //Return value
    if(swResult = OCIEnvCreate(&p_env,OCI_DEFAULT,NULL,NULL,NULL,NULL,0,NULL))
	{
		printf("environment create error!\n\n");
		return -1;
	}
    else
	{
		printf("environment create success!\n\n");
		return 0;
	}
}
 
/*init handle*/
int init_handle()
{
    int swResult;
    if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_ser,OCI_HTYPE_SERVER,0,NULL))    //服务器句柄
	{
		printf("init server handle error!\n\n");
		return -1;
	}
    else
	{
		printf("init server handle success!\n\n");
	}
 
    if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_err,OCI_HTYPE_ERROR,0,NULL))    //错误句柄
	{
		printf("init error handle error!\n\n");
		return -1;
	}
    else
	{
		printf("init error handle success!\n\n");
	}
    
	if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_usr,OCI_HTYPE_SESSION,0,NULL))    //事务句柄
	{
		printf("init session handle error!\n\n");
		return -1;
	}
    else
	{
		printf("init session handle success!\n\n");
	}
    
	if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_svc,OCI_HTYPE_SVCCTX,0,NULL))    //上下文句柄
	{
		printf("init service context handle error!\n\n");
		return -1;
	}
    else
	{
		printf("init service context handel success!\n\n");
	}
    
	if(swResult = OCIHandleAlloc(p_env,(dvoid *)&p_sql,OCI_HTYPE_STMT,0,NULL))        //SQL语句句柄
	{
		printf("init statement handle error!\n\n");
		return -1;
	}
    else
	{
		printf("init statement handle success!\n\n");
	}
    return 0;
}
 
/*connect server*/
int conn_server()
{
    int swResult;
    if(swResult = OCILogon(p_env,p_err,&p_svc,(text *)username,strlen(username),(text *)password,strlen(password),(text *)oracle,strlen(oracle)))
	{
		printf("connect error!\n\n");
		return -1;
	}
    else
        printf("connect success!\n\n");
    return 0;
}
 
/*SQL statements*/
int oci_exec()
{
    int swResult;
	sb4 errcodep;
	ub4 recordno = 1;
	OraText bufp[1024];
	sword retcode = 0;

    //准备SQL语句
    if(swResult = OCIStmtPrepare(p_sql,p_err,SQL,strlen(SQL),OCI_NTV_SYNTAX,OCI_DEFAULT))
	{
		printf("prepare SQL statements error!\n\n");
	}
    else
	{
		printf("prepare SQL statements success!\n\n");
	}
 
    //设置绑定变量
    int getId1 ;
	int getId2;
    //char getName[10];
 
    OCIBind     *p_bndp1 = NULL;
    OCIBind     *p_bndp2 = NULL;
 
    printf("输入ID1,ID2:\n");
    scanf("%d %d",&getId1,&getId2);
 
    if(swResult = OCIBindByPos(p_sql,&p_bndp1,p_err,1,(dvoid *)&getId1,(sb4)sizeof(getId1),SQLT_INT,NULL,NULL,NULL,0,NULL,OCI_DEFAULT))
	{
		printf("Bind p1 error!\n\n");
		return -1;
	}
    else
	{
		printf("bind success!\n\n");
	}

	if(swResult = OCIBindByPos(p_sql,&p_bndp2,p_err,2,(dvoid *)&getId2,(sb4)sizeof(getId2),SQLT_INT,NULL,NULL,NULL,0,NULL,OCI_DEFAULT))
	{
		printf("Bind p1 error!\n\n");
		return -1;
	}
    else
	{
		printf("bind success!\n\n");
	}

	/*
    if(swResult = OCIBindByPos(p_sql,&p_bndp2,p_err,2,&getName,(sb4)sizeof(getName),SQLT_STR, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT))
	{
		printf("Bind p2 error!\n\n");
		return -1;
	}
    else
	{
		printf("bind success!\n\n");
	}*/
 
 
    //执行SQL statements
    if(swResult = OCIStmtExecute(p_svc,p_sql,p_err,1,0,NULL,NULL,OCI_DEFAULT))
	{
		//printf("execute SQL statement error!\n\n");
		if (OCIErrorGet(p_err, recordno++, NULL, &errcodep, (OraText *)bufp, sizeof(bufp), OCI_HTYPE_ERROR) == OCI_SUCCESS)
			printf("error msg:%s\n", bufp);
		return -1;
	}
    else
	{
		printf("execute SQL statement success!\n\n");
	}
    return 0;
}
 
 
/*quit server*/
void quit_server()
{
    OCILogoff(p_svc,p_err);
    printf("Quit success!\n");
}
 
/*free handle*/
void free_handle()
{
    OCIHandleFree(p_ser,OCI_HTYPE_SERVER);            //释放服务器句柄
    OCIHandleFree(p_err,OCI_HTYPE_ERROR);            //释放错误句柄
    OCIHandleFree(p_usr,OCI_HTYPE_SESSION);        //释放事务句柄
    OCIHandleFree(p_svc,OCI_HTYPE_SVCCTX);            //释放上下文句柄
    OCIHandleFree(p_sql,OCI_HTYPE_STMT);            //释放SQL语句句柄
}
 
int main()
{
    if(create_env() == -1)                //创建环境
        return -1;
    if(init_handle() == -1)                //初始化句柄
        return -1;
    if(conn_server() == -1)                //连接数据库
        return -1;
    if(oci_exec() == -1)
        return -1;
	/*
    quit_server();                            //退出数据库
    free_handle();                            //释放句柄 */
    return 0;
}

如上示例中可以看到调用OCI相关接口需要引用oci.h这个头文件,那么 这个头文件在哪?该头文件是在安装完oracle客户端之后,对应oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm软件包,可以通过如下命令查看其安装之后的路径,如下:

[postgres@localhost:~/odbc]$ rpm -qpl oracle-instantclient19.21-devel-19.21.0.0.0-1.x86_64.rpm
/usr/include/oracle
/usr/include/oracle/19.21
/usr/include/oracle/19.21/client64
/usr/include/oracle/19.21/client64/ldap.h
/usr/include/oracle/19.21/client64/nzerror.h
/usr/include/oracle/19.21/client64/nzt.h
/usr/include/oracle/19.21/client64/occi.h
/usr/include/oracle/19.21/client64/occiAQ.h
/usr/include/oracle/19.21/client64/occiCommon.h
/usr/include/oracle/19.21/client64/occiControl.h
/usr/include/oracle/19.21/client64/occiData.h
/usr/include/oracle/19.21/client64/occiObjects.h
/usr/include/oracle/19.21/client64/oci.h
/usr/include/oracle/19.21/client64/oci1.h
/usr/include/oracle/19.21/client64/oci8dp.h
/usr/include/oracle/19.21/client64/ociap.h
/usr/include/oracle/19.21/client64/ociapr.h
/usr/include/oracle/19.21/client64/ocidef.h
/usr/include/oracle/19.21/client64/ocidem.h
/usr/include/oracle/19.21/client64/ocidfn.h
/usr/include/oracle/19.21/client64/ociextp.h
/usr/include/oracle/19.21/client64/ocikpr.h
/usr/include/oracle/19.21/client64/ociver.h
/usr/include/oracle/19.21/client64/ocixmldb.h
/usr/include/oracle/19.21/client64/ocixstream.h
/usr/include/oracle/19.21/client64/odci.h
/usr/include/oracle/19.21/client64/oratypes.h
/usr/include/oracle/19.21/client64/ori.h
/usr/include/oracle/19.21/client64/orid.h
/usr/include/oracle/19.21/client64/orl.h
/usr/include/oracle/19.21/client64/oro.h
/usr/include/oracle/19.21/client64/ort.h
/usr/include/oracle/19.21/client64/xa.h
/usr/lib/oracle
/usr/lib/oracle/19.21
/usr/lib/oracle/19.21/client64
/usr/lib/oracle/19.21/client64/lib
/usr/lib/oracle/19.21/client64/lib/ottclasses.zip
/usr/share/oracle
/usr/share/oracle/19.21
/usr/share/oracle/19.21/client64
/usr/share/oracle/19.21/client64/admin
/usr/share/oracle/19.21/client64/admin/oraaccess.xsd
/usr/share/oracle/19.21/client64/demo
/usr/share/oracle/19.21/client64/demo/cdemo81.c
/usr/share/oracle/19.21/client64/demo/demo.mk
/usr/share/oracle/19.21/client64/demo/occidemo.sql
/usr/share/oracle/19.21/client64/demo/occidemod.sql
/usr/share/oracle/19.21/client64/demo/occidml.cpp
/usr/share/oracle/19.21/client64/demo/occiobj.cpp
/usr/share/oracle/19.21/client64/demo/occiobj.typ
/usr/share/oracle/19.21/client64/demo/oraaccess.xml
/usr/share/oracle/19.21/client64/demo/ott
/usr/share/oracle/19.21/client64/demo/setuporamysql.sh
/usr/share/oracle/19.21/client64/doc
/usr/share/oracle/19.21/client64/doc/SDK_LICENSE
/usr/share/oracle/19.21/client64/doc/SDK_README
[postgres@localhost:~/odbc]$

接下来编译上述样例:

[postgres@localhost:~/odbc]$ echo $ORACLE_HOME
/usr/lib/oracle/19.21/client64
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ gcc -o ocitest ocitest.c -I/usr/include/oracle/19.21/client64 -L${ORACLE_HOME}/lib -lclntsh -g -O0
[postgres@localhost:~/odbc]$

执行可执行程序,如下:

[postgres@localhost:~/odbc]$ sqlplus c##oracle/123456@192.168.1.14:1521/orcl

SQL*Plus: Release 19.0.0.0.0 - Production on Tue Dec 19 01:02:19 2023
Version 19.21.0.0.0

Copyright (c) 1982, 2022, Oracle.  All rights reserved.

Last Successful login time: Tue Dec 19 2023 01:00:31 -08:00

Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0

SQL> create table t_oci(id1 int, id2 int);

Table created.

SQL> Disconnected from Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
[postgres@localhost:~/odbc]$ 
[postgres@localhost:~/odbc]$ ./ocitest
environment create success!

init server handle success!

init error handle success!

init session handle success!

init service context handel success!

init statement handle success!

connect success!

prepare SQL statements success!

输入ID1,ID2:
1 2  
bind success!

bind success!

execute SQL statement success!

[postgres@localhost:~/odbc]$

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1330816.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

不忍学弟学妹受苦受难!!!逐一讲解发动机原理实验报告(1)

固体火箭发动机侵蚀燃烧测试实验 经过了愉快迷糊——哦不瑟瑟发抖——哦不痛不欲生的两天&#xff0c;终于和小伙伴们协力完成了西北工业大学航天学院发动机原理实验报告。具体的实验指导书均可在本人博客资源站下载。 固体火箭发动机侵蚀燃烧测试实验&#xff0c;嗯哼—— 实…

Python脚本打包成exe文件

我们很多时候写好一个python脚本之后&#xff0c;想要发给朋友&#xff0c;可是朋友没有安装python怎么办呢&#xff1f;别急&#xff0c;今天我就教你如何将python脚本打包成exe可执行文件&#xff0c;这样无论你的朋友有没有安装python&#xff0c;都可以运行你写好的程序&am…

ebay倒计时活动攻略,ebay倒计时活动怎么做的?——站斧浏览器

ebay倒计时活动攻略 在ebay上做倒计时活动时&#xff0c;可以参考以下攻略&#xff1a; 制定合理的ebay优惠方案。可以根据消费者的需求和购买习惯&#xff0c;制定不同的优惠方案&#xff0c;例如满减、折扣、赠品等。同时&#xff0c;要保证优惠方案的真实性和公平性&#…

Pushmall共享电商2023年 十二月模块开发优化完成

Pushmall共享电商2023年 十二月模块开发优化完成 十一月模块开发优化完成 智能名片功能开发计划完成 1、搜索查询&#xff1a;个人信息与公司信息标签。搜索查询&#xff1a;对接腾讯位置服务。 2、熟人地图&#xff1a;根据就近资源推荐&#xff0c;多少公里范围的人脉推荐 …

山西电力市场日前价格预测【2023-12-24】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-12-24&#xff09;山西电力市场全天平均日前电价为324.41元/MWh。其中&#xff0c;最高日前电价为456.41元/MWh&#xff0c;预计出现在18:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

MyBatis-Plus(一):根据指定字段更新或插入

根据指定字段更新或插入 1、概述2、实现方式2、总结 1、概述 MyBatis-Plus中提供了一个saveOrUpdate()方法&#xff0c;默认情况下可以根据主键是否存在进行更新或插入操作&#xff0c;但是实际场景中&#xff0c;根据指定字段进行更新或插入的情况也非常多见&#xff0c;今天…

推荐给前端开发的 5 款 Chrome 扩展

工欲善其事&#xff0c;必先利其器。Chrome 可能是前端开发中使用最多的浏览器。在日常开发中&#xff0c;下列几款 Chrome 扩展也许能让你的开发工作事半功倍 &#x1f680; Vue.js devtools ⚙️ vue 官方专为 vue 应用开发的调试工具。 通过使用它&#xff0c;你可以快速查看…

系列八、VMWare无法启动CentOS7问题排查 解决

一、VMWare无法启动CentOS7 1.1、问题描述 今天在测试代码的时候&#xff0c;需要用到Linux&#xff0c;然后就打开VMWare进行启动&#xff0c;但是启动的时候发现无法启动起来&#xff0c;报了一个如下的错误&#xff1a; 出现了问题那就要解决问题&#xff0c;然后想起来前几…

机器学习高级实践

&#x1f482; 个人网站:【 海拥】【神级代码资源网站】【办公神器】&#x1f91f; 基于Web端打造的&#xff1a;&#x1f449;轻量化工具创作平台&#x1f485; 想寻找共同学习交流的小伙伴&#xff0c;请点击【全栈技术交流群】 前言 在当今科技飞速发展的时代&#xff0c;机…

MySQL创建member表失败

最近在做一个项目&#xff0c;在台式机上可以跑通&#xff0c;也测试了各个已完成的接口&#xff0c;提交到了GitHub后想着用宿舍的电脑跑一下&#xff0c;在测试member表相关接口时就出错了。报了SQL语法错误&#xff0c;但SQL语句很简单&#xff0c;就根据手机号查询不至于出…

抖店定好品类赛道之后,怎么选品和快速出单?相关教程分享如下!

我是王路飞。 之前分享抖店流程相关内容时&#xff0c;我说过&#xff0c;类目选择大于一切&#xff0c;且要优于、重于选品。 至于定类目的标准&#xff0c;我之前也给你们说过&#xff0c;不要以自己个人喜好为标准去判断市场&#xff0c;也不要凭借自己以往认知和经验确定…

负载电容对晶振频率稳定性的影响

在电子系统中&#xff0c;晶振是产生精确频率的关键元件&#xff0c;而负载电容是影响晶振频率稳定性的重要因素之一。本文将深入探讨负载电容对晶振频率稳定性的影响&#xff0c;并分析如何通过合理的选择和设计来减小这种影响。 一、负载电容对晶振频率稳定性的影响 负载电…

openai最新探索:超级对齐是否可行?

前言 今天来介绍一篇openai最新的paper&#xff1a;弱到强的对齐。 openai专门成立了一个团队来做大模型的超级对齐即superhuman model&#xff0c;之前chatgpt取得成功依赖RLHF即依赖人类反馈&#xff0c;但是作者期望的superhuman model将会是一个能够处理各种复杂问题的强…

Nacos单机安装

采用的版本是Nacos Release 2.3.0 (Nov 30, 2023) alibaba/nacos GitHub 依赖于jdk&#xff0c;要先安装好jdk1.8。 修改配置 下载解压后&#xff0c;修改配置文件&#xff1a;conf/application.properties。 nacos.core.auth.plugin.nacos.token.secret.key 官方文档Na…

Android EditText代码设置不可编辑不可输入

XML布局中设置 直接设置android:editable"false"&#xff0c;虽然说该属性已经废弃&#xff0c;但是还是可以生效 但是EditText中没有对应的setEditable之类的方法来通过代码设置不可编辑 其他方式&#xff0c;通过设置focusable和focusableInTouchMode为false &l…

基于java的病房管理系统论文

摘 要 当下&#xff0c;如果还依然使用纸质文档来记录并且管理相关信息&#xff0c;可能会出现很多问题&#xff0c;比如原始文件的丢失&#xff0c;因为采用纸质文档&#xff0c;很容易受潮或者怕火&#xff0c;不容易备份&#xff0c;需要花费大量的人员和资金来管理用纸质文…

C语言中二维数组的存储和二进制数在底层的排列顺序

1 二维数组变量的存储 二维数组在内存中是按照先行后列的顺序存储的&#xff0c;即先存储第一行的所有元素&#xff0c;再存储第二行的所有元素&#xff0c;以此类推。每个元素在内存中占据一定的字节数&#xff0c;这个字节数由该元素的类型决定。例如&#xff0c;int类型的元…

Zabbix和Prometheus之间的优势

一、简介 1、Prometheus Kubernetes 自从 2012 年开源以来便以不可阻挡之势成为容器领域调度和编排的领头羊。 Kubernetes 是 Google Borg 系统的开源实现&#xff0c;于此对应 Prometheus 则是 Google BorgMon 的开源实现。 Prometheus 是由 SoundCloud 开发的开源监控报警…

Stable Diffusion系列(三):网络分类与选择

文章目录 网络分类模型基座模型衍生模型二次元模型2.5D模型写实风格模型 名称解读 VAELora嵌入文件放置界面使用 网络分类 当使用SD webui绘图时&#xff0c;为了提升绘图质量&#xff0c;可以多种网络混合使用&#xff0c;可选的网络包括了模型、VAE、超网络、Lora和嵌入。 …

HBase基础知识(三):HBase架构进阶、读写流程、MemStoreFlush、StoreFile Compaction、Region Split

1. 架构原理 1&#xff09;StoreFile 保存实际数据的物理文件&#xff0c;StoreFile以HFile的形式存储在HDFS上。每个Store会有一个或多个StoreFile&#xff08;HFile&#xff09;&#xff0c;数据在每个StoreFile中都是有序的。 2&#xff09;MemStore 写缓存&#xff0c;由于…