From 5ba236f405bd89641f27eb682e02dabe1e7ad881 Mon Sep 17 00:00:00 2001 From: Usman Khalid <2200617@gmail.com> Date: Wed, 24 Sep 2014 16:21:12 +0500 Subject: [PATCH] Created commit_on_success_with_read_committed decorator. This decorator executes the decorated function inside a transaction with isolation level set to READ COMMITTED. TNL-367 --- common/djangoapps/util/db.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 common/djangoapps/util/db.py diff --git a/common/djangoapps/util/db.py b/common/djangoapps/util/db.py new file mode 100644 index 0000000000..08dd347158 --- /dev/null +++ b/common/djangoapps/util/db.py @@ -0,0 +1,33 @@ +""" +Utility functions related to databases. +""" +from functools import wraps + +from django.db import connection, transaction + + +def commit_on_success_with_read_committed(func): # pylint: disable=invalid-name + """ + Decorator which executes the decorated function inside a transaction with isolation level set to READ COMMITTED. + + If the function returns a response the transaction is committed and if the function raises an exception the + transaction is rolled back. + + Note: This only works on MySQL. + """ + @wraps(func) + def wrapper(*args, **kwargs): # pylint: disable=missing-docstring + + if connection.vendor == 'mysql': + # The isolation level cannot be changed while a transaction is in progress. So we close any existing one. + if connection.transaction_state: + connection.commit() + + # This will set the transaction isolation level to READ COMMITTED for the next transaction. + cursor = connection.cursor() + cursor.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED") + + with transaction.commit_on_success(): + return func(*args, **kwargs) + + return wrapper