ODB 框架

news2024/11/29 22:13:46

目录

概述

基本工作原理

映射C++对象到数据库表

从数据库中加载对象

持久化C++对象到数据库

ODB常用接口

表创建预处理

#pragma db

Object

table

数据表属性

id 

auto

column(“xxx”)

type("xxx")

unique

index

null

default(xxx)

 总结

查询预处理

view 

query

result

database类

连接管理接口

 事务管理接口

对象存取接口

对象查询接口

类型映射与元数据接口

数据库备份与恢复

基本使用

概述

ODB 库的目标是提供一个功能强大且类型安全的 ORM 解决方案,使得 C++ 开发者能够轻松地处理数据库操作,同时保留 C++ 中对象的优势。它通过 C++ 类和数据库表之间的自动映射来简化数据库的持久化操作。

  • 对象到数据库的映射:将 C++ 对象映射到数据库中的表
  • 数据库到对象的映射:将数据库中的记录自动映射为 C++ 对象,支持一对一、一对多、多对多等关系

优点

  • 简化代码:使用 ODB,可以省去手动编写 SQL 查询的繁琐步骤,减少 SQL 注入和数据类型转换的错误
  • 类型安全:所有操作都使用 C++ 对象,而不是原始 SQL 字符串,保证了类型的安全性
  • 支持复杂数据关系:可以轻松处理对象间的复杂关系(如一对多、多对多等)
  • 跨平台支持:支持多种数据库和操作系统,适合跨平台开发

缺点

  • 依赖生成工具:需要使用 ODB 提供的工具来生成代码,增加了构建过程的复杂性
  • 性能:虽然 ODB 在设计上注重性能,但 ORM 本身的抽象可能会导致一些性能损失,特别是在处理大量数据时

主要特性

  •  类型安全:ODB 提供类型安全的映射操作,避免了直接使用 SQL 语句时可能发生的类型转换错误。开发者不需要关心 SQL 的细节,OIB 会自动处理类型映射
  • 自动生成 SQL 代码:ODB 会根据 C++ 类和类成员的定义自动生成 SQL 查询语句,开发者不需要显式地编写 SQL 代码,减少了手动编写 SQL 的繁琐性和出错的可能性
  • ODB 支持多个关系型数据库
  • 复杂数据关系:ODB 支持对象之间复杂的关系映射,如一对多、多对多等关系,并且能够自动管理外键、级联操作等
  • 支持继承和多态:ODB 还支持 C++ 类继承和多态。你可以使用 ODB 映射继承层次结构中的类到数据库表,并且支持多态对象的持久化
  • 查询功能:ODB 还支持类似于 SQL 的查询功能,开发者可以使用 ODB 提供的查询接口来执行复杂的查询操作
  • 性能:ODB 在生成 SQL 查询时会尽量优化性能,支持批量插入、延迟加载、缓存机制等特性,从而在性能上做到了较好的平衡

基本工作原理

ODB核心步骤就两步

  • 映射:定义对象和数据库表之间的映射关系
  • 持久化:将对象保存到数据库或者从数据库中加载对象

映射C++对象到数据库表

ODB 提供了一个 database 类(通常是 odb::database)来操作数据库。开发者可以用它来保存、加载和查询 C++ 对象

db.persist(p) 会将 Person 对象的 name_age_ 持久化到数据库中的 Person

#include <odb/database.hxx>
#include <odb/transaction.hxx>
#include <odb/sqlite/database.hxx>  // 支持 SQLite

int main() {
    odb::sqlite::database db("example.db", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);

    Person p("John", 30);

    // 开始事务
    {
        odb::transaction t(db.begin());
        db.persist(p);  // 将对象持久化到数据库
        t.commit();
    }

    return 0;
}

从数据库中加载对象

b.load<Person>(1) 会根据数据库表中的 ID 为 1 的记录,自动生成一个 Person 对象

{
    odb::transaction t(db.begin());
    std::shared_ptr<Person> p = db.load<Person>(1);  // 加载 ID 为 1 的 Person 对象
    t.commit();

    std::cout << "Name: " << p->name() << ", Age: " << p->age() << std::endl;
}

持久化C++对象到数据库

ODB 提供了一个 database 类(通常是 odb::database)来操作数据库。开发者可以用它来保存、加载和查询 C++ 对象

#include <odb/database.hxx>
#include <odb/transaction.hxx>
#include <odb/sqlite/database.hxx>  // 支持 SQLite

int main() {
    odb::sqlite::database db("example.db", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);

    Person p("John", 30);

    // 开始事务
    {
        odb::transaction t(db.begin());
        db.persist(p);  // 将对象持久化到数据库
        t.commit();
    }

    return 0;
}

ODB常用接口

表创建预处理

#pragma db

  • 功能:这是 ODB 的核心预处理指令,用来指定 C++ 类或类成员与数据库字段的映射
  • 用于定义类的整体映射规则,比如将类映射为一个数据库表
  • 用于定义某个类成员的具体数据库属性,比如列名、类型、索引、默认值等

Object

  • 功能:标记一个类是数据库中的一个持久化对象(实体类)
  • 用法:#pragma db object 放在类声明的前面
  • 作用:表示 Employee 类会映射到数据库中的一个表,果类没有被标记为 object,则 ODB 不会将其映射为数据库表
#pragma db object
class Employee {
public:
    int id;
    std::string name;
};

table

  • 功能:指定类映射到数据库中的表名
  • 用法:默认情况下,ODB 将类的名字(小写)作为表名,如果需要自定义表名,那么可以使用table指令
#pragma db object table("employees_table")
class Employee {
    int id;
    std::string name;
};

数据表属性

id 

  • 功能:指定某字段为数据库表的主键
  • 用法:主键必须唯一,且必须是整形;#pragma db id放在类成员前面,表示该字段是主键
class Employee {
    #pragma db id
    int id;

    std::string name;
};

auto

  • 功能:表示主键字段是自动递增的
  • 用法:#pragma db id auto用于主键字段,告知ODB让数据库自动生成该字段
class Employee {
    #pragma db id auto
    int id;

    std::string name;
};

column(“xxx”)

  • 功能:将类成员变量映射到数据库表的某个特定列名
  • 用法:默认情况下,ODB 使用类成员的名字作为数据库列名;如果需要指定一个不同的列名,可以使用colum
class Employee {
    #pragma db column("emp_id")
    int id;

    #pragma db column("full_name")
    std::string name;
};

type("xxx")

  • 功能:指定字段在数据库表中的具体类型
  • 用法:如果需要覆盖默认映射的字段类型,可以用 type 指定
class Employee {
    #pragma db type("varchar(255)")
    std::string name;
};

unique

  • 功能:标记字段为唯一键,保证表中该字段的值不会重复
  • 用法:在需要唯一约束的字段上添加 #pragma db unique
class Employee {
    #pragma db unique
    std::string email;
};

index

  • 功能:为字段创建索引以加速查询
  • 用法:在需要加速查询的字段上使用 #pragma db index
class Employee {
    #pragma db index
    std::string name;
};

not_null

  • 功能:指定字段不能为 NULL
  • 用法:在不允许为空的字段上添加 #pragma db not_null
class Employee {
    #pragma db not_null
    std::string name;
};

null

  • 功能:允许字段为 NULL
  • 用法:使用 odb::nullable<T> 表示字段可以存储 NULL
class Employee {
    odb::nullable<std::string> middle_name;
};

default(xxx)

  • 功能:为字段指定默认值
  • 用法:在需要设置默认值的字段上使用 #pragma db default(xxx)
class Employee {
    #pragma db default("Unknown")
    std::string department;
};

 总结

// 将该类声明为 ODB 持久化对象,并映射到数据库表 "employee_table"
#pragma db object table("employee_table")
class Employee {
public:
    // 将字段 `id` 映射为数据库表的主键,并且自动递增
    #pragma db id auto
    int id;

    // 将字段 `name` 映射到数据库表的列名 "full_name",并且设置为不允许为空
    #pragma db column("full_name") not_null
    std::string name;

    // 将字段 `email` 映射到数据库表的列名 "email_address",并且设置为唯一值
    #pragma db column("email_address") unique
    std::string email;

    // 将字段 `role` 映射为数据库表的 varchar(20) 类型,并设置默认值为 "Staff"
    #pragma db type("varchar(20)") default("Staff")
    std::string role;

    // 定义字段 `phone`,允许为空,使用 odb::nullable<T> 表示
    odb::nullable<std::string> phone;

    // 将字段 `department` 创建一个普通索引,用于加速查询
    #pragma db index
    std::string department;
};

查询预处理

view 

View 是只读的结果类,用于查询数据并将查询结果映射到特定的结构体或类中。View 类本质上是查询的只读视图,不能修改底层数据

事例1

  • 通过View查询学生信息,然后通过学生ID和班级表ID进行关联,从而查询到对应班级名称
  • object(Student):指定视图操作的主要表是 Student
  • object(Classes):将 Student::_classes_idClasses::_id 进行关联,关联的表命名为 classes
#pragma db view object(Student)\
                object(Classes = classes : Student::_classes_id == classes::_id)\
                query((?))
struct classes_student {
    // 将 Student::_id 映射到视图中的 id 字段
    #pragma db column(Student::_id)
    unsigned long id; // 学生的唯一ID

    #pragma db column(Student::_sn)
    unsigned long sn; // 学号

    #pragma db column(Student::_name)
    std::string name; // 学生姓名

    #pragma db column(Student::_age)
    odb::nullable<unsigned short> age; // 学生年龄 (可为空)

    #pragma db column(classes::_name)
    std::string classes_name; // 班级名称
};

通过该视图可以执行SQL查询

SELECT Student._id, Student._sn, Student._name, Student._age, Classes._name
FROM Student
JOIN Classes ON Student._classes_id = Classes._id
WHERE <dynamic_condition>;

query

ODB 提供的查询接口,用于执行动态查询并将结果映射到 C++ 对象中。查询语句可以通过占位符参数绑定动态条件

基本用法

typedef odb::query<T> query;
// 查询所有年龄大于20的学生
typedef odb::query<Student> query;
query q = query::age > 20;

// 等效下面的SQL语句
SELECT * FROM Student WHERE age > 20;

查询所有学生信息和班级名称

void queryClassesStudent(database& db) {
    transaction t(db.begin());

    // 动态条件
    odb::result<classes_student> result(
        db.query<classes_student>("WHERE Student._age >= 18")
    );

    // 遍历结果
    for (const auto& record : result) {
        std::cout << "Student ID: " << record.id
                  << ", Name: " << record.name
                  << ", Age: " << (record.age ? *record.age : 0)
                  << ", Class: " << record.classes_name << std::endl;
    }

    t.commit();
}

result

用于存储和处理查询的结果集。它的模板参数是查询的目标类型(T),可以是数据库表对象或视图结构体

typedef odb::result<T> result;

支持类似于vector中的相关操作,迭代器、范围for等

database类

与MySQL中基本操作类似,类似于对其操作进行二次封装

连接管理接口

open()

用于打开数据库连接。如果数据库尚未连接,则建立连接。该方法可能接受连接配置(如数据库路径、用户名、密码等)作为参数

database.open("database_file");

close()

关闭数据库连接。释放所有资源

database.close();

is_open()(检查数据库是否已经打开)

if (database.is_open()) {
    // 执行数据库操作
}

 事务管理接口

begin()

database.begin();

commit()

提交事务,确保事务中的所有操作被永久保存到数据库中

database.commit();

rollback()

回滚事务,撤销事务中的所有操作

database.rollback();

is_transaction_active()

检查是否存在活动的事务

if (database.is_transaction_active()) {
    // 处理事务
}

对象存取接口

 store()

将一个对象持久化到数据库中。如果对象已经存在,它会更新对象;如果对象是新对象,它会插入一条新的记录

database.store(myObject);

 erase()

从数据库中删除一个对象

database.erase(myObject);

 load()

从数据库中加载一个对象。通常需要一个对象的标识符(如ID)来查找该对象

MyObject* obj = database.load<MyObject>(object_id);

 find()

根据条件查询数据库中的对象。这个接口通常支持各种查询条件

std::vector<MyObject> objects = database.find<MyObject>("age > 30");

对象查询接口

 query()

执行一个查询,返回符合条件的对象列表

auto results = database.query<MyObject>("SELECT * FROM MyObject WHERE age > 30");

count()

返回符合某个条件的对象数量

int count = database.count<MyObject>("age > 30");

 distinct()

查询数据库中某个字段的不同值

auto distinctNames = database.distinct<MyObject>("name");

类型映射与元数据接口

 get_type_info()

获取与某个对象类型(类)相关的元数据,包括字段、类型等

TypeInfo info = database.get_type_info<MyObject>();

 get_object_count()

获取某个对象类型在数据库中的数量

int objectCount = database.get_object_count<MyObject>();

数据库备份与恢复

backup()

执行数据库的备份操作,将数据库内容复制到一个备份文件

database.backup("backup_file");

restore()

从备份文件恢复数据库

database.restore("backup_file");

基本使用

操作流程总结

  • 构建连接池多对象
  • 构建数据库操作database对象
  • 获取事务对象然后开启事务
  • 数据库操作
  • 提交事务

创建student.hxx

#pragma once
#include <string>
#include <cstddef> // std::size_t
#include <boost/date_time/posix_time/posix_time.hpp>
#include <odb/nullable.hxx>
#include <odb/core.hxx>

#pragma db object
class Student{
    public:
        Student() {}
        Student(unsigned long sn, const std::string &name, unsigned short age, unsigned long cid):
            _sn(sn), _name(name), _age(age), _classes_id(cid){}
        void sn(unsigned long num) { _sn = num; }
        unsigned long sn() { return _sn; }

        void name(const std::string &name) { _name = name; }
        std::string name() { return _name; }

        void age(unsigned short num) { _age = num; }
        odb::nullable<unsigned short> age() { return _age; }

        void classes_id(unsigned long cid) { _classes_id = cid; }
        unsigned long classes_id() { return _classes_id; }
    private:
        friend class odb::access;
        #pragma db id auto
        unsigned long _id;
        #pragma db unique
        unsigned long _sn;
        std::string _name;
        odb::nullable<unsigned short> _age;
        #pragma db index
        unsigned long _classes_id;
};

#pragma db object
class Classes {
    public:
        Classes() {}
        Classes(const std::string &name) : _name(name){}
        void name(const std::string &name) { _name = name; }
        std::string name() { return _name; }
    private:
        friend class odb::access;
        #pragma db id auto
        unsigned long _id;
        std::string _name;
};

//查询所有的学生信息,并显示班级名称
#pragma db view object(Student)\
                object(Classes = classes : Student::_classes_id == classes::_id)\
                query((?))
struct classes_student {
    #pragma db column(Student::_id)
    unsigned long id;
    #pragma db column(Student::_sn)
    unsigned long sn;
    #pragma db column(Student::_name)
    std::string name;
    #pragma db column(Student::_age)
    odb::nullable<unsigned short>age;
    #pragma db column(classes::_name)
    std::string classes_name;
};

// 只查询学生姓名  ,   (?)  外部调用时传入的过滤条件
#pragma db view query("select name from Student" + (?))
struct all_name {
    std::string name;
};
odb -d mysql --std c++11 --generate-query --generate-schema --profile boost/date-time student.hxx

// 执行SQL文件
mysql -u <username> -p TestDB < student.sql

插入操作

void insert_classes(odb::mysql::database &db) 
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        Classes c1("一年级一班");
        Classes c2("一年级二班");
        db.persist(c1);
        db.persist(c2);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "插入数据出错:" << e.what() << std::endl;
    }
}

void insert_student(odb::mysql::database &db) 
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        Student s1(1, "张三", 18, 1);
        Student s2(2, "李四", 19, 1);
        Student s3(3, "王五", 18, 1);
        Student s4(4, "赵六", 15, 2);
        Student s5(5, "刘七", 18, 2);
        Student s6(6, "孙八", 23, 2);
        db.persist(s1);
        db.persist(s2);
        db.persist(s3);
        db.persist(s4);
        db.persist(s5);
        db.persist(s6);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "插入学生数据出错:" << e.what() << std::endl;
    }
}

查询数据

通过学生表查找某个学生的信息

Student select_student(odb::mysql::database &db)
{
    Student res;
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<Student> result;
        result r(db.query<Student>(query::name == "张三"));
        if (r.size() != 1) {
            std::cout << "数据量不对!\n";
            return Student();
        }
        res = *r.begin();
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
    return res;
}

更新学生记录

通过update()方法更新学生记录,stu是一个已经存在的学生对象,更新数据会覆盖原记录

void update_student(odb::mysql::database &db, Student &stu)
{
    try{
        odb::transaction trans(db.begin());
        db.update(stu);
        trans.commit();
    }catch(std::exception &e){
        std::cout<<"更新学生数据出错:"<<e.what()<<std::endl;
    }
}

删除某个ID的学生

// 删除classe_id==2的学生
void remove_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        db.erase_query<Student>(query::classes_id == 2);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
}

查找符合条件学生的所有信息

void classes_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<struct classes_student> query;
        typedef odb::result<struct classes_student> result;
        result r(db.query<struct classes_student>(query::classes::id == 1));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->id << std::endl;
            std::cout << it->sn << std::endl;
            std::cout << it->name << std::endl;
            std::cout << *it->age << std::endl;
            std::cout << it->classes_name << std::endl;
        }
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
}

查找student表中id == 1的学生姓名

// 查询 Student 表中 id == 1 的学生姓名
void all_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<struct all_name> result;
        result r(db.query<struct all_name>(query::id == 1));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->name << std::endl;
        }
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "查询所有学生姓名数据出错:" << e.what() << std::endl;
    }
}

代码综合测试

 

#include <odb/database.hxx>
#include <odb/mysql/database.hxx>
#include "student.hxx"
#include "student-odb.hxx"
#include <gflags/gflags.h>

DEFINE_string(host, "127.0.0.1", "这是Mysql服务器地址");
DEFINE_int32(port, 0, "这是Mysql服务器端口");
DEFINE_string(db, "TestDB", "数据库默认库名称");
DEFINE_string(user, "root", "这是Mysql用户名");
DEFINE_string(pswd, "123456", "这是Mysql密码");
DEFINE_string(cset, "utf8", "这是Mysql客户端字符集");
DEFINE_int32(max_pool, 3, "这是Mysql连接池最大连接数量");

void insert_classes(odb::mysql::database &db) 
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        Classes c1("一年级一班");
        Classes c2("一年级二班");
        db.persist(c1);
        db.persist(c2);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "插入数据出错:" << e.what() << std::endl;
    }
}

void insert_student(odb::mysql::database &db) 
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        Student s1(1, "张三", 18, 1);
        Student s2(2, "李四", 19, 1);
        Student s3(3, "王五", 18, 1);
        Student s4(4, "赵六", 15, 2);
        Student s5(5, "刘七", 18, 2);
        Student s6(6, "孙八", 23, 2);
        db.persist(s1);
        db.persist(s2);
        db.persist(s3);
        db.persist(s4);
        db.persist(s5);
        db.persist(s6);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "插入学生数据出错:" << e.what() << std::endl;
    }
}

Student select_student(odb::mysql::database &db)
{
    Student res;
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<Student> result;
        result r(db.query<Student>(query::name == "张三"));
        if (r.size() != 1) {
            std::cout << "数据量不对!\n";
            return Student();
        }
        res = *r.begin();
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
    return res;
}


void update_student(odb::mysql::database &db, Student &stu)
{
    try{
        odb::transaction trans(db.begin());
        db.update(stu);
        trans.commit();
    }catch(std::exception &e){
        std::cout<<"更新学生数据出错:"<<e.what()<<std::endl;
    }
}

// 删除classe_id==2的学生
void remove_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        db.erase_query<Student>(query::classes_id == 2);
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
}

//查询某个班级所有的学生
void classes_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<struct classes_student> query;
        typedef odb::result<struct classes_student> result;
        result r(db.query<struct classes_student>(query::classes::id == 1));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->id << std::endl;
            std::cout << it->sn << std::endl;
            std::cout << it->name << std::endl;
            std::cout << *it->age << std::endl;
            std::cout << it->classes_name << std::endl;
        }
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "更新学生数据出错:" << e.what() << std::endl;
    }
}

// 查询 Student 表中 id == 1 的学生姓名
void all_student(odb::mysql::database &db)
{
    try {
        //获取事务对象开启事务
        odb::transaction trans(db.begin());
        typedef odb::query<Student> query;
        typedef odb::result<struct all_name> result;
        result r(db.query<struct all_name>(query::id == 1));
        for (auto it = r.begin(); it != r.end(); ++it) {
            std::cout << it->name << std::endl;
        }
        //5. 提交事务
        trans.commit();
    }catch (std::exception &e) {
        std::cout << "查询所有学生姓名数据出错:" << e.what() << std::endl;
    }
}

int main(int argc , char *argv[])
{
    google::ParseCommandLineFlags(&argc, &argv, true);
    //1. 构造连接池工厂配置对象
    std::unique_ptr<odb::mysql::connection_pool_factory> cpf(
         new odb::mysql::connection_pool_factory(FLAGS_max_pool, 0));

    //2. 构建数据库操作对象
    odb::mysql::database db(
        FLAGS_user, FLAGS_pswd, FLAGS_db,
        FLAGS_host, FLAGS_port, "", FLAGS_cset,
        0, std::move(cpf));

    // 插入数据
    insert_classes(db);
    insert_student(db);

    // 查询数据
    auto stu = select_student(db);
    std::cout<<stu.sn()<<std::endl;
    std::cout<<stu.name()<<std::endl;
    if (stu.age()) std::cout << *stu.age() << std::endl;
    std::cout << stu.classes_id() << std::endl;

    //更新数据
    stu.age(15);
    update_student(db, stu);
    remove_student(db);
    classes_student(db);
    all_student(db);
    
    return 0;
}

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

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

相关文章

ModuleNotFoundError: No module named ‘_ssl‘ centos中的Python报错

1、检查系统有没有openssl&#xff0c;有的话&#xff0c;就是python安装时没有指定openssl openssl version&#xff0c;有输出版本号就有&#xff0c;没有的话&#xff0c;需要手动安装 下载地址 参见https://www.openssl.org/&#xff0c;包括以下版本&#xff1a; https:/…

小程序-基于java+SpringBoot+Vue的微信小程序养老院系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…

linux高级系统编程之进程

进程 一个正在进行的程序 并行与并发 并行:执行的程序在不同CPU上同时执行 并发:一个CPU,多个进程交替执行,因为交替速度很快,所以从宏观上来看是同时执行的,但是从围观的角度是交替执行的 单道与多道 单道程序设计:所有进程一个一个排队执行,若A阻塞,B只能等待,,即使CPU处于空…

GitHub Copilot革命性更新:整合顶尖AI模型,如何重塑开发体验?

在技术快速发展的今天&#xff0c;代码辅助工具已成为提升开发效率的利器。今天&#xff0c;我们带来了一个激动人心的消息——GitHub Copilot宣布引入多模型选择功能&#xff0c;这不仅是技术上的一次飞跃&#xff0c;更是对开发者工作流程的一次革新。 多模型选择&#xff1a…

AppFlow:支持飞书机器人调用百炼应用

AppFlow&#xff1a;支持飞书机器人调用百炼应用 简介&#xff1a; 本文介绍了如何创建并配置飞书应用及机器人&#xff0c;包括登录飞书开发者后台创建应用、添加应用能力和API权限&#xff0c;以及通过AppFlow连接流集成阿里云百炼服务&#xff0c;最后详细说明了如何将机器…

华为E9000刀箱(HWE9000V2)服务器硬件监控指标解读

随着数据中心规模的不断扩大&#xff0c;服务器的稳定性和可靠性变得尤为重要。华为E9000刀箱&#xff08;HWE9000V2&#xff09;作为一款高性能的服务器设备&#xff0c;其硬件状态的实时监控对于保障业务的连续性和系统的稳定运行至关重要。 监控易作为一款专业的IT基础设施监…

GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解

GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解 目录 GWO-SVMD分解 | Matlab实现GWO-SVMD灰狼算法优化逐次变分模态分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 GWO-SVMD灰狼算法优化逐次变分模态分解 内有15种用以优化svmd的适应度函数&#…

景联文科技:高质量数据采集标注服务引领AI革新

在当今这个数字化时代&#xff0c;数据已经成为推动社会进步和产业升级的关键资源。特别是在人工智能领域&#xff0c;高质量的数据是训练出高效、精准的AI模型的基础。景联文科技是一家专业的数据采集与标注公司&#xff0c;致力于为客户提供高质量的数据处理服务&#xff0c;…

pycharm添加gitee插件

一、拉取gitee上托管的代码到本地&#xff0c;用pycharm运行 前置条件 1.安装python运行环境 2.安装pycharm 安装&#xff1a;https://blog.csdn.net/m0_65482549/article/details/141394352 1.3.安装git git config --global user.name “" git config --global user.em…

Echarts 绘制地图

一、Apache Echarts 官网地址&#xff1a;https://echarts.apache.org/ npm install echarts --save 二、获取地图的GeoJSON 地址&#xff1a;DataV.GeoAtlas地理小工具系列 左侧是地图&#xff0c;右侧是JSON数据路径&#xff0c;点击你想要生成的地图省市、地级&#xff0…

DHCP服务(包含配置过程)

目录 一、 DHCP的定义 二、 使用DHCP的好处 三、 DHCP的分配方式 四、 DHCP的租约过程 1. 客户机请求IP 2. 服务器响应 3. 客户机选择IP 4. 服务器确定租约 5. 重新登录 6. 更新租约 五、 DHCP服务配置过程 一、 DHCP的定义 DHCP&#xff08;Dynamic Host Configur…

html+css+js网页设计 旅游 厦门旅游网14个页面

htmlcssjs网页设计 旅游 厦门旅游网14个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&am…

springboot(20)(删除文章分类。获取、更新、删除文章详细)(Validation分组校验)

目录 一、删除文章分类功能。 &#xff08;1&#xff09;接口文档。 1、请求路径、请求参数。 2、请求参数。 3、响应数据。 &#xff08;2&#xff09;实现思路与代码书写。 1、controller层。 2、service接口业务层。 3、serviceImpl实现类。 4、mapper层。 5、后端接口测试。…

现代化水库可视化管理平台:提升水库运行效率与安全保障

随着科技的飞速发展&#xff0c;现代化水利管理逐渐依赖于数字化、智能化手段。作为水利基础设施的重要组成部分&#xff0c;水库的管理不仅关乎水资源的合理利用&#xff0c;还关系到防洪、灌溉、供水等多项社会功能的实现。为了提升水库的管理水平&#xff0c;确保其运行安全…

【05】Selenium+Python 两种文件上传方式(AutoIt)

上传文件的两种方式 一、input标签上传文件 可以用send_keys方法直接上传文件 示例代码 input标签上传文件import time from selenium import webdriver from chromedriver_py import binary_path # this will get you the path variable from selenium.webdriver.common.by i…

【论文笔记】Number it: Temporal Grounding Videos like Flipping Manga

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: Number it: Temporal Grou…

软件/游戏提示:mfc42u.dll没有被指定在windows上运行如何解决?多种有效解决方法汇总分享

遇到“mfc42u.dll 没有被指定在 Windows 上运行”的错误提示&#xff0c;通常是因为系统缺少必要的运行库文件或文件损坏。以下是多种有效的解决方法&#xff0c;可以帮助你解决这个问题&#xff1a; 原因分析 出现这个错误的原因是Windows无法找到或加载MFC42u.dll文件。这可…

网络地址转换

NAT概述 解决公有地址不足&#xff0c;并且分配不均匀的问题 公有地址&#xff1a;由专门的机构管理、分配&#xff0c;可以在因特网上直接通信 私有地址&#xff1a;组织和个人可以任意使用&#xff0c;只能在内网使用的IP地址 A、B、C类地址中各预留了一些私有IP地址 A&…

机器学习-神经网络(BP神经网络前向和反向传播推导)

1.1 神经元模型 神经网络(neural networks)方面的研究很早就已出现,今天“神经网络”已是一个相当大的、多学科交叉的学科领域.各相关学科对神经网络的定义多种多样,本书采用目前使用得最广泛的一种,即“神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够…

uniapp组建scroll-view初始化页面设置scrollTop无效解决办法

官方文档&#xff1a;scroll-view | uni-app官网 一 . scroll-view的基本用法 使用竖向滚动时&#xff0c;需要给 <scroll-view> 一个固定高度&#xff0c;通过 css 设置 height&#xff1b; <scroll-view :scroll-top"scrollTop" scroll-y"true&quo…