sqlalchemy在尝试更新数据时未能在某个位置提交(但悄悄失败)

sqlalchemy在尝试更新数据时未能在某个位置提交(但悄悄失败),sqlalchemy,turbogears2,Sqlalchemy,Turbogears2,就像所有的CRUD一样,我需要向表中写入一些数据。当我向表中写入新数据时,一切都很顺利。当我需要写入表中已经存在的数据(实际上使用相同的主键更新一些数据)时,问题就开始了。 数据似乎没有写入到表中!我开始尝试使用session.merge()更新数据,但后来尝试了一种更为暴力的方法,即在表中查询相同的主键,删除它,并添加和刷新更改的对象。 在某些情况下,如果基本的添加和刷新失败,其余的就不起作用。我很高兴在这里得到线索 守则: def flush(obj_Instance, id): """ t

就像所有的CRUD一样,我需要向表中写入一些数据。当我向表中写入新数据时,一切都很顺利。当我需要写入表中已经存在的数据(实际上使用相同的主键更新一些数据)时,问题就开始了。 数据似乎没有写入到表中!我开始尝试使用session.merge()更新数据,但后来尝试了一种更为暴力的方法,即在表中查询相同的主键,删除它,并添加和刷新更改的对象。 在某些情况下,如果基本的添加和刷新失败,其余的就不起作用。我很高兴在这里得到线索

守则:

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与mssql 2005以及pyodbc 2.1.11和tg 2.1(事务管理器随附tg,我认为是基于事务的)

问题似乎在于
DBSession.rollback()
会回滚所有的添加/刷新,因为只有在事务管理器
transaction.commit()的最后才会进行提交

一个丑陋的方法是在每次循环传递后调用
transaction.commit()
。mike bayer描述了一个可能更好的解决方案:从数据库获取数据,比较、更新,然后提交,而无需
会话。回滚
。另一种解决方案是使用
session.begin_nested()
构造将
保存点添加到会话中,这样回滚就不会擦除数据