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

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

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]$

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网工内推 | 美团、中通快递,网络运维,最高30K*15薪

01 美团 招聘岗位&#xff1a;网络运维开发工程师 职责描述&#xff1a; 1.负责新零售业务门店/仓库网络的日常运维、故障处理、应急响应&#xff0c;保障网络及相关业务的稳定运行&#xff0c;处理突发事件、对疑难问题进行跟踪并最终解决。 2.负责新零售业务门店/仓库网络的…

Neural Network——神经网络

1.feature reusing——特征复用 1.1 什么是特征复用 回顾我们之前所学习的模型&#xff0c;本质上都是基于线性回归&#xff0c;但却都可以运用于非线性相关的数据&#xff0c;包括使用了如下方法 增加更多的特征产生新的特征&#xff08;多项式回归&#xff09;核函数 在本身…

router全局守卫beforeEach导致infinite redirect in navigation guard 问题

问题背景 路由加了全局守卫之后&#xff0c;报错&#xff1a; 分析原因 内部判断&#xff0c;导致路由产生了死循环 错误代码 router.beforeEach((to, from, next) > {if (store.getters.token) {if (to.path /login) {next(/)} else {next()}} else {next(/login)} })…

MeterSphere files 任意文件读取漏洞复现 (CVE-2023-25573)

0x01 产品简介 MeterSphere 是一站式开源持续测试平台, 涵盖测试跟踪、接口测试、UI 测试和性能测试等功能,全面兼容 JMeter、Selenium 等主流开源标准。 0x02 漏洞概述 MeterSphere /api/jmeter/download/files 路径文件存在文件读取漏洞,攻击者可通过该漏洞读取系统重要…

卸载MySQL——Windows

1. 停止MySQL服务 winR 打开运行&#xff0c;输入 services.msc 点击 “确定” 调出系统服务。 我这里只有一个&#xff0c;只要是以MySQL开头的全部停止 2. 卸载MySQL相关组件 打开控制面板 —> 卸载程序 —> 卸载MySQL相关所有组件 3. 删除MySQL安装目录 一般是C:\P…

win11 wsl2安装

参考视频 微软商店直接下载以后&#xff08;提前打开虚拟化&#xff0c;linux子系统选项&#xff09; 设置为wsl2 wsl --set-default-version 2然后直接打开即可 可能遇到的问题 WSL2 占位程序接收到错误数据。 Error code: Wsl/Service/0x800706f7 管理员权限启动,重启 …

蓝桥杯嵌入式——串口

CUBE里配置成异步模式&#xff0c;设置波特率&#xff0c;打开中断&#xff08;先配置LCD再配置串口&#xff09;&#xff1a; 串口发送 main.c #include "string.h" char temp[20]; sprintf(temp,"Hello World\r\n"); HAL_UART_Transmit(&huart1,(…

AutoSAR(基础入门篇)1.3-AutoSAR的概述

目录 一、到底什么是AutoSAR 1、大白话来讲 2、架构上来讲 应用软件层(APPL) 实时运行环境&#xff08;RTE&#xff09; 基础软件层(BSW) 3、工具链上来讲 二、AutoSAR的目标 一、到底什么是AutoSAR 1、大白话来讲 AUTOSAR 就是AUTomotive Open System ARchitecture的…

文件操作学习总结

磁盘上的⽂件是⽂件。 但是在程序设计中&#xff0c;我们⼀般谈的⽂件有两种&#xff1a; 程序⽂件、数据⽂件 &#xff08;从⽂件功能的⻆度来分类 的&#xff09;。 程序⽂件 &#xff1a; 程序⽂件包括源 程序⽂件&#xff08;后缀为.c&#xff09; , ⽬标⽂件&#xff0…

【操作系统】|浅谈IO模型

I/O&#xff08;Input/Output&#xff09;指的是应用程序与外部环境之间的数据交换。I/O 操作涉及从外部设备&#xff08;如硬盘、网络、键盘、鼠标等&#xff09;读取数据或向外部设备写入数据。 操作系统启动后&#xff0c;将会开启保护模式&#xff1a;将内存分为内核空间&…

Linux I/O神器之io_uring

io_uring 是 Linux 于 2019 年加入到内核的一种新型异步 I/O 模型&#xff0c;io_uring 主要为了解决 原生AIO&#xff08;Native AIO&#xff09; 存在的一些不足之处。下面介绍一下原生 AIO 的不足之处&#xff1a; 系统调用开销大&#xff1a;提交 I/O 操作和获取 I/O 操作…

Unity中 URP 下的棋盘格Shader

文章目录 前言一、制作思路法1&#xff1a;使用纹理采样后&#xff0c;修改重铺效果法2&#xff1a;计算实现 二、粗略计算实现棋盘格效果1、使 uv.x < 0.5 区域 0 。反之&#xff0c; 0.52、使 uv.y < 0.5 区域 0 。反之&#xff0c; 0.53、使两个颜色相加4、取小数…

Selenium Wire - 扩展 Selenium 能够检查浏览器发出的请求和响应

使用 Selenium 进行自动化操作时&#xff0c;会存在很多的特殊场景&#xff0c;比如会修改请求参数、响应参数等。 本篇将介绍一款 Selenium 的扩展&#xff0c;即能够检查浏览器发出的请求和响应 - Selenium Wire。 简介 Selenium Wire 扩展了 Selenium 的 Python 绑定&…

修复泰坦陨落2缺少msvcr120.dll的5种方法,亲测有效

游戏《泰坦陨落2》缺少msvcr120.dll的问题困扰着许多玩家。这个问题的主要原因可能是系统环境不完整、软件或游戏版本不匹配、DLL文件丢失或损坏以及杀毒软件误判等。msvcr120.dll是Microsoft Visual C 2013 Redistributable的一个组件&#xff0c;它包含了许多运行库文件&…

JavaScript中的await-async-事件循环-异常处理

一、async、await 1.异步函数 async function async关键字用于声明一个异步函数&#xff1a; async是asynchronous单词的缩写&#xff0c;异步、非同步&#xff1b; sync是synchronous单词的缩写&#xff0c;同步、同时&#xff1b; async异步函数可以有很多中写法&#x…

Java 数据结构篇-实现堆的核心方法与堆的应用(实现 TOP-K 问题:最小 k 个数)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 堆的说明 2.0 堆的成员变量及其构造方法 3.0 实现堆的核心方法 3.1 实现堆的核心方法 - 获取堆顶元素 peek() 3.2 实现堆的核心方法 - 下潜 down(int i) 3.3 实…

关键点检测_labelme标注的json,随机裁剪(添加偏移相当于数据增强)

import json import os import numpy as np import cv2 import glob import csv import random#通过表格获取csv # def csv_tws(root, name): # csv_path = root+"/csv/{}.png.csv".format(name)

Java并发(二十)----synchronized原理进阶

1、小故事 故事角色 老王 - JVM 小南 - 线程 小女 - 线程 房间 - 对象 房间门上 - 防盗锁 - Monitor-重量级锁 房间门上 - 小南书包 - 轻量级锁 房间门上 - 刻上小南大名 - 偏向锁 -对象专属于某个线程使用 批量重刻名 - 一个类的偏向锁撤销到达 20 阈值 -批量重偏向 …

linux之Samba服务器

环境&#xff1a;虚拟机CENTOS 7和 测试机相通 一、Samba服务器_光盘共享&#xff08;匿名访问&#xff09; 1.在虚拟机CENTOS 7安装smb服务&#xff0c;并在防火墙上允许samba流量通过 2. 挂载光盘 3.修改smb.conf配置文件&#xff0c;实现光盘匿名共享 4. 启动smb服务 5.在…

Postman使用总结--生成测试报告

1.执行生成的命令格式 newman run 用例集文件 .json -e 环境文件 .json -d 数据文件 .json/.csv -r htmlextra --reporter- htmlextra-export 测试报告名 .html -e 和 -d 是 非必须的。 如果没有使用 环境&#xff0c;不需要指定 -e 如果没有使用 数据…