黄东旭解析 TiDB 的核心优势
902
2023-06-29
本文关于(如何用TiDB和Python来构造CRUD应用程序)。
TiDB 和 Python 的简单 CRUD 应用程序
本文档将展示如何使用 TiDB 和 Python 来构造一个简单的 CRUD 应用程序。
注意
推荐使用 Python 3.10 及以上版本进行 TiDB 的应用程序的编写。
第 1 步:启动你的 TiDB 集群
本节将介绍 TiDB 集群的启动方法。
TiDB Cloud
本地集群
Gitpod
创建 TiDB Serverless 集群。
第 2 步:获取代码
git clone https://github.com/pingcap-inc/tidb-example-python.git
使用 SQLAlchemy(推荐)
使用 peewee(推荐)
使用 mysqlclient
使用 PyMySQL
使用 mysql-connector-python
SQLAlchemy 为当前比较流行的开源 Python ORM 之一。此处将以 SQLAlchemy 1.4.44 版本进行说明。
import uuidfrom typing import Listfrom sqlalchemy import create_engine, String, Column, Integer, select, funcfrom sqlalchemy.orm import declarative_base, sessionmakerengine = create_engine('mysql://root:@127.0.0.1:4000/test')Base = declarative_base()Base.metadata.create_all(engine)Session = sessionmaker(bind=engine)class Player(Base): __tablename__ = "player" id = Column(String(36), primary_key=True) coins = Column(Integer) goods = Column(Integer) def __repr__(self): return f'Player(id={self.id!r}, coins={self.coins!r}, goods={self.goods!r})'def random_player(amount: int) -> List[Player]: players = [] for _ in range(amount): players.append(Player(id=uuid.uuid4(), coins=10000, goods=10000)) return playersdef simple_example() -> None: with Session() as session: # create a player, who has a coin and a goods. session.add(Player(id="test", coins=1, goods=1)) # get this player, and print it. get_test_stmt = select(Player).where(Player.id == "test") for player in session.scalars(get_test_stmt): print(player) # create players with bulk inserts. # insert 1919 players totally, with 114 players per batch. # each player has a random UUID player_list = random_player(1919) for idx in range(0, len(player_list), 114): session.bulk_save_objects(player_list[idx:idx + 114]) # print the number of players count = session.query(func.count(Player.id)).scalar() print(f'number of players: {count}') # print 3 players. three_players = session.query(Player).limit(3).all() for player in three_players: print(player) session.commit()def trade_check(session: Session, sell_id: str, buy_id: str, amount: int, price: int) -> bool: # sell player goods check sell_player = session.query(Player.goods).filter(Player.id == sell_id).with_for_update().one() if sell_player.goods < amount: print(f'sell player {sell_id} goods not enough') return False # buy player coins check buy_player = session.query(Player.coins).filter(Player.id == buy_id).with_for_update().one() if buy_player.coins < price: print(f'buy player {buy_id} coins not enough') return Falsedef trade(sell_id: str, buy_id: str, amount: int, price: int) -> None: with Session() as session: if trade_check(session, sell_id, buy_id, amount, price) is False: return # deduct the goods of seller, and raise his/her the coins session.query(Player).filter(Player.id == sell_id). \ update({'goods': Player.goods - amount, 'coins': Player.coins + price}) # deduct the coins of buyer, and raise his/her the goods session.query(Player).filter(Player.id == buy_id). \ update({'goods': Player.goods + amount, 'coins': Player.coins - price}) session.commit() print("trade success")def trade_example() -> None: with Session() as session: # create two players # player 1: id is "1", has only 100 coins. # player 2: id is "2", has 114514 coins, and 20 goods. session.add(Player(id="1", coins=100, goods=0)) session.add(Player(id="2", coins=114514, goods=20)) session.commit() # player 1 wants to buy 10 goods from player 2. # it will cost 500 coins, but player 1 cannot afford it. # so this trade will fail, and nobody will lose their coins or goods trade(sell_id="2", buy_id="1", amount=10, price=500) # then player 1 has to reduce the incoming quantity to 2. # this trade will be successful trade(sell_id="2", buy_id="1", amount=2, price=100) with Session() as session: traders = session.query(Player).filter(Player.id.in_(("1", "2"))).all() for player in traders: print(player) session.commit()simple_example()trade_example()
相较于直接使用 Driver,SQLAlchemy 屏蔽了创建数据库连接时,不同数据库差异的细节。SQLAlchemy 还封装了大量的操作,如会话管理、基本对象的 CRUD 等,极大地简化了代码量。
Player
类为数据库表在程序内的映射。Player
的每个属性都对应着 player
表的一个字段。SQLAlchemy 使用 Player
类为了给 SQLAlchemy 提供更多的信息,使用了形如以上示例中的 id = Column(String(36), primary_key=True)
的类型定义,用来指示字段类型和其附加属性。id = Column(String(36), primary_key=True)
表示 id
字段为 String
类型,对应数据库类型为 VARCHAR
,长度为 36
,且为主键。
关于 SQLAlchemy 的更多使用方法,你可以参考 SQLAlchemy 官网。
第 3 步:运行代码
本节将逐步介绍代码的运行方法。
第 3 步第 1 部分:表初始化
小贴士
在 Gitpod Playground 中尝试 Python 与 TiDB 的连接:现在就试试
本示例需手动初始化表,若你使用本地集群,可直接运行:
MySQL CLI
MyCLI
mysql --host 127.0.0.1 --port 4000 -u root < player_init.sql
若不使用本地集群,或未安装命令行客户端,请用喜欢的方式(如 Navicat、DBeaver 等 GUI 工具)直接登录集群,并运行 player_init.sql
文件内的 SQL 语句。
第 3 步第 2 部分:TiDB Cloud 更改参数
若你使用了 TiDB Serverless 集群,此处需使用系统本地的 CA 证书,并将证书路径记为 <ca_path>
以供后续指代。请参考以下系统相关的证书路径地址:
MacOS / Alpine
Debian / Ubuntu / Arch
RedHat / Fedora / CentOS / Mageia
OpenSUSE
/etc/ssl/cert.pem
若设置后仍有证书错误,请查阅 TiDB Serverless 安全连接文档。
使用 SQLAlchemy(推荐)
使用 peewee(推荐)
使用 mysqlclient
使用 PyMySQL
使用 mysql-connector-python
若你使用 TiDB Serverless 集群,更改 sqlalchemy_example.py
内 create_engine
函数的入参:
engine = create_engine('mysql://root:@127.0.0.1:4000/test')
若你设定的密码为 123456
,而且从 TiDB Serverless 集群面板中得到的连接信息为:
Endpoint: xxx.tidbcloud.com
Port: 4000
User: 2aEp24QWEDLqRFs.root
那么此处应将 create_engine
更改为:
engine = create_engine('mysql://2aEp24QWEDLqRFs.root:123456@xxx.tidbcloud.com:4000/test', connect_args={ "ssl_mode": "VERIFY_IDENTITY", "ssl": { "ca": "<ca_path>" }})
第 3 步第 3 部分:运行
运行前请先安装依赖:
pip3 install -r requirement.txt
当以后需要多次运行脚本时,请在每次运行前先依照表初始化一节再次进行表初始化。
使用 SQLAlchemy(推荐)
使用 peewee(推荐)
使用 mysqlclient
使用 PyMySQL
使用 mysql-connector-python
python3 sqlalchemy_example.py
第 4 步:预期输出
使用 SQLAlchemy(推荐)
使用 peewee(推荐)
使用 mysqlclient
使用 PyMySQL
使用 mysql-connector-python
SQLAlchemy 预期输出
上述就是小编为大家整理的(如何用TiDB和Python来构造CRUD应用程序)
***
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。