SOCI简介-C ++数据库访问库

参赛作品


该库本身已经相当成熟-github上的第一个版本可以追溯到2004年。 当哈伯在搜索引擎中没有给我一个单独的链接链接到提及该精彩库的文章时,我感到惊讶。


发音为: soci ,重点放在第一个音节上。


SOCI通过对soci :: type_conversion的专门化来支持ORM


数据库支持(DB)(后端):



在这里,我不会翻译手册或提供示例代码,但会尝试改编(更改表的结构,并进行其他简化操作)我以前项目中的代码,以使其更加直观和有趣。


安装方式


我们从master分支下载原材料 ,将其解压缩,然后在目录内执行以下命令:


Windows中


$ mkdir build && cd build && cmake -G“ Visual Studio 15 2017 Win64” ../ && cmake --build。--config版本

或者代替最后一个命令,您可以在Visual Studio中打开生成的项目并进行编译。
Wilk提示在命令行上使用cmake进行构建)


尼克斯


$ mkdir build && cd build && cmake ../ && sudo make install

soci-9999.ebuild

如果您是Gentoo LinuxCalculate Linux的所有者,并且想从github上的官方存储库中获得系统中最新版本的SOCI ,则可以将此安装文件保存在/usr/portage/dev-db/soci/ ,然后运行该命令:


#ebuild soci-9999.ebuild清单&&出现-va = dev-db / soci-9999

 # Copyright 1999-2018 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 EAPI=6 if [[ ${PV} == *9999 ]] ; then SCM="git-r3" EGIT_REPO_URI="https://github.com/SOCI/${PN}.git" fi CMAKE_MIN_VERSION=2.6.0 inherit cmake-utils ${SCM} DESCRIPTION="Makes the illusion of embedding SQL queries in the regular C++ code" HOMEPAGE="http://soci.sourceforge.net/" if [[ ${PV} == *9999 ]] ; then SRC_URI="" KEYWORDS="~amd64 ~x86" else SRC_URI="https://github.com/SOCI/${PN}/archive/${PV}.tar.gz -> ${P}.tar.gz" KEYWORDS="amd64 x86" fi LICENSE="Boost-1.0" SLOT="0" IUSE="boost doc +empty firebird mysql odbc oracle postgres sqlite static-libs test" RDEPEND=" firebird? ( dev-db/firebird ) mysql? ( virtual/mysql ) odbc? ( dev-db/unixODBC ) oracle? ( dev-db/oracle-instantclient-basic ) postgres? ( dev-db/postgresql:= ) sqlite? ( dev-db/sqlite:3 ) " DEPEND="${RDEPEND} boost? ( dev-libs/boost ) " src_configure() { local mycmakeargs=( -DWITH_BOOST=$(usex boost) -DSOCI_EMPTY=$(usex empty) -DWITH_FIREBIRD=$(usex firebird) -DWITH_MYSQL=$(usex mysql) -DWITH_ODBC=$(usex odbc) -DWITH_ORACLE=$(usex oracle) -DWITH_POSTGRESQL=$(usex postgres) -DWITH_SQLITE3=$(usex sqlite) -DSOCI_STATIC=$(usex static-libs) -DSOCI_TESTS=$(usex test) -DWITH_DB2=OFF ) #use MYCMAKEARGS if you want enable IBM DB2 support cmake-utils_src_configure } src_install() { use doc && local HTML_DOCS=( doc/. ) cmake-utils_src_install } 

我们编写一个池来连接数据库


db_pool.hpp
 #ifndef db_pool_hpp #define db_pool_hpp //      GCC,       //    ,  deprecated auto_ptr (   4) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #include <soci/soci.h> #include <soci/connection-pool.h> #pragma GCC diagnostic pop #include <iostream> #include <string> class db_pool { soci::connection_pool* pool_; std::size_t pool_size_; public: db_pool():pool_(nullptr),pool_size_(0) {} ~db_pool() { close(); } soci::connection_pool* get_pool() { return pool_; } bool connect(const std::string& conn_str, std::size_t n = 5) { if (pool_ != nullptr) { close(); } int is_connected = 0; if (!(pool_ = new soci::connection_pool((pool_size_ = n)))) return false; try { soci::indicator ind; for (std::size_t _i = 0; _i < pool_size_; _i++) { soci::session& sql = pool_->at(_i); //        sql.open(conn_str); //     sql << "SELECT 1;", soci::into(is_connected, ind); if (!is_connected) break; else if (_i+1 < pool_size_) is_connected = 0; } } catch (std::exception const & e) { std::cerr << e.what() << std::endl; } if (!is_connected) close(); return (pool_ != nullptr); } void close () { if (pool_ != nullptr) { try { for (std::size_t _i = 0; _i < pool_size_; _i++) { soci::session& sql = pool_->at(_i); sql.close(); } delete pool_; pool_ = nullptr; } catch (std::exception const & e) { std::cerr << e.what() << std::endl; } pool_size_ = 0; } } }; #endif 

在user_info类中定义表结构


user_info.hpp
 #ifndef user_info_hpp #define user_info_hpp #include "db_pool.hpp" #include <ctime> #include <vector> #include <regex> #include <numeric> #include <algorithm> #include <iomanip> //   -        template<typename T> static void extract_integers(const std::string& str, std::vector<T>& result ) { result.clear(); using re_iterator = std::regex_iterator<std::string::const_iterator>; using re_iterated = re_iterator::value_type; std::regex re("([\\+\\-]?\\d+)"); re_iterator rit(str.begin(), str.end(), re), rend; std::transform(rit, rend, std::back_inserter(result), [](const re_iterated& it){return std::stoi(it[1]); }); } template<typename T> static void split_integers(std::string& str, const std::vector<T>& arr) { str = "{"; if (arr.size()) { str += std::accumulate(arr.begin()+1, arr.end(), std::to_string(arr[0]), [](const std::string& a, T b){return a + ',' + std::to_string(b);}); } str += "}"; } //   `users' class user_info { public: int id; //   std::tm birthday; //   std::string firstname, lastname; //    std::vector<int> friends; //   user_info():id(0),birthday(0),firstname(),lastname(),friends() {} void print() { std::cout.imbue(std::locale("ru_RU.utf8")); std::cout << "id: " << id << std::endl; std::cout << "birthday: " << std::put_time(&birthday, "%c %Z") << std::endl; std::cout << "firstname: " << firstname << std::endl; std::cout << "lastname: " << lastname << std::endl; std::string arr_str; split_integers(arr_str, friends); std::cout << "friends: " << arr_str << std::endl; } void clear() { id = 0; firstname = lastname = ""; friends.clear(); } user_info& operator=(const user_info& rhs) { if (this != &rhs) { id = rhs.id; birthday = rhs.birthday; firstname = rhs.firstname; lastname = rhs.lastname; friends = rhs.friends; } return *this; } }; //     ,  SOCI   namespace soci { template<> struct type_conversion<user_info> { typedef values base_type; static void from_base(values const& v, indicator ind, user_info& p) { if (ind == i_null) return; try { p.id = v.get<int>("id", 0); p.birthday = v.get<std::tm>("birthday", {}); p.firstname = v.get<std::string>("firstname", {}); p.lastname = v.get<std::string>("lastname", {}); std::string arr_str = v.get<std::string>("friends", {}); extract_integers(arr_str, p.friends); } catch (std::exception const & e) { std::cerr << e.what() << std::endl; } } static void to_base(const user_info& p, values& v, indicator& ind) { try { v.set("id", p.id); v.set("birthday", p.birthday); v.set("firstname", p.firstname); v.set("lastname", p.lastname); std::string arr_str; split_integers(arr_str, p.friends); v.set("friends", arr_str); ind = i_ok; return; } catch (std::exception const & e) { std::cerr << e.what() << std::endl; } ind = i_null; } }; } #endif 

测试我们的代码


test.cxx
 #ifndef test_cxx #define test_cxx #include "user_info.hpp" // g++ -std=c++11 test.cxx -o test -lsoci_core -lsoci_postgresql -lsoci_mysql && ./test int main() { db_pool db; /// \note  "postgresql"   ,         if (db.connect("postgresql://host='localhost' dbname='test' user='test' password='test'")) { try { soci::session sql(*db.get_pool()); //     std::string query_str = "CREATE TABLE IF NOT EXISTS users(id"; //     ,    -   id if (sql.get_backend_name() == "postgresql") query_str += " SERIAL "; else if (sql.get_backend_name() == "mysql") query_str += " INT AUTO_INCREMENT "; else query_str += " INT "; query_str += "NOT NULL PRIMARY KEY, birthday TIMESTAMP DEFAULT CURRENT_TIMESTAMP, firstname TEXT DEFAULT NULL, lastname TEXT DEFAULT NULL, friends TEXT DEFAULT NULL)"; //   sql << query_str; //   user_info info; std::time_t t = std::time(nullptr); info.birthday = *std::localtime(&t); info.firstname = "Dmitrij"; info.lastname = "Volin"; info.friends = {1,2,3,4,5,6,7,8,9}; sql << "INSERT INTO users(birthday, firstname, lastname, friends) VALUES(:birthday, :firstname, :lastname, :friends)", soci::use(info); t = std::time(nullptr); info.birthday = *std::localtime(&t); info.firstname = "Vasy"; info.lastname = "Pupkin"; info.friends = {11,22,33,44,55,66,77,88,99}; //       sql << "INSERT INTO users(birthday, firstname, lastname, friends) VALUES(:birthday, :firstname, :lastname, :friends)", soci::use(info); //   ,  : soci::i_ok, soci::i_null soci::indicator ind; //  MySQL  id   ,  AUTO_INCREMENT: // sql.get_backend()->get_last_insert_id(sql, "users", reinterpret_cast<long&>(id)); // //  PostgreSQL   id  ,    : // sql << "INSERT INTO users(birthday, firstname, lastname, friends) VALUES(:birthday, :firstname, :lastname, :friends) RETURNING id", soci::use(info), soci::into(id, ind); //      info.clear(); //       ,   `lastname' sql << "SELECT * FROM users WHERE lastname = :label LIMIT 1", soci::use(std::string("Volin"), "label"), soci::into(info, ind); if (ind == soci::i_null) std::cout << "      ..." << std::endl; else info.print(); std::cout << "++++++++++++++++++++++++++++++++++++++" << std::endl; //     soci::rowset<user_info> rs = (sql.prepare << "SELECT * FROM users"); for (auto it = rs.begin(); it != rs.end(); it++) { user_info& i = *it; i.print(); } //   sql << "DROP TABLE IF EXISTS users"; } catch (std::exception const & e) { std::cerr << e.what() << std::endl; } } return 0; } #endif 

结论


在本文中,我们研究了该库的主要功能。


在下一篇文章中(如果读者会感兴趣),我将写有关使用BLOB类型的信息-在数据库中存储文件和图片(在Postgresql中,这些是OID字段),以及事务和准备好的请求。


参考文献


GitHub上的SOCI
SOCI主页

Source: https://habr.com/ru/post/zh-CN422881/


All Articles