启动MySQL服务器
docker run --name mysql -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql
初始化数据库
docker exec -it mysql mysql -uroot -p123456
CREATE DATABASE test CHARACTER SET utf8 COLLATE utf8_general_ci;
use test
CREATE TABLE pairs (
k VARCHAR(20) NOT NULL,
v VARCHAR(20) NOT NULL
) ENGINE = InnoDB;
INSERT INTO pairs (k, v) VALUES ("foo", "bar");
quit
客户端代码(mysql_client.cc)
#include <cstdio>
#include <exception>
#include <string>
#include <vector>
#include <fcntl.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/poll.h>
#include <my_global.h>
#include <mysql.h>
#include <siren/async.h>
#include <siren/c_library.h>
#include <siren/elf_hook.h>
#include <siren/loop.h>
#include <siren/scope_guard.h>
#include <siren/utility.h>
#define MYSQLCLIENT_DL_FILE_NAME "libmysqlclient.so"
extern siren::Loop *siren_loop;
extern siren::Async *siren_async;
namespace {
auto elf_hooks = std::make_tuple(
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "open", siren_open),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "read", maybe_siren_read),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "write", maybe_siren_write),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "readv", maybe_siren_readv),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "writev", maybe_siren_writev),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "lseek", siren_lseek),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "close", maybe_siren_close),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "usleep", siren_usleep),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "socket", siren_socket),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "getsockopt", siren_getsockopt),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "setsockopt", siren_setsockopt),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "accept", siren_accept),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "accept4", siren_accept4),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "connect", siren_connect),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "recv", siren_recv),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "send", siren_send),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "recvfrom", siren_recvfrom),
// siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "sendto", siren_sendto),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "getaddrinfo", siren_getaddrinfo),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "getnameinfo", siren_getnameinfo),
siren::MakeELFHook(MYSQLCLIENT_DL_FILE_NAME, "poll", siren_poll)
);
class MySQLError
: public std::exception
{
public:
explicit MySQLError(MYSQL *mysql) {
description_ = "MySQLError: ";
description_ += mysql_error(mysql);
}
const char *what() const noexcept override {
return description_.c_str();
}
private:
std::string description_;
};
}
int
real_main(int fiberID)
{
char buf[1024];
MYSQL mysql;
mysql_init(&mysql);
if (mysql_real_connect(&mysql, "192.168.11.101", "root", "123456", "test", 0, nullptr, 0)
== nullptr) {
throw MySQLError(&mysql);
}
int result = 1;
auto scopeGuard = siren::MakeScopeGuard([&] () -> void {
// 事务支持
// if (result == 0) {
// mysql_commit(&mysql);
// } else {
// mysql_rollback(&mysql);
// }
mysql_close(&mysql);
});
// 事务支持
// if (mysql_autocommit(&mysql, 0)) {
// throw MySQLError(&mysql);
// }
auto query = [&] (const char *tag) -> void {
// 查
if (mysql_query(&mysql, "SELECT * FROM pairs")) {
throw MySQLError(&mysql);
}
MYSQL_RES *result = mysql_store_result(&mysql);
if (result == nullptr) {
throw MySQLError(&mysql);
}
std::printf("[%d] %s: ", fiberID, tag);
unsigned int numberOfFields = mysql_num_fields(result);
for (;;) {
MYSQL_ROW row = mysql_fetch_row(result);
if (row == nullptr) {
break;
}
for (unsigned int i = 0; i < numberOfFields; ++i) {
std::printf("%s ", row[i]);
}
std::printf("| ");
}
std::putchar('\n');
};
// 增
std::snprintf(buf, sizeof(buf), "INSERT INTO pairs (k, v) VALUES ('hello', 'world%d')", fiberID);
if (mysql_query(&mysql, buf)) {
throw MySQLError(&mysql);
}
query("AFTER INSERT");
// 改
std::snprintf(buf, sizeof(buf), "UPDATE pairs SET v = 'kitty%d' WHERE k = 'hello'", fiberID);
if (mysql_query(&mysql, buf)) {
throw MySQLError(&mysql);
}
query("AFTER UPDATE");
// 删
std::snprintf(buf, sizeof(buf), "DELETE FROM pairs WHERE k = 'hello'");
if (mysql_query(&mysql, buf)) {
throw MySQLError(&mysql);
}
query("AFTER DELETE");
result = 0;
return result;
}
int
main()
{
siren::IterateTuple(elf_hooks, [] (auto &&elf_hook) { elf_hook.toggle(); });
siren::Loop loop(16 * 1024);
siren::Async async(&loop);
siren_loop = &loop;
siren_async = &async;
int result;
for (int i = 0; i < 10; ++i) {
loop.createFiber([&, i(i)] () {
result = real_main(i);
});
}
try {
loop.run();
} catch (const std::exception &exception) {
std::fprintf(stderr, "%s\n", exception.what());
return 1;
}
return result;
}
编译运行
g++ -std=c++14 -DUSE_VALGRIND mysql_client.cc -lsiren -pthread -lmysqlclient -ldl && ./a.out