2016-09-15 10 views
0

CherryPy + Peewee 앱에서 나는 종종 다음과 같은 패턴을 사용합니다. 트랜잭션을 시작하고 작업 목록을 수행하고 결과를 보여주는 페이지를 반환합니다. 어떤 작업 중에 문제가 발생하면 로깅 테이블에 행을 추가 한 다음 해당 행을 표시하는 페이지로 리디렉션합니다.실패한 트랜잭션에서 SQL 코드 실행

CherryPy의 리디렉션이 예외를 발생시켜 수행되고 예외로 인해 일부 트랜잭션이 롤백되는 문제가 있습니다. 롤백은 내가 실패한 작업 (그리고 성공하더라도 모든 이전 작업)에 필요한 것이지만 로깅을 위해 원하는 것은 아닙니다. 다음 코드로 예를 들어

는 사용자가 a_page?a=1&b=2&c=3가는 경우 :

  • do_thisx != y을 찾아 show_message
  • do_thisTable1
  • do_thatx == y을 찾아 실행합니다에 하나 개의 레코드를 업데이트 실행되지 않습니다 show_message
  • show_messageTable1에 거래 업데이트 모두에서 만들어진하는 동안 예외가 증가 되었기 때문에 위해 예외를 발생합니다
  • show_message 전자 Message 로그 테이블은

를 기록한 메시지가 표시됩니다 해당 페이지로 리디렉션 do_this이고 show_message에 로그인 한 메시지는 롤백됩니다.

로깅 테이블에서 행을 커밋하고 다른 모든 변경 사항을 롤백하는 방법은 무엇입니까? 그것은 (확실하지 아직) 중첩 된 트랜잭션과 함께 작동하지 않을 수 있기 때문에

@cherrypy.expose 
def a_page(self, a, b, c): 
    with db.transaction(): 
     self.do_this(a, b) 
     self.do_that(b, c) 
    return render('it_worked.html') 

def do_this(self, x, y): 
    if x == y: 
     self.show_message('Wrong this') 
    Table1.update(f2=x).where(f1 == y).execute() 

def do_that(self, x, y): 
    if x != y: 
     self.show_message('Wrong that') 
    Table1.update(f3=x).where(f1 == z).execute() 

def show_message(self, message) 
    msg = Message.create(msg=message) 
    raise cherrypy.HTTPRedirect('show_message?id={}'.format(msg.id)) 
+0

아마도 중첩 된 트랜잭션, 즉 세이브 포인트입니다. –

+0

@CL. 내가 아는 한 중첩 된 트랜잭션은 내부 작업을 저장하지 못하게합니다. 반대가 필요합니다. 지금까지 실행 된 트랜잭션을 저장하고 싶지는 않지만, 마지막 트랜잭션을 저장하고 싶습니다. – stenci

+0

(1) 트랜잭션을 함수에 전달해야하며 (2) 중첩 된 트랜잭션이있는 경우 작동하지 않기 때문에 싫어하는 해결책을 찾았습니다. 내 대답은 아래에 있습니다. 그게 좋은 해결책인지 아니면 더 잘할 수 있는지 알려주세요. – stenci

답변

0

이 솔루션은 작동하는 것 같다하지만 함수에 트랜잭션을 통과해야하기 때문에 내가 싫어합니다.

import cherrypy 
import peewee 

db = peewee.SqliteDatabase('test.db', threadlocals=True) 

class PeeweeModel(peewee.Model): 
    class Meta: 
     database = db 

class Table1(PeeweeModel): 
    field1 = peewee.CharField() 

Table1.drop_table(True) 
Table1.create_table(True) 

class Log(PeeweeModel): 
    msg = peewee.CharField() 

    @staticmethod 
    def show_log(msg, txn): 
     txn.rollback() 
     msg = Log.create(msg=msg) 
     txn.commit() 
     raise cherrypy.HTTPRedirect('show_log?msg_id={}'.format(msg.id)) 

Log.drop_table(True) 
Log.create_table(True) 

def table_content(): 
    return '<br>'.join(['{} {}'.format(row.id, row.field1) for row in Table1.select()]) 

html = """<!DOCTYPE HTML> 
<html> 
<head> 
</head> 
<body> 
<a href="index">index</a><br> 
<a href="add_row">add_row</a><br> 
{}<br> 
Table1<br> 
{}<br> 
</body> 
</html>""" 

class App(): 

    @cherrypy.expose 
    def index(self, msg='Hello'): 
     return html.format(msg, table_content()) 

    @cherrypy.expose 
    def add_row(self): 
     with db.transaction() as txn: 
      Table1.update(field1=Table1.field1 + 1).execute() 
      Table1.update(field1=Table1.field1 + 1).where(Table1.id == 2).execute() 
      if Table1.select().count() == 5: 
       raise Log.show_log('Something went wrong', txn) 
      Table1.create(field1=1, field2=2) 
     return html.format('Added record to Table1', table_content()) 

    @cherrypy.expose 
    def show_log(self, msg_id): 
     msg = Log.get(Log.id == msg_id) 
     text = 'Message id {}: {}'.format(msg.id, msg.msg) 
     return html.format(text, table_content()) 

cherrypy.quickstart(App(), '/')