I didn't know that SELECT locks even false hits within serializable transaction, thanks Also, the re-submision (both automatic or initiated by user) is brilliant
Thanks! W dniu piątek, 20 grudnia 2013 22:12:32 UTC+1 użytkownik Constantin-Emil Marina napisał: > > You could use pessimistic locks in a transaction for validation AND have > an index on the e-mail field: > > http://docs.doctrine-project.org/en/2.0.x/reference/transactions-and-concurrency.html > In a serializable transaction, read queries lock index ranges explored by > a SELECT, even false hits. > > It's a bit more complicated than just dealing with the exception; also > note that you are taking a bit of a responsability on your hands: as your > model gets increasingly complicated ACID exceptions are bound to occur, > unless you use a really aggressive locking strategy; you'd need to validate > and version (see optimistic locking) absolutely every piece of data that's > about to get written (including relations etc), and to be able to do that > is kind of a birth gift for complicated models. However, since such > conditions are remote, I use a generic handle that just re-submits the > request. This way, you don't have to parse the exception to know what > really happened: on the second pass, the duplicate email address will pe > picked up in the validation (read) phase and an appropriate message will be > displayed tothe user. This can be done either automatically or manually by > the user (in case some exception occurs, prompt him a generic message > kindly asking him to try again). > > On Friday, December 20, 2013 4:35:20 PM UTC+2, Adam Zielinski wrote: >> >> I have a entity called Contact with a single unique field email. Before >> persisting, I am validating values to make sure my unique constraint won't >> be violated. >> >> Let's assume I want to persist a Contact with an email >> [email protected], of course it works. Then I try again and bam, >> validation kicked in, I know the insert is not going to work, and I can >> show nice error message right next to my "email" field. Perfect! >> >> Now I want to add another contact, this time with an email >> [email protected], but oops, someone decided to add the same email >> in exactly the same moment as me. That's okay, it happens. Both requests >> are processed like this: >> >> | My Request | Other Request-+-----------------+-----------------1| >> Validation | Validation 2| $em->flush() | $em->flush() >> >> In both cases validation passed since the Contact entity with such email >> wasn't in database yet. This leads to two Insert queries sent with the >> same email. MySQL will prevent the second one, so Doctrine will throw an >> exception, user will see error 500 instead of "Email has been already >> taken". Documentation says I should avoid database exceptions at all cost, >> but this time database exception is perfectly okay, there is no way I can >> tell if this insert will succeed other than performing an insert. >> >> My question is: *What is the Doctrine Way **(tm) to **recover from that >> exception **elegantly**?* I just want to tell the user that he have to >> type in different email address *(and I don't want to set an exclusive >> lock for the entire table).* >> >> I could of course do something like this: >> >> try { >> $em->flush();} catch (DBALException $e) { >> $pdoException = $e->getPrevious(); >> if ($pdoException && >> $pdoException instanceof PDOException && >> $pdoException->getCode() === '23000' >> ) {// let the form know about the error >> } else throw $e;} >> >> But that's wrong, requires copy-pasting the code each time I have to deal >> with unique constraints, and is trouble in case there is more than one >> unique index. *Is there any built-in component that will parse the >> MySQL/PostgreSQL/whatever error message and tell me "hey you violated this >> and this constraint"?* >> > -- You received this message because you are subscribed to the Google Groups "doctrine-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. Visit this group at http://groups.google.com/group/doctrine-user. For more options, visit https://groups.google.com/groups/opt_out.
