三周精通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.mzph.cn/news/884344.shtml

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

相关文章

C++中使用seekg函数进行随机读写

seekg(off type offset, ios::seekdir origin ); //作用:设置输入流的位置 这个函数有俩个参数,第一个是表示偏移量,第二个是表示相对位置 infile.seekg(-50, infile.end);//表示从文件结尾开始,向文件开头方向读50个字节 参数 …

2-137 基于matlab的sigmoid函数的变步长自适应语音信号增强

基于matlab的sigmoid函数的变步长自适应语音信号增强,与传统LMS相对比,比较不同的变步长函数去噪效果,并基于较好的去噪算法分析不同变步长中参数变化对降噪的影响。程序已调通,可直接运行。 下载源程序请点链接:2-13…

GBDT 算法的原理推导

GBDT的全称为梯度提升决策树(gradient boosting decision tree),其基模型(弱分类器)为CART决策树,针对分类问题的基模型为二叉分类树,对应梯度提升模型就叫GBDT;针对回归问题的基模型…

有效利用关键词研究工具提升网站流量的策略

内容概要 在当前信息泛滥的时代,关键词研究工具的重要性愈发突出。它们不仅能帮助我们识别和分析用户搜索行为,还能够精准地为网站内容定位,确保我们能够吸引并留住目标受众。关键词研究工具通过提供大量的数据,帮助站长和营销策…

探索全托的自闭症学校:打造个性化成长场所

文章详情:http://www.zibizhengwang.com/page35.html 在广州这座充满活力的城市里,有一个特别的地方,它以独特的教育理念和深切的关怀之心,为自闭症儿童提供了一个温暖的避风港。这个地方就是星贝育园自闭症儿童寄宿制学校&#…

使用RabbitMQ实现微服务间的异步消息传递

使用RabbitMQ实现微服务间的异步消息传递 RabbitMQ简介 安装RabbitMQ 在Ubuntu上安装RabbitMQ 在CentOS上安装RabbitMQ 配置RabbitMQ 创建微服务 生产者服务 安装依赖 生产者代码 消费者服务 消费者代码 运行微服务 消息模式 直接模式 生产者代码 消费者代码 扇出模式 生产…

计算机低能儿从0刷leetcode | 31.下一个排列

题目:31. 下一个排列 思路: 本题中,我们需要寻找“下一个排列”,也就是要找到增长最小的排列。 因此我们应该从尽可能从靠右侧(末尾)的位置开始增长。想象我们从末尾开始遍历数组,会遇到第一…

.net core NPOI以及NOPI mapper

我们在日常开发中对Excel的操作可能会比较频繁,好多功能都会涉及到Excel的操作。在.Net Core中大家可能使用Npoi比较多,这款软件功能也十分强大,而且接近原始编程。但是直接使用Npoi大部分时候我们可能都会自己封装一下,毕竟根据二…

Yolo V4详解

Yolo V4(You Only Look Once version 4)是一种先进的目标检测系统,于2020年推出。作为Yolo系列算法的最新版本,Yolo V4继承了其前代版本的优点,并在此基础上进行了多项改进,使得其性能得到了显著提升。本文…

Pandas数据结构之Series对象

文章目录 1. DataFrame对象1.1 创建DataFrame对象1.2 DataFrame对象常用属性和方法1.3 布尔值列表获取DataFrame对象中部分数据1.4 DataFrame对象的运算 1. DataFrame对象 DataFrame是一个表格型的结构化数据结构,它含有一组或多组有序的列(Series&…

Tomcat 11 下载/安装 与基本使用

为什么要使用Tomcat? 使用Apache Tomcat的原因有很多,以下是一些主要的优点和特点: 1. 开源与免费 Tomcat是一个完全开源的项目,任何人都可以免费使用。它由Apache软件基金会维护,拥有一个活跃的社区,这…

换热器换热面积计算

1 容积式水加热器换热面积计算 式中Q—设计小时耗热量(W) ε—由于水垢、热媒分布不均匀等影响传热效率的系数,一般采用0.8~0.6 K—传热系数[W/(m2ˑ℃)],K值对加热器换热影响很大,主要取决于热媒种类和压力、热媒和…

幸福宝宝起名器

这段代码是一个简单的“幸福宝宝取名器”网页应用&#xff0c;主要功能是根据用户输入的姓氏、性别和生成数量&#xff0c;随机生成宝宝的名字。以下是代码的主要组成部分和功能简介&#xff1a; 1. HTML 结构 - 文档类型和语言&#xff1a;使用 <!DOCTYPE html> 声明文…

【数据结构与算法】LeetCode: 贪心算法

文章目录 LeetCode&#xff1a; 贪心算法买卖股票的最佳时机 &#xff08;Hot100&#xff09;买卖股票的最佳时机 II跳跃游戏 &#xff08;Hot100&#xff09;跳跃游戏 II&#xff08;Hot100&#xff09;划分字母区间 &#xff08;Hot100&#xff09;分发饼干K次取反后最大化的…

BLG与T1谁会赢?python制作预测程序,结果显示,BLG将打败T1

决赛预测 2024英雄联盟全球总决赛 2024年英雄联盟全球总决赛&#xff0c;今天晚上&#xff08;2024年11月2日22点&#xff09;就要开始了&#xff01;今年的总决赛的队伍是BLG与T1。当然一些老的lol玩家&#xff0c;现在可能对于lol关注不多&#xff0c;并不清楚这两个队伍。…

Spring Boot 3.x 整合 Druid 数据库连接池(含密码加密)

Spring Boot 3.x 整合 Druid 数据库连接池&#xff08;含密码加密&#xff09; 1. 为什么需要数据库连接池&#xff1f; 在传统的数据库连接中&#xff0c;每一次与数据库连接都会消耗大量的系统资源和时间。数据库连接池会提前创建一定数量的数据库连接保存在池中&#xff0…

麒麟V10SP1部署postgresql+postgis+pgrouting

1、查看当前操作系统版本&#xff1a; nkvers ############## Kylin Linux Version ################# Release: Kylin Linux Advanced Server release V10 (Tercel) Kernel: 4.19.90-17.5.ky10.aarch64 Build: Kylin Linux Advanced Server release V10 (SP1) /(Tercel)-…

Spring Boot框架在信息学科平台建设中的实用技巧

摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了基于保密信息学科平台系统的开发全过程。通过分析基于保密信息学科平台系统管理的不足&#xff0c;创建了一个计算机管理基于保密信息学科平台系统的方案。文章介…

完美解决“找不到MSVCR110.dll无法继续执行代码

msvcr110.dll是一个动态链接库&#xff08;Dynamic Link Library&#xff0c;简称DLL&#xff09;文件&#xff0c;它是Microsoft Visual C 2012 Redistributable Package的一部分。这个库文件包含了大量预先编写的函数和资源&#xff0c;用于支持那些使用Visual C 2012或与之兼…

C++【string的模拟实现】

在前文我们讲解了string类接口使用&#xff08;C【string类的使用】(上),C【string类的使用】&#xff08;下&#xff09;&#xff09;&#xff0c;本片文章就来模拟实现string类。 注&#xff1a;本文实现的是string的部分重点内容&#xff0c;目的是为了更好的了解string&…