sqlalchemy 分表实现方案

1.需求及场景概述

        现有系统中因历史数据量过大,产生了将历史数据进行按月存储的要求,系统和数据库交互使用的是sqlalchemy,假设系统的原来的历史记录表(record)如下:

为了将历史数据按月分表存储,我们需要以此表为基础按月创建对应的月表来进行分表存储,同时又要使用orm的功能。面对这样的需求我们很自然的会想到创建如下模型

class Recode_202405(Base): __tablename__ = 'record_202405' id = Column(INT(11), primary_key=True) name = Column(String(100, 'utf8mb4_unicode_ci'))

这样当然可以,但是我们不可能每月手动去创建这个模型,然后重启自己的服务,这明显有问题, 那如何解决呢,下面就介绍一种在这种场景下基于sqlalchemy实现的分表存储方案。

首先,我们对我们应用场景及需求进行一下描述:

1.我们有一张基础表,这个表作为我们创建月表的模板。

2.当有新数据需要入库时,我们将数据按月存储到当前月份的月表中,如果当月表不存在系统自动创建。

3.支持使用OMR方便数据存储及查询。

2.实现方案

        既然要支持使用ORM ,我们势必要获取月表的model。sqlalchemy0.9.1版本推出了Automap,它可以自动映射数据库的表,通过数据表名映射model。大概的用法如下:

from sqlalchemy.ext.automap import automap_baseAutoBase = automap_base()# reflect the tables
AutoBase.prepare(engine, reflect=True)
tablename = "record_202405"
RecordDao = getattr(AutoBase.classes, tablename)

        既然可以通过表名映射回model,那么现在的问题就是如何基于已有的基础表创建当月的月表,可以参考如下代码:

from sqlalchemy.ext.automap import automap_base
AutoBase = automap_base()table_name = 'record'
date = '202405'
# 基于基础表创建指定月份的月表
base_table = autobase.metadata.tables[table_name]
mdata = MetaData()
new_table = base_table.tometadata(metadata=mdata, name=f'{table_name}_{date}')
try:# 创建表new_table.create(bind=engine)
except BaseException as e:print(e)

基于上述方案,我们可以封装一个方法,该方法接收两个参数,一个是表名,一个是分表的月份,其实可以进行任何程度的分表,返回该表的model,通过sqlalchemy 的ORM 进行增删改查操作,整体代码如下:

from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.ext.automap import automap_base
from urllib import parse
from contextlib import contextmanager
import timemysql_user = 'root'
mysql_password = 'root'
mysql_host = '127.0.0.1'
mysql_port = 3306
mysql_db = 'db'SQLALCHEMY_DATABASE_URL = f'mysql+pymysql://{mysql_user}:{parse.quote_plus(mysql_password)}@{mysql_host}:{mysql_port}/{mysql_db}?charset=utf8'engine = create_engine(SQLALCHEMY_DATABASE_URL, pool_recycle=7200)
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)@contextmanager
def session_maker():try:db: Session = SessionLocal()yield dbdb.commit()except Exception as e:print(e)db.rollback()finally:db.close()def get_table_model(table_name, date=None):autobase = automap_base()autobase.prepare(engine, reflect=True)print(autobase)base_model = Nonetry:base_model = getattr(autobase.classes, table_name)except Exception as e:print(e)return base_modelif date == None: # 不分表的情况return base_modelelse:            # 分表的情况# 获取基础类base_table = autobase.metadata.tables[table_name]mdata = MetaData()new_table = base_table.tometadata(metadata=mdata, name=f'{table_name}_{date}')# new_table = base_model.tometadata(metadata=mdata, name=f'{table_name}_{date}')try:# 创建表new_table.create(bind=engine)except BaseException as e:# 忽略建表异常,存在多进程同时建表情况,忽略后刷新autobase再试print(e)'''Automap的映射虽然是自动的,但是只有在启动的时候生效,也就是说如果新建一个数据表,而没有告诉Automap,那这个表是找不到的。在实际使用中,可以捕获AttributeError异常,并再次调用AutoBase.prepare(engine, reflect=True) 刷新映射关系。'''autobase = automap_base()autobase.prepare(engine, reflect=True)base_model = getattr(autobase.classes, f'{table_name}_{date}')return base_modeldef get_table_model(table_name, date=None):autobase = automap_base()autobase.prepare(engine, reflect=True)print(autobase)base_model = Nonetry:base_model = getattr(autobase.classes, table_name)except Exception as e:print(e)return base_modelif date == None: # 不分表的情况return base_modelelse:            # 分表的情况# 获取基础类base_table = autobase.metadata.tables[table_name]mdata = MetaData()new_table = base_table.tometadata(metadata=mdata, name=f'{table_name}_{date}')# new_table = base_model.tometadata(metadata=mdata, name=f'{table_name}_{date}')try:# 创建表new_table.create(bind=engine)except BaseException as e:# 忽略建表异常,存在多进程同时建表情况,忽略后刷新autobase再试print(e)'''Automap的映射虽然是自动的,但是只有在启动的时候生效,也就是说如果新建一个数据表,而没有告诉Automap,那这个表是找不到的。在实际使用中,可以捕获AttributeError异常,并再次调用AutoBase.prepare(engine, reflect=True) 刷新映射关系。'''autobase = automap_base()autobase.prepare(engine, reflect=True)base_model = getattr(autobase.classes, f'{table_name}_{date}')return base_model# 使用
Record = database.get_table_model("record", '202406')ll = Record(name="1111")with database.session_maker() as db:db.add(ll)db.commit()ll = db.query(Record).all()print(ll)

参考:sqlalchemy分表操作 - 知乎

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

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

相关文章

蓝桥杯国赛练习题真题Java(矩阵计数)

题目描述 一个 NM 的方格矩阵,每一个方格中包含一个字符 O 或者字符 X。 要求矩阵中不存在连续一行 3 个 X 或者连续一列 3 个 X。 问这样的矩阵一共有多少种? 输入描述 输入一行包含两个整数 N,M (1≤N,M≤5)。 输出描述 输出一个整数代表答案。…

C语言的34个运算符

算术运算符: 加法运算符():对两个操作数进行相加。减法运算符(-):从第一个操作数中减去第二个操作数。乘法运算符(*):将两个操作数相乘。除法运算符&#xff…

5.12 mybatis之typeAliases别名详解

文章目录 1. 通过typeAlias为每个类指定别名2. 通过package为整个包下的类指定别名 在mapper中为SQL定义POJO返回类型时,要指定POJO的全限定名,如果SQL众多,要为每个SQL书写返回类型的全限定名,比较繁琐,此时可以用typ…

Study--Oracle-01-单实例部署Oracle11G-R2

Oracle版本发布介绍 Oracle 19c和12c和11g功能区别_数据库_oracle_支持 一、CentOS 7 环境准备 1、软件准备 操作系统:CentOS 7 数据库版本: Oracle11g R2 2、操作系统环境配置 关闭selinux ,编辑 /etc/selinux/config文件,设置SELINU…

在Ubuntu上搭建并通过systemctl管理Minecraft基岩版服务器

在Ubuntu系统上运行并管理Minecraft基岩版服务器可以通过systemctl实现更高效的服务管理。本文将全面介绍如何从搭建服务器开始到使用systemctl进行管理的整个过程。 第一部分:搭建Minecraft基岩版服务器 1. 下载服务器软件 首先,访问 Minecraft官网 …

宝兰德通过广东教育行业信创适配认证,拓展教育信创生态圈

近日,由宝兰德自主研发的多款中间件产品通过广东省教育行业信创适配中心的适配测试。测试表明,宝兰德四款中间件产品(分布式缓存软件V3.0、应用服务器软件V9.5、消息中间件软件 V2.1、Web服务器软件V3.1) 与当前主流国产操作系统统…

springAI框架学习总结

springAI 1.springAI基本介绍 springAI是一个AI工程应用框架,其目标是将 Spring 生态系统设计原则(例如可移植性和模块化设计)应用于 AI 领域,并推广使用 POJO 作为 AI 领域应用程序的构建块。 2.特性 灵活的AIP支持chat,text…

Eayswoole 报错 crontab info is abnormal

在执行一个指定的定时任务时 如 php easyswoole crontab show 报错 crontab info is abnormal 如下图所示: 查询了半天 修改了如下配置: 旧的 // 创建定时任务实例 $crontab new \EasySwoole\Crontab\Crontab($crontabConfig); 修改后&#…

C++初阶学习第五弹——类与对象(下)——类与对象的收官战

类与对象(上):C初阶学习第三弹——类与对象(上)——初始类与对象-CSDN博客 类与对象(中):C初阶学习第四弹——类与对象(中)——刨析类与对象的核心点-CSDN博…

工厂自动化升级改造参考(01)--设备通信协议详解及选型

以下是整合了通信协议的特点、应用场景、优缺点以及常用接口方式的描述: 以太网/IP: 来历: 以太网是一种局域网技术,由罗伯特梅特卡夫和大卫博格在1973年开发。IP是网络层协议,负责在网络中的设备间传输数据。特点:基于标准的以太网技术,使用TCP/IP协议栈,支持高速数据传…

安泰ATA-L系列水声功率放大器驱动水声换能器可以进行哪些实验

水声功率放大器驱动水声换能器是进行水声实验中的关键设备之一,其应用范围广泛,可以进行多种实验和研究。以下是水声功率放大器驱动水声换能器可以进行的一些实验: 声纳性能测试:使用水声功率放大器驱动水声换能器可以进行声纳系统…

K8S中删除Terminating状态的命名空间

1.查看当前命名空间 [rootk8smaster1 home]# kubectl get ns NAME STATUS AGE app Active 16d default Active 17d hd Active 16d ingress-nginx Terminating 5m8s kube-node-lease …

《Video Mamba Suite》论文笔记(1)Mamba在时序建模中的作用

原文链接 https://arxiv.org/abs/2403.09626https://arxiv.org/abs/2403.09626 原文代码 https://github.com/OpenGVLab/video-mamba-suitehttps://github.com/OpenGVLab/video-mamba-suite 原文笔记 What 《Video Mamba Suite: State Space Model as a Versatile Altern…

Windows 系统使用Jenkins 实现CI一键打包部署操作

一 下载安装jenkins jenkins 中文官网链接: 下载地址 点击下载,完成后是一个.msi后缀的安装文件,双击安装 安装和普通软件一样,一路next,安装路径自己设置一下,默认是C盘,我C盘不够用了,设置…

stm32之hal库i2s驱动的封装记录

前言 本次使用的框架为threadxfilexshell组件 程序 共用驱动文件(dma和nvic) nvic文件 头文件 /** Copyright (c) 2024-2024,shchl** SPDX-License-Identifier: Apache-2.0** Change Logs:* Date Author Notes* 2024-5-3 shch…

Mac电脑设置hosts的方法

hosts文件是什么 hosts文件是一个系统文件,通过绑定域名与ip的关系,当本机访问该域名时 从这个文件中如果找到了对应域名,则转发到对应ip;如果没有找到对应域名,则走默认的DNS公网解析。 好处: 加速访问…

如何delphi7中添加自定义的控件或组件

1.问题 为了编写方便,会自己生成一些自定义的控件。 XXX.PAS:源码文件,后续可以再调整 XXX.DCU:编译后的文件 2.解决办法 1.自定义控件的文件如下 2.将这些文件保留在程式代码中,万一丢失会导致程式开启后报是否忽略 3.选择菜单栏中的com…

我独自升级崛起游戏账号登录注册教程 (5.8最新版)

新韩漫公司所发布的这项动作游戏已向玩家们敞开大门,为大家带来了前所未有的游戏体验和乐趣。这个游戏内包含了大量令人着迷的故事、令人印象深刻的战斗场景以及丰富多样的娱乐元素。在这其中最为引人注目的一点就是游戏内容中融入了“虚拟角色”的元素,…

QT:基于QT实现Boost搜索引擎客户端

文章目录 写在前面关于服务器开源仓库和项目上线其他文档说明 登录界面主体设计思路验证登录注册功能 注册界面主体界面main函数中绑定槽函数 写在前面 关于服务器 本项目使用的是一个仿mudou库one-thread-one-loop式并发服务器的组件,关于该组件的细节内容在下面…

计算机网络4——网络层8 软件定义网络 SDN

文章目录 一、介绍1、简介2、原理3、案例1)普通2)负载均衡的例子3)防火墙的例子 二、控制层面1、特征2、层次 一、介绍 1、简介 SDN的概念最初由斯坦福大学N.McKeown于2009年首先提出。当时还只是在学术界进行探讨的一种新的网络体系结构。…