首页 > 编程 > Python > 正文

Odoo中如何生成唯一不重复的序列号详解

2020-02-22 23:12:25
字体:
来源:转载
供稿:网友

前言

最近在做的项目中有一个需求是要让某个字段值根据记录产生的日期和一定的组合规则按顺序生成一个序列号,这个序列号不可重复,这原本是一个很常见的需求,没有多想就写好了。由于没有考虑到并发的情况,到后面测试的时候才发现一个比较严重的问题,如果用户同时操作产生的记录,生成的序列号会出现重复。

经过讨论和思考后有几种解决方案,一是在数据库表层加锁,一是采用类似 redis 的消息队列,还有就是通过文件锁达到数据库排他锁的目的,鉴于时间和项目当前的情况,最后采用了通过文件锁实现这个需求。

其实除了以上几种方式,Odoo 本身就有一个模型(ir.sequence)是用于生成序列的,可以很方便地实现这个需求,因为之前一直没有接触过这个模块,还是在项目之后的阶段同事使用到了并且告诉我之后才知道原来有这么个好东西的存在。在这里我将会把我原本通过文件锁实现的方式和通过 Odoo 自带的ir.sequence实现的方式都记录下来。

给文件加锁 - fcntl

fcntl是 Python 标准库里的一个模块,用来对文件进行加锁的操作。在实现中主要用到的是下面这个函数:

def flock(fd, operation): """ flock(fd, operation) Perform the lock operation op on file descriptor fd. See the Unix  manual page for flock(2) for details. (On some systems, this function is emulated using fcntl().) """ pass

其中fd是文件描述符,operation为锁的操作,总共有4种:

fcntl.LOCK_EX - 排他锁 fcntl.LOCK_NB - 非阻塞锁 fcntl.LOCK_SH - 共享锁 fcntl.LOCK_UN - 解锁

关于fcntl的其他具体内容请查看 官方标准库文档 。

下面来看一下具体的实现,在给出代码之前,先描述一下需求,假设模型中有一个字段sn用于存储按一定规则生成的序列号,序列号的组成规则如下:

固定的前缀SN 取记录生成的日期组成的6位数字%y%m%d,如2017年12月8日取值为171208 最后是3位的流水号,从001开始递增 生成的序列号不能有重复 最后的3位流水号每天自动重置,从001开始递增(这个需求涉及到一些扩展,故此文将不实现这一需求)

需求很简单,也很清楚了,下面就上代码开始具体的实现。首先创建一个模块demo_sequence:

./odoo-bin scaffold demo_sequence

然后在模块的目录下创建数据文件目录data/,在目录下创建一个data.xml文件,在后面会用到;继续在模块目录下创建静态文件目录static/,在目录下创建一个空文件SN.LOCK用作加锁的文件对象。完成之后的目录结构如下:

demo_sequence├── __init__.py├── __manifest__.py├── controllers│ ├── __init__.py│ └── controllers.py├── data│ └── data.xml├── demo│ └── demo.xml├── models│ ├── __init__.py│ └── models.py├── security│ └── ir.model.access.csv├── static│ └── SN.LOCK└── views├── templates.xml└── views.xml            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表