Hi Keywan,

AFAIK there are no savepoints for nested transactions in Doctrine DBAL.
Could you provide more information about that?
(There are savepoints in Doctrine ORM (http://doctrine.readthedocs.io/en/latest/en/manual/transactions.html#savepoints), but that is a different story.)


"What this means is that transaction control is basically passed to code higher up in the call stack and the inner transaction block is ignored, with *one important exception that is described further below*. Do not confuse this with “real” nested transactions or savepoints. These are not supported by Doctrine. There is always only a single, real database transaction."

This one important exception is
"
However,*a rollback in a nested transaction block will always mark the current transaction so that the only possible outcome of the transaction is to be rolled back*.

That means in the above example, the rollback in the inner transaction block marks the whole transaction for rollback only. Even if the nested transaction block would not rethrow the exception, the transaction is marked for rollback only and the commit of the outer transaction would trigger an exception, leading to the final rollback.

This also means that *you can not successfully commit some changes in an outer transaction if an inner transaction block fails and issues a rollback*, even if this would be the desired behavior (i.e. because the nested operation is “optional” for the purpose of the outer transaction block).
"

http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html#transaction-nesting

Best regards

Robert


On 27.11.2017 23:37, Keywan Ghadami wrote:
Hi Thomas,

the situation described by you, if I got it right, is that a (payment) module likes to avoid the rollback of a transaction in case of error.

I would try to do so by overloading methods responsible for calling that rollback.
First thing came to my mind is to overload finalizeOrder in a way
it always true, even in case of error - so no rollback will happen if finalizeOrder will fail.

Theoretically you could also overload
 recalculateOrder completely without calling the parent ( that is of cause kind of evil and should be the very last option :-) ). So you could owerrite the error handling completely avoiding rollback in all cases.

If you know all the exceptions it could also be possible to catch them before they are causing the rollback. E.g. catch the email send error, log it and continue with order.

If you really have to write something to a database independently from the current transaction you could also start a new db connection. I normally would not do so because you need to think about resource locking and referenced data but you may have a case here where it's kind of legal to do so.

One note about nested transactions: To extend what robert has written I suggest to use savepoints in case you want to use a nested transaction within the payment module and that may cause itself exceptions and related rollbacks. That way it is possible to rollback to nested transaction without having to rollback the full outer transaction. Dbal is supporting savepoints by
$conn->beginTransaction('mysavepoint');
 and
$conn->rollback('mysavepoint');

which is pretty cool, isn't it ?

One note how to avoid errors during sending emails, even that usecase was only a example choosen by to point out that there could be errors during the order, my personal opinion is that each oxid server should have a local running postfix server that acts as a local mail queue. That way the shop can always send a email even if the network is down.

best regards

K1
[Your secret expert for high security, availablity and performance.]




From: "*Marco Steinhaeuser*" <marco.steinhaeu...@oxid-esales.com <mailto:marco.steinhaeu...@oxid-esales.com>>

    Date: Mon, Nov 27, 2017 at 6:06 PM +0100
    Subject: Re: Re-2: oxid V6 MySQL transactions
    To: "dev-general@lists.oxidforge.org
    <mailto:dev-general@lists.oxidforge.org>"
    <dev-general@lists.oxidforge.org
    <mailto:dev-general@lists.oxidforge.org>>


    Folks,

    could we please stick to English in this channel?

    Cheers!
    Marco



    -------- Ursprüngliche Nachricht --------
    Von: Robert Blank <robert.bl...@oxid-esales.com
    <mailto:robert.bl...@oxid-esales.com>>
    Datum: 27.11.17 17:54 (GMT+01:00)
    An: dev-general@lists.oxidforge.org
    <mailto:dev-general@lists.oxidforge.org>
    Betreff: Re: Re-2: oxid V6 MySQL transactions

    Hallo,

    Man kann in Doctrine leider das Rollback in verschachtelten
    Transaktionen nicht feinkörnig steuern, bzw kapseln: Wenn eine der
    inneren Transaktionen einen rollback macht, werden alle daran
    beteiligten Transaktionen (auch die äußeren!) zurück gerollt.

    
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html#transaction-nesting
    
<http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html#transaction-nesting>

    "To achieve that, you need to restructure your application logic
    so as to avoid nesting transaction blocks. If this is not possible
    because the nested transaction blocks are in a third-party API
    you’re out of luck."

    Da liegt m.E. der Pudels Kern. Durch das Modulsystem haben wir
    sozusagen diesen Fall der "third-party API", denn jedes Modul kann
    ja theoretisch ein ->rollbackTransaction() aufrufen und damit sind
    dann sowieso alle Möglichkeiten hinüber. Es wird ausdrücklich
    darauf hingewiesen nicht anzufangen kreativ zu programmieren:
    Directly
    invoking|PDO#beginTransaction()|,|PDO#commit()|or|PDO#rollBack()|or
    the corresponding methods on the
    particular|Doctrine\DBAL\Driver\Connection|instance in use
    bypasses the transparent transaction nesting that is provided
    by|Doctrine\DBAL\Connection|and can therefore corrupt the nesting
    level, causing errors with broken transaction boundaries that may
    be hard to debug.
    Das Rollback lässt sich ab diesem Moment nicht mehr überschreiben.

    Die einzige Garantie die das Framework hier geben kann und will
    ist "all or nothing".


    MfG

    Robert Blank


    P.S.

    "Zumal es völlig sinnfrei ist, eine Bestellung nur wegen einer
    nicht verschickbaren Mail komplett zu verwerfen."
    (+1)


    On 27.11.2017 16:34, oxid mailinglist wrote:
    Hallo,
    die Antwort ist für mich wirklich schwer zu akzeptieren.
    "We want really all database transactions to be rolled back, if a
    problem during e.g. the payment execution occurs."
    Es passiert eine payment transaktion! Wie soll auf so ein Fall
    korrekt reagiert werden?
    Beispiel: Eine Bestellung ist komplett durchgeführt inkl
    erfolgreiche Bezahlung per Paymentanbieter. Nun kann jedoch die
    Mail an den Kunden nicht geschickt werden. Es erfolgt ein
    komplettes rollback!

    Wie soll nun ein Paymentmodul korrekt darauf reagieren können? Es
    gibt keine transaktionslog-Infos mehr.
    Zumal es völlig sinnfrei ist, eine Bestellung nur wegen einer
    nicht verschickbaren Mail komplett zu verwerfen. Aber darum geht
    es gar nicht.

    Es gibt aktuell keine Möglichkeit auf ein rollback korrekt zu
    reagieren, da nicht überladbar.
    ->
    \OxidEsales\Eshop\Core\DatabaseProvider::getDb()->startTransaction();
    Es muss doch von OXID eine Möglichkeit geben auf so ein Ereignis
    korrekt reagieren zu können, ohne dass man die eigenen
    log/transaktions-Daten in Dateien abspeichern muss!

    Mit freundlichen Grüßen
    Thomas Dartsch
    thomas.dart...@shopmodule.com <mailto:thomas.dart...@shopmodule.com>

         Original Message processed by david®
                
        **

        *Re: oxid V6 MySQL transactions* (27-Nov-2017 16:00)
        *From:* Robert Blank <mailto:robert.bl...@oxid-esales.com>
        *To:*
                dev-general@lists.oxidforge.org
        <mailto:dev-general@lists.oxidforge.org>

        Hi,

        in your use-case this may sound strange, but this is by design.
        First by OXID eShop design:
        We want really _all_ database transactions to be rolled back,
        if a problem during e.g. the payment execution occurs.

        Then there is the design of the underlying DBAL:
        As we us Doctrine DBAL, we cannot provide savepoints or
        partial rollbacks, as Doctrine DBAL does not provide this
        functionality:
        
http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html#transaction-nesting
        
<http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/transactions.html#transaction-nesting>

        You should also not try to bypass this behavior as it will
        break the nested transaction handling of Doctrine.
        In you case I fear, there is no other way as to store your
        log data into a file.

        Best regards

        Robert Blank


        On 20.11.2017 15:13, oxid mailinglist wrote:
        Hello guys,
        with oxid Version 6.0 the shop is using MySQL transactions.
        -> https://dev.mysql.com/doc/refman/5.7/en/commit.html
        <https://dev.mysql.com/doc/refman/5.7/en/commit.html>
        For example this is used in
        OxidEsales\Eshop\Application\Model\Order::recalculateOrder
        (formally known as oxorder::recalculateOrder).
        
https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L1354
        
<https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L1354>

        In the process of Order::finalizeOrder, the
        PaymentGateway::executePayment() allows
        modules to perform module based validations.
        
https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L916
        
<https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L916>

        Some payment provider will create transactions and send it
        back to the shop.
        A module will be willing to save/log these transactions to
        the database.
        If there are a failed transaction and the module save his
        object via shop standard BaseModel::save()
        and the PaymentGateway::executePayment() return a false,
        the complete MySQL transaction will be ROLLBACK'ed.
        (Order::recalculateOrder())
        
https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L1374
        
<https://github.com/OXID-eSales/oxideshop_ce/blob/472ce3d73e5f0e46a29566f5290a85d631bd00db/source/Application/Model/Order.php#L1374>

        So the module lost all informations/transactions, which are
        saved during the transaction.
        How is oxid's suggestion to save these transactions from
        ROLLBACK?

        best regards
        Kristian Hempel

-- *
        *
        Richten Sie Fehlermeldungen und Supportanfragen bitte an
        supp...@shopmodule.com <mailto:supp...@shopmodule.com>.
        ------------------------------------------------------------------------
                Fresh ideas for your business   
        ------------------------------------------------------------------------

        D³ Data Development (Inh. Thomas Dartsch)
        Stollberger Straße 23
        
<https://maps.google.com/?q=Stollberger+Stra%C3%9Fe+23&entry=gmail&source=g>
        · D-09380 Thalheim
        Fon 03721 268090 · Fax 03721 265234
        Shop:   http://www.oxidmodule.com
        <http://www.oxidmodule.com/>      Firma:
        http://www.shopmodule.com <http://www.shopmodule.com/>
        Blog:   http://blog.oxidmodule.com
        <http://blog.oxidmodule.com/>     FAQ:
        http://faq.oxidmodule.com <http://faq.oxidmodule.com/>
                OXID eSales AG
        Certified Partner
        Business Level
                        Profihost AG
        Enterprise Partner


--

        *Robert Blank*
        Software Developer OXID Platform

        *robert.bl...@oxid-esales.com
        <mailto:robert.bl...@oxid-esales.com>*
        Fon +49 761 36889-233 <tel:+49%20761%2036889233>
        Fax +49 761 36889-29 <tel:+49%20761%203688929>
        *www.oxid-esales.com
        
<http://www.oxid-esales.com?campaign=emailsignatur/oxid-esales-com&adword=OXSIG_Startseite>*



        *OXID eSales AG*
        Bertoldstraße 48
        
<https://maps.google.com/?q=Bertoldstra%C3%9Fe+48+%0D+79098+Freiburg+%0D+Deutschland&entry=gmail&source=g>
        79098 Freiburg
        Deutschland

        Vorstand: Roland Fesenmayr (Vorsitzender), Dr. Oliver Ciupke
        Vorsitzender des Aufsichtsrats: Michael Schlenk, Sitz: Freiburg
        Amtsgericht Freiburg i. Br., HRB 701648, USt-IdNr.: DE231450866




--

    *Robert Blank*
    Software Developer OXID Platform

    *robert.bl...@oxid-esales.com <mailto:robert.bl...@oxid-esales.com>*
    Fon +49 761 36889-233 <tel:+49%20761%2036889233>
    Fax +49 761 36889-29 <tel:+49%20761%203688929>
    *www.oxid-esales.com
    
<http://www.oxid-esales.com?campaign=emailsignatur/oxid-esales-com&adword=OXSIG_Startseite>*



    *OXID eSales AG*
    Bertoldstraße 48
    
<https://maps.google.com/?q=Bertoldstra%C3%9Fe+48+%0D+79098+Freiburg+%0D+Deutschland&entry=gmail&source=g>
    79098 Freiburg
    Deutschland

    Vorstand: Roland Fesenmayr (Vorsitzender), Dr. Oliver Ciupke
    Vorsitzender des Aufsichtsrats: Michael Schlenk, Sitz: Freiburg
    Amtsgericht Freiburg i. Br., HRB 701648, USt-IdNr.: DE231450866





--
Robert Blank HTML-E-Mail-Signatur

*Robert Blank*
Software Developer OXID Platform

*robert.bl...@oxid-esales.com <mailto:robert.bl...@oxid-esales.com>*
Fon +49 761 36889-233
Fax +49 761 36889-29
*www.oxid-esales.com <http://www.oxid-esales.com?campaign=emailsignatur/oxid-esales-com&adword=OXSIG_Startseite>*


*OXID eSales AG*
Bertoldstraße 48
79098 Freiburg
Deutschland

Vorstand: Roland Fesenmayr (Vorsitzender), Dr. Oliver Ciupke
Vorsitzender des Aufsichtsrats: Michael Schlenk, Sitz: Freiburg
Amtsgericht Freiburg i. Br., HRB 701648, USt-IdNr.: DE231450866



Reply via email to