1. 数据库基础概念

1.1 数据库类型

数据库主要分为关系型数据库非关系型数据库两大类。

  • 关系型数据库​:采用表格形式存储数据,使用SQL进行查询操作。常见的有:

    • MySQL
    • SQL Server
    • Oracle
    • PostgreSQL
    • SQLite
  • 非关系型数据库​:不以表格形式存储数据,包括键值对、文档、列存储等形式。常见的有:

    • Redis
    • Memcache
    • MongoDB
    • HBase

1.2 关键操作区别

DELETE、TRUNCATE 和 DROP 的区别
操作 类型 可否回滚 是否记录日志 执行速度 影响范围
DELETE DML 可以 记录 最慢 删除部分或全部行数据
TRUNCATE DDL 不可以 不记录 中等 删除所有行数据,ID从0开始
DROP DDL 不可以 不记录 最快 删除表数据及表结构

2. C++连接数据库

2.1 MySQL连接示例

C++连接MySQL数据库通常使用MySQL Connector/C++库

#include <iostream>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>

int main() {
    try {
        // 创建数据库驱动
        sql::mysql::MySQL_Driver *driver;
        sql::Connection *con;
        
        // 初始化驱动并连接数据库
        driver = sql::mysql::get_mysql_driver_instance();
        con = driver->connect("tcp://127.0.0.1:3306", "username", "password");
        
        // 选择数据库
        con->setSchema("test_db");
        std::cout << "成功连接到数据库!" << std::endl;
        
        // 执行查询
        sql::Statement *stmt;
        sql::ResultSet *res;
        
        stmt = con->createStatement();
        res = stmt->executeQuery("SELECT * FROM users");
        
        // 处理结果
        while (res->next()) {
            std::cout << "ID: " << res->getInt("id");
            std::cout << ", Name: " << res->getString("name");
            std::cout << ", Age: " << res->getInt("age") << std::endl;
        }
        
        // 释放资源
        delete res;
        delete stmt;
        delete con;
    } catch (sql::SQLException &e) {
        std::cerr << "SQL错误: " << e.what() << std::endl;
        std::cerr << "错误代码: " << e.getErrorCode() << std::endl;
    }
    return 0;
}

2.2 SQLite连接示例

对于轻量级应用,SQLite是一个不错的选择:

#include <iostream>
#include <sqlite3.h>

int main() {
    sqlite3 *db;
    char *zErrMsg = 0;
    int rc;
    
    // 打开数据库
    rc = sqlite3_open("test.db", &db);
    
    if (rc) {
        std::cerr << "无法打开数据库: " << sqlite3_errmsg(db) << std::endl;
        return(1);
    } else {
        std::cout << "成功打开数据库!" << std::endl;
    }
    
    // 创建表
    const char *sql = "CREATE TABLE IF NOT EXISTS users ("
                      "id INTEGER PRIMARY KEY AUTOINCREMENT, "
                      "name TEXT NOT NULL, "
                      "age INTEGER);";
    
    rc = sqlite3_exec(db, sql, 0, 0, &zErrMsg);
    
    if (rc != SQLITE_OK) {
        std::cerr << "SQL错误: " << zErrMsg << std::endl;
        sqlite3_free(zErrMsg);
    } else {
        std::cout << "表创建成功" << std::endl;
    }
    
    sqlite3_close(db);
    return 0;
}

3. 数据库操作

3.1 CRUD操作

在C++中执行基本的增删改查操作:

// 插入数据
sql::PreparedStatement *pstmt = con->prepareStatement(
    "INSERT INTO users(name, age) VALUES (?, ?)");
pstmt->setString(1, "John Doe");
pstmt->setInt(2, 30);
pstmt->executeUpdate();

// 查询数据
sql::ResultSet *res = stmt->executeQuery(
    "SELECT * FROM users WHERE age > 25");
    
// 更新数据
sql::PreparedStatement *pstmt = con->prepareStatement(
    "UPDATE users SET age = ? WHERE name = ?");
pstmt->setInt(1, 31);
pstmt->setString(2, "John Doe");
pstmt->executeUpdate();

// 删除数据
sql::PreparedStatement *pstmt = con->prepareStatement(
    "DELETE FROM users WHERE id = ?");
pstmt->setInt(1, 5);
pstmt->executeUpdate();

3.2 使用预处理语句

预处理语句不仅能提高性能,还能有效防止SQL注入攻击:

// 使用预处理语句插入数据
sql::PreparedStatement *pstmt = con->prepareStatement(
    "INSERT INTO users (name, email, age) VALUES (?, ?, ?)");

pstmt->setString(1, "Alice");
pstmt->setString(2, "alice@example.com");
pstmt->setInt(3, 30);
pstmt->executeUpdate();

// 使用预处理语句查询
sql::PreparedStatement *pstmt = con->prepareStatement(
    "SELECT name, age FROM users WHERE age > ? AND name LIKE ?");

pstmt->setInt(1, 25);
pstmt->setString(2, "A%");
sql::ResultSet *res = pstmt->executeQuery();

4. 事务处理

4.1 ACID特性

数据库事务必须满足ACID特性:

  • 原子性 (Atomicity)​​:事务中的所有操作要么全部完成,要么全部不完成。通过undo log实现,记录SQL执行相关信息,回滚时执行相反操作。
  • 一致性 (Consistency)​​:事务将数据库从一种一致状态转变为另一种一致状态。
  • 隔离性 (Isolation)​​:多个并发事务相互隔离,通过锁机制MVCC​(多版本并发控制)实现。
  • 持久性 (Durability)​​:事务提交后结果永久保存,通过redo log实现。

4.2 C++中的事务管理

try {
    // 禁用自动提交
    con->setAutoCommit(false);
    
    // 执行多个数据库操作
    sql::PreparedStatement *pstmt = con->prepareStatement(
        "UPDATE accounts SET balance = balance - ? WHERE id = ?");
    pstmt->setDouble(1, 100.0);
    pstmt->setInt(2, 1);
    pstmt->executeUpdate();
    
    pstmt = con->prepareStatement(
        "UPDATE accounts SET balance = balance + ? WHERE id = ?");
    pstmt->setDouble(1, 100.0);
    pstmt->setInt(2, 2);
    pstmt->executeUpdate();
    
    // 提交事务
    con->commit();
    std::cout << "事务执行成功" << std::endl;
    
} catch (sql::SQLException &e) {
    // 回滚事务
    con->rollback();
    std::cerr << "事务执行失败: " << e.what() << std::endl;
}

>>>C/C++入门及练手项目<<<

5. 数据库优化

5.1 索引优化

索引是提高查询性能的关键手段:

  • 索引类型​:B-tree索引、哈希索引、全文索引等
  • 索引设计原则​:
    • 为经常查询的列创建索引
    • 为连接操作的表连接列创建索引
    • 考虑索引选择性,高选择性列更适合索引
  • 索引失效情况​:
    • 使用LIKE时以通配符开头(如%value
    • 对索引列进行运算操作
    • 使用OR关键字且OR前后条件不全有索引
    • 类型转换会导致索引失效

5.2 查询优化

 ​1.避免使用SELECT ​​* 
尽量指定需要的列,而不是使用SELECT *:

-- 不推荐
SELECT * FROM users WHERE age > 25;

-- 推荐
SELECT id, name, age FROM users WHERE age > 25;

​2.合理使用LIMIT分页
对于大数据集,使用高效分页:

-- 低效分页(偏移量大时)
SELECT * FROM users ORDER BY id LIMIT 10000, 20;

-- 高效分页(使用索引和边界值)
SELECT * FROM users WHERE id > 10000 ORDER BY id LIMIT 20;

5.3 数据库结构优化

  1. 规范化与反规范化

    • 规范化:减少数据冗余,提高数据一致性
    • 反规范化:适当增加冗余,减少连接操作,提高查询性能
  2. 分区表
    对大数据表进行分区,提高查询性能和管理效率。

  3. 垂直拆分
    将字段多的表拆分成多个表,将常用字段和不常用字段分开。

6. 高级主题

6.1 连接池技术

在多线程环境下,使用连接池可以有效地复用连接,提高性能并减少连接创建的开销。

// 简化的连接池示例
class ConnectionPool {
private:
    std::queue<sql::Connection*> connections;
    std::mutex mtx;
    std::string url, username, password;
    
public:
    ConnectionPool(const std::string& url, const std::string& username, 
                  const std::string& password, int poolSize) {
        sql::mysql::MySQL_Driver *driver = sql::mysql::get_mysql_driver_instance();
        for (int i = 0; i < poolSize; ++i) {
            sql::Connection *con = driver->connect(url, username, password);
            connections.push(con);
        }
    }
    
    sql::Connection* getConnection() {
        std::lock_guard<std::mutex> lock(mtx);
        if (connections.empty()) {
            return nullptr;
        }
        sql::Connection* con = connections.front();
        connections.pop();
        return con;
    }
    
    void releaseConnection(sql::Connection* con) {
        std::lock_guard<std::mutex> lock(mtx);
        connections.push(con);
    }
};

6.2 ORM框架基本概念

虽然C++没有官方标准的ORM框架,但你可以理解ORM的基本概念:

  • 对象-关系映射​:将数据库表映射为类,行映射为对象,列映射为属性
  • 优势​:提高开发效率,减少重复SQL编写
  • 劣势​:可能带来性能损失,复杂查询不如原生SQL灵活

7. 完整示例:简易员工管理系统

#include <iostream>
#include <cppconn/driver.h>
#include <cppconn/exception.h>
#include <cppconn/resultset.h>
#include <cppconn/statement.h>
#include <cppconn/prepared_statement.h>

class EmployeeDB {
private:
    sql::mysql::MySQL_Driver *driver;
    sql::Connection *con;
    
public:
    EmployeeDB() {
        try {
            driver = sql::mysql::get_mysql_driver_instance();
            con = driver->connect("tcp://127.0.0.1:3306", "root", "password");
            con->setSchema("company");
        } catch (sql::SQLException &e) {
            std::cerr << "数据库连接错误: " << e.what() << std::endl;
        }
    }
    
    ~EmployeeDB() {
        delete con;
    }
    
    void addEmployee(const std::string &name, const std::string &position, double salary) {
        try {
            sql::PreparedStatement *pstmt = con->prepareStatement(
                "INSERT INTO employees (name, position, salary) VALUES (?, ?, ?)");
            pstmt->setString(1, name);
            pstmt->setString(2, position);
            pstmt->setDouble(3, salary);
            pstmt->executeUpdate();
            delete pstmt;
            
            std::cout << "员工添加成功: " << name << std::endl;
        } catch (sql::SQLException &e) {
            std::cerr << "添加员工错误: " << e.what() << std::endl;
        }
    }
    
    void listEmployees() {
        try {
            sql::Statement *stmt = con->createStatement();
            sql::ResultSet *res = stmt->executeQuery(
                "SELECT id, name, position, salary FROM employees ORDER BY id");
            
            std::cout << "ID\t姓名\t职位\t薪资" << std::endl;
            std::cout << "--------------------------------" << std::endl;
            
            while (res->next()) {
                std::cout << res->getInt("id") << "\t";
                std::cout << res->getString("name") << "\t";
                std::cout << res->getString("position") << "\t";
                std::cout << res->getDouble("salary") << std::endl;
            }
            
            delete res;
            delete stmt;
        } catch (sql::SQLException &e) {
            std::cerr << "查询员工错误: " << e.what() << std::endl;
        }
    }
    
    void updateSalary(int id, double newSalary) {
        try {
            con->setAutoCommit(false); // 开始事务
            
            sql::PreparedStatement *pstmt = con->prepareStatement(
                "UPDATE employees SET salary = ? WHERE id = ?");
            pstmt->setDouble(1, newSalary);
            pstmt->setInt(2, id);
            int affectedRows = pstmt->executeUpdate();
            
            if (affectedRows > 0) {
                con->commit(); // 提交事务
                std::cout << "员工薪资更新成功" << std::endl;
            } else {
                con->rollback(); // 回滚事务
                std::cout << "未找到指定员工" << std::endl;
            }
            
            delete pstmt;
        } catch (sql::SQLException &e) {
            con->rollback(); // 回滚事务
            std::cerr << "更新薪资错误: " << e.what() << std::endl;
        }
    }
};

int main() {
    EmployeeDB db;
    
    // 添加员工
    db.addEmployee("张三", "工程师", 15000.0);
    db.addEmployee("李四", "经理", 25000.0);
    
    // 列出所有员工
    db.listEmployees();
    
    // 更新薪资
    db.updateSalary(1, 16000.0);
    
    return 0;
}

8. 总结

本文涵盖了C++数据库编程的核心知识点,包括:

  1. 数据库基础​:了解了不同类型数据库及其特点
  2. 连接管理​:掌握了如何使用C++连接MySQL和SQLite数据库
  3. CRUD操作​:学会了执行增删改查等基本数据库操作
  4. 事务处理​:理解了ACID特性及如何在C++中实现事务管理
  5. 性能优化​:掌握了索引优化、查询优化和结构优化的关键技术
  6. 高级主题​:了解了连接池、ORM等高级概念

掌握这些知识将帮助你在C++面试中更好地应对数据库相关的问题,同时也能在实际开发中构建高效、可靠的数据库应用程序。

注意:本文中的代码示例需要安装相应的数据库驱动库,如MySQL Connector/C++,并在编译时链接这些库。

 完整C++后端八股文:>> C++八股文(完整版)<<
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐