Home  >  Article  >  Backend Development  >  Design flaws and solutions for database transaction processing in the CodeIgniter framework, codeigniter framework_PHP tutorial

Design flaws and solutions for database transaction processing in the CodeIgniter framework, codeigniter framework_PHP tutorial

WBOY
WBOYOriginal
2016-07-13 10:22:13887browse

Design flaws and solutions for database transaction processing in CodeIgniter framework, codeigniter framework

Cause:

In one of our online businesses, we use an older version of the CodeIgniter framework. In the DB class, there is a design flaw in the DB transaction processing part, which may not be considered a flaw. But it affected our production environment and caused a chain reaction. It has a great impact on the business and is difficult to troubleshoot. I reported this problem to Hex, the webmaster of codeigniter China, in mid-March this year. After that, I forgot about it. Until today, our online business once again thought of this problem, which caused me to investigate again. For the specific reasons, please listen to me slowly. (This problem also exists in the latest version Version 2.1.0)

Analysis:

Taking CodeIgniter framework Version 2.1.0 as an example, there is a $_trans_status attribute on line 58 of the CI_DB_driver class in systemdatabaseDB_driver.php.

Copy code The code is as follows:

//systemdatabaseDB_driver.php
var $trans_strict = TRUE;
var $_trans_depth = 0;
var $_trans_status = TRUE; // Used with transactions to determine if a rollback should occur
var $cache_on = FALSE;

At the same time, the query method of this class contains code for assigning this attribute, see lines 306 and 307 of the file

Copy code The code is as follows:

// This will trigger a rollback if transactions are being used
$this->_trans_status = FALSE;

A comment is also given here to tell us that if transaction processing is used, then this attribute will become a rollback decision condition.

In the transaction submission method trans_complete on line 520, the code is as follows:

Copy code The code is as follows:

/**
 * Complete Transaction
 *
 * @access public
 * @return bool
 */
function trans_complete()
{
if ( ! $this->trans_enabled)
{
return FALSE;
}

// When transactions are nested we only begin/commit/rollback the outermost ones
if ($this->_trans_depth > 1)
{
$this->_trans_depth -= 1;
return TRUE;
}

// The query() function will set this flag to FALSE in the event that a query failed
if ($this->_trans_status === FALSE)
{
$this->trans_rollback();

// If we are NOT running in strict mode, we will reset
// the _trans_status flag so that subsequent groups of transactions
// will be permitted.
if ($this->trans_strict === FALSE)
{
$this->_trans_status = TRUE;
}

log_message('debug', 'DB Transaction Failure');
return FALSE;
}

$this->trans_commit();
return TRUE;
}

In line 535, if the _trans_status attribute is false, then rollback will occur and false will be returned.

In our business code, due to the programmer's negligence, he did not judge whether the trans_complete() method was executed correctly and directly told the user that the operation was successful. However, in fact, the program had issued a rollback instruction to the DB and did not successfully update the DB record. . When the user performs the next operation, the program finds that the corresponding record has not been updated, reminds the user that the previous operation was not completed, and notifies the user to perform it again. Repeatedly...

The troubleshooting process is also quite interesting. At first, from the PHP code, I couldn't always determine the problem, and I didn't focus on the return of the trans_complete() method. It was not until later strace packet capture analysis that I found out that the rollback was caused by this attribute.

Copy code The code is as follows:

22:54:08.380085 write(9, "_ 22:54:08.380089 read(9, ": 22:54:08.381791 write(9, "21 22:54:08.381891 read(9, "7 22:54:08.382186 poll([{fd=9, events=POLLIN|POLLPRI}], 1, 0) = 0
22:54:08.382258 write(9, "v 22:54:08.382343 read(9, "7 22:54:08.382631 poll([{fd=9, events=POLLIN|POLLPRI}], 1, 0) = 0
22:54:08.382703 write(9, "22 22:54:08.401954 write(9, "v 22:54:08.402043 read(9, "7 22:54:08.417773 write(9, "v 22:54:08.417872 read(9, "7 22:54:08.418256 write(9, "[ 22:54:08.418363 read(9, "0 22:54:08.430212 write(9, "v 22:54:08.430314 read(9, "7 22:54:08.430698 write(9, "B 22:54:08.430814 read(9, "0 22:54:08.432130 write(9, "v 22:54:08.432231 read(9, "7 22:54:08.432602 write(9, "244 22:54:08.432743 read(9, "0 22:54:08.433517 write(9, "v 22:54:08.433620 read(9, "7 22:54:08.433954 write(9, "t 22:54:08.434041 read(9, "7 22:54:08.434914 write(9, "v 22:54:08.434999 read(9, "7 22:54:08.435342 write(9, "21 22:54:08.435430 read(9, "7 22:54:08.436923 write(9, "1


As you can see, at 22:54:08.380085, the update SQL statement command was sent, and the returned result was read at 22:54:08.380089, and an SQL execution error was obtained. The field "cfc4n_user_lock" does not exist; 22:54 At two time points: 08.381791 and 22:54:08.382703, PHP sends the instructions to stop "auto-commit" and "start transaction processing", and at 22:54:08.433954, it sends the "transaction rollback" instruction.

With the above code analysis, we can clearly know that the SQL execution error of "UPDATE `cfc4n_user_info` SET `cfc4n_user_lock` = 1 WHERE `cfc4n_user_id` = '6154′ AND `cfc4n_user_lock` = 0" resulted in $_trans_status The attribute is set to FALSE. When the code commits the transaction, it is judged by the trans_complete() method. It is believed that there is a SQL statement execution failure in the "previous transaction processing" (which will be analyzed in detail below), and it is decided to roll back the transaction without committing it.

I just mentioned "previous transaction processing". Some friends may not understand it. Let's go back to the code and continue to look at this attribute. Also in the trans_complete method, lines 542-545:




Copy code

The code is as follows:


// If we are NOT running in strict mode, we will reset
// the _trans_status flag so that subsequent groups of transactions
// will be permitted.
if ($this->trans_strict === FALSE)
{
$this->_trans_status = TRUE;
}

It can also be easily understood from the comments that the designer who set up the CI needs to handle it more rigorously. When there are multiple transactions in the same script, the relationship between the transactions is important. The trans_strict attribute here is a switch. When trans_strict is false, it is non-strict mode, which means that the relationship between multiple transactions is not important and does not affect each other. There is a SQL statement in the current transaction that fails to execute, which does not affect you. _trans_status is set to TRUE.
There is no doubt that this is a very thoughtful consideration. The relationship between multiple transactions is considered to ensure that the business runs on more rigorous code.

However, in our code, the wrong SQL statement is executed outside the transaction processing, not within the transaction. According to our understanding of transactions, we can clearly know that the SQL outside the transaction is more important than the SQL within the transaction. The SQL outside the transaction can be allowed to go wrong, but the SQL within the transaction must be Be correct and free from outside interference. But in the CI framework, because a statement other than a transaction fails to execute, it causes the entire transaction to be rolled back... Of course, our programmers did not make a judgment on the return of the transaction submission method, which is also a problem.

The problem is now very clear, so the solution must be very simple for you.
For example, in the trans_start method, assign a value to the _trans_status attribute, set it to TRUE, and ignore issues outside the transaction.

Copy code The code is as follows:

function trans_start($test_mode = FALSE)
{
if ($this->trans_strict === FALSE)
{
$this->_trans_status = TRUE; //When starting transaction processing, reset the value of this attribute to TRUE
}
//2012/05/01 18:00 After correction by CI Chinese community netizens http://codeigniter.org.cn/forums/space-uid-5721.html, the modification here is to add the trans_strict attribute to determine whether to reset_ trans_status as well.
if ( ! $this->trans_enabled)
{
return FALSE;
}

// When transactions are nested we only begin/commit/rollback the outermost ones
if ($this->_trans_depth > 0)
{
$this->_trans_depth += 1;
return;
}

$this->trans_begin($test_mode);
}

End:

You cannot blindly define the other party’s code evaluation without understanding the other party’s design intentions, regardless of the level of the program author. If you are stronger than yourself, you can't blindly worship them; if you are weaker than yourself, you can't make random accusations; it is a good habit to understand the design intentions and learn other people's excellent design ideas, coding styles, and algorithm efficiency. Of course the codeigniter framework is excellent.

For php CodeIgniter framework

I just read the CodeIgniter manual yesterday, and the method is explained in the CodeIgniter URLs chapter:

It is processed by adding rules in the .htaccess file, as follows

RewriteEngine on

RewriteCond $1 !^(index\.php|images|robots\.txt)

RewriteRule ^(.*)$ /index.php/$1 [L]

Related learning materials of the codeigniter framework, such as manuals, books, tutorials, etc.

CodeIgniter China - PHP Framework CodeIgniter China Community

Click on the user manual. There is a "Table of Contents" button at the top of the page. Click to open a very good Chinese manual.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/848800.htmlTechArticleCodeIgniter framework database transaction processing design flaws and solutions, codeigniter framework origin: In one of our online businesses , using an older version of the CodeIgniter framework, where...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn