-
-
Notifications
You must be signed in to change notification settings - Fork 20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rfc: better transaction disposing mechanism #52
Comments
not sure if amphp/mysql suffers from this issue as well, as i have been mostly playing around with amphp/postgres lately, though, i would assume it does. |
IMO, the example should be processing the user list and updating it within the callback given to transactional, otherwise why was the SELECT query performed in a transaction at all? This makes me favor option 1 as that would prevent such misuse. |
This is just an example, |
A service would not commit a transaction. For the service query to be executed within the context of a transaction, the Using a |
That doesn't have to be the case, e.g: using the service could look like this: use Neu\Database\DatabaseInterface;
final class SomeService
{
public function __construct(
private readonly DatabaseInterface $database,
) {}
/**
* @return iterable<User>
*/
public function fetchAllAdmins(): iterable
{
return $this->database->transactional(function($transaction): iterable {
foreach($transaction->fetchAll('users', ['role' => User::ROLE_ADMIN]) as $data) {
if ($this->isStillUsingRawPassword($data)) {
$this->hashPassword($transaction, $data);
}
yield User::fromArray($data);
}
});
}
} |
and this is a proof that solution 2 doesn't work :), i agree on going with 1, with a clear error message ( on where the commit()/rollback() happened that resulted in the dispose() of the result set ) |
while working on #50, i noticed a weird behavior within the library.
a query cannot be executed ( on the same connection ), unless all handles related to a specific transaction are released, however, the library doesn't offer a way to force release all handles.
Let's take the following example:
so far so good, we have a function that given a database link, and an operation, will execute the operation within a transaction, and return it's results.
however, let's take this a step further, simulating a more real-world usage of
transactional
function.here, we get the list of our forum admins, iterator over them, and if one of them admin has not been active, we warn them that their account is going demoted next week, if the have been warned over a week ago, we demote their account to super users.
However, this currently fails.
Since
$users
is a result set, this result set still has a reference to a handle that is associated with the transaction used to retrieve the users, while arguably the initial query shouldn't have been made within a transaction, remember that this is just an example.What i suggest is the following:
if a transaction has been rolled-back, or committed, all handles should be force released, this can be done in one of the following ways:
$users
needs a reference to the handle in order to fetch users while iterating, however, when a commit() or a rollback() is executed, we can force the result to fetch all users immediately, making it drop the reference to the handle, and still be valid.I personally prefer the second solution, while it might be bad for memory when dealing with large queries, it is the most sane behavior in my opinion, as if the user is holding a reference to that object, they are probably still going to use it, if not, they can manually call
dispose()
on the result.The text was updated successfully, but these errors were encountered: