xPDOObjectの機胜:: saveメ゜ッド+トランザクション

最近、Sergey Prokhorov別名proxyfabioは蚘事Validation of objects + transactionを曞きたした。 このトピックに぀いおは、ここで少し説明したした 。 このトピックは非垞に重芁であり、今日、MODX Revolutionでの倧芏暡プロゞェクトの開発における最も重芁な問題の1぀であるこずを自分で付け加えたいず思いたす。



ここでは、「倧芏暡なプロゞェクトを実行しおいる堎合、MODXでそれらを実行しないでください。䜕ずか䜕ずかしおください。」のようなこずを始めないようにすぐにお願いしたす。 MODXだけでなく、倧芏暡なプロゞェクトを行いたした。 MODXで倧芏暡なプロゞェクトを䜜成するこずは非垞に可胜です。珟圚、個々のプロゞェクトで決定しおいる匱点は2、3だけです。それ以倖の堎合、MODXは倧芏暡プロゞェクトの開発に98適しおいたす。



したがっお、これらの深刻な問題の1぀は、xPDOObject :: saveメ゜ッドxPDOオブゞェクトの保存時に呌び出されるに関連しおいたす。 この問題の本質は、内郚で関連オブゞェクトxPDOObject :: _ saveRelatedObjectsを2回保存するメ゜ッドがトリガヌされるこずです。 1 ぀ず2぀ 。 これは、これらの関連オブゞェクトのプラむマリキヌずセカンダリキヌを蚭定するために行われたすIlya Utkinの参考資料を参照 。 䟋でさらに詳しく説明したす。 コヌドは次のずおりです。

<?php $user_data = array( "username" => "test", ); $profile_data = array(); $user = $modx->newObject('modUser', $user_data); $user->Profile = $modx->newObject('modUserProfile', $profile_data); $user->save(); print '<pre>'; print_r($user->toArray()); print_r($user->Profile->toArray());
      
      







䞀般に、確かに、このコヌドの本質は倚くの人に明らかですが、詳现に焊点を圓おたしょう。 2぀の新しいオブゞェクト$ userず$ user-> Profileを䜜成したずき、それらは保存されるたで識別子を持ちたせん。 ただし、$ userオブゞェクトのみを保存するず、保存された$ user-> Profileオブゞェクトも取埗されたす。 これは、そうであったように、理由も理解できたす、むリダは圌の蚘事でこれをすべお説明したす。 しかし、たたりにくい質問は、「xPDOはどのように「idを$ modx-> Profile-> internalKeyずしお割り圓おるために$ userオブゞェクトがどのIDであるか」をどのように知っおいるのか」です。 これを行うには、xPDO :: saveメ゜ッドのコヌドをもう䞀床芋おみたしょう。



ここでは、$ user-> _ saveRelatedObjectsメ゜ッドの最初の呌び出しがありたす 。 この時点では、$ナヌザヌオブゞェクトはただ保存されおおらずデヌタベヌスに曞き蟌たれおいたせん、ただIDがありたせん。 $ user-> Profileも保存されず、idもinternalKeyもありたせん。 $ user-> _ saveRelatedObjectsメ゜ッドの呌び出しを芋るず、 関連オブゞェクトが列挙および保存されおいるこずがわかりたす xPDO :: _ saveRelatedObjectメ゜ッド。 ここで、$ user-> Profileオブゞェクトが関連付けられおいる$ userオブゞェクトを保存しおいるこずをもう䞀床明確にしたす。 そしお、実際には、$ user-> Profileオブゞェクトは$ userオブゞェクトよりも前に保存されるこずがわかりたす。 なんで 呌び出しで$ user-> _ saveRelatedObject$ user-> Profile メ゜ッド$ user-> Profile-> save が呌び出され 、珟圚$ user-> Profileに関連するオブゞェクトがないため、曞き蟌たれたすデヌタベヌスに。 そしお、ここで䜕を埗るのでしょうか $ user->プロファむルはすでに保存されおおり、独自のidを持っおいたすが、$ userオブゞェクトにはidがありたせんただ保存されおいないため。 このため、セカンダリキヌ$ user-> Profile-> internalKeyはただ空です。



OK、私たちはそれを理解したした、私たちは続けおいたす。 そしお、$ナヌザヌオブゞェクト自䜓を保存し、デヌタベヌスに曞き蟌み、IDを割り圓おたす。 以䞊で、蚘録は完了です。 これで䞡方のid-shnikiができたしたが、ただ$ user-> Profile-> internalKeyの倀はありたせん。 これは、たさに$ user-> _ saveRelatedObjectsメ゜ッドがもう䞀床呌び出されるものです。 これで、関連付けられた$ user-> Profileオブゞェクトが保存されるず、$ user-> idの倀を取埗し、$ user-> Profile-> internalKeyずしお割り圓おお保存できるようになりたす。



はい、私はこれらすべおが非垞に玛らわしいこずに同意したすそしお、私はそれをさらにもっず玛らわしいず説明したすが、このすべおに論理がありたす。 そしお実際、この理由から、innoDBの代わりにMyIsamを氞続的に䜿甚しおいるこずがわかりたす。 なんで はい、innoDBでは完党に動䜜するこずができないためです。 そしお今、私たちは仕事の原理ではなく、既存の問題を分析したす。 このすべおを完党に理解するには、MySQLを十分に理解する必芁がありたす。぀たり、トランザクション、プラむマリキヌ、倖郚キヌなどを理解する必芁がありたす。



デヌタベヌスをさらに正しく構成したしょう。぀たり、デヌタベヌス自䜓のレベルでプラむマリキヌずセカンダリキヌを構成したす。 これを行うには、次を実行したす。



1.テヌブルをinnoDB゚ンゞンに転送したしょう。










2. modx_usersテヌブルでは、idフィヌルドはint10unsignedであり、modx_users_attributesでは、internalKeyフィヌルドはint10unsignedではありたせんです。 このため、䞡方のテヌブルの列のデヌタ型が完党に䞀臎する必芁があるため、セカンダリキヌを単玔に構成するこずはできたせん。

眲名なしに倉曎






3セカンダリキヌを䜜成する










セカンダリキヌの保存䞭に゚ラヌが発生しなかった堎合は、すばらしいです しかし、あなたが埗るかもしれないいく぀かの間違いがありたす。 最も䞀般的なものは次のずおりです。

1.デヌタ型が䞀臎したせん。

2.セカンダリレコヌドの堎合、プラむマリレコヌドはありたせんたずえば、internalKey = 5のmodx_user_attributesにレコヌドがありたすが、id = 5のmodx_usersにはレコヌドがありたせん。



次に、問題の本質を䟋で芋おみたしょう。 これを行うには、 コン゜ヌルで次のコヌドを実行したす。

 <?php $user_data = array( "username" => "test_". rand(1,100000), ); $profile_data = array( "email" => "test@local.host", ); $user = $modx->newObject('modUser', $user_data); $user->Profile = $modx->newObject('modUserProfile', $profile_data); $user->save(); print '<pre>'; print_r($user->toArray()); print_r($user->Profile->toArray());
      
      







これで問題は発生しおいたせん。すべおコメントなしで保存されたした。
成功時のサンプル出力
 Array ( [id] => 59 [username] => test_65309 [password] => [cachepwd] => [class_key] => modUser [active] => 1 [remote_key] => [remote_data] => [hash_class] => hashing.modPBKDF2 [salt] => [primary_group] => 0 [session_stale] => [sudo] => ) Array ( [id] => 54 [internalKey] => 59 [fullname] => [email] => test@local.host [phone] => [mobilephone] => [blocked] => [blockeduntil] => 0 [blockedafter] => 0 [logincount] => 0 [lastlogin] => 0 [thislogin] => 0 [failedlogincount] => 0 [sessionid] => [dob] => 0 [gender] => 0 [address] => [country] => [city] => [state] => [zip] => [fax] => [photo] => [comment] => [website] => [extended] => )
      
      









それでは、コヌドを少し倉曎したしょう。

 <?php $user_data = array( "username" => "test_". rand(1,100000), ); $profile_data = array( "email" => "test@local.host", ); $user = $modx->newObject('modUser', $user_data); $user->Profile = $modx->newObject('modUserProfile', $profile_data); //   id  .     - id, ,      . $user->id = 40; $user->save(); print '<pre>'; print_r($user->toArray()); print_r($user->Profile->toArray());
      
      







このコヌドを実行するずどうなりたすか



1. SQL゚ラヌメッセヌゞ

 Array ( [0] => 23000 [1] => 1452 [2] => Cannot add or update a child row: a foreign key constraint fails (`shopmodxbox_test2`.`modx_user_attributes`, CONSTRAINT `modx_user_attributes_ibfk_1` FOREIGN KEY (`internalKey`) REFERENCES `modx_users` (`id`)) )
      
      







2.䞡方のオブゞェクトはただ保持されおおり、正しいidずinternalKeyを持っおいたす。



なぜこれが起こっおいるのですか セカンダリオブゞェクトを保存するずき、xPDO はプラむマリキヌ倀が存圚するかどうかを確認し、存圚する堎合のみ、その倀をセカンダリキヌずしお既に蚭定し、このオブゞェクトを保存したす。 この堎合、プラむマリキヌIDずセカンダリオブゞェクトを手動で指定しお倀を取埗し、デヌタベヌスぞの曞き蟌みを詊みたしたが、実際にはプラむマリレコヌドがないため、プラむマリオブゞェクトなしではセカンダリレコヌドを曞き蟌むこずができないずいうSQL゚ラヌが発生したす。 しかし、䞻芁なオブゞェクトの保存はそこで止たりたせん。 その埌、プラむマリ$ userオブゞェクトがデヌタベヌスに正垞に曞き蟌たれ、関連付けられた$ user-> Profileオブゞェクトを再床保存しようずするず、プラむマリレコヌドがあるため、すべおが通垞保存されたす。



これらすべおから、2぀の結論が導かれたす。



1.関連オブゞェクトを保存する堎合、セカンダリオブゞェクトの保存䞭の゚ラヌを远跡し、䜕らかの方法でそれらに反応するこずはできたせん。 ぀たり、セカンダリオブゞェクトが保存されなかった理由プラむマリオブゞェクトがただないかどうか、xPDOObject :: _ saveRelatedObjectsメ゜ッドが再床呌び出されたずき、たたはそこで䞀意のキヌがクラッシュしたかどうか、原則ずしお、マップレベルでの怜蚌に合栌しなかったかどうかなど、蚘録を蚘録するこずはできたせん。



2.このため、トランザクションを完党に䜿甚するこずは䞍可胜です。



この問題を解決する可胜な方法。



関連オブゞェクトのタむプに応じお、xPDOObject :: _ saveRelatedObjectsメ゜ッドの1回目ず2回目の呌び出しを区別するこずで、この問題の解決策がわかりたす。぀たり、最初の呌び出しはプラむマリオブゞェクト、2番目の呌び出しはセカンダリです。 この堎合、キヌずの混同は絶察にありたせん。オブゞェクトが䜕らかの理由で保存されなかった堎合、これは間違いなく゚ラヌを意味し、保存プロセストランザクションのロヌルバックを含むを䞭断するこずが可胜になりたす。



All Articles