当前位置: 首页 > news >正文

ODB 框架

目录

概述

基本工作原理

映射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>  // 支持 SQLiteint 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>  // 支持 SQLiteint 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 idint id;std::string name;
};

auto

  • 功能:表示主键字段是自动递增的
  • 用法:#pragma db id auto用于主键字段,告知ODB让数据库自动生成该字段
class Employee {#pragma db id autoint 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 uniquestd::string email;
};

index

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

not_null

  • 功能:指定字段不能为 NULL
  • 用法:在不允许为空的字段上添加 #pragma db not_null
class Employee {#pragma db not_nullstd::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 autoint id;// 将字段 `name` 映射到数据库表的列名 "full_name",并且设置为不允许为空#pragma db column("full_name") not_nullstd::string name;// 将字段 `email` 映射到数据库表的列名 "email_address",并且设置为唯一值#pragma db column("email_address") uniquestd::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 indexstd::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 autounsigned long _id;#pragma db uniqueunsigned long _sn;std::string _name;odb::nullable<unsigned short> _age;#pragma db indexunsigned 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 autounsigned 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;
}

相关文章:

ODB 框架

目录 概述 基本工作原理 映射C对象到数据库表 从数据库中加载对象 持久化C对象到数据库 ODB常用接口 表创建预处理 #pragma db Object table 数据表属性 id auto column&#xff08;“xxx”&#xff09; type("xxx") unique index null default&…...

Ubuntu WiFi检测

ubuntu检测到多个同名wifi&#xff0c;怎么鉴别假冒的wifi&#xff1f; 在Ubuntu中&#xff0c;如果检测到多个同名的Wi-Fi网络&#xff0c;可能存在假冒的Wi-Fi&#xff08;例如“蜜罐”攻击&#xff09;。以下是一些鉴别假冒Wi-Fi的方法&#xff1a; 检查信号强度&#xff1a…...

QILSTE H4-108TCG高亮纯lu光LED灯珠 发光二极管LED

型号&#xff1a;H4-108TCG 在电子领域&#xff0c;H4-108TCG LED以其卓越的性能和微小的尺寸1.6x0.8x0.4mm脱颖而出。这款高亮纯绿光LED&#xff0c;采用透明平面胶体&#xff0c;符合EIA标准包装&#xff0c;是环保产品&#xff0c;符合ROHS标准。防潮等级为Level 3&#xf…...

IP与“谷子”齐飞,阅文“乘势而上”?

爆火的“谷子经济”&#xff0c;又捧出一只“潜力股”。 近日&#xff0c;阅文集团股价持续上涨&#xff0c;5日累计涨幅达13.20%。这其中&#xff0c;周三股价一度大涨约15%至29.15港元&#xff0c;强势突破20日、30日、120日等多根均线&#xff0c;市值突破280亿港元关口。 …...

Java阶段三05

第3章-第5节 一、知识点 动态代理、jdk动态代理、cglib动态代理、AOP、SpringAOP 二、目标 理解什么是动态代理和它的作用 学会使用JAVA进行动态代理 理解什么是AOP 学会使用AOP 理解什么是AOP的切入点 三、内容分析 重点 理解什么是动态代理和它的作用 理解什么是AO…...

C# yield 关键字

文章目录 前言一、yield 关键字的语法形式及使用场景&#xff08;一&#xff09;yield return&#xff08;二&#xff09;yield break 二、yield 关键字的工作原理三、yield 关键字的优势与应用场景&#xff08;一&#xff09;优势&#xff08;二&#xff09;应用场景 前言 在 …...

SpringBoot开发——结合Nginx实现负载均衡

文章目录 负载均衡介绍介绍Nginx实现负载均衡的示例图:负载均衡策略1.Round Robin:2.Least Connections:3.IP Hash :4.Generic Hash:5.Least Time (NGINX Plus only)6.Random:Nginx+SpringBoot实现负载均衡环境准备Nginx 配置负载均衡测试负载均衡介绍 介绍 在介绍Nginx的负…...

RabbitMQ在手动消费的模式下设置失败重新投递策略

最近在写RabbitMQ的消费者&#xff0c;因为业务需求&#xff0c;希望失败后重试一定次数&#xff0c;超过之后就不处理了&#xff0c;或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的&#xff0c;问了kimi&#xff0c;按它的方法配置之后&#xff0c;发…...

TsingtaoAI具身智能高校实训方案通过华为昇腾技术认证

日前&#xff0c;TsingtaoAI推出的“具身智能高校实训解决方案-从AI大模型机器人到通用具身智能”基于华为技术有限公司AI框架昇思MindSpore&#xff0c;完成并通过昇腾相互兼容性技术认证。 TsingtaoAI&华为昇腾联合解决方案 本项目“具身智能高校实训解决方案”以实现高…...

【Linux】线程池设计 + 策略模式

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 一&#xff1a;&#x1f525; 线程池 1-1 ⽇志与策略模式1-2 线程池设计1-3 线程安全的单例模式1-3-1 什么是单例模式1-3-2 单例模式的特点1-3-3 饿汉实现⽅式和懒汉实现⽅式1-3-4 饿汉…...

网络原理(一):应用层自定义协议的信息组织格式 HTTP 前置知识

目录 1. 应用层 2. 自定义协议 2.1 根据需求 > 明确传输信息 2.2 约定好信息组织的格式 2.2.1 行文本 2.2.2 xml 2.2.3 json 2.2.4 protobuf 3. HTTP 协议 3.1 特点 4. 抓包工具 1. 应用层 在前面的博客中, 我们了解了 TCP/IP 五层协议模型: 应用层传输层网络层…...

Python-链表数据结构学习(1)

一、什么是链表数据&#xff1f; 链表是一种通过指针串联在一起的数据结构&#xff0c;每个节点由2部分组成&#xff0c;一个是数据域&#xff0c;一个是指针域&#xff08;存放下一个节点的指针&#xff09;。最后一个节点的指针域指向null&#xff08;空指针的意思&#xff0…...

性能优化经验:关闭 SWAP 分区

关闭 SWAP 分区&#xff0c;特别是在性能敏感场景&#xff08;如 Elasticsearch 服务&#xff09;中&#xff0c;主要与 SWAP 的工作机制和对应用性能的影响有关。以下是详细原因&#xff1a; 1. SWAP 的工作机制导致高延迟 SWAP 是什么&#xff1a; SWAP 分区是系统将物理内存…...

SpringBoot小知识(2):日志

日志是开发项目中非常重要的一个环节&#xff0c;它是程序员在检查程序运行的手段之一。 1.日志的基础操作 1.1 日志的作用 编程期调试代码运营期记录信息&#xff1a; * 记录日常运营重要信息(峰值流量、平均响应时长……) * 记录应用报错信息(错误堆栈) * 记录运维过程数据(…...

java虚拟机——jvm是怎么去找垃圾对象的

JVM&#xff08;Java虚拟机&#xff09;通过特定的算法和机制来查找和识别垃圾对象&#xff0c;以便进行垃圾回收。以下是JVM查找垃圾对象的主要方法和步骤&#xff1a; 一、可达性分析法 JVM使用可达性分析法来识别垃圾对象。这种方法从一组称为“GC Roots”的对象作为起始点…...

Macos远程连接Linux桌面教程;Ubuntu配置远程桌面;Mac端远程登陆Linux桌面;可能出现的问题

文章目录 1. Ubuntu配置远程桌面2. Mac端远程登陆Linux桌面3. 可能出现的问题1.您用来登录计算机的密码与登录密钥环里的密码不再匹配2. 找不到org->gnome->desktop->remote-access 1. Ubuntu配置远程桌面 打开设置->共享->屏幕共享。勾选允许连接控制屏幕&…...

hadoop_HA高可用

秒懂HA HA概述HDFS-HA工作机制工作要点元数据同步参数配置手动故障转移自动故障转移工作机制相关命令 YARN-HA参数配置自动故障转移机制相关命令 附录Zookeeper详解 HA概述 H(high)A(avilable)&#xff1a; 高可用&#xff0c;意味着必须有容错机制&#xff0c;不能因为集群故障…...

【MySQL】MySQL中的函数之JSON_ARRAY_APPEND

在 MySQL 8.0 及更高版本中&#xff0c;JSON_ARRAY_APPEND() 函数用于在 JSON 数组的指定位置追加一个或多个值。这个函数非常有用&#xff0c;特别是在你需要在 JSON 数组的末尾或特定位置添加新的元素时。 基本语法 JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ..…...

torch.is_nonzero(input)

torch.is_nonzero(input) input: 输入张量 若输入是 不等于零的单元素张量 则返回True&#xff0c;否则返回False 不等于零的单元素张量&#xff1a;torch.tensor([0.]) 或 torch.tensor([0]) 或 torch.tensor([False])单元素张量: 只有一个数 的张量 import torch print(t…...

文本搜索程序(Qt)

头文件 #ifndef TEXTFINDER_H #define TEXTFINDER_H#include <QWidget> #include <QFileDialog> #include <QFile> #include <QTextEdit> #include <QLineEdit> #include <QTextStream> #include <QPushButton> #include <QMess…...

使用 Python 剪辑视频的播放速度

要使用 Python 调整视频的播放速度&#xff0c;可以利用 moviepy 库中的 fx&#xff08;特效&#xff09;模块来实现这一功能。通过 moviepy.editor 中的 VideoFileClip 类和 fx.speedx 函数&#xff0c;可以轻松地调整视频的播放速度。 安装 moviepy 首先&#xff0c;确保已…...

深入理解计算机系统,源码到可执行文件翻译过程:预处理、编译,汇编和链接

1.前言 从一个高级语言到可执行程序&#xff0c;要经过预处理、编译&#xff0c;汇编和链接四个过程。大家可以思考下&#xff0c;为什么要有这样的过程&#xff1f; 我们学习计算机之处&#xff0c;就应该了解到&#xff0c;计算机能够识别的只有二进制语言&#xff08;这是…...

Linux开发者的CI/CD(11)jenkins变量

文章目录 1. **环境变量 (Environment Variables)**常见的环境变量:示例:2. **构建参数 (Build Parameters)**常见的构建参数类型:示例:3 **在 `stages` 块内定义局部变量**示例:使用 `script` 步骤定义局部变量4 变量引用陷阱在 Jenkins 中,变量是自动化流程中非常重要的…...

深度学习视频编解码开源项目介绍【持续更新】

DVC (Deep Video Compression) 介绍&#xff1a;DVC (Deep Video Compression) 是一个基于深度学习的视频压缩框架&#xff0c;它的目标是通过深度神经网络来提高视频编码的效率&#xff0c;并降低比特率&#xff0c;同时尽可能保持视频质量。DVC 是一个端到端的神经网络模型&…...

Canva迁移策略深度解析:应对每日5000万素材增长,从MySQL到DynamoDB的蜕变

随着数字化设计的蓬勃发展&#xff0c;Canva作为一款备受欢迎的在线设计平台&#xff0c;面临着日益增长的用户生成内容挑战。每天&#xff0c;平台上新增的素材数量高达5000万&#xff0c;这对数据库系统提出了前所未有的要求。为了应对这一挑战&#xff0c;Canva决定对其数据…...

nacos常见面试题(2024)

nacos永久实例与临时实例区别 nacos实例有2种&#xff0c;分别为临时实例&#xff08;一般业务服务是临时的&#xff09;和永久实例&#xff08;如mysql、redis这种运维服务需要实时看到状态的设置为永久实例&#xff09;。 临时实例只会缓存到服务注册列表中&#xff0c;下线…...

68000汇编实战01-编程基础

文章目录 简介产生背景应用领域 语言学习EASy68K帮助文档IDE使用 编程语言commentslabels开始标签指令标签位置标签 opcode 操作码常用操作码数据传送算术运算逻辑运算控制流分支跳转地址跳转子程序跳转 位操作比较堆栈操作 IO操作码其他操作码 directives 指令DC指令EQU 指令S…...

你的网站真的安全吗?如何防止网站被攻击?

你的网站被黑客攻击过&#xff0c;很可能不止一次&#xff01; 这可不是危言耸听。微软最近发布了《2024 年微软数字防御报告》&#xff0c;报告中写到&#xff1a;“Windows 用户每天面临超过 6 亿次网络犯罪和国家级别的攻击&#xff0c;涵盖了从勒索软件到网络钓鱼再到身份…...

UE5 材质编辑器CheapContrast 节点

在 Unreal Engine 材质编辑器中&#xff0c;CheapContrast 节点是一个非常实用的节点&#xff0c;主要用于对图像或纹理的 对比度 进行调整&#xff0c;且执行效率较高&#xff0c;适合在性能要求较高的场景中使用。 CheapContrast 节点的作用 CheapContrast 节点通过调整输入…...

健身房小程序服务渠道开展

健身不单单是锻炼身体、保持身材&#xff0c;也是一种社交方式&#xff0c;城市里门店不少&#xff0c;每家都有一定流量和老客&#xff0c;但仅靠传统线下拉客/自然流量前往和线上朋友圈、短视频发硬广等方式还不够。 商家需要找到更多潜在目标客户&#xff0c;而消费者也对门…...

长春网站建设建站系统/html友情链接代码

参考链接&#xff1a;http://www.cnblogs.com/xianglan/archive/2011/01/01/1923779.html 主思路和程序基本上都是参考博主的&#xff0c;只是在思路理解上和Python3的一些小修改. 首先是算法原理介绍&#xff1a;图像细化&#xff1a; 图像细化主要是针对二值图而言&#xff0…...

网站建设ppt/百度新闻头条

摘要&#xff1a;分形(Fractal)是在二十世纪70年代兴起的最重要的非线性科学之一,曼德尔布罗特(Mandelbrot)通过数学公式迭代和计算机编程技术构建了以自己名字命名的Mandelbrot集,分形理论由此产生.分形理论是一种新型的数学语言,可以用于对大自然几何图形的描述,可以在分形理…...

国家重点建设网站/优化工作流程

我使用了macos10.13系统&#xff0c;用phpbrew来管理多版本 php&#xff0c;系统自带的 php 版本是 7.1.16 &#xff0c;我用 phpbrew 下载来 php5.6 的版本&#xff0c;然后我用命令phpbrew switch 5.6切换了 php 版本&#xff0c;然后在终端下输入命令php -v输出结果为&#…...

宁波专业做网站的公司有哪些/职业技能培训网

什么是索引&#xff1f;1、索引索引是表的目录&#xff0c;在查找内容之前可以先在目录中查找索引位置&#xff0c;以此快速定位查询数据。对于索引&#xff0c;会保存在额外的文件中。2、索引&#xff0c;是数据库中专门用于帮助用户快速查询数据的一种数据结构。类似于字典中…...

java做网站怎么验证登录/营销培训课程视频

原题链接&#xff1a;1022 Digital Library (30分) 题目大意&#xff1a; 一本书&#xff0c;只有一位作者&#xff0c;包含的关键词不超过 5 个。 总共不超过 1000 个不同的关键词&#xff0c;不超过 1000 个不同的出版商。 图书信息介绍完毕后&#xff0c;有一行包含一个整…...

网站建设 图片/百度一下网页版浏览器百度

ListView内item与Button共存的点击监听问题 2016-03-11 12:34 179人阅读 评论(0) 收藏 举报 分类&#xff1a; android&#xff08;14&#xff09; 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 最近写ListView&#xff0c;在其中的item中加入…...