C++ ODB框架详解:现代C++对象关系映射解决方案

目录

  • 框架简介
  • 安装与配置
  • 基础概念
  • 实体映射
  • 数据库操作
  • 查询操作
  • 高级功能
  • 性能优化
  • 最佳实践

框架简介

ODB(Object-Relational Database)是一个专为C++设计的对象关系映射(ORM)框架,由CodeSynthesis公司开发。它提供了一种现代化的方式来处理C++应用程序中的数据库操作,将复杂的SQL操作抽象为简单的C++对象操作。

主要特性

  • 类型安全:编译时类型检查,避免运行时错误
  • 高性能:零开销抽象,接近原生SQL性能
  • 多数据库支持:MySQL、PostgreSQL、SQLite、Oracle、SQL Server
  • 自动代码生成:基于C++类自动生成数据库访问代码
  • 事务支持:完整的ACID事务处理
  • 查询语言:类型安全的查询DSL
  • 模式演化:数据库模式版本管理

架构概述

┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   应用程序      │    │   ODB编译器     │    │   数据库        │
│                 │    │                 │    │                 │
│ C++对象模型     │◄──►│ 代码生成器      │◄──►│ 关系模型        │
│                 │    │                 │    │                 │
│ 业务逻辑        │    │ SQL映射         │    │ 数据存储        │
└─────────────────┘    └─────────────────┘    └─────────────────┘

安装与配置

系统要求

  • C++11或更高版本编译器
  • 支持的数据库客户端库
  • CMake 3.5+(推荐)

安装步骤

1. 下载ODB编译器
# Ubuntu/Debian
sudo apt-get install odb libodb-dev# CentOS/RHEL
sudo yum install odb libodb-devel# 或从源码编译
wget https://www.codesynthesis.com/download/odb/2.4/odb-2.4.0.tar.gz
tar -xzf odb-2.4.0.tar.gz
cd odb-2.4.0
./configure --prefix=/usr/local
make && sudo make install
2. 安装数据库特定库
# MySQL支持
sudo apt-get install libodb-mysql-dev# PostgreSQL支持  
sudo apt-get install libodb-pgsql-dev# SQLite支持
sudo apt-get install libodb-sqlite-dev
3. CMake配置
cmake_minimum_required(VERSION 3.5)
project(ODBExample)set(CMAKE_CXX_STANDARD 11)# 查找ODB库
find_package(PkgConfig REQUIRED)
pkg_check_modules(ODB REQUIRED libodb)
pkg_check_modules(ODB_MYSQL REQUIRED libodb-mysql)# 设置包含目录和链接库
include_directories(${ODB_INCLUDE_DIRS} ${ODB_MYSQL_INCLUDE_DIRS})
link_directories(${ODB_LIBRARY_DIRS} ${ODB_MYSQL_LIBRARY_DIRS})# 添加可执行文件
add_executable(example main.cpp person.cxx person-odb.cxx)
target_link_libraries(example ${ODB_LIBRARIES} ${ODB_MYSQL_LIBRARIES})# ODB代码生成规则
add_custom_command(OUTPUT person-odb.hxx person-odb.ixx person-odb.cxxCOMMAND odb --database mysql --generate-query --generate-schema person.hxxDEPENDS person.hxxCOMMENT "Generating ODB files"
)

基础概念

持久化类

在ODB中,需要持久化到数据库的C++类称为持久化类。通过pragma指令标记:

#include <odb/core.hxx>
#include <string>#pragma db object
class Person {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string first_name_;std::string last_name_;unsigned short age_;public:Person() = default;Person(const std::string& first, const std::string& last, unsigned short age): first_name_(first), last_name_(last), age_(age) {}// Gettersunsigned long id() const { return id_; }const std::string& first_name() const { return first_name_; }const std::string& last_name() const { return last_name_; }unsigned short age() const { return age_; }// Settersvoid first_name(const std::string& name) { first_name_ = name; }void last_name(const std::string& name) { last_name_ = name; }void age(unsigned short a) { age_ = a; }
};

数据库连接

#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include <memory>std::unique_ptr<odb::database> create_database() {return std::make_unique<odb::mysql::database>("user",           // 用户名"password",       // 密码"database_name",  // 数据库名"localhost",      // 主机3306,            // 端口nullptr,         // socket"utf8"           // 字符集);
}

基本CRUD操作

#include "person.hxx"
#include "person-odb.hxx"
#include <odb/transaction.hxx>void basic_operations() {auto db = create_database();// 创建表结构{odb::transaction t(db->begin());db->execute("DROP TABLE IF EXISTS Person");db->execute(R"(CREATE TABLE Person (id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,first_name VARCHAR(255) NOT NULL,last_name VARCHAR(255) NOT NULL,age SMALLINT UNSIGNED NOT NULL))");t.commit();}// 插入数据{odb::transaction t(db->begin());Person john("John", "Doe", 30);Person jane("Jane", "Smith", 25);db->persist(john);db->persist(jane);t.commit();std::cout << "John ID: " << john.id() << std::endl;std::cout << "Jane ID: " << jane.id() << std::endl;}// 查询数据{odb::transaction t(db->begin());std::unique_ptr<Person> p(db->load<Person>(1));std::cout << "Loaded: " << p->first_name() << " " << p->last_name() << std::endl;t.commit();}// 更新数据{odb::transaction t(db->begin());std::unique_ptr<Person> p(db->load<Person>(1));p->age(31);db->update(*p);t.commit();}// 删除数据{odb::transaction t(db->begin());db->erase<Person>(2);t.commit();}
}#### 多对多关系```cpp
#pragma db object
class Student {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string name_;#pragma db many_to_many("student_course")std::vector<odb::lazy_shared_ptr<Course>> courses_;public:// 构造函数和访问器...
};#pragma db object
class Course {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string title_;#pragma db many_to_many("student_course") inverse(courses_)std::vector<odb::lazy_weak_ptr<Student>> students_;public:// 构造函数和访问器...
};

继承映射

#pragma db object polymorphic
class Animal {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string name_;public:virtual ~Animal() = default;// 构造函数和访问器...
};#pragma db object
class Dog : public Animal {
private:friend class odb::access;std::string breed_;public:// 构造函数和访问器...
};#pragma db object
class Cat : public Animal {
private:friend class odb::access;bool indoor_;public:// 构造函数和访问器...
};

数据库操作

事务管理

#include <odb/transaction.hxx>void transaction_example() {auto db = create_database();try {odb::transaction t(db->begin());// 批量操作for (int i = 0; i < 100; ++i) {Person p("User" + std::to_string(i), "Test", 20 + i % 50);db->persist(p);}t.commit();std::cout << "Transaction committed successfully" << std::endl;}catch (const odb::exception& e) {std::cerr << "Database error: " << e.what() << std::endl;// 事务会自动回滚}
}// 嵌套事务
void nested_transaction_example() {auto db = create_database();odb::transaction outer(db->begin());try {Person p1("Alice", "Johnson", 28);db->persist(p1);// 保存点odb::transaction inner(db->begin());try {Person p2("Bob", "Wilson", 35);db->persist(p2);inner.commit();}catch (...) {// inner事务回滚,但outer事务继续}outer.commit();}catch (...) {// outer事务回滚}
}

批量操作

void batch_operations() {auto db = create_database();// 批量插入{odb::transaction t(db->begin());std::vector<Person> people;for (int i = 0; i < 1000; ++i) {people.emplace_back("User" + std::to_string(i), "Batch", 20 + i % 50);}for (auto& person : people) {db->persist(person);}t.commit();}// 批量更新{odb::transaction t(db->begin());db->execute("UPDATE Person SET age = age + 1 WHERE age < 30");t.commit();}// 批量删除{odb::transaction t(db->begin());db->erase_query<Person>(odb::query<Person>::age > 65);t.commit();}
}

查询操作

基础查询

#include "person-odb.hxx"void basic_queries() {auto db = create_database();odb::transaction t(db->begin());// 简单查询typedef odb::query<Person> query;typedef odb::result<Person> result;// 按年龄查询result r(db->query<Person>(query::age >= 25 && query::age <= 35));for (const auto& person : r) {std::cout << person.first_name() << " " << person.last_name() << " (age: " << person.age() << ")" << std::endl;}// 按姓名查询result r2(db->query<Person>(query::first_name == "John"));// 模糊查询result r3(db->query<Person>(query::last_name.like("%son")));// 排序查询result r4(db->query<Person>(query::age > 20 + "ORDER BY" + query::age));t.commit();
}

高级查询

void advanced_queries() {auto db = create_database();odb::transaction t(db->begin());typedef odb::query<Person> query;typedef odb::result<Person> result;// 参数化查询std::string name_pattern = "J%";int min_age = 25;result r(db->query<Person>(query::first_name.like(query::_ref(name_pattern)) &&query::age >= query::_val(min_age)));// 聚合查询typedef odb::query<PersonStat> stat_query;typedef odb::result<PersonStat> stat_result;#pragma db view object(Person)struct PersonStat {#pragma db column("count(*)")std::size_t count;#pragma db column("avg(age)")double avg_age;#pragma db column("min(age)")unsigned short min_age;#pragma db column("max(age)")unsigned short max_age;};stat_result sr(db->query<PersonStat>());const PersonStat& stat = *sr.begin();std::cout << "Total persons: " << stat.count << std::endl;std::cout << "Average age: " << stat.avg_age << std::endl;// 连接查询typedef odb::query<PersonAddress> pa_query;typedef odb::result<PersonAddress> pa_result;#pragma db view object(Person) object(Address)struct PersonAddress {#pragma db column(Person::first_name_)std::string first_name;#pragma db column(Person::last_name_)std::string last_name;#pragma db column(Address::city_)std::string city;};pa_result par(db->query<PersonAddress>(pa_query::Person::address == pa_query::Address::id &&pa_query::Address::city == "New York"));t.commit();
}

延迟加载

void lazy_loading_example() {auto db = create_database();// 保存数据{odb::transaction t(db->begin());auto dept = std::make_shared<Department>("Engineering");db->persist(*dept);Employee emp1("Alice", dept);Employee emp2("Bob", dept);db->persist(emp1);db->persist(emp2);t.commit();}// 延迟加载{odb::transaction t(db->begin());std::unique_ptr<Employee> emp(db->load<Employee>(1));// 此时department_还未加载std::cout << "Employee: " << emp->name() << std::endl;// 访问时才加载if (emp->department().loaded()) {std::cout << "Department already loaded" << std::endl;} else {std::cout << "Loading department..." << std::endl;auto dept = emp->department().load();std::cout << "Department: " << dept->name() << std::endl;}t.commit();}
}

高级功能

视图(Views)

// 简单视图
#pragma db view object(Person)
struct PersonView {#pragma db column(Person::first_name_ + " " + Person::last_name_)std::string full_name;#pragma db column(Person::age_)unsigned short age;
};// 复杂视图
#pragma db view query("SELECT p.first_name, p.last_name, a.city " \"FROM Person p " \"LEFT JOIN Address a ON p.address_id = a.id " \"WHERE p.age > (?) AND a.city IS NOT NULL")
struct PersonCityView {std::string first_name;std::string last_name;std::string city;
};void view_example() {auto db = create_database();odb::transaction t(db->begin());// 使用简单视图typedef odb::result<PersonView> view_result;view_result vr(db->query<PersonView>());for (const auto& pv : vr) {std::cout << pv.full_name << " (age: " << pv.age << ")" << std::endl;}// 使用参数化视图typedef odb::result<PersonCityView> city_result;city_result cr(db->query<PersonCityView>(25));for (const auto& pcv : cr) {std::cout << pcv.first_name << " " << pcv.last_name << " lives in " << pcv.city << std::endl;}t.commit();
}

回调函数

#pragma db object callback(db_callback)
class Person {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string first_name_;std::string last_name_;unsigned short age_;#pragma db transientmutable std::string cached_full_name_;public:// 构造函数和访问器...// 回调函数void db_callback(odb::callback_event e, odb::database& db) const {switch (e) {case odb::callback_event::pre_persist:std::cout << "About to persist: " << first_name_ << std::endl;break;case odb::callback_event::post_persist:std::cout << "Persisted with ID: " << id_ << std::endl;break;case odb::callback_event::pre_load:cached_full_name_.clear();break;case odb::callback_event::post_load:cached_full_name_ = first_name_ + " " + last_name_;std::cout << "Loaded: " << cached_full_name_ << std::endl;break;case odb::callback_event::pre_update:std::cout << "About to update: " << first_name_ << std::endl;break;case odb::callback_event::post_update:std::cout << "Updated: " << first_name_ << std::endl;break;case odb::callback_event::pre_erase:std::cout << "About to erase: " << first_name_ << std::endl;break;}}
};

模式演化

// 版本1的Person类
#pragma db object table("person_v1")
class PersonV1 {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string name_;unsigned short age_;
};// 版本2的Person类 - 添加了email字段
#pragma db object table("person_v2")
class PersonV2 {
private:friend class odb::access;#pragma db id autounsigned long id_;std::string first_name_;std::string last_name_;unsigned short age_;#pragma db nullstd::string email_;
};// 数据迁移
void migrate_schema() {auto db = create_database();odb::transaction t(db->begin());// 创建新表db->execute(R"(CREATE TABLE person_v2 (id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,first_name VARCHAR(255) NOT NULL,last_name VARCHAR(255) NOT NULL,age SMALLINT UNSIGNED NOT NULL,email VARCHAR(255)))");// 迁移数据db->execute(R"(INSERT INTO person_v2 (id, first_name, last_name, age)SELECT id, SUBSTRING_INDEX(name, ' ', 1) as first_name,SUBSTRING_INDEX(name, ' ', -1) as last_name,ageFROM person_v1)");// 删除旧表db->execute("DROP TABLE person_v1");t.commit();
}

性能优化

连接池

#include <odb/connection-pool-factory.hxx>class DatabaseManager {
private:std::unique_ptr<odb::database> db_;public:DatabaseManager() {// 创建连接池工厂std::unique_ptr<odb::connection_pool_factory> pool_factory(new odb::connection_pool_factory(10, 0)  // 最大10个连接,无最小连接数);db_ = std::make_unique<odb::mysql::database>("user", "password", "database", "localhost", 3306,nullptr, "utf8", 0, std::move(pool_factory));}odb::database& get_database() { return *db_; }
};// 单例模式
DatabaseManager& get_db_manager() {static DatabaseManager manager;return manager;
}

预编译语句

void prepared_statement_example() {auto db = create_database();// 预编译查询typedef odb::query<Person> query;typedef odb::prepared_query<Person> prepared_query;odb::transaction t(db->begin());// 准备查询语句prepared_query pq(db->prepare_query<Person>("find_by_age", query::age >= query::_ref(age_param)));// 多次执行for (int age = 20; age <= 30; ++age) {int age_param = age;odb::result<Person> r(pq.execute());std::cout << "People aged " << age << ":" << std::endl;for (const auto& person : r) {std::cout << "  " << person.first_name() << " " << person.last_name() << std::endl;}}t.commit();
}

批量操作优化

void optimized_batch_operations() {auto db = create_database();// 使用事务批量插入const size_t batch_size = 1000;std::vector<Person> people;// 准备数据for (size_t i = 0; i < 10000; ++i) {people.emplace_back("User" + std::to_string(i), "Test", 20 + i % 50);}// 分批插入for (size_t i = 0; i < people.size(); i += batch_size) {odb::transaction t(db->begin());size_t end = std::min(i + batch_size, people.size());for (size_t j = i; j < end; ++j) {db->persist(people[j]);}t.commit();std::cout << "Inserted batch " << (i / batch_size + 1) << std::endl;}
}

查询优化

void query_optimization() {auto db = create_database();odb::transaction t(db->begin());typedef odb::query<Person> query;typedef odb::result<Person> result;// 使用索引result r1(db->query<Person>(query::last_name == "Smith" + "ORDER BY" + query::first_name));// 限制结果集大小result r2(db->query<Person>(query::age > 25 + "LIMIT 100"));// 使用缓存result r3(db->query<Person>(query::age >= 30));std::vector<Person> cached_results(r3.begin(), r3.end());// 延迟加载优化typedef odb::query<Employee> emp_query;typedef odb::result<Employee> emp_result;emp_result er(db->query<Employee>(emp_query::department->name == "Engineering"));for (auto& emp : er) {// 批量加载关联对象if (!emp.department().loaded()) {emp.department().load();}}t.commit();
}

最佳实践

1. 项目结构

project/
├── src/
│   ├── models/           # 实体类
│   │   ├── person.hxx
│   │   ├── department.hxx
│   │   └── employee.hxx
│   ├── dao/             # 数据访问对象
│   │   ├── person_dao.hxx
│   │   └── person_dao.cxx
│   ├── services/        # 业务逻辑
│   │   ├── person_service.hxx
│   │   └── person_service.cxx
│   └── main.cxx
├── generated/           # ODB生成的文件
│   ├── person-odb.hxx
│   ├── person-odb.ixx
│   └── person-odb.cxx
├── sql/                # SQL脚本
│   ├── schema.sql
│   └── migrations/
└── CMakeLists.txt

2. DAO模式实现

// person_dao.hxx
#pragma once
#include "models/person.hxx"
#include <odb/database.hxx>
#include <memory>
#include <vector>class PersonDAO {
private:std::shared_ptr<odb::database> db_;public:explicit PersonDAO(std::shared_ptr<odb::database> db) : db_(db) {}// CRUD操作void create(Person& person);std::unique_ptr<Person> find_by_id(unsigned long id);std::vector<Person> find_by_age_range(unsigned short min_age, unsigned short max_age);void update(const Person& person);void remove(unsigned long id);// 统计操作size_t count_all();double average_age();
};// person_dao.cxx
#include "dao/person_dao.hxx"
#include "generated/person-odb.hxx"
#include <odb/transaction.hxx>void PersonDAO::create(Person& person) {odb::transaction t(db_->begin());db_->persist(person);t.commit();
}std::unique_ptr<Person> PersonDAO::find_by_id(unsigned long id) {odb::transaction t(db_->begin());auto result = db_->load<Person>(id);t.commit();return result;
}std::vector<Person> PersonDAO::find_by_age_range(unsigned short min_age, unsigned short max_age) {odb::transaction t(db_->begin());typedef odb::query<Person> query;typedef odb::result<Person> result;result r(db_->query<Person>(query::age >= min_age && query::age <= max_age));std::vector<Person> people(r.begin(), r.end());t.commit();return people;
}void PersonDAO::update(const Person& person) {odb::transaction t(db_->begin());db_->update(person);t.commit();
}void PersonDAO::remove(unsigned long id) {odb::transaction t(db_->begin());db_->erase<Person>(id);t.commit();
}

3. 服务层实现

// person_service.hxx
#pragma once
#include "dao/person_dao.hxx"
#include <string>class PersonService {
private:std::unique_ptr<PersonDAO> dao_;public:explicit PersonService(std::shared_ptr<odb::database> db): dao_(std::make_unique<PersonDAO>(db)) {}// 业务方法unsigned long register_person(const std::string& first_name, const std::string& last_name, unsigned short age);bool update_person_age(unsigned long id, unsigned short new_age);std::vector<Person> get_adults();bool delete_person(unsigned long id);// 统计方法size_t get_total_count();double get_average_age();
};// person_service.cxx
#include "services/person_service.hxx"unsigned long PersonService::register_person(const std::string& first_name,const std::string& last_name,unsigned short age) {if (first_name.empty() || last_name.empty()) {throw std::invalid_argument("Name cannot be empty");}if (age > 150) {throw std::invalid_argument("Invalid age");}Person person(first_name, last_name, age);dao_->create(person);return person.id();
}bool PersonService::update_person_age(unsigned long id, unsigned short new_age) {try {auto person = dao_->find_by_id(id);if (!person) {return false;}person->age(new_age);dao_->update(*person);return true;}catch (const odb::exception&) {return false;}
}std::vector<Person> PersonService::get_adults() {return dao_->find_by_age_range(18, 150);
}

4. 错误处理

#include <odb/exception.hxx>void error_handling_example() {try {auto db = create_database();odb::transaction t(db->begin());// 数据库操作Person person("John", "Doe", 30);db->persist(person);t.commit();}catch (const odb::database_exception& e) {std::cerr << "Database error: " << e.what() << std::endl;std::cerr << "Database message: " << e.message() << std::endl;}catch (const odb::connection_lost& e) {std::cerr << "Connection lost: " << e.what() << std::endl;// 实现重连逻辑}catch (const odb::timeout& e) {std::cerr << "Operation timeout: " << e.what() << std::endl;}catch (const odb::object_not_persistent& e) {std::cerr << "Object not persistent: " << e.what() << std::endl;}catch (const odb::object_already_persistent& e) {std::cerr << "Object already persistent: " << e.what() << std::endl;}catch (const odb::exception& e) {std::cerr << "ODB error: " << e.what() << std::endl;}catch (const std::exception& e) {std::cerr << "Standard error: " << e.what() << std::endl;}
}

5. 配置管理

// config.hxx
#pragma once
#include <string>struct DatabaseConfig {std::string host = "localhost";unsigned int port = 3306;std::string database = "test";std::string user = "root";std::string password = "";std::string charset = "utf8";unsigned int pool_size = 10;unsigned int timeout = 30;
};class ConfigManager {
private:DatabaseConfig db_config_;public:void load_from_file(const std::string& filename);void load_from_env();const DatabaseConfig& get_db_config() const { return db_config_; }
};// 使用配置
std::unique_ptr<odb::database> create_configured_database() {ConfigManager config;config.load_from_file("config.json");const auto& db_config = config.get_db_config();std::unique_ptr<odb::connection_pool_factory> pool_factory(new odb::connection_pool_factory(db_config.pool_size, 0));return std::make_unique<odb::mysql::database>(db_config.user,db_config.password,db_config.database,db_config.host,db_config.port,nullptr,db_config.charset,0,std::move(pool_factory));
}

总结

ODB框架为C++开发者提供了一个强大而灵活的ORM解决方案。它的主要优势包括:

  1. 类型安全:编译时检查,减少运行时错误
  2. 高性能:接近原生SQL的性能表现
  3. 多数据库支持:支持主流关系数据库
  4. 现代C++特性:充分利用C++11/14/17特性
  5. 灵活的映射:支持复杂的对象关系映射

在实际项目中使用ODB时,建议:

  • 合理设计实体类和关系映射
  • 使用DAO模式组织数据访问代码
  • 实现适当的错误处理和事务管理
  • 利用连接池和预编译语句优化性能
  • 遵循最佳实践,保持代码的可维护性

通过正确使用ODB框架,可以显著提高C++应用程序的数据库操作效率和代码质量。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/82746.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ai书签管理工具开发全记录(一):项目总览与技术蓝图

文章目录 Ai书签管理工具开发全记录&#xff08;一&#xff09;&#xff1a;项目总览与技术蓝图 ✨1. 项目背景与核心价值 &#x1f4a1;1.1. 核心特点 2. 技术架构分析 &#x1f3d7;️功能架构全景图典型工作流 3. 核心技术栈选择 &#x1f6e0;️4. 预期使用功能说明 &#…

GUI 编程——python

GUI 编程核心概念 GUI&#xff08;图形用户界面&#xff0c;Graphical User Interface&#xff09; 是一种通过图形元素&#xff08;窗口、按钮、菜单等&#xff09;与用户交互的应用程序形式&#xff0c;相比命令行界面更直观易用。以下是学习 GUI 编程的基础概念和流程&…

【Doris基础】Apache Doris 基本架构深度解析:从存储到查询的完整技术演进

目录 1 引言 2 Doris 架构全景图 2 核心组件技术解析 2.1 Frontend 层&#xff08;FE&#xff09; 2.2 Backend 层&#xff08;BE&#xff09; 3 数据存储与复制机制 3.1 存储架构演进 3.2 副本复制策略 4 查询处理全流程解析 4.1 查询生命周期 5 高可用设计 5.1 F…

光电赋能低空场景,灵途科技助力无人机持续升级

2025 UASE 主题为“步入低空经济新时代”的“2025第九届世界无人机大会暨国际低空经济与无人系统博览会/第十届深圳国际无人机展览会”5月23日在深圳会展中心隆重开幕。本届展会汇聚了全球800余家企业参展&#xff0c;展示5000多款无人机及系统设备&#xff0c;全面呈现低空经…

iOS QQ抽屉式导航的实现

QQ个人中心的侧滑功能(通常称为"抽屉式导航")可以通过以下几种方式在iOS中实现&#xff1a; 主要实现方案 使用第三方库 最快速的方式是使用成熟的第三方库&#xff1a; SWRevealViewController&#xff1a;最流行的侧滑菜单库MMDrawerController&#xff1a;另一…

【Pandas】pandas DataFrame drop

Pandas2.2 DataFrame Reindexing selection label manipulation 方法描述DataFrame.add_prefix(prefix[, axis])用于在 DataFrame 的行标签或列标签前添加指定前缀的方法DataFrame.add_suffix(suffix[, axis])用于在 DataFrame 的行标签或列标签后添加指定后缀的方法DataFram…

长短期记忆网络 (LSTM) 详解:从原理到应用

一、引言&#xff1a;序列数据处理的挑战​ 在自然语言处理、语音识别、时间序列分析等领域&#xff0c;数据通常以序列形式存在&#xff0c;前后数据点之间存在依赖关系。传统循环神经网络 (RNN) 虽然能捕捉序列依赖&#xff0c;但存在严重的梯度消失 / 爆炸问题&#xff0c;…

三天掌握PyTorch精髓:从感知机到ResNet的快速进阶方法论

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 一、分析式AI基础与深度学习核心概念 1.1 深度学习三要素 数学基础&#xff1a; f(x;W,b)σ(Wxb)(单层感知机) 1.2 PyTorch核心组件 张量操作示例…

Linux操作系统概述

一、操作系统的作用 1、五大基本功能 &#xff08;1&#xff09;进程和线程的管理&#xff1a;进程线程的状态、控制、同步互斥、通信调度等 (2&#xff09;存储管理&#xff1a;分配/回收、地址转换、存储保护等 (3&#xff09;文件管理&#xff1a;文件目录、文件操作、磁盘…

Python爬虫第22节- 结合Selenium识别滑动验证码实战

目录 一、引言 二、滑动验证码原理与反爬机制 2.1 验证码原理 2.2 反爬机制 三、工程实战&#xff1a;滑动验证码识别全流程 3.1 工程准备 3.1.1 环境依赖 3.1.2 目标网站与验证码识别案例 3.2 核心破解流程 3.2.1 自动化打开网页与登录 3.2.2 获取验证码图片&#…

NSSCTF-[NISACTF 2022]huaji?

下载附件得到文件 放到kali里面看看 发现是一张图片 用binwalk命令对其进行分离 发现需要密码 用010打开图片进行查看 对其进行解密 分别得到 ctf_NISA_2022 nisa_2022 发现ctf_NISA_2022是密码 得到flag NSSCTF{Nls_FumYEnnOjy}

nt!CcGetVacbMiss函数分析之设置好nt!_VACB然后调用函数nt!SetVacb

第一部分&#xff1a;MmMapViewInSystemCache函数返回 Status MmMapViewInSystemCache (SharedCacheMap->Section, &Vacb->BaseAddress, &NormalOffset, …

Uniapp+UView+Uni-star打包小程序极简方案

一、减少主包体积 主包污染源&#xff08;全局文件依赖&#xff09;劲量独立导入 componentsstaticmain.jsApp.vueuni.css 分包配置缺陷&#xff0c;未配置manifest.json中mp-weixin节点 "usingComponents" : true,"lazyCodeLoading" : "requiredC…

Teigha应用——解析CAD文件(DWG格式)Teigha在CAD C#二次开发中的基本应用

Teigha是一款专为开发者设计的工具&#xff0c;其核心技术在于强大的API和丰富的功能集&#xff0c;提供了一系列工具和方法&#xff0c;使开发者能够轻松地读取、解析和操作DWG文件。它支持多种操作系统&#xff0c;能在处理大型DWG文件时保持高效性能&#xff0c;还可用于构建…

JavaWeb:SpringBoot Bean管理

获取Bean Bean作用域 解决循环依赖方式 1.粗暴删除依赖 2.打破依赖配置 3.使用lazy注解 引入第三方Bean

Lua 脚本在 Redis 中的运用-23(Lua 脚本语法教程)

在 Redis 中编写和执行 Lua 脚本 Lua 脚本是在 Redis 中执行自定义逻辑的强大功能&#xff0c;可以直接在 Redis 服务器上执行。这减少了延迟&#xff0c;提高了性能&#xff0c;并能够实现客户端脚本难以或不可能实现的原子操作。通过在 Redis 中嵌入 Lua 脚本&#xff0c;您…

从零实现本地语音识别(FunASR)

FunASR 是达摩院开源的综合性语音处理工具包&#xff0c;提供语音识别&#xff08;ASR&#xff09;、语音活动检测&#xff08;VAD&#xff09;、标点恢复&#xff08;PUNC&#xff09;等全流程功能&#xff0c;支持多种主流模型&#xff08;如 Paraformer、Whisper、SenseVoic…

deepseek开源资料汇总

参考&#xff1a;DeepSeek“开源周”收官&#xff0c;连续五天到底都发布了什么? 目录 一、首日开源-FlashMLA 二、Day2 DeepEP 三、Day3 DeepGEMM 四、Day4 DualPipe & EPLB 五、Day5 3FS & Smallpond 总结 一、首日开源-FlashMLA 多头部潜在注意力机制&#x…

【C++ Qt】认识Qt、Qt 项目搭建流程(图文并茂、通俗易懂)

每日激励&#xff1a;“不设限和自我肯定的心态&#xff1a;I can do all things。 — Stephen Curry” 绪论​&#xff1a; 本章将开启Qt的学习&#xff0c;Qt是一个较为古老但仍然在GUI图形化界面设计中有着举足轻重的地位&#xff0c;因为它适合嵌入式和多种平台而被广泛使用…

AI应用 Markdown 渲染对比与原生实现方案

DeepSeek、豆包、腾讯元宝、ChatGPT 渲染实现对比表 产品解析方式渲染引擎/库UI 组件架构Markdown支持范围流程图/导图支持扩展架构及裁剪流式解析渲染DeepSeek原生解析&#xff08;非WebView&#xff09;采用 CommonMark 标准解析器&#xff08;推测使用 Markwon 库&#xff…