ORM框架(SQLAlchemy 与 Tortoise )

news2025/6/9 0:27:52

:本文是python的学习笔记;不是教程!不是教程!内容可能有所疏漏,欢迎交流指正。


框架概述

什么是ORM?

ORM(Object-Relational Mapping,对象关系映射)是一种编程技术,用于在面向对象编程语言和关系数据库之间建立映射关系。它允许开发者使用面向对象的方式操作数据库,而不需要编写复杂的SQL语句。

ORM的核心优势:

  • 代码可读性:使用Python对象而非SQL语句,代码更直观
  • 数据库无关性:同一套代码可以在不同数据库间切换
  • 安全性:自动防止SQL注入攻击
  • 维护性:模型变更时自动处理数据库结构变化

SQLAlchemy

SQLAlchemy是Python生态系统中最成熟、功能最全面的ORM框架,自2006年发布以来一直是企业级应用的首选。它提供了完整的SQL工具包和对象关系映射系统。

核心优势:

  • 成熟稳定:经过15+年生产环境验证,bug少,稳定性高
  • 功能全面:支持复杂的数据库操作,包括原生SQL、存储过程、视图等
  • 灵活架构:支持Core(表达式语言)和ORM两种使用模式
  • 强大查询:提供类似SQL的查询构建器,支持复杂的联表查询
  • 丰富生态:拥有大量第三方扩展,如Flask-SQLAlchemy、FastAPI-SQLAlchemy等
  • 多数据库支持:支持PostgreSQL、MySQL、SQLite、Oracle、SQL Server等

适用场景:

  • 企业级应用开发
  • 复杂的数据库操作需求
  • 需要高度定制化的项目
  • 对稳定性要求极高的系统

Tortoise ORM

Tortoise ORM是受Django ORM启发的异步ORM框架,专为现代异步Python应用设计。它提供了简洁的API和出色的异步性能。

核心优势:

  • 原生异步:所有操作都是异步的,性能优异,特别适合高并发场景
  • 语法简洁:类似Django ORM的语法,学习曲线平缓
  • 完美集成:与FastAPI、Starlette等异步框架无缝集成
  • 自动化程度高:减少样板代码,开发效率高
  • 现代化设计:基于Python 3.7+的现代特性设计
  • 类型提示:完整的类型提示支持,IDE友好

适用场景:

  • 现代异步Web应用(FastAPI、Starlette)
  • 高并发API服务
  • 微服务架构
  • 对开发效率要求高的项目

核心特性对比

特性SQLAlchemyTortoise ORM详细说明
同步/异步同步为主,2.0版本支持异步原生异步Tortoise在异步场景下性能更优
学习曲线较陡峭,概念复杂平缓,类似Django ORM新手更容易上手Tortoise
性能优秀,但同步操作有限制异步操作性能卓越高并发场景Tortoise优势明显
生态系统非常丰富,插件众多相对较新,生态在快速发展SQLAlchemy生态更成熟
文档质量详尽完整,示例丰富良好,但不如SQLAlchemy全面SQLAlchemy文档更完善
社区支持庞大活跃,问题解决快快速增长,响应积极SQLAlchemy社区更大
企业采用广泛使用,大厂首选新兴选择,增长迅速SQLAlchemy更适合企业级
数据库支持全面支持主流数据库支持主要数据库SQLAlchemy支持更全面
查询复杂度支持极复杂查询支持常见复杂查询SQLAlchemy在复杂查询上更强
代码风格显式,配置灵活隐式,约定优于配置看个人和团队偏好



SQLAlchemy 与 Tortoise ORM

一:Tortoise ORM 特性

  • 异步特性:Tortoise ORM 的所有数据库操作都是异步的,这意味着它们可以在单线程中同时处理多个数据库请求,而不会阻塞彼此。这大大提高了应用的并发性和性能。
  • 模型定义:在Tortoise ORM 中,开发者使用Python类来定义数据库表结构。这些类中的属性对应于数据库表中的列,这使得数据库操作更加直观和易于理解。
  • 查询构建:Tortoise ORM 提供了强大的查询构建功能,允许开发者构建复杂的查询条件,以检索所需的数据。这包括使用链式调用、比较运算符、逻辑运算符等。
  • 关系映射:Tortoise ORM 支持定义模型之间的关系,如一对一、一对多、多对多等。这使得开发者可以轻松地处理复杂的数据关系,并在代码中以直观的方式表示它们。
  • 迁移和同步:Tortoise ORM 还提供了数据库迁移工具,用于管理数据库模式的变更。这使得在应用开发过程中,可以轻松地添加、修改或删除表结构,而无需手动编写SQL语句。

二:模型定义

1. SQLAlchemy ORM

SQLAlchemy 是 Python 中最成熟的 ORM 框架,但其语法与 Django ORM 有较大差异。在 FastAPI 中,通常使用 SQLAlchemy 的声明式方式定义模型。
SQLAlchemy使用声明式方式定义模型,需要显式定义所有关系

# models.py

# 需要先导入所有需要使用的字段类型
from sqlalchemy import Column, Integer, String, ForeignKey, Numeric

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

# 主表 (模型B)
class Category(Base):
    __tablename__ = "categories"	# 数据库表名称
    
    id = Column(Integer, primary_key=True)
    name = Column(String(50))
    
    # 必须显式定义反向关系
    products = relationship("Product", back_populates="category")

    
    
# 从表 (模型A)
class Product(Base):
    __tablename__ = "products"
    
    id = Column(Integer, primary_key=True)
    name = Column(String(100))
    price = Column(Numeric(10, 2))
    
    # 第一步:定义外键约束, 这是数据库级别的外键约束
    category_id = Column(Integer, ForeignKey("categories.id"))
    
    # 第二步:定义反向关系, 这是 Python 对象级别的关系
    category = relationship("Category", back_populates="products")
    
    
    
# 在 SQLAlchemy 中,定义关系需要两步:
1. 在从表定义外键约束
2. 在两侧都定义 relationship 来创建对象间的关联

# 使用方式:
通过 product.category 访问产品所属类别
通过 category.products 访问类别下所有产品

2. Tortoise ORM

Tortoise ORM 语法与 Django ORM 非常相似,更加简洁直观自动处理反向关系。

CharField 字符串类型字段

  • max_length:字符串的最大长度。
  • default:字段的默认值。
  • null:是否允许字段为NULL。默认为False。
  • unique:字段值是否必须在数据库中唯一。默认为False。
  • index:是否为该字段创建索引。默认为False。
  • description:字段的描述信息,主要用于文档和生成的SQL schema。
  • pk:是否将此字段设置为主键。默认为False。
  • generated:是否为自动生成的字段(如自增主键)。默认为False。

FloatField 浮点类型字段

  • default, null, unique, index, description, pk, generated: 与CharField相同。
  • gt, lt, ge, le:用于设置字段值的范围限制(大于、小于、大于等于、小于等于)。

IntegerField 整数类型字段

  • default, null, unique, index, description, pk, generated:与CharField相同。
  • gt, lt, ge, le:用于设置字段值的范围限制(大于、小于、大于等于、小于等于)。

BooleanField 布尔类型字段

  • default, null, description:与CharField相同。

DateField 和 DateTimeField 日期时间类型字段

  • auto_now:如果设置为True,则在对象保存时自动设置为当前日期/时间。默认为False。
  • auto_now_add:如果设置为True,则在对象第一次保存时自动设置为当前日期/时间。默认为False。
  • default, null, unique, index, description, pk:与CharField相同。

ForeignKeyField 关系型字段

  • to (str or Type[Model]):指定外键关联的模型。
  • related_name (str):在关联模型上创建反向关系的名称。
  • on_delete (str):当关联的对象被删除时的行为(如CASCADE、SET_NULL等)。
  • default, null, description, pk, index:与CharField相同。

ManyToManyField 关系型字段

  • through:用于定义多对多关系的中间表。如果不指定,Tortoise ORM将自动创建一个中间表。
  • related_name:与ForeignKeyField中的用法相同,用于反向查询。
  • default, null, description, pk, index:与CharField相同。

TextField文本类型字段

  • default, null, description:与CharField相同。通常用于存储大量文本。

JSONField序列话类型字段

  • default, null, description:与CharField相同。用于存储JSON格式的数据。
# models.py
from tortoise import fields, models
from tortoise.contrib.pydantic import pydantic_model_creator


# 主表 (模型B)
class Category(models.Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=50)
    
    # 不需要显式定义反向关系,会自动创建 products 属性
    # products = fields.ReverseRelation["Product"]  # 这行可以不写,会自动生成

    
    
# 从表 (模型A)
class Product(models.Model):
    id = fields.IntField(pk=True)
    name = fields.CharField(max_length=100)
    price = fields.DecimalField(max_digits=10, decimal_places=2)
    
    # 只需在这一侧定义外键
    category = fields.ForeignKeyField("models.Category", related_name="products", on_delete=fields.CASCADE)

    
    
# 使用方式:
通过 product.category 访问产品所属类别
通过 category.products 访问类别下所有产品	# 通过外键的related_name="products" 的名字来访问

模型定义对比总结:

方面SQLAlchemyTortoise ORM
语法复杂度较复杂,需要显式定义关系简洁,自动处理反向关系
字段定义需要导入具体字段类型统一的fields模块
关系定义双向显式定义单向定义,自动生成反向
元数据配置使用__tablename__使用Meta类

字段参数详解

通用参数:

  • null: 是否允许为空(默认False)
  • default: 默认值
  • unique: 是否唯一(默认False)
  • index: 是否创建索引(默认False)
  • description: 字段描述

CharField特有参数:

  • max_length: 最大长度(必需)

数值字段特有参数:

  • ge: 大于等于
  • gt: 大于
  • le: 小于等于
  • lt: 小于

时间字段特有参数:

  • auto_now: 每次保存时自动更新
  • auto_now_add: 创建时自动设置

外键字段特有参数:

  • related_name: 反向关系名称
  • on_delete: 删除策略(CASCADE、SET_NULL、RESTRICT等)



三:数据库迁移

1. SQLAlchemy ORM迁移(使用 Alembic)

SQLAlchemy 本身不提供迁移工具,通常与 Alembic 配合使用。

1:安装 Alembic 库

pip install alembic

2:初始化 Alembic

alembic init alembic

# 这会创建以下文件结构:
# alembic/
# ├── versions/         # 迁移文件目录
# ├── env.py            # 环境配置
# ├── script.py.mako    # 迁移脚本模板
# └── alembic.ini       # 配置文件

3:配置 alembic.ini 文件

sqlalchemy.url = sqlite:///./app.db

4:配置env.py文件



2. Tortoise ORM迁移(使用 aerich)

Tortoise ORM 使用 aerich 进行迁移。

1:安装 aerich 库

pip install aerich

2:在 FastAPI 应用中配置数据库

# main.py
from fastapi import FastAPI
from tortoise.contrib.fastapi import register_tortoise

app = FastAPI()

TORTOISE_ORM = {
    "connections": {"default": "postgresql://user:password@localhost/dbname"},
    "apps": {
        "models": {
            "models": ["app.models", "aerich.models"],
            "default_connection": "default",
        },
    },
}

register_tortoise(
    app,
    config=TORTOISE_ORM,
    generate_schemas=False,  # 不自动生成表,使用迁移
    add_exception_handlers=True,
)

3:初始化配置(整个项目只需执行一次)

aerich init -t app.main.TORTOISE_ORM	# TORTOISE_ORM配置的位置


# 初始化完成会在 当前目录下 生成一个文件(pyproject.toml) 和文件夹(migrations)
# pyproject.toml:保存配置文件路径,低版本可能是aerich.ini
# migrations:存放迁移文件的目录

4:模型迁移(在数据库创建对应模型的数据表)

aerich init-db

# 此时数据库中就会有对应数据模型的数据表
# 如果TORTOISE_ORM配置文件中的models改了名字,则执行这条命令时需要增加**–app**参数,来指定修改的名称

5:更改模型字段后重新生成迁移文件

aerich migrate [--name '迁移记录']	# 标记修改操作记录(可选)

6:数据迁移(更新数据库的表字段)

aerich upgrade	# 基于第五步操作

7:回滚迁移

aerich downgrade	# 默认回退上一步的版本

8:查看历史迁移记录

aerich history



四:数据库操作(CURD)

1. SQLAlchemy CURD 操作

from sqlalchemy.orm import Session
from . import models, schemas

# 创建 (Create)
def create_user(db: Session, user: schemas.UserCreate):
    """创建用户"""
    # 方法1:使用构造函数
    db_user = models.User(
        username=user.username,
        email=user.email,
        hashed_password="hashed_password"
    )
    db.add(db_user)  # 添加到会话
    db.commit()      # 提交事务
    db.refresh(db_user)  # 刷新对象属性
    return db_user

# 读取 (Read)
def get_user(db: Session, user_id: int):
    return db.query(models.User).filter(models.User.id == user_id).first()

def get_users(db: Session, skip: int = 0, limit: int = 100):
    return db.query(models.User).offset(skip).limit(limit).all()

def get_users_by_filter(db: Session):
    # 复杂查询示例
    return (db.query(models.User)
            .filter(models.User.is_active == True)
            .order_by(models.User.username)
            .all())

# 更新 (Update)
def update_user(db: Session, user_id: int, user_data: schemas.UserUpdate):
    db_user = db.query(models.User).filter(models.User.id == user_id).first()
    if db_user:
        # 更新模型属性
        for key, value in user_data.dict(exclude_unset=True).items():
            setattr(db_user, key, value)
        db.commit()
        db.refresh(db_user)
    return db_user

# 删除 (Delete)
def delete_user(db: Session, user_id: int):
    db_user = db.query(models.User).filter(models.User.id == user_id).first()
    if db_user:
        db.delete(db_user)
        db.commit()
    return db_user

# 关系查询
def get_user_posts(db: Session, user_id: int):
    db_user = db.query(models.User).filter(models.User.id == user_id).first()
    if db_user:
        return db_user.posts  # 使用关系属性
    return []

# 多对多关系
def add_tag_to_post(db: Session, post_id: int, tag_id: int):
    post = db.query(models.Post).filter(models.Post.id == post_id).first()
    tag = db.query(models.Tag).filter(models.Tag.id == tag_id).first()
    if post and tag:
        post.tags.append(tag)
        db.commit()

2. Tortoise ORM CURD 操作

from tortoise.transactions import in_transaction
from . import models, schemas

# 创建 (Create)
async def create_user(user: schemas.UserCreate):
    return await models.User.create(
        username=user.username,
        email=user.email,
        hashed_password="hashed_password"
    )

# 读取 (Read)
async def get_user(user_id: int):
    '''
    get() 方法用于根据主键获取单条数据。如果数据不存在,则抛出错误
    get_or_none() 方法用于根据主键获取单条数据。如果数据不存在,将返回 None
    '''
    return await models.User.get(id=user_id)
	return await models.User.get_or_none(id=user_id)

async def get_user(user_id: int):
    '''
    filter() 方法用于根据条件查询数据,返回满足条件的数据集(QuerySet对象)。
	使用 first() 方法获取第一个结果;
	使用 all() 方法获取所有的查询结果。
    '''
    return await models.User.filter(id=user_id).first()
	return await models.User.filter(id=user_id).all()

async def get_users(skip: int = 0, limit: int = 100):
    '''
    all() 方法用于查询所有数据,返回所有数据集(QuerySet对象)。
	如果不加任何条件,它会返回表中的所有记录。
    '''
    return await models.User.all().offset(skip).limit(limit)

async def get_users_by_filter():
    # 复杂查询示例
    return await (models.User.filter(is_active=True).order_by('username'))

# 更新 (Update)
async def update_user(user_id: int, user_data: schemas.UserUpdate):
    # 方法 1:先查询再更新
    user = await models.User.filter(id=user_id).first()
    if user:
        user_data_dict = user_data.dict(exclude_unset=True)
        for key, value in user_data_dict.items():
            setattr(user, key, value)
        await user.save()
        return user
    
    # 方法 2:直接使用 update
    updated = await models.User.filter(id=user_id).update(**user_data.dict(exclude_unset=True))
    if updated:
        return await models.User.filter(id=user_id).first()
    return None

# 删除 (Delete)
async def delete_user(user_id: int):
    user = await models.User.filter(id=user_id).first()
    if user:
        await user.delete()
        return user
    return None

# 关系查询
async def get_user_posts(user_id: int):
    # 方法 1:通过用户查询
    user = await models.User.filter(id=user_id).first().prefetch_related('posts')
    if user:
        return user.posts
    
    # 方法 2:直接查询文章
    return await models.Post.filter(author_id=user_id)

# 多对多关系
async def add_tag_to_post(post_id: int, tag_id: int):
    post = await models.Post.filter(id=post_id).first()
    tag = await models.Tag.filter(id=tag_id).first()
    if post and tag:
        await post.tags.add(tag)  # 添加多对多关系
        return True
    return False

# 事务处理
async def create_post_with_tags(post_data, tag_ids):
    async with in_transaction() as conn:
        # 在事务中创建文章
        post = await models.Post.create(
            title=post_data.title,
            content=post_data.content,
            author_id=post_data.author_id,
            using_db=conn
        )
        # 添加标签
        for tag_id in tag_ids:
            tag = await models.Tag.filter(id=tag_id).using_db(conn).first()
            if tag:
                await post.tags.add(tag, using_db=conn)
        return post

2. 比较运算符
async def get_users():
    '''
    获取(= 等于)1的数据
    '''
    return await models.User.filter(id=1).all()

async def get_users():
    '''
    获取(__not 不等于)1的数据
    '''
    return await models.User.filter(id__not=1).all()

async def get_users():
    '''
    获取(__gt 大于)1的数据
    '''
    return await models.User.filter(id__gt=1).all()

async def get_users():
    '''
    获取(id__gte 大于等于)1的数据
    '''
    return await models.User.filter(id__gte=1).all()

async def get_users():
    '''
    获取(id__lt 小于)1的数据
    '''
    return await models.User.filter(id__lt=1).all()

async def get_users():
    '''
    获取(id__lte 小于等于)1的数据
    '''
    return await models.User.filter(id__lte=1).all()

3. 成员运算符
async def get_users():
    '''
    获取(__in 在)列表中的数据
    '''
    names = ['张三', '李四', '王五']
    return await models.User.filter(user__in=names).all()

4. 模糊查询
# Tortoise ORM 不直接支持SQL中的LIKE模糊查询,

async def get_users():
    '''
    获取(__icontains 包含)200的数据
    '''
    return await models.User.filter(num__icontains='200').all()

async def get_users():
    '''
    获取(__istartswith 开头)200的数据
    '''
    return await models.User.filter(num__istartswith='200').all()

async def get_users():
    '''
    获取(__iendswith 结尾)200的数据
    '''
    return await models.User.filter(num__iendswith='200').all()

async def get_users():
    '''
    获取(__range 指定范围之间)的数据
    '''
    # 获取学号在[2021, 2024]之间的数据
    return await models.User.filter(num__range=[2021, 2024]).all()

async def get_users():
    '''
    获取(__isnull 是否为空)的数据
    '''
    return await models.User.filter(num__isnull=True).all()

5. exclude():排除

用于排除满足条件的数据,返回不满足条件的数据集

async def get_users(name : str = '张三'):
    '''
    (exclude 排除)名字不是 '张三' 的所有数据
    '''
    return await models.User.exclude(user=name).all()

6. count():统计

用于统计满足条件的数据数量

async def get_users(num: int = 18):
    '''
    (count 统计)(__gt 大于)18的数据量
    '''
    return await models.User.filter(age__gt=num).count()

7. order_by():排序

用于安装指定字段排序查询结果

async def get_users():
    '''
    按id进行排序, 获取所有数据
    '''
    return await models.User.all().orderby('id')	# 升序
	return await models.User.all().orderby('id')	# 降序



原生SQL查询

SQLAlchemy 原生SQL
from sqlalchemy import text

def execute_raw_sql(db: Session):
    """执行原生SQL"""
    result = db.execute(text("""
        SELECT u.username, COUNT(p.id) as post_count
        FROM users u
        LEFT JOIN posts p ON u.id = p.author_id
        GROUP BY u.id, u.username
        ORDER BY post_count DESC
    """))
    return result.fetchall()

def execute_raw_sql_with_params(db: Session, min_posts: int):
    """带参数的原生SQL"""
    result = db.execute(text("""
        SELECT u.username, COUNT(p.id) as post_count
        FROM users u
        LEFT JOIN posts p ON u.id = p.author_id
        GROUP BY u.id, u.username
        HAVING COUNT(p.id) >= :min_posts
        ORDER BY post_count DESC
    """), {"min_posts": min_posts})
    return result.fetchall()

Tortoise ORM 原生SQL
from tortoise import connections

async def execute_raw_sql():
    """执行原生SQL"""
    conn = connections.get("default")
    result = await conn.execute_query("""
        SELECT u.username, COUNT(p.id) as post_count
        FROM users u
        LEFT JOIN posts p ON u.id = p.author_id
        GROUP BY u.id, u.username
        ORDER BY post_count DESC
    """)
    return result

async def execute_raw_sql_with_params(min_posts: int):
    """带参数的原生SQL"""
    conn = connections.get("default")
    result = await conn.execute_query("""
        SELECT u.username, COUNT(p.id) as post_count
        FROM users u
        LEFT JOIN posts p ON u.id = p.author_id
        GROUP BY u.id, u.username
        HAVING COUNT(p.id) >= $1
        ORDER BY post_count DESC
    """, [min_posts])
    return result



选择建议

何时选择SQLAlchemy

适合场景:

  1. 企业级应用:需要高度稳定性和成熟的生态系统
  2. 复杂业务逻辑:涉及复杂的数据库操作和查询
  3. 团队经验:团队对SQLAlchemy有丰富经验
  4. 数据库多样性:需要支持多种数据库类型
  5. 现有项目:已有基于SQLAlchemy的项目需要维护

优势:

  • 生态系统成熟,第三方工具丰富
  • 文档详尽,社区支持强大
  • 功能全面,支持复杂的数据库操作
  • 经过长期生产环境验证

何时选择Tortoise ORM

适合场景:

  1. 现代异步应用:基于FastAPI、Starlette等异步框架
  2. 高并发需求:需要处理大量并发请求
  3. 快速开发:追求开发效率和代码简洁性
  4. 新项目:从零开始的新项目
  5. 微服务架构:轻量级的微服务应用

优势:

  • 原生异步支持,性能优异
  • 语法简洁,学习成本低
  • 与现代异步框架集成度高
  • 开发效率高,代码量少

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

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

相关文章

go语言map扩容

map是什么? ​在Go语言中,map是一种内置的无序key/value键值对的集合,可以根据key在O(1)的时间复杂度内取到value,有点类似于数组或者切片结构,可以把数组看作是一种特殊的map,数组的key为数组的下标&…

5.3 Spring Boot整合JPA

本文详细介绍了如何在Spring Boot项目中整合Spring JPA,实现对数据库的高效操作。首先,创建Spring Boot项目并添加必要的依赖,如Druid数据源。接着,配置数据源属性,创建实体类Comment和Article,并使用JPA注…

腾讯开源视频生成工具 HunyuanVideo-Avatar,上传一张图+一段音频,就能让图中的人物、动物甚至虚拟角色“活”过来,开口说话、唱歌、演相声!

腾讯混元团队提出的 HunyuanVideo-Avatar 是一个基于多模态扩散变换器(MM-DiT)的模型,能够生成动态、情绪可控和多角色对话视频。支持仅 10GB VRAM 的单 GPU运行,支持多种下游任务和应用。例如生成会说话的虚拟形象视频&#xff0…

[文献阅读] Emo-VITS - An Emotion Speech Synthesis Method Based on VITS

[文献阅读]:An Emotion Speech Synthesis Method Based on VITS 在VITS基础上通过参考音频机制,获取情感信息,从而实现的情感TTS方式。 摘要 VITS是一种基于变分自编码器(VAE)和对抗神经网络(GAN&#xf…

OpenCV-Python Tutorial : A Candy from Official Main Page(持续更新)

OpenCV-Python 是计算机视觉领域最流行的开源库之一,它结合了 OpenCV (Open Source Computer Vision Library) 的 C 高性能实现和 Python 的简洁易用特性,为开发者提供了强大的图像和视频处理能力。具有以下优势: 典型应用领域: …

【Vue】指令补充+样式绑定+计算属性+侦听器

【指令补充】 【指令修饰符】 指令修饰符可以让指令的 功能更强大,书写更便捷 分类: 1.按键修饰符(侦测当前点击的是哪个按键) 2.事件修饰符(简化程序对于阻止冒泡, 一些标签的默认默认行为的操作&…

LLM 笔记:Speculative Decoding 投机采样

1 基本介绍 投机采样(Speculative Sampling)是一种并行预测多个可能输出,然后快速验证并采纳正确部分的加速策略 在不牺牲输出质量的前提下,减少语言模型生成 token 所需的时间 传统的语言模型生成是 串行 的 必须生成一个&…

当SAP系统内计划订单转换为生产订单时发生了什么?

【SAP系统研究】 #SAP #计划订单 #生产订单 #采购申请 一、关于计划订单的一点疑惑 曾经对SAP为什么会有计划订单,是感到很疑惑的。 这个界面简单,配置点也不多,能被随意“摆布”,一旦要变形就消失得无影无踪的计划订单,why? 但是,再次重新审视过之后,才发现它其实…

PDF转PPT转换方法总结

你是否遇到过这些场景? 收到客户发来的产品手册PDF,明天就要用它做演示; 公司历史资料只有PDF版,领导突然要求更新为幻灯片。 这时PDF转PPT工具就成了救命稻草。接下来,介绍三种PDF转PPT工具。 1. iLoveOFD在线转换…

3D Web轻量化引擎HOOPS Communicator的定制化能力全面解析

HOOPS Communicator 是Tech Soft 3D推出的高性能Web工程图形引擎。它通过功能丰富的JavaScript API,帮助开发团队在浏览器中快速添加2D/3D CAD模型的查看与交互功能。该引擎专为工程应用优化,支持大规模模型的流畅浏览、复杂装配的智能导航、流式加载和服…

【力扣链表篇】19.删除链表的倒数第N个节点

题目: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5]示例 2: 输入:head [1], n 1 输出:[]…

如何使用Jmeter进行压力测试?

🍅 点击文末小卡片,免费获取软件测试全套资料,资料在手,涨薪更快 一、什么是压力测试 软件测试中:压力测试(Stress Test),也称为强度测试、负载测试。压力测试是模拟实际应用的软硬…

Grafana-ECharts应用讲解(玫瑰图示例)

工具: MySQL 数据库 MySQL Workbench 数据库管理工具(方便编辑数据) Grafana v11.5.2 Business Charts 6.6(原 Echarts插件) 安装 安装 MySQL社区版安装 MySQL Workbench安装 Grafana在 Grafana 插件中搜索 Business Charts 进行安装以上安装步骤网上教程很多,自行搜…

前端vue3 上传/导入文件 调用接口

点击按钮导入&#xff1a; <el-uploadaction"https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15":auto-upload"false":on-change"handleFileChange":show-file-list"false"><el-button type"warning"…

Python训练营-Day22-Titanic - Machine Learning from Disaster

Description linkkeyboard_arrow_up &#x1f44b;&#x1f6f3;️ Ahoy, welcome to Kaggle! You’re in the right place. This is the legendary Titanic ML competition – the best, first challenge for you to dive into ML competitions and familiarize yourself w…

FreeCAD:开源世界的三维建模利器

FreeCAD 开发模式 FreeCAD的开发采用多语言协作模式&#xff0c;其核心框架与高性能模块主要使用C构建&#xff0c;而用户界面与扩展功能则通过Python脚本实现灵活定制。具体来说&#xff1a; C核心层&#xff1a;作为基础架构&#xff0c;C负责实现与Open CASCADE Technology…

嵌入式里的时间魔法:RTC 与 BKP 深度拆解

文章目录 RTC实时时钟与BKPUnix时间戳UTC/GMT时间戳转换时间戳转换BKP简介BKP基本结构1. 电池供电模块&#xff08;VBAT 输入&#xff09;2. 侵入检测模块&#xff08;TAMPER 输入&#xff09;3. 时钟输出模块&#xff08;RTC 输出&#xff09;4. 内部寄存器组 RTC简介RTC时钟源…

图卷积网络:从理论到实践

图卷积网络&#xff08;Graph Convolutional Networks, GCNs&#xff09;彻底改变了基于图的机器学习领域&#xff0c;使得深度学习能够应用于非欧几里得结构&#xff0c;如社交网络、引文网络和分子结构。本文将解释GCN的直观理解、数学原理&#xff0c;并提供代码片段帮助您理…

ES 学习总结一 基础内容

ElasticSearch学习 一、 初识ES1、 认识与安装2、 倒排索引2.1 正向索引2.2 倒排索引 3、 基本概念3.1 文档和字段3.2 索引和倒排 4 、 IK分词器 二、 操作1、 mapping 映射属性2、 索引库增删改查3、 文档的增删改查3.1 新增文档3.2 查询文档3.3 删除文档3.4 修改文档3.5 批处…

Maven 构建缓存与离线模式

🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程,高并发设计,Springboot和微服务,熟悉Linux,ESXI虚拟化以及云原生Docker和K8s,热衷于探…