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_id
与Classes::_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(“xxx”) type("xxx") unique index null default&…...
Ubuntu WiFi检测
ubuntu检测到多个同名wifi,怎么鉴别假冒的wifi? 在Ubuntu中,如果检测到多个同名的Wi-Fi网络,可能存在假冒的Wi-Fi(例如“蜜罐”攻击)。以下是一些鉴别假冒Wi-Fi的方法: 检查信号强度:…...
QILSTE H4-108TCG高亮纯lu光LED灯珠 发光二极管LED
型号:H4-108TCG 在电子领域,H4-108TCG LED以其卓越的性能和微小的尺寸1.6x0.8x0.4mm脱颖而出。这款高亮纯绿光LED,采用透明平面胶体,符合EIA标准包装,是环保产品,符合ROHS标准。防潮等级为Level 3…...

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

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

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

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的消费者,因为业务需求,希望失败后重试一定次数,超过之后就不处理了,或者放入死信队列。我这里就达到重试次数后就不处理了。本来以为很简单的,问了kimi,按它的方法配置之后,发…...

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

【Linux】线程池设计 + 策略模式
🌈 个人主页:Zfox_ 🔥 系列专栏:Linux 目录 一:🔥 线程池 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)
一、什么是链表数据? 链表是一种通过指针串联在一起的数据结构,每个节点由2部分组成,一个是数据域,一个是指针域(存放下一个节点的指针)。最后一个节点的指针域指向null(空指针的意思࿰…...
性能优化经验:关闭 SWAP 分区
关闭 SWAP 分区,特别是在性能敏感场景(如 Elasticsearch 服务)中,主要与 SWAP 的工作机制和对应用性能的影响有关。以下是详细原因: 1. SWAP 的工作机制导致高延迟 SWAP 是什么: SWAP 分区是系统将物理内存…...

SpringBoot小知识(2):日志
日志是开发项目中非常重要的一个环节,它是程序员在检查程序运行的手段之一。 1.日志的基础操作 1.1 日志的作用 编程期调试代码运营期记录信息: * 记录日常运营重要信息(峰值流量、平均响应时长……) * 记录应用报错信息(错误堆栈) * 记录运维过程数据(…...
java虚拟机——jvm是怎么去找垃圾对象的
JVM(Java虚拟机)通过特定的算法和机制来查找和识别垃圾对象,以便进行垃圾回收。以下是JVM查找垃圾对象的主要方法和步骤: 一、可达性分析法 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): 高可用,意味着必须有容错机制,不能因为集群故障…...
【MySQL】MySQL中的函数之JSON_ARRAY_APPEND
在 MySQL 8.0 及更高版本中,JSON_ARRAY_APPEND() 函数用于在 JSON 数组的指定位置追加一个或多个值。这个函数非常有用,特别是在你需要在 JSON 数组的末尾或特定位置添加新的元素时。 基本语法 JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ..…...
torch.is_nonzero(input)
torch.is_nonzero(input) input: 输入张量 若输入是 不等于零的单元素张量 则返回True,否则返回False 不等于零的单元素张量: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…...
Java 语言特性(面试系列2)
一、SQL 基础 1. 复杂查询 (1)连接查询(JOIN) 内连接(INNER JOIN):返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...