V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
banxi1988
V2EX  ›  Python

SQLAlchemy报键冲突,跑进去一看却没有对应键值的行

  •  
  •   banxi1988 ·
    banxi1988 · 2013-09-24 15:55:06 +08:00 · 3131 次点击
    这是一个创建于 4078 天前的主题,其中的信息可能已经有所发展或是发生改变。
    RT:
    错误信息如下:
    (IntegrityError) duplicate key value violates unique constraint "ix_cid"

    下面是我生成cid的方法:
    _cid_rlock = threading.RLock()
    def generate_cid():
    with _cid_rlock:
    return long((time.time()-1377964800.000000)*1000000000)

    但是经过我使用多线程测试,发现不太可能生成相同的id(测试代码见下)

    应用用的是Flask,数据库层SQLAlchemy,Flask-SQLAlchemy插件(默认配置)
    数据库postgresql 9.1.9
    系统ubuntu 12.04.2
    应用跑在 gunicorn 加gevent
    gunicorn -k gevent app:app -w 2

    在做提交的时候,直接用的是:
    类似如下的代码:
    db.session.execute(Story.__table__.insert(), story_values)
    db.session.commit()

    Google了一阵子了,还是没有找出原因来. 不知道从哪里debug起了....


    测试生成cid的代码如下:
    6 条回复    1970-01-01 08:00:00 +08:00
    BOYPT
        1
    BOYPT  
       2013-09-24 17:48:33 +08:00
    什么叫不太可能生成相同的id,你的核心id生成要素仅仅是time.time()一个元素而已。
    banxi1988
        2
    banxi1988  
    OP
       2013-09-24 21:23:27 +08:00
    @BOYPT
    你可以跑下我的测试代码,我跑过很多,没有可能生成相同的id,相差都比较大.
    除非系统的时钟不可信,
    而且我们是单系统.

    而且就算是重复的id,冲突之后数据库中没有对应id值的数据行怎么解释呢?
    keakon
        3
    keakon  
       2013-09-24 22:54:18 +08:00   ❤️ 1
    time.time() 的精度甚至不保证达到一秒,你放大那么多倍就别期待它的精度了……

    你用了 2 个进程,加锁也没意义……

    story_values 里如果有重复的键,插入第一次是成功的,第二次会失败,然后抛出异常,程序退出,断开连接,事务回滚,数据库里当然就没这条记录了。
    banxi1988
        4
    banxi1988  
    OP
       2013-09-25 00:30:53 +08:00
    @keakon
    你说的给了我点感觉.感谢已发.
    你说time.time()精度1秒都达不到,我看到文档有句原话:
    not all systems provide time with a better precision than 1 second
    但是我上面测试的时候基本可以达到很高很高的精度.001纳秒.

    嗯,我在服务器上测试下先.

    PS:请教下,要生成比较可靠的id(要求整型,不太连续)应该怎么做?
    banxi1988
        5
    banxi1988  
    OP
       2013-09-25 00:46:19 +08:00
    @keakon
    我试了下:
    [20760718020319L, 20760718020689L, 20760718020811L, 20760718020908L, 20760718020999L, 20760718021090L, 20760718021180L, 20760718021259L, 20760718021349L, 20760718021440L, 20760718021531L, 20760718021609L, 20760718021700L, 20760718021779L, 20760718021860L, 20760718021950L, 20760718022029L, 20760718022120L, 20760718022210L, 20760718022298L, 20760718022379L, 20760718022460L, 20760718022539L, 20760718022630L, 20760718022708L, 20760718022789L, 20760718022880L, 20760718022971L, 20760718023049L, 20760718023130L, 20760718023219L, 20760718023300L, 20760718023390L, 20760718023469L, 20760718023550L, 20760718023629L, ]

    上面提我在服务端跑出来的部分id.可以看出几乎不会重复的.而且还是程序单纯生成id不做其他事件的情况下.在正常的应用声场景下原因是id重量的可能性不太.
    time.time()在对应服务器的精度也是很高的.
    keakon
        6
    keakon  
       2013-09-25 01:00:30 +08:00   ❤️ 1
    @banxi1988 那个精度是骗你的,它只负责给你一个 float,这玩意是 64 位的,但并不表示实际精度是那么多位。

    生成 ID 可以参考这个: http://www.zhihu.com/question/20180484
    比较简单的办法是用 Redis 的 INCRBY / HINCRBY,每次增加一个随机数即可。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1923 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 00:39 · PVG 08:39 · LAX 16:39 · JFK 19:39
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.