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.
At the same time, the query method of this class contains code for assigning this attribute, see lines 306 and 307 of the file
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:
// 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.
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.
// 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.
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]
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.