首页 > 数据库 > MySQL > 正文

介绍一个针对C++程序的MySQL访问库soci

2024-07-24 13:07:05
字体:大 中 小
来源:转载
供稿:网友

这篇文章主要介绍了介绍一个针对C++程序的MySQL访问库soci,文章中还讲了其中的一些操作方法,需要的朋友可以参考下

一直以来,笔者都在不停寻找一种更人性化的数据库访问方式(并不是说默认的方式不好,而是有时候的确在模块化设计中不太方便)。

后来有幸在php中找到codeigniter的ActiveReord,详细参考这篇文章:抽离CodeIgniter的数据库访问类!

然而c++却始终用着最原始的方式,昨天趁着项目要用的机会,在网上搜索了好久,总算让我找到两套c++的数据库访问框架:

soci

litesql

两套代码我都拿下来看了一下,litesql实现了一套完整的代码自动生成,功能强大,但是也很重;soci相对要轻量,但是同样也实现了数据结构到数据库表的映射。本人还是比较喜欢轻量的东西,所以最终选择了soci。经过这两天的试用,感觉非常不错。

官方的文档也很详细,所以这里就用我写的单元测试代码来做一下简单的讲解:

首先创建库表:

 

 
  1. create database soci; 
  2. CREATE TABLE `tb_test` ( 
  3. `id` int(11) NOT NULL auto_increment, 
  4. `name` varchar(32) default "", 
  5. `sex` int(11) default 0, 
  6. PRIMARY KEY (`id`), 
  7. UNIQUE KEY `name` (`name`) 
  8. ); 
  9.  
  10. create database soci; 
  11. CREATE TABLE `tb_test` ( 
  12. `id` int(11) NOT NULL auto_increment, 
  13. `name` varchar(32) default "", 
  14. `sex` int(11) default 0, 
  15. PRIMARY KEY (`id`), 
  16. UNIQUE KEY `name` (`name`) 
  17. ); 

1.简单的select单条记录

 

 
  1. TEST(soci,select_one) 
  2. { 
  3. try 
  4. { 
  5. session sql(mysql, "host=localhost db=soci user=dantezhu"); 
  6. indicator ind; 
  7.  
  8. string name = "dandan"; 
  9. int sex; 
  10. sql << "select sex from tb_test where name = :name", 
  11. into(sex, ind), use(name); 
  12.  
  13. ASSERT_EQ(ind, i_ok) << name; 
  14. } 
  15. catch (exception const &e) 
  16. { 
  17. FAIL()<<e.what(); 
  18. } 
  19. } 
  20.  
  21. TEST(soci,select_one) 
  22. { 
  23. try 
  24. { 
  25. session sql(mysql, "host=localhost db=soci user=dantezhu"); 
  26. indicator ind; 
  27.  
  28. string name = "dandan"; 
  29. int sex; 
  30. sql << "select sex from tb_test where name = :name", 
  31. into(sex, ind), use(name); 
  32.  
  33. ASSERT_EQ(ind, i_ok) << name; 
  34. } 
  35. catch (exception const &e) 
  36. { 
  37. FAIL()<<e.what(); 
  38. } 
  39. } 

select的结果,如果成功则ind会为i_ok,同值sex被赋值;如果失败则反之

2.简单的select多条记录

 

 
  1. TEST(soci,select_multi2) 
  2. { 
  3. try 
  4. { 
  5. session sql(mysql, "db=soci user=dantezhu"); 
  6. indicator ind; 
  7.  
  8. int count; 
  9. sql << "select count(*) from tb_test", into(count, ind); 
  10. ASSERT_EQ(ind, i_ok) << count; 
  11.  
  12. if (count == 0) 
  13. { 
  14. SUCCEED(); 
  15. return; 
  16. } 
  17.  
  18. int sex = 1; 
  19. vector<string> vec_name(count); 
  20. vector<int> vec_sex(count); 
  21. sql << "select name,sex from tb_test where sex = :sex", 
  22. into(vec_name), into(vec_sex), use(sex); 
  23. } 
  24. catch (exception const &e) 
  25. { 
  26. FAIL()<<e.what(); 
  27. } 
  28. } 
  29.  
  30. TEST(soci,select_multi2) 
  31. { 
  32. try 
  33. { 
  34. session sql(mysql, "db=soci user=dantezhu"); 
  35. indicator ind; 
  36.  
  37. int count; 
  38. sql << "select count(*) from tb_test", into(count, ind); 
  39. ASSERT_EQ(ind, i_ok) << count; 
  40.  
  41. if (count == 0) 
  42. { 
  43. SUCCEED(); 
  44. return; 
  45. } 
  46.  
  47. int sex = 1; 
  48. vector<string> vec_name(count); 
  49. vector<int> vec_sex(count); 
  50. sql << "select name,sex from tb_test where sex = :sex", 
  51. into(vec_name), into(vec_sex), use(sex); 
  52. } 
  53. catch (exception const &e) 
  54. { 
  55. FAIL()<<e.what(); 
  56. } 
  57. } 

与select单条记录唯一的区别即,into()的参数是一个vector。其实用多个vector这种方式并不是一个很好的选择,后面会介绍基于数据结构的方式。

3.简单的insert

 

 
  1. TEST(soci,insert_exist) 
  2. { 
  3. try 
  4. { 
  5. session sql(mysql, "db=soci user=dantezhu"); 
  6.  
  7. string name = "dandan"; 
  8. int sex = 1; 
  9.  
  10. sql << "insert into tb_test(name, sex) values(:name, :sex)", 
  11. use(name), use(sex); 
  12. } 
  13. catch (exception const &e) 
  14. { 
  15. SUCCEED()<<e.what(); 
  16. } 
  17. } 
  18.  
  19. TEST(soci,insert_exist) 
  20. { 
  21. try 
  22. { 
  23. session sql(mysql, "db=soci user=dantezhu"); 
  24.  
  25. string name = "dandan"; 
  26. int sex = 1; 
  27.  
  28. sql << "insert into tb_test(name, sex) values(:name, :sex)", 
  29. use(name), use(sex); 
  30. } 
  31. catch (exception const &e) 
  32. { 
  33. SUCCEED()<<e.what(); 
  34. } 
  35. } 

insert,update,delete都有两个同样的问题:

a)affect_rows(操作的行数)没有办法返回

b)操作的id无法知道,尤其对于insert的主键是自增的情况下,无法知道插入的主键的值是多少。

update和delete都与insert相似,这里就不再多说。

接下来是这个框架的很重要的一个特性,即数据库表与数据结构绑定:

首先我们需要定义一个结构体,并告知soci怎么让列名和数据结构的字段对应起来:

 

 
  1. struct Person 
  2. { 
  3. int id; 
  4. std::string name; 
  5. int sex; 
  6. }; 
  7.  
  8. namespace soci 
  9. { 
  10. template<> struct type_conversion<Person> 
  11. { 
  12. typedef values base_type; 
  13. static void from_base(values const & v, indicator /* ind */, Person & p) 
  14. { 
  15. p.id = v.get<int>("id"); 
  16. p.name = v.get<std::string>("name"); 
  17. p.sex = v.get<int>("sex"); 
  18. } 
  19. static void to_base(const Person & p, values & v, indicator & ind) 
  20. { 
  21. v.set("id", p.id); 
  22. v.set("name", p.name); 
  23. v.set("sex", p.sex); 
  24. ind = i_ok; 
  25. } 
  26. }; 
  27. } 
  28.  
  29. struct Person 
  30. { 
  31. int id; 
  32. std::string name; 
  33. int sex; 
  34. }; 
  35.  
  36. namespace soci 
  37. { 
  38. template<> struct type_conversion<Person> 
  39. { 
  40. typedef values base_type; 
  41. static void from_base(values const & v, indicator /* ind */, Person & p) 
  42. { 
  43. p.id = v.get<int>("id"); 
  44. p.name = v.get<std::string>("name"); 
  45. p.sex = v.get<int>("sex"); 
  46. } 
  47. static void to_base(const Person & p, values & v, indicator & ind) 
  48. { 
  49. v.set("id", p.id); 
  50. v.set("name", p.name); 
  51. v.set("sex", p.sex); 
  52. ind = i_ok; 
  53. } 
  54. }; 
  55. } 

关于

 

 
  1. template<> struct type_conversion<Person> 
  2.  
  3. template<> struct type_conversion<Person> 

这里,官方的文档是是有误的,我查了好长时间,按照上面的写法来写即可。

1.用数据结构来select

 

 
  1. TEST(soci,select_obj_one) 
  2. { 
  3. try 
  4. { 
  5. session sql(mysql, "db=soci user=dantezhu"); 
  6. indicator ind; 
  7.  
  8. int count; 
  9. sql << "select count(*) from tb_test", into(count, ind); 
  10. ASSERT_EQ(ind, i_ok) << count; 
  11.  
  12. string name = "dandan"; 
  13. Person p; 
  14. sql << "select id,name,sex from tb_test where name = :name", 
  15. into(p, ind), use(name); 
  16.  
  17. ASSERT_EQ(ind, i_ok) << name; 
  18.  
  19. if (sql.got_data()) 
  20. { 
  21. cout<< p.id  
  22. << "," 
  23. << p.name 
  24. << "," 
  25. << p.sex  
  26. << endl; 
  27. } 
  28.  
  29. } 
  30. catch (exception const &e) 
  31. { 
  32. FAIL()<<e.what(); 
  33. } 
  34. } 
  35.  
  36. TEST(soci,select_obj_one) 
  37. { 
  38. try 
  39. { 
  40. session sql(mysql, "db=soci user=dantezhu"); 
  41. indicator ind; 
  42.  
  43. int count; 
  44. sql << "select count(*) from tb_test", into(count, ind); 
  45. ASSERT_EQ(ind, i_ok) << count; 
  46.  
  47. string name = "dandan"; 
  48. Person p; 
  49. sql << "select id,name,sex from tb_test where name = :name", 
  50. into(p, ind), use(name); 
  51.  
  52. ASSERT_EQ(ind, i_ok) << name; 
  53.  
  54. if (sql.got_data()) 
  55. { 
  56. cout<< p.id  
  57. << "," 
  58. << p.name 
  59. << "," 
  60. << p.sex  
  61. << endl; 
  62. } 
  63.  
  64. } 
  65. catch (exception const &e) 
  66. { 
  67. FAIL()<<e.what(); 
  68. } 
  69. } 

2.用数据结构来进行insert

 

 
  1. TEST(soci,insert_obj_noexist) 
  2. { 
  3. try 
  4. { 
  5. session sql(mysql, "db=soci user=dantezhu"); 
  6.  
  7. Person p = { 
  8. 0, 
  9. "niuniu", 
  10. 2 
  11. }; 
  12.  
  13. sql << "insert into tb_test(name, sex) values(:name, :sex)", 
  14. use(p); 
  15. } 
  16. catch (exception const &e) 
  17. { 
  18. FAIL()<<e.what(); 
  19. } 
  20. } 
  21.  
  22. TEST(soci,insert_obj_noexist) 
  23. { 
  24. try 
  25. { 
  26. session sql(mysql, "db=soci user=dantezhu"); 
  27.  
  28. Person p = { 
  29. 0, 
  30. "niuniu", 
  31. 2 
  32. }; 
  33.  
  34. sql << "insert into tb_test(name, sex) values(:name, :sex)", 
  35. use(p); 
  36. } 
  37. catch (exception const &e) 
  38. { 
  39. FAIL()<<e.what(); 
  40. } 
  41. } 

整个就是这样~~下面是文中代码文件的下载路径:

http://code.google.com/p/vimercode/source/browse/#svn%2Ftrunk%2Fsoci_test

另外,虽然python下的mysql访问也算比较简单,但还是想知道是否有更Pythonic的库或接口,如果有朋友知道,欢迎不吝告知。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表