C 言語ライブラリを使用して、mysql データを追加、削除、変更、確認してみてください。
1. 新しいデータベースとテーブルを追加する
最初はデータベースにパスワードもユーザーも設定されていなかったので、root ユーザーで直接ログインしました。
mysql -uroot;
データベースを作成しhello
、このデータベースを入力します
create database hello;
use hello;
stu_student
データテーブルを作成する
create table stu_test(
id int primary key auto_increment,
name varchar(30),
age int,
score decimal(4,2)
);
最初の ID のタイプは int で、 に設定されておりauto_increment
、データが挿入されるたびに増加します。
name は文字列型、age は int 型、score は浮動小数点型です。
decimal(4,2) 表示的范围是 -99.99 ~ 99.99
decimal(4,2)unsigned 表示的范围是 0 ~ 99.99
ここまでで事前準備は完了です。
2. インターフェースの簡単な理解
コメントに従って、mysql ライブラリのいくつかのインターフェイスを簡単に理解しましょう
//头文件
#include <mysql/mysql.h>
//Mysql操作句柄初始化
MYSQL *mysql_init(MYSQL *mysql);
//参数为空则动态申请句柄空间进行初始化
//失败返回NULL
//连接mysql服务器
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--初始化完成的句柄
//host---连接的mysql服务器的地址
//user---连接的服务器的用户名
//passwd-连接的服务器的密码
//db ----默认选择的数据库名称
//port---连接的服务器的端口: 默认0是3306端口
//unix_socket---通信管道文件或者socket文件,通常置NULL
//client_flag---客户端标志位,通常置0
//返回值:成功返回句柄,失败返回NULL
//设置当前客户端的字符集
int mysql_set_character_set(MYSQL *mysql, const char *csname)
//mysql--初始化完成的句柄
//csname--字符集名称,通常:"utf8"
//返回值:成功返回0, 失败返回非0
//选择操作的数据库
int mysql_select_db(MYSQL *mysql, const char *db)
//mysql--初始化完成的句柄
//db-----要切换选择的数据库名称
//返回值:成功返回0, 失败返回非0
//执行sql语句
int mysql_query(MYSQL *mysql, const char *stmt_str)
//mysql--初始化完成的句柄
//stmt_str--要执行的sql语句
//返回值:成功返回0, 失败返回非0
//保存查询结果到本地
MYSQL_RES *mysql_store_result(MYSQL *mysql)
//mysql--初始化完成的句柄
//返回值:成功返回结果集的指针, 失败返回NULL
//获取结果集中的行数与列数
uint64_t mysql_num_rows(MYSQL_RES *result);
//result--保存到本地的结果集地址
//返回值:结果集中数据的条数;
unsigned int mysql_num_fields(MYSQL_RES *result)
//result--保存到本地的结果集地址
//返回值:结果集中每一条数据的列数;
//遍历结果集
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
//result--保存到本地的结果集地址
//返回值:实际上是一个char **的指针,将每一条数据做成了字符串指针数组 row[0]-第0列 row[1]-第1列
//并且这个接口会保存当前读取结果位置,每次获取的都是下一条数据
//释放结果集
void mysql_free_result(MYSQL_RES *result)
//result--保存到本地的结果集地址
//返回值:void
//关闭数据库客户端连接,销毁句柄:
void mysql_close(MYSQL *mysql)
//获取mysql接口执行错误原因
const char *mysql_error(MYSQL *mysql)
mysql は動的ライブラリであるため、コンパイル時にライブラリ名にリンクを追加する必要があります。
g++ test.cpp -o test -lmysqlclient
私のシステムでは、MySQL ライブラリは/usr/lib64
ディレクトリ内にあるため、ライブラリへのパスを指定する必要はありません。システムにこのディレクトリがない場合は、ライブラリのインストールへのパスを見つけ、コマンドを使用してパスを指定するlibmysqlclient.so
必要があります。-L
g++ test.cpp -o test -L/path/to/mysql/lib -lmysqlclient
3.コード
コードの作成を開始し、mysql のさまざまなインターフェイスについて段階的に学習します。
3.1 データベースに接続する
私のデータベースはデフォルト環境にあるため、アカウントのパスワードは必要ありません。次のマクロを使用して、その後の変更を容易にするために操作する必要があるデータベース情報を定義します。
#include <mysql/mysql.h>
#define HOST "127.0.0.1"
#define PORT 3306
#define USER "root"
#define PASSWD ""
#define DBNAME "hello"
最初のステップは、init を使用してMYSQL
構造体を初期化し、ポインタを使用してそれを受け取ることです。
2 番目のステップでは、mysql_real_connect
関数を使用してデータベースに接続し、先ほど作成したマクロ定義を入力します。
mariadb
3 番目のステップは、環境の初期構成で、中国語をより適切にサポートするために、データベースの文字セットを utf8 に設定します。また、エンコーディングの問題によるデータの文字化けを避けるために、コードも同時に変更する必要があります。
最後のステップは、mysql 構造を破壊することです
int main()
{
// 连接数据库
// 初始化
MYSQL *mysql = mysql_init(nullptr);
if (mysql == nullptr) // 返回值为空代表init失败
{
cerr << "[ERR] init mysql handle failed!\n";
return -1;
}
// 连接
cout << "[INFO] connect to " << HOST << ":" << PORT << " " << USER << " " << DBNAME << endl;
// 第一个参数为输出型参数。返回值为MYSQL的起始地址,如果错误返回NULL
if (mysql_real_connect(mysql, HOST, USER, PASSWD, DBNAME, PORT, nullptr, 0) == nullptr)
{
cerr << "[ERR] mysql connect error: " << mysql_error(mysql) << endl;
return -1;
}
// 配置为和数据库同步的utf8字符集
mysql_set_character_set(mysql, "utf8");
// 到这里就已经成功了
cout << "[INFO] mysql database connect success!" << endl;
// 关闭连接
mysql_close(mysql);
return 0;
}
コンパイルして実行し、データベースに正常にリンクしました
$ make
g++ test.cpp -o test -lmysqlclient
$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
3.2 キー値の追加
次に行う必要があるのは、既存のテーブルに新しいキー値を追加することです。
mysql コードの操作には実際には SQL ステートメントの使用が必要であることに注意してください (これは非常に面倒だと思います)。
insert文は以下の通りで、括弧内のキー値はデータベース内のテーブルのキー値と1対1に対応している必要があります。
insert into stu_test value (null,'牛爷爷',50,64.6);
したがって、私たちがしなければならないことは、受信パラメータを SQL ステートメントに結合する関数を作成し、それを処理のために mysql に渡すことです。
// 将double转为string
std::string double2string(const double& d)
{
std::stringstream s_tmp;
s_tmp << d;
std::string s = s_tmp.str();
return s;
}
int add_key_to_stu(MYSQL *mysql,const std::string& name,int age,double score)
{
// 1.将传入的参数处理为一个完整的sql语句
// 因为第一个编号参数,配置的是自增,所以需要传入null
std::string sql_cmd = "insert into stu_test value (null,'";
sql_cmd+= name;
sql_cmd+= "',";
sql_cmd+= std::to_string(age);
sql_cmd+= ",";
sql_cmd+= double2string(score);
sql_cmd+= ");";
cout << "[INFO] " << sql_cmd << endl;
// 2.执行语句
int ret = mysql_query(mysql,sql_cmd.c_str());
if(ret!=0)
{
cerr << "[ERR] mysql insert error: " << mysql_error(mysql) << endl;
}
return ret;
}
次のコードテスト
// 添加一个数据
add_key_to_stu(mysql,"牛爷爷",50,64.6);
add_key_to_stu(mysql,"小图图",5,72.8);
ご覧のとおり、正常に実行されました。
$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] insert into stu_test value (null,'牛爷爷',50,64.6);
[INFO] insert into stu_test value (null,'小图图',5,72.8);
mysql コマンド ラインを入力し、次のコマンドを使用して既存のキー値をクエリします。
select * from stu_test;
ご覧のとおり、処理は成功しました。
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 1 | 牛爷爷 | 50 | 64.60 |
| 2 | 小图图 | 5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.001 sec)
3.3 既存のキー値を変更する
SQL ステートメントは次のとおりです。現在のデータベース内のGrandpa Niustu_test
という名前のエントリのスコアを70 に変更します。
update stu_test set score=70 where name='牛爷爷';
// 修改已有学生的成绩
int mod_score_in_stu(MYSQL *mysql,const std::string& name,double score)
{
std::string sql_cmd = "update ";
sql_cmd += TABLENAME;
sql_cmd += " set score=";
sql_cmd += double2string(score);
sql_cmd += " where name='";
sql_cmd += name;
sql_cmd += "';";
cout << "[INFO] " << sql_cmd << endl;
// 2.执行语句
int ret = mysql_query(mysql,sql_cmd.c_str());
if(ret!=0)
{
cerr << "[ERR] mysql mod_score error: " << mysql_error(mysql) << endl;
}
return ret;
}
処刑が成功した後、牛おじいちゃんの結果が変わったことがわかります。
$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] update stu_test set score=70 where name='牛爷爷';
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 1 | 牛爷爷 | 50 | 64.60 |
| 2 | 小图图 | 5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.001 sec)
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 1 | 牛爷爷 | 50 | 70.00 |
| 2 | 小图图 | 5 | 72.80 |
+----+-----------+------+-------+
2 rows in set (0.000 sec)
他のキー値を変更する場合は、この手順に従います。
実際のシナリオでは、データ エントリには変更されていないキー値が必ず含まれます。たとえば、私の学生テーブルでは、各学生の名前が変更されていないと仮定して、名前フィールドに基づいてキー値を見つけ、他の値を変更できます。
本気でやるなら名前で検索しても絶対にダメなので、学生ごとに学生IDかUIDを生成して、そのIDで検索すればいいのです。データを変更する前に、ターゲット データの uid 値を知っておく必要があります。
3.4 キー値の削除
次のステートメントは、test_tb
テーブル内の Zhang San という名前のキー値を削除します。
delete from test_tb where name='张三';
削除する前に、新しいキー値をデータベースに追加しました
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 1 | 牛爷爷 | 50 | 70.00 |
| 2 | 小图图 | 5 | 72.80 |
| 3 | 大司马 | 42 | 87.30 |
+----+-----------+------+-------+
3 rows in set (0.001 sec)
次に、コードを使用して牛おじいちゃんを削除します
// 删除键值(根据名字)
int del_key_in_stu(MYSQL *mysql,const std::string& name)
{
std::string sql_cmd = "delete from ";
sql_cmd += TABLENAME;
sql_cmd += " where name='";
sql_cmd += name;
sql_cmd += "';";
cout << "[INFO] " << sql_cmd << endl;
// 执行语句
int ret = mysql_query(mysql,sql_cmd.c_str());
if(ret!=0)
{
cerr << "[ERR] mysql mod_score error: " << mysql_error(mysql) << endl;
}
return ret;
}
// 删除已有键值
del_key_in_stu(mysql,"牛爷爷");
コンパイルして実行する
$ ./test
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] delete from stu_test where name='牛爷爷';
丹生おじいちゃんは削除されました
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 2 | 小图图 | 5 | 72.80 |
| 3 | 大司马 | 42 | 87.30 |
+----+-----------+------+-------+
2 rows in set (0.000 sec)
3.4.1 自己増加IDについて
このとき、新しいキー値を挿入すると、idは予備の1には埋まらず、4から増え続けていることがわかります。
MariaDB [hello]> select * from stu_test;
+----+-----------+------+-------+
| id | name | age | score |
+----+-----------+------+-------+
| 2 | 小图图 | 5 | 72.80 |
| 3 | 大司马 | 42 | 87.30 |
| 4 | 乐迪 | 32 | 99.00 |
+----+-----------+------+-------+
3 rows in set (0.001 sec)
これだけは知っておいてください
3.5 クエリ
データベースの場合、クエリも高頻度の操作です
select * from tb where name=key;
上記のステートメントは、データベース テーブル tb 内でキー値名をキーとして持つデータを検索します。
// 返回用户的所有信息,name为空返回所有
void get_all_in_stu(MYSQL *mysql,const std::string& name="")
{
std::string sql_cmd = "select * from ";
sql_cmd += TABLENAME;
if(name.size()!=0)
{
sql_cmd += " where name='";
sql_cmd += name;
sql_cmd += "'";
}
sql_cmd += ";";
cout << "[INFO] " << sql_cmd << endl;
int ret = mysql_query(mysql,sql_cmd.c_str());
if(ret!=0)
{
cerr << "[ERR] mysql query error: " << mysql_error(mysql) << endl;
return ;
}
// 获取结果
MYSQL_RES *res = mysql_store_result(mysql);
if (res == nullptr)
{
cerr << "[ERR] mysql store_result error: " << mysql_error(mysql) << endl;
return ;
}
int row = mysql_num_rows(res); // 行
int col = mysql_num_fields(res); //列
printf("%10s%10s%10s%10s\n", "ID", "姓名", "年龄", "成绩");
for (int i = 0; i < row; i++)
{
MYSQL_ROW row_data = mysql_fetch_row(res);
for (int i = 0; i < col; i++)
{
printf("%10s", row_data[i]);
}
printf("\n");
}
// 释放结果
mysql_free_result(res);
}
get_all_in_stu(mysql);
実行結果は以下のようになり、テーブル内のすべての値が表示されます
[INFO] connect to 127.0.0.1:3306 root hello
[INFO] mysql database connect success!
[INFO] select * from stu_test;
ID 姓名 年龄 成绩
2 小图图 5 72.80
3 大司马 42 87.30
4 乐迪 32 99.00
特定の名前を渡すと、変更された名前のすべての値のみが返されます。
get_all_in_stu(mysql,"乐迪");
[INFO] select * from stu_test where name='乐迪';
ID 姓名 年龄 成绩
4 乐迪 32 99.00
これによりクエリ操作が実装されます。
3.5.1 ファジーマッチング
it を使用することに加えて、このステートメントを使用してあいまい一致を実行することもできます。つまり、名前の前後の内容は気にせず、名前を含むデータがある限り、それはフィルターで除外されますname=
。name like %名字%
select * from %s where name like '%牛%';
このようにして、名前に牛が含まれるすべてのデータを除外できます。
3.5.2 クエリインタフェース動作時の注意事項
クエリの戻り値は文字列の 2 次元配列であるため、対応するフィールドの内容をフィールド名から取得することはできません。このため、プログラマーは添字を通じて正しいフィールドを取得して処理できるように、このテーブル内のフィールドの順序を知っている必要があります。
cpp は Python のような変数の型をサポートしていないため、対応する型のデータをフィルターで除外するには、対応する関数を自分で呼び出してデータを変換する必要があります。
たとえば、atoi
関数を使用して文字列を整数に変換します。
終わり
基本的な操作はここまでですが、その後の操作についてはこのブログで更新していきます。