背景
话说sqlalchemy真是一个非常好用的库,python orm基本上是舍我其谁了,文档还非常全面,基本上没有什么硬伤,现在也冲出了1.0版本,未来更加值得期待。
我最早用django orm,不过很快就觉得很多功能不够用,我当时用的版本是1.3.1,没有bulk insert也没有锁,没有这两个功能,好多应用就没法用django开发了。之后开始接触sqlalchemy,一直用到现在,总的体会是只有你想不到没有它做不到。
我们项目里有一个需求,就是数据按月分表,比如:2014年6月数据就存在record_201406表中, 其他月数据按此方法类推。这个需求如果是用sqlalchemy来获取数据,我们怎么做呢?
一般方法有什么问题?
一般情况下,我们很自然想到使用如下方法:
|
|
或者简化点:
|
|
这样实现确实没问题,但回到需求上,既然是按月分表,难不成我要每个月写一个这样的model?每月上次线?当然不行,那我们怎么解决呢?
官网解决方法,有什么问题?
有经验的同学可能发现,这个不就是水平sharding么?这么说不完全对,看一下sharding的wiki定义:
A database shard is a horizontal partition of data in a database or search engine. Each individual partition is referred to as a shard or database shard. Each shard is held on a separate database server instance, to spread load.
我们这个需求只涉及单数据库,就不算sharding了,可以称为partitioning(分区),然而强大的sqlalchemy这两个情况都考虑到了,并且官网都提供了example,我们挑对应场景的partitioning出来看看:
|
|
使用了继承的方法,抽象的好,但我们之前的问题解决了吗?没有。还是需要预定义好所有表的model类,才能正确使用,迫不得已,我们只能自己想办法了。
函数方法解决
经过一番探索,我得出了如下方法:
|
|
每次想获取对应月表数据的model,调用get_model方法即可。这个方法一直沿用到现在,虽然有点丑陋,但却是解决了以上问题。直到sqlalchemy 0.9.1版本推出Automap
Automap方法
sqlalchemy文档完备,具体可点击Automap,它可以自动映射数据库的表,通过数据表名映射model,简单直接,实现起来如下:
|
|
这样就可以了,很清晰。但是这个方法有一个缺点,Automap的映射虽然是自动的,但是只有在启动的时候生效,也就是说如果新建一个数据表,而没有告诉Automap,那这个表是找不到的。在实际使用中,可以捕获AttributeError异常,并再次调用AutoBase.prepare(engine, reflect=True)
刷新映射关系。