def _run(query, dbconn, roll_back, table_to_lock=None):
    """Run a query with a single table locked. If an exception
    is thrown, we roll back the transaction and then unlock the table
    before re-raising the exception.

    :param query: a function which takes a db cursor as its only argument
    :param dbconn: any DBI-compliant MySQL connection object
    :param str table_to_lock: optional table to lock (in WRITE mode) while
                              running the query
    :param bool roll_back: if true, always roll back after issuing the query

    If there is already a transaction in progress on *dbconn*, we'll roll
    it back, and unlock any tables currently locked.
    """
    dbconn.rollback()
    cursor = dbconn.cursor()
    try:
        cursor.execute('START TRANSACTION')
        cursor.execute('UNLOCK TABLES')
        cursor.execute('SET autocommit = 0')
        if table_to_lock:
            cursor.execute('LOCK TABLES `%s` WRITE' % table_to_lock)
        result = query(cursor)
        if roll_back:
            dbconn.rollback()
        else:
            dbconn.commit()
        return result
    except:
        dbconn.rollback()
        raise
    finally:
        cursor.execute('UNLOCK TABLES')
