• 一个简单好用的操作mysql的c++类,在mysql c api的基础上封装的,没有使用官方的c++ connector(转)


    目前 mysql 官方的 c++ connector 还没有针对vs2017编译的二进制包,在mysql官方网站上下载的release二进制包在vs2017下可以用,但是下载的debug包在vs2017下运行时却提示找不到vcruntime140_1D.dll 而下载c++ connector源码进行编译,它还要依赖boost,而且编译过程中还出现一些找不到sys/types.h头文件的之类错误,搞的我整个人都不好了。干脆在mysql的c api基础上自己写了一个。

    特点:header only,基于C++17,依赖fmt库(fmt库也是header only的,而且fmt库是即将进入c++20标准的format库);

    本人对需要编译的库深恶痛绝,只要能做成header only的就绝不搞成需要编译的,宁可增加编译时间,也不要那种还要看通篇的编译说明,编译参数等等之类的来增加心智负担。

    代码地址:https://gitee.com/zhllxt/mysql_modern_cpp

    github:https://github.com/zhllxt/mysql_modern_cpp

    下面是示例代码,用起来还是相当简单的。

    struct user
    {
    std::string name;
    int age{};
    std::tm birth{};

    template <class Recordset>
    bool orm(Recordset & rs)
    {
    return rs(name, age, birth);
    }
    };

    mysql::database db;
    db.connect("localhost", "root", "123456", "mir3_user");

    // R"()" 是 c++ 11 的 raw string 语法,避免字符串换行时还要在行尾添加反斜杠
    db << R"(CREATE TABLE `tbl_user` (
    `name` VARCHAR(20) NOT NULL,
    `age` INT NULL DEFAULT NULL,
    `birth` DATETIME NULL DEFAULT NULL,
    PRIMARY KEY(`name`)
    )
    COLLATE = 'gbk_chinese_ci'
    ENGINE = InnoDB
    ;)";

    // "db << ..." 这种操作符方式会生成一个临时变量 当这个临时变量销毁时会在析构函数中自动执行sql语句
    // 注意这种情况下执行sql语句时如果出现错误不会进到示例这里最后面的catch块中
    db << "insert into tbl_user (name,age) values (?, ?);"
    << "admin"
    << 102;
    db << "update tbl_user set age=?,birth=? where name=?;"
    << nullptr
    << nullptr
    << "admin";
    db << "update tbl_user set age=?,birth=? where name=?;"
    << 55
    << "1990-03-14 15:15:15"
    << "admin";

    user u;
    // 查询数据到自定义结构体中
    db << "select name,age,birth from tbl_user where name=?" << "admin" >> u;
    db.execute("select name,age,birth from tbl_user where name=?", "admin").fetch(u);
    db << "select name,age,birth from tbl_user" >> [](user u)
    {
    printf("%s %d ", u.name.data(), u.age);
    };

    // 自定义结构体的信息添加到数据库中
    u.name += std::to_string(std::rand());
    db << "insert into tbl_user (name,age,birth) values (?,?,?)" << u;


    db << "delete from tbl_user where name=?;"
    << "tester";

    // 直接调用 db.execute 会直接执行sql语句 如果出现错误可以进到示例这里最后面的catch块中
    db.execute("insert into tbl_user values (?, ?, ?);", "tester", 32, "2020-03-14 10:10:10");

    std::string name, age, birth;

    int count = 0;
    db << "select count(*) from tbl_user;"
    >> count;

    db << "select name from tbl_user where age=55;"
    >> name;

    std::tm tm_birth{}; // 将获取到的日期存储到c++语言的结构体tm中
    db << "select birth from tbl_user where name=?;"
    << name
    >> tm_birth;

    const char * inject_name = "admin' or 1=1 or '1=1"; // sql 注入
    db << "select count(*) from tbl_user where name=?;"
    << inject_name
    >> count;

    // 将获取的内容存储到绑定数据中 这样你可以直接操作数据的缓冲区buffer
    // 但此时必须要用auto rs = 这种方式将recordset临时变量保存起来
    // 否则operator>>结束后临时变量就销毁了 binder 指针指向的内容就是非法的了
    mysql::binder * binder = nullptr;
    auto rs = db << "select birth from tbl_user where name='admin';";
    rs >> binder;
    MYSQL_TIME * time = (MYSQL_TIME *)(binder->buffer.get());
    printf("%d-%d-%d %d:%d:%d ", time->year, time->month, time->day, time->hour, time->minute, time->second);

    // 查询到数据后直接调用 lambda 回调函数,有多少行数据,就会调用多少次
    (db << "select name,age,birth from tbl_user where age>?;")
    << 10
    >> [](std::string_view name, int age, std::string birth)
    {
    printf("%s %d %s ", name.data(), age, birth.data());
    };

    db << "select age,birth from tbl_user;"
    >> std::tie(age, birth);

    db.execute("select name,age,birth from tbl_user where name=?;", name) >>
    [](std::string_view name, int age, std::string birth)
    {
    };

    // set_fields_format 用来设置返回的字符串的格式,注意只有返回字符串时才起作用
    // c++ 20 的format语法
    // {:>15} 表示右对齐 共占15个字符的宽度
    // {:04} 共占4个字符的宽度 如果不足4个字符在前面补0
    rs = (db << "select name,age,birth from tbl_user;");
    // 总共select了三列数据,所以set_fields_format必须要设置三个格式信息
    // 可以调用set_fields_format设置格式,如果调用了就必须有几列,就填几个格式信息
    // 也可以不调用set_fields_format,此时会使用默认的格式
    rs.set_fields_format("{:>15}", "{:04}", "{:%Y-%m-%d %H:%M:%S}");
    auto rs2 = std::move(rs);
    // 按照自己的要求一行一行的获取数据
    while (rs2.fetch(name, age, binder))
    {
    MYSQL_TIME * time = (MYSQL_TIME *)(binder->buffer.get());
    printf("%s %s %d-%d-%d ", name.data(), age.data(), time->year, time->month, time->day);
    }

    std::tuple<int, std::string> tup;
    db << "select age,birth from tbl_user;"
    >> tup;
    auto &[_age, _birth] = tup;
    printf("%d %s ", _age, birth.data());

    另外再说一下mysql的一些步骤:

    1、安装mysql,安装完之后,在mysql的安装目录下会有include和lib目录,里面是mysql的c api的头文件和库

    2、由于这个类是mysql的c api的基础上实现的,所以需要在vs工程设置中包含mysql的c api的include目录和lib目录

    3、编译后运行会提示找不到libmysql.dll的话,到mysql的安装目录下的lib目录中找到libmysql.dll拷到你生成的exe目录下,可能还会提示找不到libcrypto-1_1-x64.dll和libssl-1_1-x64.dll 到mysql的安装目录下的bin目录中能找到这两个文件,拷到你生成的exe目录下即可

    4、如果还提示找不到libeay32.dll和ssleay32.dll 你可以在你的C盘全盘搜索一下,一般能搜到这两个文件,拷到你生成的exe目录下即可,如果搜不到,可以下载HeidiSQL这个工具(HeidiSQL是一个免费的操作mysql和postgresql的工具),安装之后在它的目录下能找到这两个文件。

    关键词:mysql c++ libeay32 ssleay32 connector
    ————————————————
    版权声明:本文为CSDN博主「zhllxt」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/zhllxt/article/details/104901732

  • 相关阅读:
    每种特定的迭代器如何使用
    常量迭代器
    容器迭代器
    三十分钟掌握STL
    高快省的排序算法
    FloatTest32 Example
    /浮点数的比较
    java第一天
    ACwing 898
    POJ 3268
  • 原文地址:https://www.cnblogs.com/xihong2014/p/14953138.html
Copyright © 2020-2023  润新知