Linux下MySQL的简单使用

Linux下MySQL的简单使用

  • 导语
  • MySQL安装与配置
    • MySQL安装
    • 密码设置
  • MySQL管理
    • 命令
      • myisamchk
      • mysql
      • 其他
    • 常见操作
  • C语言访问MYSQL
    • 连接例程
    • 错误处理
    • 使用SQL
  • 总结
  • 参考文献

导语

这一章是MySQL的使用,一些常用的MySQL语句属于本科阶段内容,然后是C语言和MySQl之间的交互,可以看到C语言已经有成熟的和MySQL的接口

MySQL安装与配置

MySQL安装

MySQL的安装很简单,只需要执行几个shell命令就行,需要注意的是,对于Ubuntu新机器来说最好不要一开始就执行sudo apt update,因为很多包之间的依赖是复杂且未知的,如果直接全部更新可能会导致在跟书上同步实验时出问题(命令参考了ubuntu 23.10.1 mysql 安装)

sudo apt install mysql-server -y#这里就安装好了服务器
systemctl start mysql#开启mysql服务
systemctl status mysql#检查状态,如果出现mysql>就没问题

sudo mysul -u root mysql#进入mysql
ps -el | grep mysqld#可以看mysql是否启动

下面这个是备选方案,是在新机器上装的

sudo apt-get update
sudo apt-get install libmysqlclient-dev
mysql_config --cflags
mysql_config --libs

后两条命令是检测MySQL Connector/C是否安装完成,由于新版本的MySQL已经不支持书上的写法,所以需要安装这个包,正常应该显示如下图

在这里插入图片描述

之后直接安装服务器即可

sudo apt-get update
sudo apt-get install mysql-server

通过下面的程序验证安装是否成功

#include <stdio.h>
#include <mysql/mysql.h>

int main() {
    MYSQL *conn;
    conn = mysql_init(NULL);

    if (conn == NULL) {
        fprintf(stderr, "mysql_init() failed\n");
        return EXIT_FAILURE;
    }

    if (mysql_real_connect(conn, "localhost", "user", "password", "database", 0, NULL, 0) == NULL) {
        fprintf(stderr, "mysql_real_connect() failed: %s\n", mysql_error(conn));
        mysql_close(conn);
        return EXIT_FAILURE;
    }

    printf("Connected to the database successfully!\n");

    mysql_close(conn);
    return EXIT_SUCCESS;
}

执行的命令和结果如下

gcc -o test_program test_program.c $(mysql_config --cflags) $(mysql_config --libs)

在这里插入图片描述

密码设置

一开始的root是没有密码的,可以通过命令查看各用户的密码如下,可以看到root密码为空

在这里插入图片描述

这里需要注意的是新版的MySQL和老版的不一样,新版本的password列改成了authentication_string

可以执行命令来设置密码,修改后查看,可以看到root有密码,但是被MySQL加密过了,再次登录时直接回车发现无法识别,只有输入密码才能识别用户

在这里插入图片描述

这里我们删除除去root之外的默认用户,并且删除从localhost以外任何主机的登录

在这里插入图片描述

到此为止,我们有了一个运行的MySQL,该MySQL只有设定密码的root通过本地才能连接,为了方便后续的操作,这里创建一个普通用户rick,它将能用三种方法来连接MySQL(本地连接,从IP连接,从wiley.com域中任何机器连接)

首先为rick创建一个本地登录,这里书上给的代码太老了,已经不适配现在的MySQL,更改成了现在版本的,最新的 MySQL 版本中,GRANT 语句不再用于设置用户密码。密码应该通过单独的 CREATE USER 或 SET PASSWORD 语句来设置。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

通过三种不同的方式设置了三个用户,可以通过select命令展示,可以看到三种方式都成功了,并且rick的权利很大

在这里插入图片描述

MySQL管理

命令

所有命令都接受三个标准参数

-u 用于指定用户(用户名)
-p 用于提示密码(如果在命令行中未直接提供)
-h 用于指定主机(MySQL 服务器地址)

除了标准参数之外,每个命令还有自己的命令选项

myisamchk

通常情况下,myisamchk以创建的mysql用户运行并且工作目录为数据表在的目录中,常见的命令选项有

-c 检查表以发现错误
-e 执行扩展检查
-r 修复发现的错误

mysql

使用mysql可以不经过MySQL的控制台完成很多功能,通过在命令行最后添加数据库名称作为参数即可,可以通过 mysql --help | less来查看所有的命令行选项列表

其他

还有一些其他的命令,如mysqladmin、mysqlbug等,由于MySQL已经相对于书上更新很多了,所以很多命令已经过时,在此不多赘述

常见操作

书上提供的常见操作包括grant、revoke以及数据类型等,这些属于本科阶段SQL的基本内容,在此不再赘述,跳过

C语言访问MYSQL

连接例程

C语言连接MySQL需要先初始化一个连接句柄结构,然后再进行实际的连接,句柄通过mysql_init函数初始化,函数原型具体如下,mysql_init() 函数通常是在使用 MySQL 客户端 API 进行数据库编程时的第一个步骤。它为连接操作做了准备,确保在进行连接操作之前,连接对象处于一个已初始化的状态

MYSQL *mysql_init(MYSQL *);
//mysql:一个指向 MYSQL 结构体的指针。如果该指针为空,
//mysql_init() 将分配一个新的 MYSQL 结构体并返回它。如果提供了一个非空指针,它会用新的数据初始化该对象

真正与数据库进行连接的是mysql_real_connect函数,函数原型如下

MYSQL *mysql_real_connect(MYSQL *mysql, 
                          const char *host, 
                          const char *user, 
                          const char *passwd, 
                          const char *dbname, 
                          unsigned int port, 
                          const char *unix_socket, 
                          unsigned long client_flag);
//mysql是初始化之后的句柄

还有例程函数和关闭函数,在此不赘述

现在尝试创立一个数据库,向其中填入数据并通过C语言访问它

在这里插入图片描述

逐行输入对数据库的操作比较麻烦,并且容易出错,可以把要执行的命令单独做成文件,然后直接导入执行

-- Create the table children

CREATE TABLE children (
    childno int(11) NOT NULL auto_increment,
    fname varchar(30),
    age int(11),
    PRIMARY KEY (childno)
);

-- Populate the table 'children'

INSERT INTO children (childno, fname, age) VALUES (1, 'Jenny', 21);
INSERT INTO children (childno, fname, age) VALUES (2, 'Andrew', 17);
INSERT INTO children (childno, fname, age) VALUES (3, 'Gavin', 8);
INSERT INTO children (childno, fname, age) VALUES (4, 'Duncan', 6);
INSERT INTO children (childno, fname, age) VALUES (5, 'Emma', 4);
INSERT INTO children (childno, fname, age) VALUES (6, 'Alex', 15);
INSERT INTO children (childno, fname, age) VALUES (7, 'Adrian', 9);

在这里插入图片描述
在这里插入图片描述

可以看到数据都被成功插入了

之后可以通过上述函数来连接数据库,由于系统和包之间的依赖问题以及mysql的版本问题,导致这个程序无法在旧机上运行,暂时没有找到解决方案,在新机上可以运行,运行结果和程序如下

#include <stdlib.h>
#include <stdio.h>
#include <mysql/mysql.h>  // 包含新版 MySQL Connector/C 的头文件

int main(int argc, char *argv[])
{
    MYSQL *con;

    // 初始化 MySQL 连接句柄
    con = mysql_init(NULL);
    if (con == NULL) {
        fprintf(stderr, "mysql_init() failed\n");
        return EXIT_FAILURE;
    }

    // 连接数据库
    if (mysql_real_connect(con, "localhost", "rick", "111111", "foo", 0, NULL, 0) == NULL) {
        fprintf(stderr, "mysql_real_connect() failed\n");
        fprintf(stderr, "Error: %s\n", mysql_error(con));
        mysql_close(con);
        return EXIT_FAILURE;
    }

    // 输出连接成功状态
    printf("Connected successfully!\n");

    // 关闭连接
    mysql_close(con);
    return EXIT_SUCCESS;
}

在这里插入图片描述

执行的时候需要添加对应的inlcude路径和库文件路径

错误处理

MySQL使用一系列由连接句柄结构报告的返回码来获取错误信息,具体的函数原型如下

unsigned int mysql_errno(MYSQL *connection);
//返回错误码
char *mysql_error(MYSQL *connection);
//返回有意义的文本信息

这里是书上给出的一个例子以及运行结果,可以看到屏幕上输出了错误信息

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

int main(int argc, char *argv[]) {
    MYSQL my_connection;

    mysql_init(&my_connection);
    if (mysql_real_connect(&my_connection, "localhost", "rick", "I do not know", "foo", 0, NULL, 0)) {
        printf("Connection success\n");
        mysql_close(&my_connection);
    } else {
        fprintf(stderr, "Connection failed\n");
        if (mysql_errno(&my_connection)) {
            fprintf(stderr, "Connection error %d: %s\n",
                    mysql_errno(&my_connection), mysql_error(&my_connection));
        }
    }
    return EXIT_SUCCESS;
}

在这里插入图片描述

使用SQL

这里直接给出一些C语言执行SQL语句的函数原型和简单解释

int mysql_query(MYSQL *connection, const char *query);
//第一个是初始化后的句柄,第二个是sql语句,返回错误码
my_ulonglong mysql_affected_rows(MYSQL *connection);
//查询上一条指令运行后影响了多少行

书上给出了一个使用AUTO_INCREMENT的代码实例,下面是修改后的程序和运行结果,AUTO_INCREMENT对每次插入的数据分配一个新的id值并进行追踪

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

#define DB_HOST "localhost"
#define DB_USER "rick"  // 用户名 'rick'
#define DB_PASS "111111" // 数据库密码
#define DB_NAME "foo" // 数据库名称 'foo'

// 错误处理函数,减少冗余代码
void handle_error(MYSQL *connection, const char *message) {
    fprintf(stderr, "%s\nError %d: %s\n", message, mysql_errno(connection), mysql_error(connection));
    mysql_close(connection);
    exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
    MYSQL my_connection;
    MYSQL_RES *res_ptr;
    MYSQL_ROW sqlrow;
    int res;

    // 初始化 MySQL 连接对象
    mysql_init(&my_connection);

    // 连接数据库
    if (!mysql_real_connect(&my_connection, DB_HOST, DB_USER, DB_PASS, DB_NAME, 0, NULL, 0)) {
        handle_error(&my_connection, "Connection failed");
    }

    printf("Connection success\n");

    // 插入数据到表中
    res = mysql_query(&my_connection, "INSERT INTO children(fname, age) VALUES('Robert', 7)");
    if (res) {
        handle_error(&my_connection, "Insert error");
    } else {
        printf("Inserted %lu rows\n", (unsigned long)mysql_affected_rows(&my_connection));
    }

    // 查询最后插入的数据
    res = mysql_query(&my_connection, "SELECT LAST_INSERT_ID()");
    if (res) {
        handle_error(&my_connection, "SELECT error");
    }

    // 获取查询结果
    res_ptr = mysql_use_result(&my_connection);
    if (res_ptr) {
        // 迭代结果集并输出
        while ((sqlrow = mysql_fetch_row(res_ptr))) {
            printf("We inserted childno %s\n", sqlrow[0]);
        }
        // 释放结果集
        mysql_free_result(res_ptr);
    } else {
        fprintf(stderr, "Failed to retrieve result set.\n");
    }

    // 关闭连接
    mysql_close(&my_connection);

    return EXIT_SUCCESS;
}

可以看到成功插入了一行,并且通过LAST_INSERT_ID拿到了ID

在这里插入图片描述

这里附上书上数据对应的插入代码

-- Create the table children

CREATE TABLE children (
    childno INT(11) AUTO_INCREMENT NOT NULL PRIMARY KEY,
    fname VARCHAR(30),
    age INT
);

-- Populate the table 'children'

INSERT INTO children (fname, age) VALUES ('Jenny', 21);
INSERT INTO children (fname, age) VALUES ('Andrew', 17);
INSERT INTO children (fname, age) VALUES ('Gavin', 8);
INSERT INTO children (fname, age) VALUES ('Duncan', 6);
INSERT INTO children (fname, age) VALUES ('Emma', 4);
INSERT INTO children (fname, age) VALUES ('Alex', 15);
INSERT INTO children (fname, age) VALUES ('Adrian', 9);
INSERT INTO children (fname, age) VALUES ('Ann', 3);
INSERT INTO children (fname, age) VALUES ('Ann', 4);
INSERT INTO children (fname, age) VALUES ('Ann', 3);
INSERT INTO children (fname, age) VALUES ('Ann', 4);

除了上述两个基本的函数之外还有一些其他的函数,函数原型如下

MYSQL_RES *mysql_store_result(MYSQL *connection);
//从返回数据的语句中提取所有的数据,返回一个指向结果集的指针
my_ulonglong mysql_num_rows(MYSQL_RES *result);
//统计返回结果中的行数
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
//从结果集中提取一行,把这一行放在行机构里,每次使用一个
void mysql_data_seek(MYSQL_RES *result, my_ulonglong offset);
//在结果集中跳转,第二个参数是行号,设置下一个被fetch操作返回的行
MYSQL_ROW_OFFSET mysql_row_tell(MYSQL_RES *result);
//返回一个偏移值,表示结果集中的当前位置(不是行号)
void mysql_free_result(MYSQL_RES *result);
//对结果集的操作完成后,需要调用这个函数清理已经分配的对象
MYSQL_RES *mysql_use_result(MYSQL *connection);
//提取一行数据,返回指向对象的指针,不会缓存
//适合处理大数据量的查询结果,因为它允许逐行读取而不会将所有行一次性加载到内存中,这样可以有效减少内存的使用
unsigned int mysql_field_count(MYSQL *connection);
//获取最近一次查询的结果集中字段(列)的数量
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result);
//用于从查询结果的字段列表中获取每个字段的描述信息,类似于字段的元数据。
//返回一个指向 MYSQL_FIELD 结构体的指针,这个结构体包含了字段的详细信息(例如字段名、类型等)。

下面是书上给出的一个综合程序(用chatgpt优化了),基本上用到了上面的所有函数,还有运行结果和具体的程序解释

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

// MySQL 连接对象和结果集
MYSQL my_connection;
MYSQL_RES *res_ptr;
MYSQL_ROW sqlrow;

// 函数声明
void display_header();
void display_row();

int main(int argc, char *argv[]) {
    int res;
    int first_row = 1;  // 用于确保我们只显示一次表头

    // 初始化 MySQL 连接对象
    mysql_init(&my_connection);

    // 尝试连接到数据库
    if (mysql_real_connect(&my_connection, "localhost", "rick", "111111", "foo", 0, NULL, 0)) {
        printf("Connection success\n");

        // 执行 SQL 查询,选择年龄大于 5 的记录
        res = mysql_query(&my_connection, "SELECT childno, fname, age FROM children WHERE age > 5");
        if (res) {
            // 查询执行失败,打印错误信息
            fprintf(stderr, "SELECT error: %s\n", mysql_error(&my_connection));
        } else {
            // 使用 mysql_store_result() 获取结果集到内存
            res_ptr = mysql_store_result(&my_connection);
            if (res_ptr) {
                // 获取每行的数据并显示
                while ((sqlrow = mysql_fetch_row(res_ptr))) {
                    if (first_row) {
                        // 首次显示表头
                        display_header();
                        first_row = 0;
                    }
                    // 显示每行数据
                    display_row();
                }

                // 释放结果集资源
                mysql_free_result(res_ptr);
            } else {
                // 获取结果集失败,打印错误信息
                fprintf(stderr, "Failed to retrieve result set: %s\n", mysql_error(&my_connection));
            }
        }

        // 关闭数据库连接
        mysql_close(&my_connection);
    } else {
        // 连接失败,打印错误信息
        fprintf(stderr, "Connection failed\n");
        if (mysql_errno(&my_connection)) {
            fprintf(stderr, "Connection error %d: %s\n",
                    mysql_errno(&my_connection), mysql_error(&my_connection));
        }
    }

    return EXIT_SUCCESS;
}

// 显示表头,列出字段名称及其相关属性
void display_header() {
    MYSQL_FIELD *field_ptr;//获得列名

    printf("Column details:\n");
    while ((field_ptr = mysql_fetch_field(res_ptr)) != NULL) {
        // 显示字段的名称
        printf("\t Name: %s\n", field_ptr->name);
        printf("\t Type: ");

        // 判断字段类型并显示
        if (IS_NUM(field_ptr->type)) {//数字
            printf("Numeric field\n");
        } else {
            switch (field_ptr->type) {//字符串
                case FIELD_TYPE_VAR_STRING:
                    printf("VARCHAR\n");
                    break;
                case FIELD_TYPE_LONG:
                    printf("LONG\n");
                    break;
                default:
                    printf("Type is %d, check in mysql_com.h\n", field_ptr->type);
            }
        }

        // 显示字段的最大长度
        printf("\t Max width %ld\n", field_ptr->length);

        // 检查字段是否具有 AUTO_INCREMENT 属性
        if (field_ptr->flags & AUTO_INCREMENT_FLAG) {
            printf("\t Auto increments\n");
        }
        printf("\n");
    }
}

// 显示查询结果的每一行
void display_row() {
    unsigned int field_count;

    // 遍历每一列,打印其值
    field_count = 0;
    while (field_count < mysql_num_fields(res_ptr)) {//如果域名数量比当前索引大
        if (sqlrow[field_count]) {//sqlrow存了这一行的数据
            printf("%s ", sqlrow[field_count]);
        } else {
            printf("NULL ");
        }
        field_count++;
    }
    printf("\n");
}

在这里插入图片描述

还有更多的函数,在此不再赘述,可以查看MYSQL手册相关

总结

可以看到C语言已经有了很成熟的与MySQL交互的接口,并且大部分函数的使用是和MySQL版本不相关的,但实际在Ubuntu运行的时候还是需要注意MySQL的版本和包的问题,因为新版本的MySQL库修改了一些配置文件的位置和相关的依赖包

参考文献

  1. ubuntu 23.10.1 mysql 安装
  2. ChatGPT

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

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

相关文章

动态规划-背包问题——1049.最后一块石头的重量II

1.题目解析 题目来源 1049.最后一块石头的重量II——力扣 测试用例 2.算法原理 首先需要将该问题转化为0-1背包问题后再做分析 1.状态表示 根据数学中的知识我们知道将一个数字分为两个子数后求这两个子数的最小差值&#xff0c;那么就要求这两个子数尽可能接近于原数字的一…

MarkDown语法入门【保姆级教程】

MarkDown语法介绍 Markdown是一种轻量级标记语言 关于MarkDown语法的定义&#xff0c;官方已经有概述了&#xff1a; Markdown是一种轻量级标记语言&#xff0c;排版语法简洁&#xff0c;让人们更多地关注内容本身而非排版。它使用易读易写的纯文本格式编写文档&#xff0c;可…

5G与4G互通的桥梁:N26接口

5G的商用部署进程将是一个基于4G系统进行的长期的替换、升级、迭代的过程&#xff0c;4G系统是在过渡到5G全覆盖过程中&#xff0c;作为保障用户业务连续性体验这一目的的最好补充。 因此4G/5G融合组网&#xff0c;以及互操作技术将是各大运营商在网络演进中需要重点考虑的问题…

Transformer中的算子:其中Q,K,V就是算子

目录 Transformer中的算子 其中Q,K,V就是算子 一、数学中的算子 二、计算机科学中的算子 三、深度学习中的算子 四、称呼的由来 Transformer中的算子 其中Q,K,V就是算子 “算子”这一称呼源于其在数学、计算机科学以及深度学习等多个领域中的广泛应用和特定功能。以下是…

【UGUI】Unity 游戏开发:背包系统初始化道具教程

在游戏开发中&#xff0c;背包系统是一个非常常见的功能模块。它允许玩家收集、管理和使用各种道具。今天&#xff0c;我们将通过一个简单的示例来学习如何在 Unity 中初始化一个背包系统。我们将使用 Unity 2021.3.7 版本&#xff0c;并结合 C# 脚本来实现这一功能。 1. 场景…

Web端、App端的日志查看

开发和测试过程中&#xff0c;日志是定位问题的重要工具之一。无论是Web端还是App端&#xff0c;日志的作用如同医生的诊断报告&#xff0c;可以帮我们快速找到问题的根源。那么&#xff0c;如何高效查看并分析这些日志呢&#xff1f; 面对Web端和App端的不同特点&#xff0c;…

机器学习基础02_特征工程

目录 一、概念 二、API 三、DictVectorize字典列表特征提取 四、CountVectorize文本特征提取 五、TF-IDF文本1特征词的重要程度特征提取 六、无量纲化预处理 1、MinMaxScaler 归一化 2、StandardScaler 标准化 七、特征降维 1、特征选择 VarianceThreshold 底方差…

SpringCloud-使用FFmpeg对视频压缩处理

在现代的视频处理系统中&#xff0c;压缩视频以减小存储空间、加快传输速度是一项非常重要的任务。FFmpeg作为一个强大的开源工具&#xff0c;广泛应用于音视频的处理&#xff0c;包括视频的压缩和格式转换等。本文将通过Java代码示例&#xff0c;向您展示如何使用FFmpeg进行视…

释放高级功能:Nexusflows Athene-V2-Agent在工具使用和代理用例方面超越 GPT-4o

在不断发展的人工智能领域&#xff0c;Nexusflows 推出了 Athene-V2-Agent 作为其模型系列的强大补充。这种专门的代理模型设计用于在功能调用和代理应用中发挥出色作用&#xff0c;突破了人工智能所能达到的极限。 竞争优势 Athene-V2-Agent 不仅仅是另一种人工智能模型&…

自己动手写Qt Creator插件

文章目录 前言一、环境准备1.先看自己的Qt Creator IDE的版本2.下载源码 二、使用步骤1.参考原本的插件2.编写自定义插件1.cmakelist增加一个模块2.同理&#xff0c;qbs文件也增加一个3.插件源码 三、效果总结 前言 就目前而言&#xff0c;Qt Creator这个IDE&#xff0c;插件比…

网上商城系统设计与Spring Boot框架

3 系统分析 当用户确定开发一款程序时&#xff0c;是需要遵循下面的顺序进行工作&#xff0c;概括为&#xff1a;系统分析–>系统设计–>系统开发–>系统测试&#xff0c;无论这个过程是否有变更或者迭代&#xff0c;都是按照这样的顺序开展工作的。系统分析就是分析系…

【时间之外】IT人求职和创业应知【37】-AIGC私有化

目录 新闻一&#xff1a;2024智媒体50人成都会议暨每经20周年财经媒体峰会召开 新闻二&#xff1a;全球机器学习技术大会在北京召开 新闻三&#xff1a;区块链技术在金融领域的应用取得新突破 不知不觉的坚持了1个月&#xff0c;按照心理学概念&#xff0c;还要坚持2个月&am…

双子数(枚举素数)

#include <iostream> #include <vector> #include <cmath> using namespace std;vector<long long> generate(long long n) {vector<bool> is(n 1, true);// 标记是否为素数&#xff0c;初始值全为 truevector<long long> v;is[0] is[1]…

硬盘物理故障的表现、原因和解决方法全解析

硬盘作为计算机数据存储的核心部件&#xff0c;其稳定性和可靠性直接关系到数据的完整性和系统的正常运行。然而&#xff0c;硬盘在使用过程中可能会遇到各种故障&#xff0c;其中物理故障是最具破坏性和难以修复的一类。 一、硬盘物理故障的表现 1、异常声音 硬盘在运行时发…

如何查看电脑关机时间

要查看电脑的关机时间&#xff0c;可以按照以下步骤进行操作&#xff1a; 1. 打开事件查看器&#xff1a;按下键盘上的Windows键R键&#xff0c;然后在弹出的运行对话框中输入"eventvwr.msc"&#xff0c;并按下Enter键。 2. 在事件查看器窗口中&#xff0c;单击左侧窗…

【MyBatis源码】深入分析TypeHandler原理和源码

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 原始 JDBC 存在的问题自定义 TypeHandler 实现TypeHandler详解BaseTypeHandler类TypeReference类型参考器43个类型处理器类型注册表&a…

对话 OpenCV 之父 Gary Bradski:灾难性遗忘和持续学习是尚未解决的两大挑战 | Open AGI Forum

作者 | Annie Xu 采访、责编 | Eric Wang 出品丨GOSIM 开源创新汇 Gary Bradski&#xff0c;旺盛的好奇心、敢于冒险的勇气、独到的商业视角让他成为计算视觉、自动驾驶领域举重若轻的奠基者。 Gary 曾加入 Stanley 的团队&#xff0c;帮助其赢得 2005 年美国穿越沙漠 DA…

IDEA 开发工具常用快捷键有哪些?

‌在IDEA中&#xff0c;输出System.out.println()的快捷键是sout&#xff0c;输入后按回车&#xff08;或Tab键&#xff09;即可自动补全为System.out.println()‌‌。 此外&#xff0c;IDEA中还有一些其他常用的快捷键&#xff1a; 创建main方法的快捷键是psvm&#xff0c;代…

el-table合并单元格之后,再进行隔行换色的且覆盖表格行鼠标移入的背景色的实现

el-table 中有现成的隔行换色功能&#xff0c;只要增加 stripe 属性即可。但是如果有单元格合并的话&#xff0c;这个属性就不可用了。这时候我们就需要动点小心思了。 基于相同字段进行合并 单元格合并&#xff1a;基于表头中的某一列&#xff0c;具有相同值的个数相加进行合…

ChatGPT学术专用版,一键润色纠错+中英互译+批量翻译PDF

ChatGPT academic项目是由中科院团队基于ChatGPT专属定制。论文润色、语法检查、中英互译、代码解释等可一键搞定&#xff0c;堪称科研神器。 功能介绍 我们以3.5版本为例&#xff0c;ChatGPT学术版总共分为五个区域&#xff1a;输入控制区、输出对话区、基础功能区、函数插件…