ODB 框架

news/2024/11/29 20:01:00/

目录

概述

基本工作原理

映射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;
}


http://www.ppmy.cn/news/1550976.html

相关文章

Github 基本使用学习笔记

1. 基本概念 1.1 一些名词 Repository&#xff08;仓库&#xff09; 用来存放代码&#xff0c;每个项目都有一个独立的仓库。 Star&#xff08;收藏&#xff09; 收藏你喜欢的项目&#xff0c;方便以后查看。 Fork&#xff08;克隆复制项目&#xff09; 复制别人的仓库&…

【力扣热题100】—— Day3.相交链表

被你改变的那部分我&#xff0c;代替你&#xff0c;永远与我站在一起 —— 24.11.28 160. 相交链表 给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 …

连续变量的 交叉熵 如何计算 python tensorflow

连续变量的交叉熵通常在机器学习中的回归问题中使用&#xff0c;但它也可以用于分类问题&#xff0c;当概率分布是连续的时。连续变量的交叉熵计算公式如下&#xff1a; 设 \( p(x) \) 是真实概率密度函数&#xff0c;\( q(x) \) 是预测概率密度函数&#xff0c;交叉熵 \( H(p…

ELK配置索引清理策略

在ELFK&#xff08;Elasticsearch, Logstash,Filebeat, Kibana&#xff09;堆栈中配置索引清理策略是一个常见的需求&#xff0c;因为日志数据会随着时间的推移而积累&#xff0c;占用大量的存储空间。以下是一些配置索引清理策略的方法&#xff1a; 1. 使用索引生命周期管理&…

Linux操作系统2-进程控制3(进程替换,exec相关函数和系统调用)

上篇文章&#xff1a;Linux操作系统2-进程控制2(进程等待&#xff0c;waitpid系统调用&#xff0c;阻塞与非阻塞等待)-CSDN博客 本篇代码Gitee仓库&#xff1a;Linux操作系统-进程的程序替换学习 d0f7bb4 橘子真甜/linux学习 - Gitee.com 本篇重点&#xff1a;进程替换 目录 …

第二节——计算机网络(四)物理层

车载以太网采用差分双绞线车载以太网并未指定特定的连接器&#xff0c;连接方式更为灵活小巧&#xff0c;能够大大减轻线束重量。传统以太网一般使用RJ45连接器连接。车载以太网物理层需满足车载环境下更为严格的EMC要求&#xff0c;100BASE-T1\1000BASE-T1对于非屏蔽双绞线的传…

如何在Python中进行数学建模?

数学建模是数据科学中使用的强大工具&#xff0c;通过数学方程和算法来表示真实世界的系统和现象。Python拥有丰富的库生态系统&#xff0c;为开发和实现数学模型提供了一个很好的平台。本文将指导您完成Python中的数学建模过程&#xff0c;重点关注数据科学中的应用。 数学建…

MemVerge与美光科技利用CXL®内存提升NVIDIA GPU利用率

该联合解决方案将 GPU 利用率提高了 77%&#xff0c;并将 OPT-66B 批量推理的速度提高了一倍以上。 2023 年 3 月 18 日&#xff0c;作为大内存软件领域领导者的 MemVerge&#xff0c;与美光科技联手推出了一项突破性解决方案&#xff0c;该方案通过智能分层的 CXL 内存&#x…