C++调用MySQL数据库完整教程
目录
环境准备
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管理资源 - 正确处理异常以避免内存泄漏
- 及时释放不再使用的连接
最佳实践
- 连接池管理:对于高并发应用,实现连接池
- 预处理语句:使用预处理语句防止SQL注入
- 异常处理:妥善处理所有可能的异常
- 资源管理:使用RAII原则管理数据库资源
- 配置外部化:将数据库配置信息放在配置文件中
- 日志记录:记录数据库操作日志便于调试
扩展学习
- 学习数据库连接池实现
- 了解事务处理机制
- 掌握数据库性能优化
- 学习ORM框架的使用
- 研究异步数据库操作
本教程提供了C++调用MySQL数据库的完整指南,从基础连接到完整项目实现。按照步骤操作即可快速上手C++数据库开发。