sqlalchemy在尝试更新数据时无法提交某个地方(但是无声地失败)

时间:2013-03-17 20:57:38

标签: sqlalchemy turbogears2

像所有CRUD一样,我需要将一些数据写入表中。当我将新数据写入表格时,一切都像魅力一样。当我需要编写表中已存在的数据时(实际上使用相同的主键更新某些数据),问题就开始了。 数据似乎没有写入表格!我开始尝试使用session.merge()更新数据,但后来尝试了更强力的方法,查询表中的相同primary_key,删除它以及添加和刷新更改的对象。 在某些地方,如果基本的添加和冲洗失败,其余的不起作用。我很高兴在这里得到一个线索。

代码:

def flush(obj_Instance, id):
"""
taking care of the sqlalchemy flushing
params:
        Instance: an object Instance to flush into
        id: the unique object instance id
"""

DBSession2.add(obj_Instance)

try:

    try:
        DBSession2.flush()
        print ("flushed:", str(obj_Instance))
    except (FlushError, IntegrityError) as err:
        DBSession2.rollback()
        if ('conflicts with persistent instance' in str(err)) or ('Duplicate key was ignored' in str(err)):
            transaction.begin()
            #my original slick take:
            DBSession2.merge(obj_instance) # but after it failed to update correctly I changed to a more brute force approach
            #DBSession2.flush()  #to save the merge
            #from here on trying to brute force it
            #saving for further reference - another try
            newInstance = deepcopy(obj_Instance)
            print ("deleting: %s" % id)
            DBSession2.query(type(obj_Instance)).filter_by(ids = id).delete()
            DBSession2.flush() #at this point, I was so desperate for this to work I literated the code with flush commands.
            DBSession2.add(newInstance)
            DBSession2.flush()
            return
        else:
            raise #handling the case of the same key problem isn't the source of conflicts

except Exception as err:  # supposed to find out the error type and message
# the code doesn't get here, only in real exceptions it was planned to catch, 3 rows in 10,000 uploaded to the db
#TODO: make this less general and more specific
    print str(err)
    write_log(num=id, msg="some sql or sqlalchemy error use num %s as id identifier with object: %s" % (id, obj_Instance.name), timestamp=
        datetime.now(), errtype="sql error", log=str(err))
    DBSession2.rollback()
    transaction.begin()

使用sqlalchemy 0.7.3 vs mssql 2005 with pyodbc 2.1.11和tg 2.1(事务管理器附带tg,我认为是基于事务)

1 个答案:

答案 0 :(得分:0)

问题似乎是DBSession.rollback()发出了所有add / flush的回滚,因为提交只发生在事务管理器transaction.commit()的最后。 一个丑陋的黑客将在每次循环传递后调用transaction.commit()。 mike bayer here 描述了一个可能更好的解决方案:从数据库获取chuncked数据,比较,更新,然后在没有session.rollback的情况下提交。另一种解决方案是使用session.begin_nested()构造将SAVEPOINTS添加到会话中,因此回滚不会删除数据。