Mysql 数据库APi 编程(c/c++)-1.0

MySQL数据库API库

访问MySQL服务器,这需要使用mysqlclient库,MySQL的大多数客户端API(除Java和.NET)都是通过这个库来和MySQL服务器通讯的,而这个库正是使用C语言编写的。

可使用mysql -V 命令查看当前系统内所使用的mysql数据库版本信息。数据库版本为5.6.20版。因此,我们可从帮助手册refman-5.6-en.a4.pdf入手,了解学习MySQL C API使用的一般信息。

从API手册23.8中可获取信息,MySQL客户端使用 libmysqlclient 库内部的函数访问MySQL服务器。因此我们在编程过程中,如若使用到库内的函数,必须链接函数库,对应的要找到头文件所在目录位置、函数库路径。以便我们在使用gcc编译工具时可以填充参数-I、-L、-l。

从手册中可获知,函数库名为mysqlclient。

因此我们使用命令find / -name libmysqlclient* 查找该库的路径。得到 /usr/lib64/mysql/libmysqlclient.a。

nm /usr/lib64/mysql/libmysqlclient.a命令可查看库内包含的函数。

编写hello应用链接函数库

编写一个hello.c应用程序,链接使用该库。  

用到头文件 <mysql.h> 可使用locate mysql.h查看其目录位置/usr/include/mysql/mysql.h。

编译引用了库的应用程序。

gcc hello.c -o hello -I/usr/include/mysql/ -L/usr/lib64/mysql/ -lmysqlclient

参见帮助手册refman-5.6-en.a4.pdf:23.8.4.3小节。

MySQL API常用函数

总体印象

使用MySQL库API函数的一般步骤:

a. 初始化. MYSQL *mysql_init(MYSQL *mysql)

b. 错误处理 unsigned int mysql_errno(MYSQL *mysql)

char *mysql_error(MYSQL *mysql);

c. 建立连接. MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd,const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag);

d. 执行SQL语句 int mysql_query(MYSQL *mysql, const char *stmt_str)

e. 获取结果 MYSQL_RES *mysql_store_result(MYSQL *mysql)

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)

f. 释放内存 void mysql_free_result(MYSQL_RES *result)

g. 关闭连接 void mysql_close(MYSQL *mysql)

初始化

编写程序测试 初始化函数MYSQL *mysql_init(MYSQL *mysql)。

其中有一种新数据类型MYSQL。可在头文件mysql.h → 263. typedef struct st_mysql {...} MYSQL;找到其定义。是一个结构体。

处理错误码的函数:unsigned int mysql_errno(MYSQL *mysql)

#include <stdio.h>

#include "mysql.h"



int main(void)

{

int i, ret = 0, num = 0;



MYSQL *mysql = mysql_init(NULL);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}

printf("init ok...\n");



return 0;

}

编译出错,原因是64位Linux环境下,动态库配置不完整。需手动指定编译所用的动态库。根据错误提示分析需要加入如下函数库:

1. __gxx_personality_v0    --> -lstdc++ 使用g++相关的环境

2. dlclose/dlopen/dlsym   --> -ldl 完成用一个程序加载其他动态库的作用。

3. pthread_* -->  -lpthread 线程库

4. `my_getsystime'/`clock_gettime' -->  -lrt librt.so是glibc中对real-time的支持库

使用ldd命令可以查看该可执行文件运行所依赖的库文件。

Makefile 管理

src = $(wildcard *.c)

target = $(patsubst %.c, %, $(src))

inc_path = /usr/include/mysql/

lib_path = /usr/lib64/mysql/

all: $(target)

%:%.c

gcc $< -o $@ -I$(inc_path) -L$(lib_path) -lmysqlclient -lstdc++ -lpthread -ldl -lrt

clean:

-rm -rf $(target)

.PHONY: all clean

注意:在测试makefile时,应先使用-n参数,检查无误再执行。

连接数据库关闭连接

依据proc猜想应该是一个类似于connect的函数,查看API文档发现:mysql_connect();但该函数已经过时,应该使用手册中推荐的mysql_real_connect函数取而代之。

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)

根据手册中的描述,我们可以使用基础的链接方式与MySQL数据库建立连接。

mysql = mysql_real_connect(mysql, "localhost", "root", "123456", "mydb61", 0, NULL, 0);

连接数据库成功。对表中数据进行访问,访问结束需调用void mysql_close(MYSQL *mysql) 函数关闭连接。该函数在断开连接的同时,还可以解除分配由mysql指向的连接句柄。

mysql_close(mysql);

读取数据

查询表数据

mysql_query函数不单单能完成查询sql的功能,还能完成非select语句在c程序中的执行。是一个十分万能的c程序中执行SQL语句的函数。并且该函数本身直接支持静态SQL。查询以\0结尾的字符串。如果语句中包含二进制数据,则需要调用mysql_real_query来执行查询语句。

函数原型:int mysql_query(MYSQL *mysql, const char *query); 成功返回0,失败返回非0

char *psql = "select * from emp";

ret = mysql_query(mysql, psql);

若执行的是UPDATE, DELETE或INSERT语句,则可通过mysql_affected_rows()获知受影响的记录数。

若执行的是SELECT语句,查询结束后,查询结果被保存在mysql句柄中。需要使用获取结果集的API函数将结果集获取出来。有两种方式可以获取结果集。

注意: mysql_query执行的SQL语句不应为语句添加终结分号(‘;’)或“\g”。

获取结果集

一种方式是通过mysql_store_result()将整个结果集全部取回来。另一种方式则是调用mysql_use_result()初始化获取操作,但暂时不取回任何记录。视结果集的条目数选择获取结果集的函数。两种方法均通过mysql_fetch_row()来访问每一条记录。

MYSQL_RES *mysql_store_result(MYSQL *mysql) 成功返回MYSQL_RES结果集指针,失败返回NULL。

MYSQL_RES是一个结构体类型,可以从mysql.h头文件中找到该结构体的定义:

mysql.h → 308. typedef struct st_mysql_res {...} MYSQL_RES;

整体获取的结果集,保存在 MYSQL_RES 结构体指针中,通过检查mysql_store_result()是否返回NULL,可检测函数执行是否成功:

MYSQL_RES *result = mysql_store_result(mysql);

if (result == NULL) {

ret = mysql_errno(mysql);

printf("mysql_store_result error: %s\n", mysql_error(mysql));

return ret;

}

该函数调用成功,则SQL查询的结果被保存在result中,但我们不清楚有多少条数据。所以应使用游标的方式将结果集中的数据逐条取出。

解析结果集

通过游标一行一行fetch结果集中的数据。根据游标使用的一般特性,应使用循环结构,到达结尾或者出错,返回NULL。

函数原型:MYSQL_ROW mysql_fetch_row(MYSQL_RES *result) 成功返回下一行的MYSQL_ROW结构。如果没有更多要检索的行或出现了错误,返回NULL。-----MYSQL_ROW定义在118行

select * from emp  可以看到emp表一共有8列数据。可以循环将每行上每一列的数据显示到屏幕。

MYSQL_ROW row = NULL; //typedef char **MYSQL_ROW;

while ((row = mysql_fetch_row(result))) {

printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7]);

}

MYSQL_ROW的本质是 typedef char ** MYSQL_ROW; 数据信息存储的形式如下图所示:

从mysql.h头文件可查看MYSQL_ROW定义: 118. typedef char **MYSQL_ROW; /*return data as array of string*/

从上图分析MYSQL_ROW为什么被定义为char**类型呢?推测mysq_fetch_row()的函数实现大致思想如下:

char **mysql_fetch_row(){

char **tmp = (char **) malloc(sizeof(char *) * 8);

for (i = 0; i < 8; i++) {

tmp[i] = (char *)malloc(50);

}

strcpy(tmp[0], "7369");

strcpy(tmp[1], "SMITH");

strcpy(tmp[2], "CLERK");

...

return tmp;

}
释放结果集

结果集处理完成,应调用对应的函数释放所占用的内存。

void mysql_free_result(MYSQL_RES *result); 成功释放参数传递的结果集。没有失败情况。

mysql_free_result(result);

思考:上述实现是直接在MySQL工具中数出列数。找寻能获取列数的API函数、获取表头的API函数。

获取列数

查看帮助手册可以看到,有两个函数具备获取列数的功能:

unsigned int mysql_field_count(MYSQL *mysql) 从mysql句柄中获取有多少列。

unsigned int mysql_num_fields(MYSQL_RES *result) 从返回的结果集中获取有多少列。

选择任意一种方式均可以完成该功能。

int num = mysql_field_count(connect);

while (row = mysql_fetch_row(result)) {

for (i = 0; i < num; i++) {

printf("%s\t", row[i]);

}

printf("\n");

//printf("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7]);

}

获取表头

获取表头的API函数同样有两个:

MYSQL_FIELD *mysql_fetch_fields(MYSQL_RES *result) 全部获取

MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result) 获取单个

MYSQL_FIELD也是一个结构体类型,其内部保存了选择列表项的信息,其中的name成员变量就保存着列名。可从头文件mysql.h中94-116行找到其定义。

MYSQL_FIELD *fields = NULL;

fields = mysql_fetch_fields(result); //得到表头的结构体数组

for (i = 0; i < num; i++) { //已通过 mysql_field_count 获取了总列数

printf("%s\t", fields[i].name); //每一列的列名保存在name成员中

    }

printf("\n");

示例程序

#include <stdio.h>

#include "mysql.h"

int main(void)

{

int i, ret = 0, num = 0;

char *psql = "select * from emp";  

MYSQL_RES *result = NULL;

MYSQL_FIELD *fields = NULL;

MYSQL_ROW row = NULL;



MYSQL *mysql = mysql_init(NULL);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}



printf("init ok...\n");

mysql = mysql_real_connect(mysql, "localhost", "root", "123456", "mydb61", 0, NULL, 0);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}



printf("connect ok...\n");

ret = mysql_query(mysql, psql);

if (ret != 0) {

printf("mysql_query error: %s\n", mysql_error(mysql));

return ret;

}



num = mysql_field_count(mysql);



result = mysql_store_result(mysql);

if (result == NULL) {

ret = mysql_errno(mysql);

printf("mysql_store_result error: %s\n", mysql_error(mysql));

return ret;

}



fields = mysql_fetch_fields(result);

for (i = 0; i < num; i++) {

printf("%10s\t", fields[i].name);

}

printf("\n");



while ((row = mysql_fetch_row(result))) {

for (i = 0; i < num; i++) {

printf("%10s\t", row[i]);

}

printf("\n");

}

mysql_free_result(result);

mysql_close(mysql);

return 0;

}

MySQL tools实现

依托我们所学习的MySQL基础类API函数,可以编写程序实现简单的sqlplus/mysql 工具的功能。

思路分析

  1. 仿照mysql工具,应在连接数据库成功之后,在一个while循环中不断的接受用户输入的SQL语句。定义char sqlbuf[1024] 存储用户输入的SQL语句。初始化该buf,并提示用户输入SQL语句。使用gets函数在循环中动态接收用户输入。

while (1) {

memset(sqlbuf, 0, sizeof(sqlbuf));

printf("\nYourSQL> ");

fgets(sqlbuf, sizeof(sqlbuf), stdin);

}

  1. 在mysql_query(connect, sqlbuf)之前,如果用户输入了“exit”那么程序直接结束。
  2. 在执行完 mysql_query(connect, sqlbuf)之后,应该判别用户输入的是否为select语句。如不是select语句不需要查询结果集、处理结果集等繁复操作。
  3. 如用户输入的是有结果集的SQL语句,将获取列数、获取结果集、获取表头、解析结果集、释放结果集等相关代码一起并入if (strncmp(sqlbuf, "select", 6))中。

测试注意:执行SQL语句时不要在结尾加“;”

程序实现

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "mysql.h"

int main(void)

{

int i, ret = 0, num = 0;

//char *psql = "select * from emp";  

char sqlbuf[1024];

MYSQL *mysql = mysql_init(NULL);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}

printf("init ok...\n");

mysql = mysql_real_connect(mysql, "localhost", "root", "123456", "mydb61", 0, NULL, 0);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}

printf("connect ok...\n");

ret = mysql_query(mysql, "set names utf8");

if (ret != 0) {

printf("mysql_query error: %s\n", mysql_error(mysql));

return ret;

}

while (1) { memset(sqlbuf, 0, sizeof(sqlbuf));

printf("YourSQL> ");

fgets(sqlbuf, sizeof(sqlbuf), stdin);



if (strncmp(sqlbuf, "exit", 4) == 0 || strncmp(sqlbuf, "quit", 4) == 0) {

break;

}



ret = mysql_query(mysql, sqlbuf);

if (ret != 0) {

printf("mysql_query error: %s\n", mysql_error(mysql));

return ret;

}



if (strncmp(sqlbuf, "select", 6) == 0 || strncmp(sqlbuf, "SELECT", 6) == 0) {

num = mysql_field_count(mysql);



MYSQL_RES *result = NULL;

result = mysql_store_result(mysql);

if (result == NULL) {

ret = mysql_errno(mysql);

printf("mysql_store_result error: %s\n", mysql_error(mysql));

return ret;

}



//打印表头

MYSQL_FIELD *fields = NULL;

fields = mysql_fetch_fields(result);

for (i = 0; i < num; i++) {

printf("%10s\t", fields[i].name);

}

printf("\n");



//解析结果集

MYSQL_ROW row = NULL; //typedef char **MYSQL_ROW;

while ((row = mysql_fetch_row(result))) {

for (i = 0; i < num; i++) {

printf("%10s\t", row[i]);

}

printf("\n");

}

mysql_free_result(result);

} else {

printf("\n--- not select sql---\n");

printf("affected: %ld\n", (long)mysql_affected_rows(mysql));

}

}

mysql_close(mysql);

return 0;

}

中文问题:

修改mysql_real_connect()参数,连接到表中有中文数据的数据库,如mydb2,执行程序,测试显示中文出现乱码。我们可以使用mysql_query函数来解决该问题。

在 while (1) 之前使用 ret = mysql_query(mysql, "set names utf8"); 来设置查询属性(也可以加到while中)。表示在查询的时候使用utf8的形式进行查询。

或者mysql_set_character_set(mysql, "utf8");

获取当前使用的字符集:  const char *mysql_character_set_name(MYSQL *mysql)

预处理类API函数:

该类函数解决问题:处理带有占位符的SQL语句。insert into table111(col1, col2, col3) values(?, ?, ?);

这种SQL语句由两部分组成,一部分是SQL语句体模型部分,另一部分是?所匹配的值。

性能、调优是数据库编程永恒不变的主题!如果能把SQL语句框架预先处理好,当真正要执行SQL语句时只需要发送对应的参数到对应的SQL框架中,就能提高客户端访问服务器的速度,且数据量小,可以减少网络通信量,提高数据传输效率高。

元数据(Metadata):又称中介数据、中继数据,为描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能。

根据API提供的案例学习该部分内容。主要有 4 个函数:

mysql_stmt_init() 初始化预处理环境句柄。 返回一个结构体指针 MYSQL_STMT *stmt

mysql_stmt_prepare() 向上面句柄中添加SQL语句,带有 (?,?,?) 占位符

mysql_stmt_param_count() 求绑定变量的个数(辅助函数), 有多少个'?'就返回多少

mysql_stmt_bind_param() 将?对应的实参,设置到预处理环境句柄中

mysql_stmt_execute() 执行预处理的SQL语句

在不熟悉这套API函数的情况下,如何能快速的找到一个完整的案例,使用这套函数呢?分析:在以上4个过程中,哪个最重要呢?找到它,去查看API文档!发现有对应的demo程序。将该demo导入到我们的程序中,运行,观察它的作用。

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include "mysql.h"

#define STRING_SIZE 50

#define DROP_SAMPLE_TABLE "DROP TABLE IF EXISTS test_table"

#define CREATE_SAMPLE_TABLE "CREATE TABLE test_table(col1 INT,\

                                                 col2 VARCHAR(40),\

                                                 col3 SMALLINT,\

                                                 col4 TIMESTAMP)"

#define INSERT_SAMPLE "INSERT INTO test_table(col1,col2,col3) VALUES(?,?,?)"

int main(void)

{

int ret = 0;



MYSQL *mysql = mysql_init(NULL);

if (mysql == NULL) {

//unsigned int mysql_errno(MYSQL *mysql)

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}

printf("init ok...\n");

mysql = mysql_real_connect(mysql, "localhost", "root", "123456", "mydb61", 0, NULL, 0);

if (mysql == NULL) {

ret = mysql_errno(mysql);

printf("mysql_init err:%d\n", ret);

return ret;

}

printf("connect ok...\n");

以下为demo源码

MYSQL_STMT    *stmt;

MYSQL_BIND    bind[3];

my_ulonglong  affected_rows;

int           param_count;

short         small_data;

int           int_data;

char          str_data[STRING_SIZE];

unsigned long str_length;

my_bool       is_null;

if (mysql_query(mysql, DROP_SAMPLE_TABLE))

{

fprintf(stderr, " DROP TABLE failed\n");

fprintf(stderr, " %s\n", mysql_error(mysql));

exit(0);

}

if (mysql_query(mysql, CREATE_SAMPLE_TABLE))

{

fprintf(stderr, " CREATE TABLE failed\n");

fprintf(stderr, " %s\n", mysql_error(mysql));

exit(0);

}

/* Prepare an INSERT query with 3 parameters */

/* (the TIMESTAMP column is not named; the server */

/*  sets it to the current date and time) */

stmt = mysql_stmt_init(mysql);

if (!stmt)

{

fprintf(stderr, " mysql_stmt_init(), out of memory\n");

exit(0);

}

if (mysql_stmt_prepare(stmt, INSERT_SAMPLE, strlen(INSERT_SAMPLE)))

{

fprintf(stderr, " mysql_stmt_prepare(), INSERT failed\n");

fprintf(stderr, " %s\n", mysql_stmt_error(stmt));

exit(0);

}

fprintf(stdout, " prepare, INSERT successful\n");

/* Get the parameter count from the statement */

param_count= mysql_stmt_param_count(stmt);

fprintf(stdout, " total parameters in INSERT: %d\n", param_count);



if (param_count != 3) /* validate parameter count */

{

fprintf(stderr, " invalid parameter count returned by MySQL\n");

exit(0);

}



/* Bind the data for all 3 parameters */



memset(bind, 0, sizeof(bind));



/* INTEGER PARAM */

/* This is a number type, so there is no need to specify buffer_length */

bind[0].buffer_type= MYSQL_TYPE_LONG;

bind[0].buffer= (char *)&int_data;

bind[0].is_null= 0;

bind[0].length= 0;



/* STRING PARAM */

bind[1].buffer_type= MYSQL_TYPE_STRING;

bind[1].buffer= (char *)str_data;

bind[1].buffer_length= STRING_SIZE;

bind[1].is_null= 0;

bind[1].length= &str_length;



/* SMALLINT PARAM */

bind[2].buffer_type= MYSQL_TYPE_SHORT;

bind[2].buffer= (char *)&small_data;

bind[2].is_null= &is_null;

bind[2].length= 0;



/* Bind the buffers */

if (mysql_stmt_bind_param(stmt, bind))

{

fprintf(stderr, " mysql_stmt_bind_param() failed\n");

fprintf(stderr, " %s\n", mysql_stmt_error(stmt));

exit(0);

}

/* Specify the data values for the first row */

int_data= 10;             /* integer */

strncpy(str_data, "MySQL", STRING_SIZE); /* string  */

str_length= strlen(str_data);



/* INSERT SMALLINT data as NULL */

is_null= 1;



/* Execute the INSERT statement - 1*/

if (mysql_stmt_execute(stmt))

{

fprintf(stderr, " mysql_stmt_execute(), 1 failed\n");

fprintf(stderr, " %s\n", mysql_stmt_error(stmt));

exit(0);

}



/* Get the total number of affected rows */

affected_rows= mysql_stmt_affected_rows(stmt);

fprintf(stdout, " total affected rows(insert 1): %lu\n",

            (unsigned long) affected_rows);



if (affected_rows != 1) /* validate affected rows */

{

fprintf(stderr, " invalid affected rows by MySQL\n");

exit(0);

}



/* Specify data values for second row, then re-execute the statement */



int_data= 1000;

strncpy(str_data, "The most popular Open Source database", STRING_SIZE);

str_length= strlen(str_data);

small_data= 1000;         /* smallint */

is_null= 0;               /* reset */



/* Execute the INSERT statement - 2*/

if (mysql_stmt_execute(stmt))

{

fprintf(stderr, " mysql_stmt_execute, 2 failed\n");

fprintf(stderr, " %s\n", mysql_stmt_error(stmt));

exit(0);

}



/* Get the total rows affected */

affected_rows= mysql_stmt_affected_rows(stmt);

fprintf(stdout, " total affected rows(insert 2): %lu\n",

            (unsigned long) affected_rows);



if (affected_rows != 1) /* validate affected rows */

{

fprintf(stderr, " invalid affected rows by MySQL\n");

exit(0);

}



/* Close the statement */

if (mysql_stmt_close(stmt))

{

fprintf(stderr, " failed while closing the statement\n");

fprintf(stderr, " %s\n", mysql_stmt_error(stmt));

exit(0);

}

mysql_close(mysql);



printf("hello mysql...\n");



return 0;

}

注意:bind --> mysql.h下 MYSQL_BIND结构体  bind[3]; 是一个结构体数组。有3个‘?’占位符,所以用三个结构体(数组)来对应保存信息。0->第一列;1->第二列;2->第三列。

mysql.h中查找 MYSQL_BIND 结构体原型。对比:select * from teat_table;  和 desc test_table; 的查询结果。

帮助理解bind的小程序框架:

typedef struct xxx{

char *p1;

char *p2;

char *p3;

} MYSQL_BIND;

void saveXXXInfo(MYSQL_BIND *bind, int num)

{

insert into test_table valudes(bind[0].p2, bind[1].p3, bind[2].p1);

}

int main(void)

{

MYSQL_BIND bind[3];

bind[0].p1 = "类型1"; //第一列

bind[0].p2 = "10";

bind[0].p3 = "其他数据";



bind[1].p1 = "类型"; //第二列

bind[1].p2 = "数据";

bind[1].p3 = "描述";



bind[2].p1 = "p1p1p1"; //第三列     

//第四列是时间戳,不需要用户使用?来指定,直接使用了系统时间。

bind[2].p2 = "数据";

bind[2].p3 = "其他限定条件";



saveXXXInfo(bind, 3);

}

 

 

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

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

相关文章

C# Onnx yolov8n csgo player detection

目录 效果 模型信息 项目 代码 下载 C# Onnx yolov8n csgo player detection 效果 模型信息 Model Properties ------------------------- date&#xff1a;2023-12-22T15:01:08.014205 author&#xff1a;Ultralytics task&#xff1a;detect license&#xff1a;AGPL-…

从0到1部署gitlab自动打包部署项目

本文重点在于配置ci/cd打包 使用的是docker desktop 第一步安装docker desktop Docker简介 Docker 就像一个盒子&#xff0c;里面可以装很多物件&#xff0c;如果需要某些物件&#xff0c;可以直接将该盒子拿走&#xff0c;而不需要从该盒子中一件一件的取。Docker中文社区、…

集合论:二元关系(1)

集合论这一章内容很多&#xff0c;重点是二元关系中关系矩阵&#xff0c;关系图和关系性质:自反、反自反、对称、反对称、传递以及关系闭包的运算&#xff0c;等价关系&#xff0c;偏序关系&#xff0c;哈斯图&#xff0c;真吓人&#xff01; 1.笛卡儿积 由两个元素x和y按照一…

Opencv计算机视觉的分类

传统的计算机视觉可以使用Opencv等Python库&#xff0c;对图像进行简单的操作&#xff0c;例如对图像缩放、滤波、阈值分割等等。对于计算机来说&#xff0c;一张彩色图片就是一个三通道的矩阵&#xff0c;分别对应红绿蓝&#xff08;RGB&#xff09;三种颜色&#xff0c;通过改…

计算机网络 应用层上 | 域名解析系统DNS 文件传输协议FTP,NFS 万维网URL HTTP HTML

文章目录 1 域名系统DNS1.1 域名vsIP&#xff1f;1.2 域名结构1.3 域名到IP的解析过程域名服务器类型 2 文件传送协议2.1 FTP 文件传输协议2.2 NFS 协议2.3 简单文件传送协议 TFTP 3 万维网WWW3.1 统一资源定位符URL3.2 超文本传送协议HTTP3.2.1 HTTP工作流程3.2.2 HTTP报文结构…

生物系统学中的进化树构建和分析R工具包V.PhyloMaker2的介绍和详细使用

V.PhyloMaker2是一个R语言的工具包&#xff0c;专门用于构建和分析生物系统学中的进化树&#xff08;也称为系统发育树或phylogenetic tree&#xff09;。以下是对V.PhyloMaker2的一些基本介绍和使用说明&#xff1a; 论文介绍&#xff1a;V.PhyloMaker2: An updated and enla…

混合精度训练(MAP)

一、介绍 使用精度低于32位浮点数的数字格式有很多好处。首先&#xff0c;它们需要更少的内存&#xff0c;可以训练和部署更大的神经网络。其次&#xff0c;它们需要更少的内存带宽&#xff0c;这加快了数据传输操作。第三&#xff0c;数学运算在降低精度的情况下运行得更快&a…

web架构师编辑器内容-创建业务组件和编辑器基本行为

编辑器主要分为三部分&#xff0c;左侧是组件模板库&#xff0c;中间是画布区域&#xff0c;右侧是面板设置区域。 左侧是预设各种组件模板进行添加 中间是使用交互手段来更新元素的值 右侧是使用表单的方式来更新元素的值。 大致效果&#xff1a; 左侧组件模板库 最初的模板…

博客引擎 Hexo 入门介绍+安装笔记

Hexo Hexo is a fast, simple & powerful blog framework. 一直使用的是 jekyll&#xff0c;文章越写越多&#xff0c;不太好管理。是时候换个博客尝试一下。 Prepare blog zh_CN 本机为 MAC。不同系统会略有不同&#xff0c;但是大同小异。 Node.js 必须。 作用&…

LLM之RAG实战(八)| 使用Neo4j和LlamaIndex实现多模态RAG

人工智能和大型语言模型领域正在迅速发展。一年前&#xff0c;没有人使用LLM来提高生产力。时至今日&#xff0c;很难想象我们大多数人或多或少都在使用LLM提供服务&#xff0c;从个人助手到文生图场景。由于大量的研究和兴趣&#xff0c;LLM每天都在变得越来越好、越来越聪明。…

网站使用https认证

随着网络的普及和依赖程度的增加&#xff0c;网站安全性问题也日益凸显。为了确保用户和网站之间的数据传输安全&#xff0c;采用HTTPS认证已经变得至关重要。 1.数据安全是首要任务 在互联网上&#xff0c;信息传输是网站运作的基础。然而&#xff0c;未加密的传输容易受到中…

计算机网络——计算机网络的概述(一)

前言&#xff1a; 面对马上的期末考试&#xff0c;也为了以后找工作&#xff0c;需要掌握更多的知识&#xff0c;而且我们现实生活中也已经离不开计算机&#xff0c;更离不开计算机网络&#xff0c;今天开始我们就对计算机网络的知识进行一个简单的学习与记录。 目录 一、什么…

案例136:基于微信小程序的公交信息在线查询系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…

使用Velero备份、恢复k8s集群上的资源

一、Velero简介 Velero提供备份和恢复 Kubernetes 集群资源和持久卷的工具。 Velero功能&#xff1a; 对群集进行备份&#xff0c;并在丢失时进行还原。将集群资源迁移到其他集群。 Velero 包括&#xff1a; 在群集上运行的服务器在本地运行的命令行客户端 开源地址&…

【终极教程】Cocos2dx服务端重构(优化cocos2dx服务端)

文章目录 概述问题概述1. 代码混淆代码加密具体步骤测试和配置阶段IPA 重签名操作步骤2. 缺乏文档3. 缺乏推荐的最佳实践4. 性能问题 总结 概述 Cocos2dx是一个非常流行的跨平台游戏引擎&#xff0c;开发者可以使用这个引擎来开发iOS、Android和Web游戏。同时&#xff0c;Coco…

SSTI模板注入(Flask+Jinja2)

文章目录 一、前置知识1.1 模板引擎1.2 渲染 二、SSTI模板注入2.1 原理2.2 沙箱逃逸沙箱逃逸payload讲解其他重要payload 2.3 过滤绕过 三、PasecaCTF-2019-Web-Flask SSTI 一、前置知识 1.1 模板引擎 模板引擎&#xff08;这里特指用于Web开发的模板引擎&#xff09;是为了使…

nodejs+vue+ElementUi会员制停车场车位系统

总之&#xff0c;智能停车系统使停车场管理工作规范化&#xff0c;系统化&#xff0c;程序化&#xff0c;避免停车场管理的随意性&#xff0c;提高信息处理的速度和准确性&#xff0c;能够及时、准确、有效的查询和修改停车场情况。 三、任务&#xff1a;小组任务和个人任务 智…

Linux中vim中进行替换/批量替换

Linux中vim中进行替换/批量替换 一:在 Vim 中进行文本替换的操作是通过使用 :s&#xff08;substitute&#xff09;命令来实现的。这里是一些基本的替换命令 替换当前行的第一个匹配项: :s/old/new/这将替换当前行中第一个出现的 “old” 为 “new”。 替换当前行的所有匹配项…

工作实践篇 Flink(一:flink提交jar)

一&#xff1a;参数 flink 模式 – standalone 二&#xff1a;步骤 1. 将本地测试好的代码进行本地运行。确保没问题&#xff0c;进行打包。 2. 找到打好的jar包&#xff0c;将jar包上传到对应的服务器。 3. 执行flink命令&#xff0c;跑代码。 /opt/flink/flink-1.13.6/bi…

ASP.Net实现姓名添加查询(三层架构)

目录 演示功能&#xff1a; 点击启动生成页面 点击搜索模糊查询 点击添加跳转新界面 点击Button添加姓名 步骤&#xff1a; 1、建文件 2、添加引用关系 3、根据数据库中的列写Models下的XueshengModels类 4、DAL下的DBHelper&#xff08;对数据库进行操作&#xff09;…
最新文章