Continuing a transaction after primary key violation error

前端 未结 4 1054
旧巷少年郎
旧巷少年郎 2020-11-30 07:56

I am doing a bulk insert of records into a database from a log file. Occasionally (~1 row out of every thousand) one of the rows violates the primary key and causes the tran

4条回答
  •  感情败类
    2020-11-30 08:50

    You can do a rollback to the transaction or a rollback to a save point just before the code that raises the exception (cr is the cursor):

    name = uuid.uuid1().hex
    cr.execute('SAVEPOINT "%s"' % name)
    try:
        # your failing query goes here
    except Exception:
        cr.execute('ROLLBACK TO SAVEPOINT "%s"' % name)
        # your alternative code goes here 
    else:
        cr.execute('RELEASE SAVEPOINT "%s"' % name)
    

    This code assumes there is running transaction, otherwise you would not receive that error message.

    Django postgresql backend creates cursors directly from psycopg. Maybe in the future they make a proxy class for the Django cursor, similar to the cursor of odoo. They extend the cursor with the following code (self is the cursor):

    @contextmanager
    @check
    def savepoint(self):
        """context manager entering in a new savepoint"""
        name = uuid.uuid1().hex
        self.execute('SAVEPOINT "%s"' % name)
        try:
            yield
        except Exception:
            self.execute('ROLLBACK TO SAVEPOINT "%s"' % name)
            raise
        else:
            self.execute('RELEASE SAVEPOINT "%s"' % name)
    

    That way the context makes your code easier, it will be:

    try:
        with cr.savepoint():
            # your failing query goes here
    except Exception:
        # your alternative code goes here 
    

    and the code is more readable, because the transaction stuff is not there.

提交回复
热议问题