Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat]: Add a demo of Python sqlalchemy #57

Merged
merged 3 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ jobs:
- name: 'mysql-connector-python'
language: 'python'
with_oceanbase_container: true
- name: 'sqlalchemy'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The with_oceanbase_container field of mysql-connector-python is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fix

language: 'python'
with_oceanbase_container: true
- name: 'mybatis-plus'
language: 'java'
with_oceanbase_container: false
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,6 @@ build/
### JavaScript ###
node_modules
.svelte-kit

### Python ###
__pycache__
113 changes: 113 additions & 0 deletions python/sqlalchemy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Python 连接 OceanBase 指南(SQLAlchemy)

本文介绍如何通过 SQLAlchemy ORM 连接 OceanBase 数据库。

## SQLAlchemy 介绍

[SQLAlchemy](https://www.sqlalchemy.org/) 是一个开源的 SQL 工具包和对象关系映射(ORM)系统,用于 Python 应用程序。它提供了全面的数据库功能,包括操作数据库(CRUD 操作)、构建复杂的查询以及映射数据库表到 Python 类。

作为 SQL 工具包,SQLAlchemy 允许开发者编写原生 SQL 语句,同时提供了构建 SQL 的高级接口,使得数据库操作更为直观和安全。

作为 ORM,SQLAlchemy 允许开发者以面向对象的方式处理数据库。这意味着你可以定义 Python 类来表示数据库中的表,并且类的实例对应于表中的行。通过这种方式,你可以用 Python 代码来操作数据库,而不必编写大量的 SQL 代码。

SQLAlchemy 支持多种数据库系统,包括但不限于 OceanBase、PostgreSQL、MySQL、SQLite 等。它还提供了会话管理、事务控制、连接池等高级功能,使得数据库编程更加高效和可靠。

总而言之,SQLAlchemy 是 Python 中一个功能强大且灵活的数据库解决方案,适用于从简单应用到复杂企业级应用的各种场景。


## 安装 OceanBase 数据库

首先,可以选择本地安装 OceanBase 数据库,安装步骤如下:

```
# 下载并安装 all-in-one (需要联网)
bash -c "$(curl -s https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/oceanbase-all-in-one/installer.sh)"
source ~/.oceanbase-all-in-one/bin/env.sh

# 快速部署 OceanBase database
obd demo
```

但这里推荐通过[免费试用](https://www.oceanbase.com/free-trial),无需安装和配置,即可获得一个可用的 OceanBase 数据库实例。

![](img/1.png)

⚠️ 注意:
1. 创建完数据库实例,等待 OceanBase 数据库实例创建完成,点击「实例列表」进入到实例详情页,进行后续操作。
2. 在「数据库实例」页面开通公网地址,点击「实例白名单」添加自己机器的公网 IP。
3. 在「数据库管理」页面创建数据库,用于存储数据。
4. 在「账号管理」页面,点击「创建账号」,创建一个账号,用于连接数据库。

完成以上工作后,可以通过命令行或者图形化工具连接数据库,确保连接信息正确,方便后续的使用。

![](img/2.png)

## 快速开始

为了防止环境问题,推荐使用 anaconda 配置 python 3.x 环境。

在开始之前,需要先确保 SQLAlchemy 已安装:`pip install -r requirements.txt`。

下面,我提供了一个简单的示例代码([example.py](example.py)),以及一个 [demo](demo) 目录,它包含了使用 SQLAlchemy 的极简目录结构和代码。

### 示例代码

以 [example.py](example.py) 为例,仅需替换文件最上方的 OceanBase 连接信息,即可运行示例代码。

```
# OceanBase 数据库连接参数
username = 'root' # 「账号管理」页面创建的账号
password = '' # 「账号管理」页面创建的账号密码
host = 'localhost' # 「数据库实例」页面开通的公网地址
port = '2881' # OceanBase 端口号
database = 'test' # 「数据库管理」页面创建的数据库
```

修改代码中的连接信息,在命令行进入到 `python/sqlalchemy` 目录,直接执行 `python example.py` 运行示例代码,输出结果如下:

```
<User(name=Alice, age=30)>
<User(name=Bob, age=25)>
<User(name=Alice, age=30)>
<User(name=Bob, age=25)>
```

### 目录结构

上面的 `example.py` 是面条代码,在实际项目中,我们需要更好的组织代码,这里提供了一个极简的目录结构,如下:

```
.
├── db
│   ├── __init__.py
│   ├── base.py # 基类
│   ├── config.py # 数据库连接信息
│   ├── curd.py # 增删改查
│   └── models.py # 数据库模型
└── main.py # 入口文件
```

其中,`db` 目录下是数据库相关的代码,`main.py` 是入口文件,代码如下:

```python
from db.base import get_db
from db.curd import insert_user, query_all_user


if __name__ == '__main__':
with get_db() as db:
# 新增用户
insert_user(db, 'HelloGitHub', 8)
# 查询所有用户
query_all_user(db)
```

进入到 `python/sqlalchemy/demo` 目录,执行 `python main.py` 即可得到运行结果。

```
<User(name=HelloGitHub, age=8)>
```

最后,通过数据库命令行工具或者图形化工具查看数据库,可以看到新增的用户数据。

![](img/3.png)
Empty file.
35 changes: 35 additions & 0 deletions python/sqlalchemy/demo/db/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# Date : 2024-05-29 14:28
# Desc : SQLAlchemy 引擎和 OceanBase 基表定义
from contextlib import contextmanager
from typing import Generator

from sqlalchemy import create_engine, Column, Integer
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm import DeclarativeBase

from .config import ob_db_url as db_url


# 创建SQLAlchemy引擎
engine = create_engine(db_url)
# 创建一个 session 类型
Session = sessionmaker(bind=engine)


class Base(DeclarativeBase):
id = Column(Integer, primary_key=True, autoincrement=True)


@contextmanager
def get_db() -> Generator:
session = Session()
try:
yield session
except Exception:
session.rollback()
raise
finally:
session.close()
23 changes: 23 additions & 0 deletions python/sqlalchemy/demo/db/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# Date : 2024-05-29 14:28
# Desc : 配置文件


class Config(object):

@staticmethod
def oceanbase_db_url():
# OceanBase 数据库连接参数
username = 'root'
password = ''
host = 'localhost'
port = '2881'
database = 'test'
db_url = 'mysql+pymysql://{username}:{password}@{host}:{port}/{database}'.format(
username=username, password=password, host=host, port=port, database=database)
return db_url


ob_db_url = Config.oceanbase_db_url()
22 changes: 22 additions & 0 deletions python/sqlalchemy/demo/db/curd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# Date : 2024-05-29 14:28
# Desc : 操作表的数据
from sqlalchemy.orm import Session

from db.models import User


def insert_user(db: Session, name: str, age: int):
# 新增用户数据
user = User(name=name, age=age)
db.add(user)
# 提交事务, 保存数据。get_db 中做了所以这里不需要再提交
db.commit()


def query_all_user(db: Session):
users = db.query(User).all()
for user in users:
print(user)
25 changes: 25 additions & 0 deletions python/sqlalchemy/demo/db/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/usr/bin/env python
# -*- coding:utf-8 -*-
#
# Date : 2024-05-29 14:28
# Desc : 配置文件
from sqlalchemy import Column, Integer, VARCHAR

from db.base import Base, engine


# 定义一个 ORM 模型,映射到数据库中的表
class User(Base):
__tablename__ = 'users'

id = Column(Integer, primary_key=True)
name = Column(VARCHAR(50))
age = Column(Integer)

def __repr__(self):
return f"<User(name={self.name}, age={self.age})>"


if __name__ == '__main__':
# 创建数据库表(如果表不存在)
Base.metadata.create_all(engine)
14 changes: 14 additions & 0 deletions python/sqlalchemy/demo/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# -*- coding:utf-8 -*-
#
# Date : 2024-05-29 14:28
# Desc : 运行入口
from db.base import get_db
from db.curd import insert_user, query_all_user


if __name__ == '__main__':
with get_db() as db:
# 新增用户
insert_user(db, 'HelloGitHub', 8)
# 查询所有用户
query_all_user(db)
61 changes: 61 additions & 0 deletions python/sqlalchemy/example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/python3
from sqlalchemy import create_engine, Column, Integer, VARCHAR
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base

# OceanBase 数据库连接参数
username = 'root'
password = ''
host = 'localhost'
port = '2881'
database = 'test'

# 创建一个 SQLAlchemy 引擎,连接到 OceanBase 数据库
# 创建数据库连接字符串
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database}'
# 创建SQLAlchemy引擎
engine = create_engine(connection_string)


# 创建一个 session 类型
Session = sessionmaker(bind=engine)

# 创建一个基类,用于定义 ORM 模型
Base = declarative_base()


# 定义一个 ORM 模型,映射到数据库中的表
class User(Base):
__tablename__ = 'users'

id = Column(Integer, primary_key=True)
name = Column(VARCHAR(50))
age = Column(Integer)

def __repr__(self):
return f"<User(name={self.name}, age={self.age})>"


# 创建数据库表(如果表不存在)
Base.metadata.create_all(engine)

# 创建 session 实例
session = Session()

# 添加一些用户数据
new_user_1 = User(name='Alice', age=30)
new_user_2 = User(name='Bob', age=25)

session.add(new_user_1)
session.add(new_user_2)

# 提交事务
session.commit()

# 查询数据
users = session.query(User).all()
for user in users:
print(user)

# 关闭 session
session.close()
Binary file added python/sqlalchemy/img/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/sqlalchemy/img/2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added python/sqlalchemy/img/3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions python/sqlalchemy/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pymysql==1.1.1
sqlalchemy==2.0.30
2 changes: 2 additions & 0 deletions python/sqlalchemy/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
python3 -m pip install -r requirements.txt
python3 example.py
Loading