三周精通FastAPI:27 使用使用SQLModel操作SQL (关系型) 数据库

官网文档:https://fastapi.tiangolo.com/zh/tutorial/sql-databases/

SQL (关系型) 数据库¶

FastAPI不需要你使用SQL(关系型)数据库。

但是您可以使用任何您想要的关系型数据库。

这里我们将看到一个使用SQLModel的示例。

SQLModel是在SQLAlchemy和Pydantic的基础上构建的。它是由FastAPI的同一作者制作的,与需要使用SQL数据库的FastAPI应用程序完美匹配。

小贴士

你可以使用任何其他你想要的SQL或NoSQL数据库库(在某些情况下称为“ORM”),FastAPI不会强迫你使用任何东西。

由于SQLModel基于SQLAlchemy,您可以轻松使用SQLAlchemi支持的任何数据库(这使得它们也受SQLModel支持)您可以很容易地将其调整为任何SQLAlchemy支持的数据库,如:

  • PostgreSQL
  • MySQL
  • SQLite
  • Oracle
  • Microsoft SQL Server,等等其它数据库

在此示例中,我们将使用SQLite,因为它使用单个文件并且 在Python中具有集成支持。因此,您可以复制此示例并按原样来运行它。

稍后,对于您的产品级别的应用程序,您可能会要使用像PostgreSQL这样的数据库服务器。

Tip

这儿有一个FastAPIPostgreSQL的官方项目生成器,全部基于Docker,包括前端和更多工具:https://github.com/tiangolo/full-stack-fastapi-postgresql

这是一个非常简单而简短的教程,如果你想了解数据库、SQL或更高级的功能,请参阅SQLModel文档。

安装SQLModel

首先,确保创建虚拟环境,激活它,然后安装sqlmodel:

pip install sqlmodel

Successfully installed SQLAlchemy-2.0.36 sqlmodel-0.0.22

使用单个模型创建应用程序

我们将首先使用单个SQLModel模型创建该应用程序最简单的第一个版本。

稍后,我们将通过以下多种型号来提高它的安全性和多功能性。🤓

from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass Hero(SQLModel, table=True):id: int | None = Field(default=None, primary_key=True)name: str = Field(index=True)age: int | None = Field(default=None, index=True)secret_name: strsqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:session.add(hero)session.commit()session.refresh(hero)return hero@app.get("/heroes/")
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}

创建模型

导入SQLModel并创建数据库模型:

from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass Hero(SQLModel, table=True):id: int | None = Field(default=None, primary_key=True)name: str = Field(index=True)age: int | None = Field(default=None, index=True)secret_name: str

🤓 其他版本和变体

Hero类与Pydantic模型非常相似(事实上,在下面,它实际上是一个Pydantic模式)。

存在一些差异:

  • table=True告诉SQLModel这是一个表模型,它应该表示SQL数据库中的一个表,它不仅仅是一个数据模型(就像任何其他常规Pydantic类一样)。
  • 字段(primary_key=True)告诉SQLModel id是SQL数据库中的主键(您可以在SQLModel文档中了解有关SQL主键的更多信息)。
  • 通过将类型设置为int|None,SQLModel将知道该列在SQL数据库中应该是INTEGER,并且应该是NULLABLE。
  • 字段(index=True)告诉SQLModel,它应该为该列创建SQL索引,这样在读取由该列筛选的数据时可以更快地在数据库中查找。
  • SQLModel将知道声明为str的内容将是TEXT类型的SQL列(或VARCHAR,具体取决于数据库)。

创建引擎

SQLModel引擎(其下实际上是SQLAlchemy引擎)负责保存与数据库的连接。

您将有一个单一的引擎对象,用于所有代码连接到同一个数据库。

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)

使用check_same_thread=False允许FastAPI在不同线程中使用相同的SQLite数据库。这是必要的,因为一个请求可能会使用多个线程(例如在依赖关系中)。

别担心,根据代码的结构方式,我们将确保稍后每个请求使用一个SQLModel会话,这实际上是check_same_thread试图实现的。

创建表格

然后,我们添加一个函数,该函数使用SQLModel.media.create_all(engine)为所有表模型创建表。

def create_db_and_tables():SQLModel.metadata.create_all(engine)

创建会话依赖关系

会话是将对象存储在内存中并跟踪数据中所需的任何更改,然后使用引擎与数据库通信。

我们将使用yield创建一个FastAPI依赖关系,为每个请求提供一个新的Session。这就是确保我们每个请求使用单个会话的原因。🤓

然后,我们创建一个带注释的依赖项SessionDep,以简化将使用此依赖项的其余代码。

def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]

启动时创建数据库表

我们将在应用程序启动时创建数据库表。

app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()

在这里,我们在应用程序启动事件上创建表。

对于生产环境,您可能会使用在启动应用程序之前运行的迁移脚本。🤓

小贴士

SQLModel将有封装Alembic的迁移实用程序,但现在,您可以直接使用Alembic。

创建英雄库

因为每个SQLModel模型也是一个Pydantic模型,所以您可以在使用Pydantics模型的相同类型注释中使用它。

例如,如果你声明一个Hero类型的参数,它将从JSON正文中读取。

同样,您可以将其声明为函数的返回类型,然后数据的形状将显示在自动API文档UI中。

@app.post("/heroes/")
def create_hero(hero: Hero, session: SessionDep) -> Hero:session.add(hero)session.commit()session.refresh(hero)return hero

在这里,我们使用SessionDep依赖项(Session)将新的Hero添加到Session实例中,将更改提交到数据库中,刷新Hero中的数据,然后返回它。

读英雄库

我们可以使用select()从数据库中读取Heros。我们可以包含一个限制和偏移量来对结果进行分页。

@app.get("/heroes/")
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
) -> list[Hero]:heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes

读一个英雄条目

我们可以读一个英雄。

@app.get("/heroes/{hero_id}")
def read_hero(hero_id: int, session: SessionDep) -> Hero:hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero

如果不是英雄:

引发HTTPException(状态码=404,详细信息=“未找到英雄”)

删除英雄

我们也可以删除英雄。

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}

运行应用程序

您可以运行该应用程序:

fastapi-dev-main.py

然后转到/docs UI,您将看到FastAPI正在使用这些模型来记录API,它也将使用它们来序列化和验证数据。

使用多个模型更新应用程序

现在,让我们稍微重构一下这个应用程序,以提高安全性和多功能性。

如果你查看之前的应用程序,在UI中你可以看到,到目前为止,它让客户端决定要创建的英雄的id。😱

我们不应该让这种情况发生,他们可能会覆盖我们已经在数据库中分配的id。决定id应该由后端或数据库完成,而不是由客户端完成。

此外,我们为英雄创建了一个secret_name,但到目前为止,我们到处都在返回它,这不是什么秘密。。。😅

我们将通过添加一些额外的模型来解决这些问题。SQLModel将在这里大放异彩。✨

源代码:

from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: strclass HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = Nonesqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]
app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}

创建多个模型

在SQLModel中,任何具有table=True的模型类都是表模型。
任何没有table=True的模型类都是数据模型,这些模型实际上只是Pydantic模型(带有一些小的额外功能)。🤓
使用SQLModel,我们可以使用继承来避免在所有情况下复制所有字段。


HeroBase-基类

让我们从一个HeroBase模型开始,该模型包含所有模型共享的所有字段:
名称
年龄

  • name
  • age
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)

英雄-桌子模型


然后,让我们创建Hero,即实际的表模型,其中包含其他模型中并不总是包含的额外字段:
身份证件
秘密名称

  • id
  • secret_name

因为Hero继承自HeroBase,所以它也有在HeroBase中声明的字段,所以Hero的所有字段都是:
身份证件
名称
年龄
秘密名称

  • id
  • name
  • age
  • secret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: str

HeroPublic-公共数据模型


接下来,我们创建一个HeroPublic模型,该模型将返回给API的客户端。
它具有与HeroBase相同的字段,因此不包括secret_name。
最后,我们英雄的身份得到了保护!🥷
它还重新声明id:int。通过这样做,我们与API客户端签订了合同,这样他们就可以总是期望id在那里并且是int(永远不会是None)。


小贴士
让返回模型确保一个值总是可用的,并且总是int(而不是None)对API客户端非常有用,他们可以编写更简单的具有这种确定性的代码。
此外,自动生成的客户端将具有更简单的接口,因此与您的API通信的开发人员可以更好地使用您的API。😎


HeroPublic中的所有字段都与HeroBase中的相同,id声明为int(不是None):
身份证件
名称
年龄
秘密名称

  • id
  • name
  • age
  • secret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: int

HeroCreate-创建英雄的数据模型


现在我们创建一个HeroCreate模型,这个模型将验证来自客户端的数据。
它具有与HeroBase相同的字段,还具有secret_name。
现在,当客户端创建一个新英雄时,他们将发送secret_name,它将存储在数据库中,但这些秘密名称不会在API中返回给客户端。


小贴士
这就是你处理密码的方式。接收它们,但不要在API中返回它们。
您还可以在存储密码之前对其值进行哈希运算,切勿以纯文本形式存储。


HeroCreate的字段包括:
名称
年龄
秘密名称

  • name
  • age
  • secret_name
class HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: str

HeroUpdate-更新英雄的数据模型


在之前的应用程序版本中,我们没有更新英雄的方法,但现在有了多个模型,我们可以做到。🎉
HeroUpdate数据模型有点特殊,它具有创建新英雄所需的所有相同字段,但所有字段都是可选的(它们都有一个默认值)。这样,当你更新英雄时,你可以只发送你想要更新的字段。
因为所有字段实际上都发生了变化(类型现在包括None,它们现在的默认值为None),我们需要重新声明它们。
我们真的不需要从HeroBase继承,因为我们正在重新声明所有字段。为了保持一致性,我会让它继承,但这不是必需的。这更多的是个人品味的问题。🤷
HeroUpdate的字段包括:


名称
年龄
秘密名称

  • name
  • age
  • secret_name
class HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = None


使用HeroCreate创建并返回一个HeroPublic


现在我们有了多个模型,我们可以更新应用程序中使用它们的部分。
我们在请求中接收HeroCreate数据模型,并从中创建Hero表模型。
这个新的表模型Hero将具有客户端发送的字段,并且还将具有数据库生成的id。
然后,我们返回与函数中相同的表模型Hero。但是,当我们使用HeroPublic数据模型声明response_model时,FastAPI将使用HeroPublic来验证和序列化数据。

@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero


小贴士
现在我们使用response_model=HeroPublic而不是返回类型注释->HeroPublic,因为我们返回的值实际上不是HeroPublic。
如果我们声明了->HeroPublic,你的编辑和linter会抱怨(这是理所当然的)你返回的是Hero而不是HeroPublic。
通过在response_model中声明它,我们告诉FastAPI去做它的事情,而不会干扰类型注释以及编辑器和其他工具的帮助。


用HeroPublic阅读英雄


我们可以像以前一样读取Heros,同样,我们使用response_model=list[HeroPublic]来确保数据被正确验证和序列化。

@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes


与HeroPublic一起阅读《一个英雄》


我们可以读一个英雄:

@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero


使用HeroUpdate更新英雄


我们可以更新英雄。为此,我们使用HTTP PATCH操作。
在代码中,我们得到一个包含客户端发送的所有数据的字典,只有客户端发送的数据,不包括任何仅作为默认值的值。为此,我们使用exclude_unset=True。这是主要的伎俩。🪄
然后,我们使用hero_db.sqlmodel_update(hero_data)用hero_da中的数据更新hero_db。

@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db


再次删除英雄


删除英雄几乎是一样的。
我们不会满足在这个项目中重构所有内容的愿望。😅

@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}


再次运行应用程序


您可以再次运行该应用程序:

fastapi dev main.py


输出信息:Uvicorn正在运行http://127.0.0.1:8000(按CTRL+C退出)



如果你转到/docs API UI,你会看到它现在已经更新,并且它不会期望在创建英雄时从客户端接收id,等等。


回顾


您可以使用SQLModel与SQL数据库交互,并使用数据模型和表模型简化代码。
您可以在SQLModel文档中了解更多信息,其中有一个关于使用SQLModel和FastAPI的较长迷你教程。🚀

实践

 安装SQLModel

首先,确保创建虚拟环境,激活它,然后安装sqlmodel:

pip install sqlmodel

源代码

存储文件到sql.py

from typing import Annotatedfrom fastapi import Depends, FastAPI, HTTPException, Query
from sqlmodel import Field, Session, SQLModel, create_engine, selectclass HeroBase(SQLModel):name: str = Field(index=True)age: int | None = Field(default=None, index=True)class Hero(HeroBase, table=True):id: int | None = Field(default=None, primary_key=True)secret_name: strclass HeroPublic(HeroBase):id: intclass HeroCreate(HeroBase):secret_name: strclass HeroUpdate(HeroBase):name: str | None = Noneage: int | None = Nonesecret_name: str | None = Nonesqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, connect_args=connect_args)def create_db_and_tables():SQLModel.metadata.create_all(engine)def get_session():with Session(engine) as session:yield sessionSessionDep = Annotated[Session, Depends(get_session)]
app = FastAPI()@app.on_event("startup")
def on_startup():create_db_and_tables()@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate, session: SessionDep):db_hero = Hero.model_validate(hero)session.add(db_hero)session.commit()session.refresh(db_hero)return db_hero@app.get("/heroes/", response_model=list[HeroPublic])
def read_heroes(session: SessionDep,offset: int = 0,limit: Annotated[int, Query(le=100)] = 100,
):heroes = session.exec(select(Hero).offset(offset).limit(limit)).all()return heroes@app.get("/heroes/{hero_id}", response_model=HeroPublic)
def read_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")return hero@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate, session: SessionDep):hero_db = session.get(Hero, hero_id)if not hero_db:raise HTTPException(status_code=404, detail="Hero not found")hero_data = hero.model_dump(exclude_unset=True)hero_db.sqlmodel_update(hero_data)session.add(hero_db)session.commit()session.refresh(hero_db)return hero_db@app.delete("/heroes/{hero_id}")
def delete_hero(hero_id: int, session: SessionDep):hero = session.get(Hero, hero_id)if not hero:raise HTTPException(status_code=404, detail="Hero not found")session.delete(hero)session.commit()return {"ok": True}

启动服务

执行命令:

fastapi dev sql.py

执行后显示:

INFO     Importing from /Users/skywalk/work/fastapi                ╭─ Python module file ─╮                                          │                      │                                          │  🐍 sql.py           │                                          │                      │                                          ╰──────────────────────╯                                          INFO     Importing module sql                                      
INFO     Found importable FastAPI app                              ╭─ Importable FastAPI app ─╮                                      │                          │                                      │  from sql import app     │                                      │                          │                                      ╰──────────────────────────╯                                      INFO     Using import string sql:app                               ╭────────── FastAPI CLI - Development mode ───────────╮           │                                                     │           │  Serving at: http://127.0.0.1:8000                  │           │                                                     │           │  API docs: http://127.0.0.1:8000/docs               │           │                                                     │           │  Running in development mode, for production use:   │           │                                                     │           │  fastapi run                                        │           │                                                     │           ╰─────────────────────────────────────────────────────╯           INFO:     Will watch for changes in these directories: ['/Users/xxx/work/fastapi']
INFO:     Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO:     Started reloader process [37935] using WatchFiles
INFO:     Started server process [37941]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

测试

浏览docs页面:

执行curl添加指令

curl -X 'POST' \'http://127.0.0.1:8000/heroes/' \-H 'accept: application/json' \-H 'Content-Type: application/json' \-d '{"name": "string","age": 0,"secret_name": "string"
}'

 输出:

{"name":"string","age":0,"id":2}

证明一条信息被添加

查看一下:

curl http://127.0.0.1:8000/heroes/
[{"name":"string","age":0,"id":1},{"name":"string","age":0,"id":2}]

果然多了一条信息。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 ——— 学习和使用 strstr 函数,并模拟实现

目录 strstr 函数的作用 学习 strstr 函数​编辑 使用 strstr 函数 模拟实现 strstr 函数 strstr 函数的作用 查找子字符串 返回指向 str1 中第一次出现的 str2 的指针,如果 str2 不是 str1 的一部分,则返回 null 指针 学习 strstr 函数 函数的参数…

将 IBM WatsonX 数据与 Milvus 结合使用,构建用于知识检索的智能 Slack 机器人

在当今快节奏的工作环境中,快速轻松地访问信息对于保持生产力和效率至关重要。无论是在 Runbook 中查找特定说明,还是访问关键知识转移 (KT) 文档,快速检索相关信息的能力都可以产生重大影响。 本教程将指导您构建一个…

《高频电子线路》—— 振荡器稳定性问题

文章内容来源于【中国大学MOOC 华中科技大学通信(高频)电子线路精品公开课】,此篇文章仅作为笔记分享。 振荡器稳定性问题 频率准确度 & 频率稳定度 希望频率稳定度越小越好。 频率稳定度分类 影响振荡频率稳定度的参数 振荡频率是和电…

基本查询【MySQL】

文章目录 基本查询插入时是否更新替换查询指定列查询查询字段为表达式为查询结果指定别名结果去重where条件NULL 的查询 结果排序筛选分页结果UpdateDelete截断表聚合函数分组(group by)having && where 基本查询 建表 mysql> create table Student (-> id int…

Android15音频进阶之Cuttlefish搭建音频开发环境(九十二)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

Qt QCheckBox、QPushButton和QRadioButton详解

QCheckBox(复选框) 功能:QCheckBox用于创建一个复选框控件,允许用户从多个选项中选择多个。 属性: checkable:决定复选框是否可以被选中或取消选中。checked:表示复选框当前的选中状态&#…

【SpringMVC】传递json,获取url参数,上传文件

【传递json数据】 【json概念】 一种轻量级数据交互格式,有自己的格式和语法,使用文本表示一个对象或数组的信息,其本质上是字符串,负责在不同的语言中数据传递与交换 json数据以字符串的形式体现 【json字符串与Java对象互转…

2024/11/1 操作系统pv大题总结

2014: 2022: 2020: 2019: 2011: 读者写者问题:

00-开发环境 MPLAB IDE 配置

MPLAB IDE V8.83 File 菜单简介 New (CtrlN): 创建一个新文件,用于编写新的代码。 Add New File to Project...: 将新文件添加到当前项目中。 Open... (CtrlO): 打开现有文件。 Close (CtrlE): 关闭当前打开的文件。 …

如何在Apple Vision Pro上打造成功的沉浸式叙述应用

随着科技的进步,沉浸式叙述应用正在成为一种全新的娱乐方式。Apple Vision Pro的发布,标志着空间计算技术迈上了新的台阶。本文将探讨如何在Vision Pro上构建一款类似Encounter Dinosaur的沉浸式叙述应用,具体通过分析《Out There》这款作品,总结出一系列关键点,帮助创作者…

Linux练习作业

1.搭建dns服务器能够对自定义的正向或者反向域完成数据解析查询。 2.配置从DNS服务器,对主dns服务器进行数据备份 环境准备 主从服务器都需要进行的操作#关闭防火墙、SELinnux systemctl stop firewalld setenforce 0#软件安装 yum install bind -y实验一&#…

计算机网络:网络层 —— IP 多播技术

文章目录 基本概念IP多播地址和多播组 IP多播的类型硬件多播将IPv4多播地址映射为多播MAC地址 基本概念 多播(Multicast,也称为组播)是一种实现“一对多”通信的技术,允许一台或多台主机(多播源)发送单一数…

掌握AI Prompt的艺术:如何有效引导智能助手

开头叙述: 在人工智能的世界里,Prompt(提示)是沟通人类意图与机器理解之间的桥梁。它不仅是一串简单的文字,而是一把钥匙,能够解锁AI模型的潜力,引导它们执行复杂的任务。本文将探讨Prompt的重…

[SAP ABAP] SMW0上传模板

通常来说,一个批量导入的程序必须使用指定的模板,我们需要将模板保存到SAP系统中,以便用户下载并更改。这里我们可以使用事务码SMW0解决上述的问题 1.选择二进制类型 2.输入存放的包 3.创建对象 选择需要进行上传的本地模板文件到SAP系统中 …

第二十六章 Vue之在当前组件范围内获取dom元素和组件实例

目录 一、概述 二、获取dom 2.1. 具体步骤 2.2. 完整代码 2.2.1. main.js 2.2.2. App.vue 2.3. BaseChart.vue 三、获取组件实例 3.1. 具体步骤 3.2. 完整代码 3.2.1. main.js 3.2.2. App.vue 3.2.3. BaseForm.vue 3.3. 运行效果 一、概述 我们过去在想要获取一…

基于树莓派的安保巡逻机器人--(一、快速人脸录入与精准人脸识别)

目录 零、前言 一、人脸检测 二、人脸识别 1、采集人脸 2、训练人脸识别模型 3、人脸识别应用 零、前言 随着智能安防需求的增长,基于人工智能和物联网的安保系统逐渐成为趋势。树莓派因其低成本、高扩展性等特点,成为很多AI项目的理想平台。本文将为大…

软件测试学习笔记丨Flask操作数据库-对象与数据模型

本文转自测试人社区,原文链接:https://ceshiren.com/t/topic/23440 对象与数据模型 数据模型:是数据特征的抽象,抽象层次上描述了系统的静态特征、动态行为和约束条件,为数据库系统的信息表示与操作提供一个抽象的框架…

信号量本质 信号量实验(控制车辆运行,优先级反转)互斥量

信号量本质 前面介绍的队列(queue)可以用于传输数据:在任务之间、任务和中断之间。 消息队列用于传输多个数据,但是有时候我们只需要传递状态,这个状态值需要用一个 数值表示,比如: ⚫ 卖家:做好了 1 …

【STL_list 模拟】——打造属于自己的高效链表容器

一、list节点 ​ list是一个双向循环带头的链表&#xff0c;所以链表节点结构如下&#xff1a; template<class T>struct ListNode{T val;ListNode* next;ListNode* prve;ListNode(int x){val x;next prve this;}};二、list迭代器 2.1、list迭代器与vector迭代器区别…

VLAN间通信以及ospf配置

目录 1.基础知识介绍 1.1 什么是VLAN&#xff1f; 1.2 VLAN有什么用&#xff1f; 1.3 不同VLAN如何实现通信&#xff1f; 1.4 什么是路由汇总&#xff1f; 1.4.1 路由汇总的好处&#xff1a; 2. 实验 2.1 网络拓扑设计 2.2 实验配置要求 2.2.1 三层交换配置&#xff…