Detailed description of the Instance code used for transactions in Yii2, and detailed description of yii2 transaction instances
Preface
Generally, we do not associate only one data table with the business logic, so we are faced with transaction problems.
Database Transaction refers to a series of operations performed as a single logical unit of work, either completely or completely. Transaction Processing ensures that data-oriented resources are not updated permanently unless all operations in the transaction unit are successfully completed. By combining a set of related operations into a unit that either succeeds or fails, you can simplify error recovery and make the application more reliable. To become a transaction, a logical unit of work must meet the so-called ACID (atomicity, consistency, isolation, and durability) attributes. A transaction is a logical unit in the database operation. The transaction management subsystem in the DBMS is responsible for processing transactions.
Preparation
The database engine is innodb
The yii version used in this article is 2.0.5. As long as it is 2.0 or above, there is no problem.
The runtime environment is PHP7.0.0 and Mysql5.6.
Transactions in Yii
Exception Handling
/*** Test transaction */public function actionTest () {// create a transaction $ tr = Yii: $ app-> db-> beginTransaction (); try {for ($ I = 1; $ I <= 3; $ I ++) {$ test = new Areas (); $ test-> name = 'name '. $ I; $ test-> sort = 1; if ($ test-> save () {echo "save $ I |" ;}}$ test = new Areas (); $ test-> name = 'AB '. $ I; $ test-> sorta = 1; // write a nonexistent field if (! $ Test-> save () {"save fail"; // output if no data is written} // submit $ tr-> commit ();} catch (Exception $ e) {// rollBack $ tr-> rollback (); echo "rollBack ";}}
Running result
save 1 | save 2 | save 3 | rollback
Note that the transaction rollback is triggered because the last data is not inserted successfully, so no new data is generated in the data table.
The cause of triggering transaction rollback is that the Code has encountered an Exception ).
Data processing failed
Generally, the code we run does not have this obvious exception, which will be eliminated during the development and testing process.
What actually causes data to be rolled back is a problem in one of our services, resulting in no data written.
/*** Test transaction */public function actionTest () {// create a transaction $ tr = Yii: $ app-> db-> beginTransaction (); try {for ($ I = 1; $ I <= 3; $ I ++) {$ test = new Areas (); $ test-> name = 'name '. $ I; $ test-> sort = 1; if ($ test-> save () {echo "save $ I |" ;}}$ test = new Areas (); $ test-> name = null; // the database design name cannot be blank, causing a write failure. $ Test-> sort = 1; // write if (! $ Test-> save () {echo "save fail"; // output if no data is written} // submit $ tr-> commit ();} catch (Exception $ e) {// rollBack $ tr-> rollback (); echo "rollBack ";}}
The running result is as follows. Three pieces of data are inserted into the database.
save 1 | save 2 | save 3 | save fail
That is to say, if a data table is not written or rolled back due to business logic.
The improvement scheme is as follows:
/*** Test transaction */public function actionTest () {// create a transaction $ tr = Yii: $ app-> db-> beginTransaction (); try {for ($ I = 1; $ I <= 3; $ I ++) {$ test = new Areas (); $ test-> name = 'name '. $ I; $ test-> sort = 1; if ($ test-> save () {echo "save $ I |" ;}}$ test = new Areas (); $ test-> name = null; // the database design name cannot be blank, causing a write failure. $ Test-> sort = 1; // write if (! $ Test-> save () {throw new \ yii \ db \ Exception (); // manually throw an Exception and capture it below .} // Submit $ tr-> commit ();} catch (Exception $ e) {// rollBack $ tr-> rollback (); echo "rollBack ";}}
The running result is as follows. The database does not insert new data and the transaction is rolled back.
save 1 | save 2 | save 3 | rollback
Scattered Data Processing
Because of the complexity of the actual project, our database operations are dispersed in different models.
Therefore, the actual project code will not look like above.
Simulation requirements
Receiving parameters:
Name
Gender
Signature
Business Process:
Receiving Parameters
The sender obtains the uid of the user. The sender adds a number to the data table.
Write the name, gender, signature, and uid in the previous step into the user information table.
Initialize the user balance table
Rollback triggering time:
Initialize the remainder table. The uid is not input and exported. No data is written.
Actual code
// Controller/*** test transaction-registered user */public function actionReg () {// obtain the request $ request = Yii: $ app-> request; // set the return format $ response = Yii: $ app-> response; $ response-> format = \ yii \ web \ Response: FORMAT_JSON; // return json // test code. Remove the authentication procedure $ name = $ request-> get ("name "); $ gender = $ request-> get ("gender"); $ sign = $ request-> get ("sign"); // test code, omit parameter verification steps $ tr = Yii: $ app-> db-> beginTransaction (); try {// get uid $ uid = App: getSeNo (); UserProfile: Add ($ uid, $ name, $ gender, 1, $ sign); $ user_balance = UserBalance: initUserBalance ($ uid); $ tr-> commit (); // submit data} catch (Exception $ e) {// roll back $ tr-> rollBack (); return $ e-> getMessage (); // return custom exception information} return $ user_balance ;} // UserProfile/*** Add User information * @ param $ user_id * @ param $ nikename * @ param $ gender * @ param $ user_type * @ param string $ intro * @ return UserProfile * @ throws \ Exception */public static function add ($ User_id, $ nikename, $ gender, $ user_type, $ intro = "") {$ model = new UserProfile (); $ model-> gender = $ gender; $ model-> nikename = $ nikename; $ model-> user_id = $ user_id; $ model-> user_type = $ user_type; $ model-> intro = $ intro; $ model-> update_time = time (); $ insert = $ model-> insert (); if (! $ Insert) {throw new Exception ("user data is not written");} return $ model ;} // UserBalance/*** initialize the withdrawal balance of the user * @ param $ user_id */public static function initUserBalance ($ user_id) {$ info = self: find () -> where (['user _ id' => $ user_id])-> one (); if (! $ Info) {$ model = new UserBalance (); $ model-> user_id = $ user_id; $ model-> price = "0 "; $ model-> update_time = time (); $ insert = $ model-> insert (); if (! $ Insert) {throw new Exception ("User balance not initialized");} $ info = $ model;} return $ info-> attributes ;}
The normal result is as follows:
{"id":124,"user_id":1473179883,"price":"0","update_time":1473179883}
If the user_id of the user balance part is not passed successfully, the returned result is as follows:
"User balance not initialized"
We can locate the error location based on the specific situation and modify it in time.
Transaction)
From the actual code above, we can see that if a transaction is created within the scope, the exception NG can be returned even for other models introduced to complete the rollback operation.
Generally, the Yii application uses the same database connection, or a singleton.
The transaction object is cached in yii \ db \ Connection:
Class Connection extends Component {// Save the valid Transaction object private $ _ transaction for the current Connection; // The Transaction object is cached and valid, this transaction object is returned // otherwise nullpublic function getTransaction () {return $ this-> _ transaction & $ this-> _ transaction-> getIsActive ()? $ This-> _ transaction: null;} // check how the public function beginTransaction ($ isolationLevel = null) of the transaction object is used when the transaction is enabled) {$ this-> open (); // The cached transaction object is valid, use the transaction object in the cache // otherwise create a new transaction object if ($ transaction = $ this-> getTransaction () = null) {$ transaction = $ this-> _ transaction = new Transaction (['db' => $ this]);} $ transaction-> begin ($ isolationLevel ); return $ transaction ;}}
Therefore, the entire Yii application uses the same Transaction object. That is to say, Transaction: _ level is continuous throughout the application lifecycle. This is the key and prerequisite for implementing transaction nesting.
The above is a detailed description of the Instance code used for transactions in Yii2. I hope it will help you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!