2016-09-15 53 views
0

在我的CherryPy + Peewee应用程序中,我经常使用以下模式:启动事务,执行操作列表并返回显示结果的页面。如果在任何操作过程中出现问题,我会在日志表中添加一行,然后重定向到显示该行的页面。在失败的事务中执行某些SQL代码

问题是CherryPy中的重定向是通过引发异常来执行的,异常导致一些事务回滚。回滚是我失败的操作所需要的(以及之前的所有操作,即使它们成功了),但这不是我想要的日志记录。

例如用下面的代码,如果用户进入a_page?a=1&b=2&c=3

  • do_this会发现x != y,而不是执行show_message
  • do_this将在Table1
  • do_that会发现x == y并执行更新一个记录show_message
  • show_message会增加一行到第ËMessage日志表
  • show_message将为了引发异常重定向到一个页面,会显示消息刚刚登录

因为在事务中,双方就Table1更新的破例已上升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(), '/')