cphalcon icon indicating copy to clipboard operation
cphalcon copied to clipboard

[BUG]: Transaction manager does not create a new transaction after first commit

Open serge-webspark opened this issue 2 years ago • 4 comments

Hi there! I am trying to figure out the transaction manager flow. In the documentation, I see that the manager should always return the active transaction (https://docs.phalcon.io/5.6/db-models-transactions/#dependency-injection), but in my case, I always receive the same transaction even after the commit. The transactional mode works only until the first commit or rollback, all future commits and rollbacks will not work because the "active" transaction is not under actual DB transaction. Please explain the behavior.

        // Inside controller action
        $user = Users::findFirst(173431);
        $transactionManager = $this->di->get('transactionManager');

        $transactionManager->get(true);
        $user->balance = 10;
        $user->save();
        $transactionManager->commit(); // Successful commit, balance changed to 10

        $transactionManager->get(true);
        $user->balance = 20;
        $user->save();
        $transactionManager->rollback(); // Rollback has no effect, the balance changed to 20

Expected behavior Here I expect that when I call the $transactionManager->get(true) I will receive an active DB transaction with autobegin so I can use the transactional mode in the loop. In my code example I want rollback to cancel the last save so the user balance will be 10.

Details

  • Phalcon version: 5.3.0
phalcon => enabled
Author => Phalcon Team and contributors
Version => 5.3.0
Build Date => Dec 14 2023 01:13:10
Powered by Zephir => Version 0.17.0-9f99da6
Directive => Local Value => Master Value
phalcon.db.escape_identifiers => On => On
phalcon.db.force_casting => Off => Off
phalcon.orm.case_insensitive_column_map => Off => Off
phalcon.orm.cast_last_insert_id_to_int => Off => Off
phalcon.orm.cast_on_hydrate => Off => Off
phalcon.orm.column_renaming => On => On
phalcon.orm.disable_assign_setters => On => On
phalcon.orm.enable_implicit_joins => On => On
phalcon.orm.enable_literals => On => On
phalcon.orm.events => On => On
phalcon.orm.exception_on_failed_save => Off => Off
phalcon.orm.exception_on_failed_metadata_save => On => On
phalcon.orm.ignore_unknown_columns => Off => Off
phalcon.orm.late_state_binding => Off => Off
phalcon.orm.not_null_validations => On => On
phalcon.orm.resultset_prefetch_records => 0 => 0
phalcon.orm.update_snapshot_on_save => On => On
phalcon.orm.virtual_foreign_keys => On => On
phalcon.orm.dynamic_update => On => On
phalcon.warning.enable => On => On
  • PHP Version: 8.1.20
  • Operating System: Debian GNU/Linux 10
  • Installation type: installing via package manager
  • Server: Nginx
  • Other related info (Database, table schema): MySQL 5.7

serge-webspark avatar Jan 30 '24 16:01 serge-webspark

Stupid questions since I haven't worked with transaction handling in Phalcon in a long time...

Does the find() need to be inside the transaction for the transaction to work on the $user object?

kgrammer avatar Jan 30 '24 16:01 kgrammer

Not necessarily, more important is the part where we execute actual DB queries. The same behavior with plain queries:

        $transactionManager = $this->di->get('transactionManager');

        $transactionManager->get(true);
        $this->db->execute('update users set balance = 10 where id = 1');
        $transactionManager->commit();

        $transactionManager->get(true);
        $this->db->execute('update users set balance = 20 where id = 1');
        $transactionManager->rollback(); // Rollback has no effect, the balance changed to 20

serge-webspark avatar Jan 30 '24 17:01 serge-webspark

I need to write a test for this. I see a potential issue with the commit() but need to verify

niden avatar Jan 30 '24 17:01 niden

It works for the transaction received from the transaction manager

        $user = Users::findFirst(173431);
        $transactionManager = $this->di->get('transactionManager');

        $transaction = $transactionManager->get(true);
        $user->balance = 10;
        $user->save();
        $transaction->commit(); // Successful commit, balance changed to 10

        $transaction = $transactionManager->get(true);
        $user->balance = 20;
        $user->save();
        $transaction->rollback(); // Successful rollback, balance stays the same (10)

but it would be nice if the manager could properly commit and rollback.

serge-webspark avatar Jan 31 '24 14:01 serge-webspark