C++调用MySQL数据库完整教程

C++调用MySQL数据库完整教程

目录

  1. 环境准备
  2. [安装MySQL Connector/C++](#安装MySQL Connector/C++)
  3. 基础连接示例
  4. 数据库操作
  5. 完整项目示例
  6. 编译和运行
  7. 常见问题

环境准备

1. 安装MySQL服务器

bash 复制代码
# Ubuntu/Debian
sudo apt update
sudo apt install mysql-server mysql-client

# CentOS/RHEL
sudo yum install mysql-server mysql

# 启动MySQL服务
sudo systemctl start mysql
sudo systemctl enable mysql

# 设置root密码和基本配置
sudo mysql_secure_installation

2. 创建测试数据库和用户

sql 复制代码
-- 登录MySQL
mysql -u root -p

-- 创建数据库
CREATE DATABASE testdb;

-- 创建用户并授权
CREATE USER 'testuser'@'localhost' IDENTIFIED BY 'testpass';
GRANT ALL PRIVILEGES ON testdb.* TO 'testuser'@'localhost';
FLUSH PRIVILEGES;

-- 使用数据库并创建测试表
USE testdb;
CREATE TABLE users (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    age INT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 插入测试数据
INSERT INTO users (name, email, age) VALUES 
('张三', 'zhangsan@example.com', 25),
('李四', 'lisi@example.com', 30),
('王五', 'wangwu@example.com', 28);

安装MySQL Connector/C++

Ubuntu/Debian 系统

bash 复制代码
# 方法1:使用包管理器安装
sudo apt update
sudo apt install libmysqlcppconn-dev

# 方法2:从官网下载安装包
# 访问 https://dev.mysql.com/downloads/connector/cpp/
# 下载对应版本的deb包并安装

CentOS/RHEL 系统

bash 复制代码
# 下载并安装MySQL官方仓库
sudo yum install mysql-connector-c++-devel

从源码编译安装

bash 复制代码
# 下载源码
wget https://dev.mysql.com/get/Downloads/Connector-C++/mysql-connector-c++-8.0.33-src.tar.gz
tar -xzf mysql-connector-c++-8.0.33-src.tar.gz
cd mysql-connector-c++-8.0.33-src

# 安装依赖
sudo apt install cmake libssl-dev

# 编译安装
mkdir build && cd build
cmake ..
make
sudo make install

基础连接示例

基础头文件包含

cpp 复制代码
#include <mysql_driver.h>        // 数据库驱动
#include <mysql_connection.h>    // 连接管理,数据库链接对象
#include <cppconn/statement.h>   // SQL语句执行
#include <cppconn/resultset.h>   // 查询结果处理
#include <cppconn/exception.h>   // 异常处理
#include <cppconn/prepared_statement.h>  // 预处理语句,防止SQL注入
#include <iostream>
#include <memory>
#include <string>

简单连接示例

cpp 复制代码
// simple_connect.cpp
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/exception.h>
#include <iostream>

int main() {
    try {
        // 获取MySQL驱动实例
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();//返回静态对象指针,是单例
        
        // 创建数据库连接
        std::unique_ptr<sql::Connection> conn(
            //主机地址和端口,数据库用户名, 用户密码,注意协议和双斜杠
            driver->connect("tcp://192.168.1.100:3306", "aaa", "123456")
        );
        
        // 选择数据库
        conn->setSchema("databases_name1");
        
        std::cout << "成功连接到MySQL数据库!" << std::endl;
        
    } catch (sql::SQLException& e) {
        std::cerr << "数据库错误: " << e.what() << std::endl;
        std::cerr << "错误代码: " << e.getErrorCode() << std::endl;
        std::cerr << "SQL状态: " << e.getSQLState() << std::endl;
        return 1;
    }
    
    return 0;
}

数据库操作

1. 查询操作

cpp 复制代码
// select_demo.cpp
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
#include <cppconn/exception.h>
#include <iostream>
#include <memory>

void selectUsers() {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(
            driver->connect("tcp://192.168.1.100:3306", "aaa", "123456")
        );
        conn->setSchema("databases_name1");
        
        // 创建SQL执行器
        std::unique_ptr<sql::Statement> stmt(conn->createStatement());
        
        // 执行查询
        std::unique_ptr<sql::ResultSet> res(
            stmt->executeQuery("SELECT id, name, email, age FROM users")
            //executeQuery()->用于select,返回ResultSet*
            //executeUpdate()->用于insert update delete,返回int(影响行数)
            //execute()->通用,返回bool(是否有结果集)
        );
        
        std::cout << "用户列表:" << std::endl;
        std::cout << "ID\t姓名\t\t邮箱\t\t\t年龄" << std::endl;
        std::cout << "----------------------------------------" << std::endl;
        
        // 遍历结果集
        while (res->next()) {
            std::cout << res->getInt("id") << "\t";
            std::cout << res->getString("name") << "\t\t";
            std::cout << res->getString("email") << "\t";
            std::cout << res->getInt("age") << std::endl;
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "查询错误: " << e.what() << std::endl;
    }
}

int main() {
    selectUsers();
    return 0;
}

2. 插入操作

cpp 复制代码
// insert_demo.cpp
#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/exception.h>
#include <iostream>
#include <memory>

void insertUser(const std::string& name, const std::string& email, int age) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(
            driver->connect("tcp://192.168.1.100:3306", "aaa", "123456")
        );
        conn->setSchema("testdb");
        
        // 使用预处理语句防止SQL注入
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("INSERT INTO users (name, email, age) VALUES (?, ?, ?)")
        );
        
        pstmt->setString(1, name);
        pstmt->setString(2, email);
        pstmt->setInt(3, age);
        
        int rows = pstmt->executeUpdate();
        
        if (rows > 0) {
            std::cout << "成功插入用户: " << name << std::endl;
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "插入错误: " << e.what() << std::endl;
    }
}

int main() {
    insertUser("赵六", "zhaoliu@example.com", 32);
    insertUser("孙七", "sunqi@example.com", 27);
    return 0;
}

3. 更新操作

cpp 复制代码
// update_demo.cpp
void updateUser(int userId, const std::string& newEmail) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(
            driver->connect("tcp://127.0.0.1:3306", "testuser", "testpass")
        );
        conn->setSchema("testdb");
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("UPDATE users SET email = ? WHERE id = ?")
        );
        
        pstmt->setString(1, newEmail);
        pstmt->setInt(2, userId);
        
        int rows = pstmt->executeUpdate();
        
        if (rows > 0) {
            std::cout << "成功更新用户ID " << userId << " 的邮箱" << std::endl;
        } else {
            std::cout << "未找到用户ID " << userId << std::endl;
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "更新错误: " << e.what() << std::endl;
    }
}

4. 删除操作

cpp 复制代码
// delete_demo.cpp
void deleteUser(int userId) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(
            driver->connect("tcp://127.0.0.1:3306", "testuser", "testpass")
        );
        conn->setSchema("testdb");
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("DELETE FROM users WHERE id = ?")
        );
        
        pstmt->setInt(1, userId);
        
        int rows = pstmt->executeUpdate();
        
        if (rows > 0) {
            std::cout << "成功删除用户ID " << userId << std::endl;
        } else {
            std::cout << "未找到用户ID " << userId << std::endl;
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "删除错误: " << e.what() << std::endl;
    }
}

完整项目示例

数据库管理类

cpp 复制代码
// DatabaseManager.h
#ifndef DATABASE_MANAGER_H
#define DATABASE_MANAGER_H

#include <mysql_driver.h>
#include <mysql_connection.h>
#include <cppconn/statement.h>
#include <cppconn/resultset.h>
#include <cppconn/prepared_statement.h>
#include <cppconn/exception.h>
#include <memory>
#include <string>
#include <vector>

struct User {
    int id;
    std::string name;
    std::string email;
    int age;
};

class DatabaseManager {
private:
    std::string host;
    std::string username;
    std::string password;
    std::string database;
    
public:
    DatabaseManager(const std::string& host, const std::string& username, 
                   const std::string& password, const std::string& database);
    
    bool connect();
    std::vector<User> getAllUsers();
    bool insertUser(const User& user);
    bool updateUser(const User& user);
    bool deleteUser(int userId);
    User getUserById(int userId);
};

#endif
cpp 复制代码
// DatabaseManager.cpp
#include "DatabaseManager.h"
#include <iostream>

DatabaseManager::DatabaseManager(const std::string& host, const std::string& username,
                               const std::string& password, const std::string& database)
    : host(host), username(username), password(password), database(database) {
}

bool DatabaseManager::connect() {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        std::cout << "数据库连接成功!" << std::endl;
        return true;
    } catch (sql::SQLException& e) {
        std::cerr << "数据库连接失败: " << e.what() << std::endl;
        return false;
    }
}

std::vector<User> DatabaseManager::getAllUsers() {
    std::vector<User> users;
    
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        
        std::unique_ptr<sql::Statement> stmt(conn->createStatement());
        std::unique_ptr<sql::ResultSet> res(
            stmt->executeQuery("SELECT id, name, email, age FROM users ORDER BY id")
        );
        
        while (res->next()) {
            User user;
            user.id = res->getInt("id");
            user.name = res->getString("name");
            user.email = res->getString("email");
            user.age = res->getInt("age");
            users.push_back(user);
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "查询用户失败: " << e.what() << std::endl;
    }
    
    return users;
}

bool DatabaseManager::insertUser(const User& user) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("INSERT INTO users (name, email, age) VALUES (?, ?, ?)")
        );
        
        pstmt->setString(1, user.name);
        pstmt->setString(2, user.email);
        pstmt->setInt(3, user.age);
        
        int rows = pstmt->executeUpdate();
        return rows > 0;
        
    } catch (sql::SQLException& e) {
        std::cerr << "插入用户失败: " << e.what() << std::endl;
        return false;
    }
}

bool DatabaseManager::updateUser(const User& user) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("UPDATE users SET name=?, email=?, age=? WHERE id=?")
        );
        
        pstmt->setString(1, user.name);
        pstmt->setString(2, user.email);
        pstmt->setInt(3, user.age);
        pstmt->setInt(4, user.id);
        
        int rows = pstmt->executeUpdate();
        return rows > 0;
        
    } catch (sql::SQLException& e) {
        std::cerr << "更新用户失败: " << e.what() << std::endl;
        return false;
    }
}

bool DatabaseManager::deleteUser(int userId) {
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("DELETE FROM users WHERE id = ?")
        );
        
        pstmt->setInt(1, userId);
        
        int rows = pstmt->executeUpdate();
        return rows > 0;
        
    } catch (sql::SQLException& e) {
        std::cerr << "删除用户失败: " << e.what() << std::endl;
        return false;
    }
}

User DatabaseManager::getUserById(int userId) {
    User user = {0, "", "", 0};
    
    try {
        sql::mysql::MySQL_Driver* driver = sql::mysql::get_mysql_driver_instance();
        std::unique_ptr<sql::Connection> conn(driver->connect(host, username, password));
        conn->setSchema(database);
        
        std::unique_ptr<sql::PreparedStatement> pstmt(
            conn->prepareStatement("SELECT id, name, email, age FROM users WHERE id = ?")
        );
        
        pstmt->setInt(1, userId);
        
        std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
        
        if (res->next()) {
            user.id = res->getInt("id");
            user.name = res->getString("name");
            user.email = res->getString("email");
            user.age = res->getInt("age");
        }
        
    } catch (sql::SQLException& e) {
        std::cerr << "查询用户失败: " << e.what() << std::endl;
    }
    
    return user;
}

主程序示例

cpp 复制代码
// main.cpp
#include "DatabaseManager.h"
#include <iostream>
#include <vector>

void printMenu() {
    std::cout << "\n========== 用户管理系统 ==========" << std::endl;
    std::cout << "1. 显示所有用户" << std::endl;
    std::cout << "2. 添加新用户" << std::endl;
    std::cout << "3. 更新用户信息" << std::endl;
    std::cout << "4. 删除用户" << std::endl;
    std::cout << "5. 查找用户" << std::endl;
    std::cout << "0. 退出程序" << std::endl;
    std::cout << "请选择操作: ";
}

void printUsers(const std::vector<User>& users) {
    std::cout << "\n用户列表:" << std::endl;
    std::cout << "ID\t姓名\t\t邮箱\t\t\t年龄" << std::endl;
    std::cout << "------------------------------------------------" << std::endl;
    
    for (const auto& user : users) {
        std::cout << user.id << "\t" << user.name << "\t\t" 
                  << user.email << "\t" << user.age << std::endl;
    }
}

int main() {
    DatabaseManager db("tcp://127.0.0.1:3306", "testuser", "testpass", "testdb");
    
    if (!db.connect()) {
        std::cerr << "无法连接到数据库,程序退出。" << std::endl;
        return 1;
    }
    
    int choice;
    
    while (true) {
        printMenu();
        std::cin >> choice;
        
        switch (choice) {
            case 1: {
                auto users = db.getAllUsers();
                printUsers(users);
                break;
            }
            
            case 2: {
                User newUser;
                std::cout << "输入姓名: ";
                std::cin >> newUser.name;
                std::cout << "输入邮箱: ";
                std::cin >> newUser.email;
                std::cout << "输入年龄: ";
                std::cin >> newUser.age;
                
                if (db.insertUser(newUser)) {
                    std::cout << "用户添加成功!" << std::endl;
                } else {
                    std::cout << "用户添加失败!" << std::endl;
                }
                break;
            }
            
            case 3: {
                User updateUser;
                std::cout << "输入要更新的用户ID: ";
                std::cin >> updateUser.id;
                
                User existingUser = db.getUserById(updateUser.id);
                if (existingUser.id == 0) {
                    std::cout << "用户不存在!" << std::endl;
                    break;
                }
                
                std::cout << "当前信息 - 姓名: " << existingUser.name 
                          << ", 邮箱: " << existingUser.email 
                          << ", 年龄: " << existingUser.age << std::endl;
                
                std::cout << "输入新姓名: ";
                std::cin >> updateUser.name;
                std::cout << "输入新邮箱: ";
                std::cin >> updateUser.email;
                std::cout << "输入新年龄: ";
                std::cin >> updateUser.age;
                
                if (db.updateUser(updateUser)) {
                    std::cout << "用户信息更新成功!" << std::endl;
                } else {
                    std::cout << "用户信息更新失败!" << std::endl;
                }
                break;
            }
            
            case 4: {
                int userId;
                std::cout << "输入要删除的用户ID: ";
                std::cin >> userId;
                
                if (db.deleteUser(userId)) {
                    std::cout << "用户删除成功!" << std::endl;
                } else {
                    std::cout << "用户删除失败或用户不存在!" << std::endl;
                }
                break;
            }
            
            case 5: {
                int userId;
                std::cout << "输入用户ID: ";
                std::cin >> userId;
                
                User user = db.getUserById(userId);
                if (user.id != 0) {
                    std::cout << "用户信息:" << std::endl;
                    std::cout << "ID: " << user.id << std::endl;
                    std::cout << "姓名: " << user.name << std::endl;
                    std::cout << "邮箱: " << user.email << std::endl;
                    std::cout << "年龄: " << user.age << std::endl;
                } else {
                    std::cout << "用户不存在!" << std::endl;
                }
                break;
            }
            
            case 0:
                std::cout << "程序退出。" << std::endl;
                return 0;
                
            default:
                std::cout << "无效选择,请重新输入。" << std::endl;
                break;
        }
    }
    
    return 0;
}

编译和运行

CMakeLists.txt 配置

cmake 复制代码
cmake_minimum_required(VERSION 3.10)
project(MySQLCppDemo)

set(CMAKE_CXX_STANDARD 11)

# 查找MySQL Connector/C++
find_path(MYSQLCPPCONN_INCLUDE_DIR 
    NAMES mysql_driver.h
    PATHS /usr/include/mysql-cppconn /usr/local/include/mysql-cppconn
)

find_library(MYSQLCPPCONN_LIBRARY 
    NAMES mysqlcppconn
    PATHS /usr/lib /usr/local/lib
)

# 包含头文件路径
include_directories(${MYSQLCPPCONN_INCLUDE_DIR})

# 添加可执行文件
add_executable(simple_connect simple_connect.cpp)
add_executable(select_demo select_demo.cpp)
add_executable(insert_demo insert_demo.cpp)
add_executable(mysql_manager main.cpp DatabaseManager.cpp)

# 链接库
target_link_libraries(simple_connect ${MYSQLCPPCONN_LIBRARY})
target_link_libraries(select_demo ${MYSQLCPPCONN_LIBRARY})
target_link_libraries(insert_demo ${MYSQLCPPCONN_LIBRARY})
target_link_libraries(mysql_manager ${MYSQLCPPCONN_LIBRARY})

使用g++直接编译

bash 复制代码
# 编译单个文件
g++ -std=c++11 simple_connect.cpp -o simple_connect -lmysqlcppconn

# 编译完整项目
g++ -std=c++11 main.cpp DatabaseManager.cpp -o mysql_manager -lmysqlcppconn

# 如果头文件路径不在默认路径中,需要指定
g++ -std=c++11 -I/usr/include/mysql-cppconn main.cpp DatabaseManager.cpp -o mysql_manager -lmysqlcppconn

Makefile 配置

makefile 复制代码
CXX = g++
CXXFLAGS = -std=c++11 -Wall
INCLUDES = -I/usr/include/mysql-cppconn
LIBS = -lmysqlcppconn

SOURCES = main.cpp DatabaseManager.cpp
TARGET = mysql_manager

$(TARGET): $(SOURCES)
	$(CXX) $(CXXFLAGS) $(INCLUDES) $(SOURCES) -o $(TARGET) $(LIBS)

simple_connect: simple_connect.cpp
	$(CXX) $(CXXFLAGS) $(INCLUDES) simple_connect.cpp -o simple_connect $(LIBS)

select_demo: select_demo.cpp
	$(CXX) $(CXXFLAGS) $(INCLUDES) select_demo.cpp -o select_demo $(LIBS)

clean:
	rm -f $(TARGET) simple_connect select_demo

.PHONY: clean

运行程序

bash 复制代码
# 编译
make

# 运行
./mysql_manager

常见问题

1. 编译错误

问题 :找不到头文件 mysql_driver.h

复制代码
fatal error: mysql_driver.h: No such file or directory

解决方案

bash 复制代码
# 查找头文件位置
find /usr -name "mysql_driver.h" 2>/dev/null

# 添加到编译命令中
g++ -I/usr/include/mysql-cppconn ...

2. 链接错误

问题 :找不到 -lmysqlcppconn

复制代码
/usr/bin/ld: cannot find -lmysqlcppconn

解决方案

bash 复制代码
# 查找库文件
find /usr -name "libmysqlcppconn*" 2>/dev/null

# 安装开发库
sudo apt install libmysqlcppconn-dev

3. 运行时错误

问题:连接数据库失败

复制代码
SQLException: Access denied for user 'testuser'@'localhost'

解决方案

  • 检查用户名和密码是否正确
  • 确认MySQL服务正在运行
  • 验证用户权限设置

4. 字符编码问题

问题:中文显示乱码

解决方案

cpp 复制代码
// 在连接后设置字符集
conn->setSchema("testdb");
stmt->execute("SET NAMES utf8mb4");

5. 内存管理

建议

  • 使用智能指针 std::unique_ptr 管理资源
  • 正确处理异常以避免内存泄漏
  • 及时释放不再使用的连接

最佳实践

  1. 连接池管理:对于高并发应用,实现连接池
  2. 预处理语句:使用预处理语句防止SQL注入
  3. 异常处理:妥善处理所有可能的异常
  4. 资源管理:使用RAII原则管理数据库资源
  5. 配置外部化:将数据库配置信息放在配置文件中
  6. 日志记录:记录数据库操作日志便于调试

扩展学习

  • 学习数据库连接池实现
  • 了解事务处理机制
  • 掌握数据库性能优化
  • 学习ORM框架的使用
  • 研究异步数据库操作

本教程提供了C++调用MySQL数据库的完整指南,从基础连接到完整项目实现。按照步骤操作即可快速上手C++数据库开发。

相关推荐
曾凡宇先生3 小时前
无法远程连接 MySQL
android·开发语言·数据库·sql·tcp/ip·mysql·adb
苏小瀚3 小时前
[MySQL] 事务和视图
数据库·mysql·1024程序员节
让我们一起加油好吗3 小时前
【数论】欧拉定理 && 扩展欧拉定理
c++·算法·数论·1024程序员节·欧拉定理·欧拉降幂·扩展欧拉定理
Yupureki4 小时前
从零开始的C++学习生活 14:map/set的使用和封装
c语言·数据结构·c++·学习·visual studio·1024程序员节
一匹电信狗4 小时前
【LeetCode_876_2.02】快慢指针在链表中的简单应用
c语言·数据结构·c++·算法·leetcode·链表·stl
keineahnung23454 小时前
C++中的Aggregate initialization
c++·1024程序员节
胖咕噜的稞达鸭4 小时前
算法入门---专题二:滑动窗口2(最大连续1的个数,无重复字符的最长子串 )
c语言·数据结构·c++·算法·推荐算法·1024程序员节
Yupureki4 小时前
从零开始的C++学习生活 15:哈希表的使用和封装unordered_map/set
c语言·数据结构·c++·学习·visual studio·1024程序员节
我是华为OD~HR~栗栗呀4 小时前
华为OD-Java面经-21届考研
java·c++·后端·python·华为od·华为·面试