2013-03-17 2 views
0

모든 CRUD와 마찬가지로 일부 데이터를 테이블에 써야합니다. 테이블에 새로운 데이터를 쓸 때 모든 것이 매력처럼 작동합니다. 이 문제는 테이블에 이미 존재하는 데이터를 쓰고 싶을 때 시작됩니다. 실제로 같은 기본 키로 일부 데이터를 업데이트합니다. 데이터가 테이블에 기록되지 않은 것처럼 보입니다! session.merge()를 사용하여 데이터를 업데이트하려고 시도했지만 나중에 테이블에서 동일한 primary_key를 쿼리하고 삭제하고 변경된 객체를 추가하고 플러시하는 등 더 무차별적인 접근 방식을 시도했습니다. 일부 기본 추가 및 플러시가 실패하면 나머지는 작동하지 않습니다. 나는 단서를 보게되어 기쁘다.데이터를 업데이트하려고 할 때 sqlalchemy가 어딘지에서 커밋하지 못했습니다. (자동으로 실패합니다)

코드 :

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() 
pyodbc 2.1.11로 MSSQL 2005 대 SQLAlchemy의 0.7.3을 사용

와 TG 2.1 (기반 트랜잭션을 트랜잭션 관리자는 TG와 함께 제공하고 나는 생각한다)

답변

0

문제 DBSession.rollback()은 커밋이 트랜잭션 관리자 transaction.commit()의 마지막에만 발생하기 때문에 모든 추가/삭제 롤백을 실행하는 것으로 보입니다.
모든 루프가 끝날 때마다 transaction.commit() 번을 부르는 것이 좋습니다. 아마도 더 나은 해결책은 마이크 바이어 here : db에서 chuncked 데이터를 얻고, 비교하고, 업데이트 한 다음 session.rollback없이 커밋하는 것으로 설명되었습니다. 또 다른 해결책은 session.begin_nested() 구조를 사용하여 SAVEPOINTS을 세션에 추가하므로 롤백은 데이터를 지우지 않습니다.