飞码网-免费源码博客分享网站

点击这里给我发消息

如何使用C/C++进行数据库编程

飞码网-免费源码博客分享网站 飞码网-https://www.codefrees.com 设计代做,博客教程 飞码网-免费源码博客分享网站

如何使用C/C++进行数据库编程

          用C/C++创建数据库应用程序是一项艰巨的任务,特别是对于一个新手程序员来说。虽然实际代码很简单,但配置问题,如导入正确的库,使用的驱动程序,如何访问它们等等,才是一场艰苦的战斗。现代高级语言在这些问题上是相当直接的。它们相当简单方便,有一个一体化的库,很少有配置上的麻烦。使用高级语言的一个有趣之处在于,你几乎可以在对底层原理稍有了解的情况下就开始编码。而C/C++则是另一个品种。它不容易踩到哪怕是一步的肤浅。这使得它更有吸引力,更具挑战性,那就是你写的每一段代码都在考验你的技能。但是,一旦你克服了初步的障碍,就没有什么比C/C++更适合你了。而数据库编程呢?其实挺好玩的。本文就让我们先来体验一下C/C++的数据库代码。

一、概述

         在C/C++中访问数据库有很多实用的方法。除了ODBC;它的API不是标准的。大多数数据库厂商都提供了一个本地客户端库来访问数据库。客户端库是特定于厂商的;也就是说,虽然基本原理是一样的,但一个厂商提供的API与另一个厂商的API是不同的。例如,MySQL有自己的客户端库,其提供的API与PostgreSQL客户端库提供的API有很大不同。如果你坚持使用一个特定厂商的数据库,比如说MySQL,那么用C/C++进行数据库编程的驱动选项是。
        MySQL客户端库。它是随MySQL一起分发的本地C API库,在libmysqlclient库中实现。如果你安装了MySQL Server,很可能已经安装了客户端API库。(否则,可以用命令下载,比如在Ubuntu/Mint中使用sudo apt-get install libmysqlclient<version> libmysqlclient<version>-dev)。
MySQL C/C++连接器。它是一个创新的盛世,使数据库连接变得简单方便。该API部分基于JDBC4.0 API标准,随着其成熟,或许将成为访问数据库的标准方式。有一个单独的C和以及C++的连接器。在使用C++连接器时,不需要调用C函数。
        ODBC(Open Database Connectivity)。由微软在90年代开发的,它为访问数据库系统提供了一个厂商中立的API。大多数数据库厂商除了提供本机支持外,至少还提供了一个ODBC驱动。ODBC基本上是一个驱动模型,它包含了将标准命令集转换为底层系统理解的调用的逻辑。它站在应用程序和数据库系统之间,实现它们之间调用/响应的互惠交换。近年来,由于瘦客户机计算的出现,ODBC提供的虚拟化要求已经降低。大多数Web开发平台都是以HTML作为用户和应用程序之间的中介层工作的。而且,在大多数情况下,底层数据库层与目标数据库有直接的联系。这使得原生库比ODBC更受欢迎。由于这些原因,近几年来ODBC的发展有所松懈。

二、C/C++和MySQL

         让我们用一个非常基本的、低级的MySQL客户端C API库来尝试一个数据库应用。数据库访问例程或多或少包括以下步骤。

1. 初始化连接手柄结构

MYSQL *mysql_init(MYSQL *);

2. 进行连接

MYSQL mysql_real_connect(
   MYSQL connection,
   const char *host,
   const char *username,
   const char *password,
   const char *database_name,
   unsigned int port,
   const char *unix_socket_name,
   unsigned int flags
);

3. 执行SQL语句

int mysql_query(MYSQL *connection, const char *query);

4. 用于数据检索的功能

unsigned int mysql_errno(MYSQL *connection);
 
char *mysql_error(MYSQL *connection);

5.错误处理

unsigned int mysql_errno(MYSQL *connection);
 
char *mysql_error(MYSQL *connection);

6. 关闭连接

void mysql_close(MYSQL *connection);
         还有很多其他的函数,但这些都是我们在以后创建应用程序时要用到的函数,请查阅MySQl C API手册,了解这些函数和其他API的更多细节。关于这些和其他API的更多细节,请查阅MySQl C API手册。综上所述,你基本上至少需要以下软件。

应用程序名称                                                          源码                                                          细节

数据库                                                               MySQL 5                                                     MySQL数据库服务器将是我们的后台数据库。
数据库API                                                          MySQL客户端库                                        提供本地驱动程序和库:libmysqlclient作为应用程序和数据库之间的接口。确保                                                                                                                                               客户端API库已经安装。安装后,头文件和库一般分别在/usr/include/mysql                                                                                                                                                     和/usr/lib/mysql中找到,否则,请确认系统中的正确路径。
编译器                                                                g++ GNU                                                  C++ 编译器
IDE                                                                    CodeLite 9.1.8                                            使用IDE并不是绝对必要的,但使用IDE是很方便的。在Linux中,有很多用于                                                                                                                                                   C/C++编程的IDE。对我来说,CodeLite似乎是现代的、简单的、直观的。此外,                                                                                                                                               它还会自动创建make文件。你可以选择任何其他的,即使是简单的gedit,vi,                                                                                                                                              或 者任何其他简单的文本编辑器,如nano也可以。在这种情况下,如果你需要手                                                                                                                                              动操作,请查阅相应的手册,了解配置和设置以及如何创建make文件。

 

一个例子(事务处理系统)

         这是一个非常简单和初级的事务处理系统的实现。由于MySQL API函数调用是C格式的,所以代码可以用C风格编写(没有类)。但是,为了让大家感受到用C++面向对象的数据库编程,我们使用了类。在很多情况下,我们不得不通过偶尔的铸造和转换,强迫其参数走C++的精髓。应用处理可以想象成如图1所示。


图1:交易处理系统

         配置和设置在IDE中。配置和设置的IDE: CodeLite
        确保在项目设置的全局设置中设置了以下配置。额外的包含路径 = .;/usr/include/mysql。选项 = -lmysqlclient库路径 = .;/usr/lib/mysql。

图2:项目设置
#ifndef BANKACCOUNT_H
#define BANKACCOUNT_H
 
#include <string>
using std::string;
 
class BankAccount
{
public:
   static const int MAX_SIZE = 30;
 
   BankAccount(int = 0, string = "",
      string = "", double = 0.0);
   ~BankAccount();
 
   void setAccountNumber(int);
   void setLastName(string);
   void setFirstName(string);
   void setBalance(double);
 
   int getAccountNumber() const;
   string getFirstName() const;
   string getLastName() const;
   double getBalance() const;
 
private:
   int accountNumber;
   char firstName[MAX_SIZE];
   char lastName[MAX_SIZE];
   double balance;
};
 
#endif   // BANKACCOUNT_H
Listing 1: BankAccount.h
#include "BankAccount.h"
 
#include <string>
#include <cstring>
 
using std::string;
 
BankAccount::BankAccount(int accno, string fname,
   string lname, double bal)
{
   setAccountNumber(accno);
   setFirstName(fname);
   setLastName(lname);
   setBalance(bal);
}
 
void BankAccount::setAccountNumber(int accno)
{
   accountNumber = accno;
}
 
void BankAccount::setLastName(string lname)
{
   const char* ln = lname.data();
   int len = lname.size();
   len = (len < MAX_SIZE ? len : MAX_SIZE - 1);
   strncpy(lastName, ln, len);
   lastName[len] = '\0';
}
 
void BankAccount::setFirstName(string fname)
{
   const char* fn = fname.data();
   int len = fname.size();
   len = (len < MAX_SIZE ? len : MAX_SIZE - 1);
   strncpy(firstName, fn, len);
   firstName[len] = '\0';
}
 
void BankAccount::setBalance(double bal)
{
   balance = bal;
}
 
int BankAccount::getAccountNumber() const
{
   return accountNumber;
}
 
string BankAccount::getFirstName() const
{
   return firstName;
}
 
string BankAccount::getLastName() const
{
   return lastName;
}
 
double BankAccount::getBalance() const
{
   return balance;
}
 
BankAccount::~BankAccount()
{
}
Listing 2: BankAccount.cpp
#ifndef BANKTRANSACTION_H
#define BANKTRANSACTION_H
 
#include <mysql.h>
#include <string>
 
class BankAccount;
 
using namespace std;
class BankTransaction
{
public:
   BankTransaction(const string = "localhost",
      const string = "",
   const string = "", const string = "");
   ~BankTransaction();
   void createAccount(BankAccount*);
   void closeAccount(int);
   void deposit(int, double);
   void withdraw(int, double);
   BankAccount* getAccount(int);
   void printAllAccounts();
   void message(string);
 
private:
   MYSQL* db_conn;
};
 
#endif   // BANKTRANSACTION_H
Listing 3: BankTransaction.h
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <iomanip>
 
#include "BankTransaction.h"
#include "BankAccount.h"
 
BankTransaction::BankTransaction(const string HOST,
   const string USER, const string PASSWORD,
   const string DATABASE)
{
   db_conn = mysql_init(NULL);
   if(!db_conn)
      message("MySQL initialization failed! ");
   db_conn = mysql_real_connect(db_conn, HOST.c_str(),
      USER.c_str(), PASSWORD.c_str(), DATABASE.c_str(), 0,
         NULL, 0);
   if(!db_conn)
      message("Connection Error! ");
}
 
BankTransaction::~BankTransaction()
{
   mysql_close(db_conn);
}
 
BankAccount* BankTransaction::getAccount(int acno)
{
   BankAccount* b = NULL;
   MYSQL_RES* rset;
   MYSQL_ROW row;
   stringstream sql;
   sql << "SELECT * FROM bank_account WHERE acc_no="
      << acno;
 
   if(!mysql_query(db_conn, sql.str().c_str())) {
      b = new BankAccount();
      rset = mysql_use_result(db_conn);
      row = mysql_fetch_row(rset);
      b->setAccountNumber(atoi(row[0]));
      b->setFirstName(row[1]);
      b->setLastName(row[2]);
      b->setBalance(atof(row[3]));
   }
   mysql_free_result(rset);
   return b;
}
 
void BankTransaction::withdraw(int acno, double amount)
{
   BankAccount* b = getAccount(acno);
   if(b != NULL) {
      if(b->getBalance() < amount)
         message("Cannot withdraw. Try lower amount.");
      else {
         b->setBalance(b->getBalance() - amount);
         stringstream sql;
         sql << "UPDATE bank_account SET balance="
            << b->getBalance()
            << " WHERE acc_no=" << acno;
         if(!mysql_query(db_conn, sql.str().c_str())) {
            message("Cash withdraw successful.
               Balance updated.");
         } else {
            message("Cash deposit unsuccessful!
               Update failed");
         }
      }
   }
}
 
void BankTransaction::deposit(int acno, double amount)
{
   stringstream sql;
   sql << "UPDATE bank_account SET balance=balance+" << amount
      << " WHERE acc_no=" << acno;
   if(!mysql_query(db_conn, sql.str().c_str())) {
      message("Cash deposit successful. Balance updated.");
   } else {
      message("Cash deposit unsuccessful! Update failed");
   }
}
 
void BankTransaction::createAccount(BankAccount* ba)
{
   stringstream ss;
   ss << "INSERT INTO bank_account(acc_no, fname, lname,
         balance)"
      << "values (" << ba->getAccountNumber() << ", '"
         << ba->getFirstName() + "','"
         << ba->getLastName() << "',"
         << ba->getBalance() << ")";
   if(mysql_query(db_conn, ss.str().c_str()))
      message("Failed to create account! ");
   else
      message("Account creation successful.");
}
 
void BankTransaction::closeAccount(int acno)
{
   stringstream ss;
   ss << "DELETE FROM bank_account WHERE acc_no="
      << acno;
   if(mysql_query(db_conn, ss.str().c_str()))
      message("Failed to close account! ");
   else
      message("Account close successful.");
}
 
void BankTransaction::message(string msg)
{
   cout << msg << endl;
}
void BankTransaction::printAllAccounts()
{
   MYSQL_RES* rset;
   MYSQL_ROW rows;
   string sql = "SELECT * FROM bank_account";
   if(mysql_query(db_conn, sql.c_str())) {
      message("Error printing all accounts! ");
      return;
   }
 
   rset = mysql_use_result(db_conn);
 
   cout << left << setw(10) << setfill('-') << left << '+'
        << setw(21) << setfill('-') << left << '+'
        << setw(21)
        << setfill('-') << left << '+' << setw(21)
        << setfill('-')
        << '+' << '+' << endl;
   cout << setfill(' ') << '|' << left << setw(9)
        << "Account"
        << setfill(' ') << '|' << setw(20) << "First Name"
        << setfill(' ') << '|' << setw(20) << "Last Name"
        << setfill(' ') << '|' << right << setw(20)
        << "Balance" << '|' << endl;
 
   cout << left << setw(10) << setfill('-') << left
       << '+' << setw(21) << setfill('-') << left << '+'
       << setw(21)
       << setfill('-') << left << '+' << setw(21) << setfill('-')
       << '+' << '+' << endl;
   if(rset) {
      while((rows = mysql_fetch_row(rset))) {
         cout << setfill(' ') << '|' << left << setw(9) << rows[0]
              << setfill(' ') << '|' << setw(20) << rows[1]
              << setfill(' ') << '|' << setw(20) << rows[2]
              << setfill(' ') << '|' << right << setw(20)
              << rows[3] << '|' << endl;
      }
      cout << left << setw(10) << setfill('-') << left
           << '+' << setw(21) << setfill('-') << left << '+'
           << setw(21)
           << setfill('-') << left << '+' << setw(21)
           << setfill('-')
           << '+' << '+' << endl;
   }
   mysql_free_result(rset);
}
Listing 4: BankTransaction.cpp
#include <iostream>
#include <sstream>
#include <iomanip>
 
#include <cstdlib>
#include <mysql.h>
 
#include "BankAccount.h"
#include "BankTransaction.h"
 
using namespace std;
 
enum Options { PRINT = 1, NEW, WITHDRAW, DEPOSIT,
               CLOSE, END };
 
int mainMenu()
{
   cout << "\nMenu Options" << endl
        << "1 - Print All Account"
        << endl << "2 - Open New Account" << endl
        << "3 - Withdraw" << endl << "4 - Deposit"
        << endl << "5 - Close Account" << endl
        << "6 - End Transaction" << endl;
   int ch;
   cin >> ch;
   return ch;
}
 
int main(int argc, char** argv)
{
   BankTransaction* bt =
      new BankTransaction("localhost", "root",
                          "passwd123", "mybank");
 
   int choice;
   int acno;
   string fname, lname;
   double bal;
 
   while(1) {
      choice = mainMenu();
      if(choice == END)
         break;
      switch(choice) {
      case PRINT:
         bt->printAllAccounts();
         break;
      case NEW:
         cout << "\nEnter account no, first name,
                             last name, balance: "
              << endl << "? ";
         cin >> acno;
         cin >> fname;
         cin >> lname;
         cin >> bal;
         if(acno < 1) {
            cout << "Invalid account number." << endl;
            break;
         }
         bt->createAccount(new BankAccount(acno, fname, lname,
                                           bal));
         break;
      case WITHDRAW:
         cout << "\nEnter account no, amount to withdraw "
              << endl << "? ";
         cin >> acno;
         cin >> bal;
         if(bal < 0) {
            cout << "Invalid amount." << endl;
            break;
         }
         bt->withdraw(acno, bal);
         break;
      case DEPOSIT:
         cout << "\nEnter account no, amount to deposit "
              << endl << "? ";
         cin >> acno;
         cin >> bal;
         if(bal < 0) {
            cout << "Invalid amount." << endl;
            break;
         }
         bt->deposit(acno, bal);
         break;
     case CLOSE:
         cout << "\nEnter account no to close account "
              << endl << "? ";
         cin >> acno;
         bt->closeAccount(acno);
         break;
      default:
         cerr << "Invalid choice!" << endl;
         break;
      }
   }
   return 0;
}

Listing 5: main.cpp

建立和执行项目


图3:已完成的项目

结论

       许多检查和验证是未实现的,以保持尽可能简单的事情。只使用了libmysqlclient API库中绝对最少的函数。实现了最小的CRUD操作,因此它可以作为进一步改进的基础。
 
飞码网-免费源码博客分享网站 飞码网-https://www.codefrees.com 设计代做,博客教程 飞码网-免费源码博客分享网站
赞 ()
内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: