laravel-mongodb
laravel-mongodb copied to clipboard
Database Transactions not working
Hello everyone, i stumbled on this issue today:
When i try to use laravel's transactions like this
DB::transaction(function() use($data) {
$this->repository->create($data);
});
I get the following:
Call to a member function beginTransaction() on null
/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:108
/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:92
/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:23
/vendor/laravel/framework/src/Illuminate/Database/DatabaseManager.php:327
/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:221
I'm using laravel 5.4 and php version 7.1.
Is there any workaround for this issue?
This package is helping me out a lot with my personal project and i guess there is no other option for laravel and mongodb, so anything that solves it will do for me i guess.
I'm having the same issue and can't seem to find a solution.
Mongodb not support transactions. It has another logic for this. Check https://docs.mongodb.com/manual/tutorial/perform-two-phase-commits/
MongoDB 4.0 now supports multi-document transactions.
@jenssegers Any chance to have transactions working here? Let me know if you need help.
Any update on this @jenssegers ?
This would be another excellent feature of the package!
Any update on this @jenssegers ?
use DB::connection('mongodb')->getMongoClient() to access original MongoDB\Driver and use DB::connection('mongodb')->getMongoClient()->startSession() to create a session and then start a transaction.
DB::connection('mongodb')->getMongoClient()->startSession() does not work, even i use getDatabase method. but dont have this function.
got any idea two collection if got error, rollback the data.
mongo transaction is a little different from mysql. you need to create a session first, and pass this session as a option when you do update.
@ycgambo How to create a session and pass the session as option by using laravel-mongodb ?
I got it working like this
$session = DB::getMongoClient()->startSession();
$session->startTransaction();
try {
// Perform actions.
$session->commitTransaction();
} catch(Exception $e) {
$session->abortTransaction();
}
As answered here
I got it working like this
$session = DB::getMongoClient()->startSession(); $session->startTransaction(); try { // Perform actions. $session->commitTransaction(); } catch(Exception $e) { $session->abortTransaction(); }As answered here
it's not working for me is any ideal ,i was wrong?
here is my code
$book = $this->model->find(1);
$session = DB::getMongoClient()->startSession();
$session->startTransaction();
try {
$this->repository->updateBook($book, $attributes);
//testing when error
throw \Exception('db error testing');
// Perform actions.
$session->commitTransaction();
} catch(Exception $e) {
$session->abortTransaction();
dd($e->getMessage());
}
Repository
public function updateBook($book, array $attributes)
{
return $book->update($attributes);
}
it response 'db error testing' string, but my mongoDB didn't rollback.
thanks a lot
pass this session as a option when you do update.
$session = MongoDB::startSession();
$session->startTransaction();
try {
Player::document()->update($updates, ['session' => $session]);
$session->commitTransaction();
return true;
} catch (\Exception $e) {
$session->abortTransaction();
return false;
}
From the MongoDB documentation
To associate read and write operations with a transaction, you must pass the session to each operation in the transaction. For examples, see Transactions in Applications.
This is needed to be done internally by the author.
pass this session as a option when you do update.
$session = MongoDB::startSession(); $session->startTransaction(); try { Player::document()->update($updates, ['session' => $session]); $session->commitTransaction(); return true; } catch (\Exception $e) { $session->abortTransaction(); return false; }
@salalaslam @ycgambo Thanks for replying,But It still not work My MongoDB did not rollback how can i fix it ?
here is my code
$book = $this->model->find(1);
$session = DB::getMongoClient()->startSession();
$session->startTransaction();
try {
//update bookmark
$result = $this->repository->updateBook($book, $attributes, $session);
throw new \Exception('db error');
$session->commitTransaction();
} catch (\Exception $e) {
$session->abortTransaction();
dd($e->getMessage());
}
Repository
public function updateBook($book, array $attributes, $session)
{
return $book->update($attributes, ['session' => $session]);
}
The same problem with my transaction is not supported @leoku7020 Did you find any solution for that?
@rahamanh939 Sry , I don't have any idea
@leoku7020 you should do update on the mongo document object (not the model)
@ycgambo Can you give us an example.
$mongoClient = DB::connection('mongodb')->getMongoClient(); $session = $mongoClient->startSession(); try { $mongoClient->{data_base_name}->{collection_name}->deleteMany(['type' => $this->service::ROUND_NUMBER_SIMILAR]); $mongoClient->{data_base_name}->{collection_name}->insertMany($roundNumbers); $session->commitTransaction(); } catch (\Exception $e) { $session->abortTransaction(); $success = false; }
Hallo, im have a problem with abortTransaction if insert 2 table
$session = DB::connection('mongodb')->getMongoClient()->startSession();
$session->startTransaction();
try {
DB::connection('mongodb')->collection('table1')->insert($data1);
DB::connection('mongodb')->collection('table2')->insert($data2); // failed insert
$session->commitTransaction();
return true;
} catch (\Exception $e) {
$session->abortTransaction();
return false;
}
in my case the first data still entered into table1 not aborted, but table2 data not entered can help me ?
$mongoClient = DB::connection('mongodb')->getMongoClient(); $session = $mongoClient->startSession(); try { $mongoClient->{data_base_name}->{collection_name}->deleteMany(['type' => $this->service::ROUND_NUMBER_SIMILAR]); $mongoClient->{data_base_name}->{collection_name}->insertMany($roundNumbers); $session->commitTransaction(); } catch (\Exception $e) { $session->abortTransaction(); $success = false; }
Does it work?
pass this session as a option when you do update.
$session = MongoDB::startSession(); $session->startTransaction(); try { Player::document()->update($updates, ['session' => $session]); $session->commitTransaction(); return true; } catch (\Exception $e) { $session->abortTransaction(); return false; }
How About create method?
@masssoud Just use the empty array [] for option $session->startTransaction([]);
PR with implementation https://github.com/jenssegers/laravel-mongodb/pull/1904
It would be great to have this functions working on this package.
So, I've been doing some tests about transactions using Laravel 8 and this package and I noted some things.
First of all: Anyone, wherever you are, whatever you do, (if you're reading this too) transactions never gonna work if you have not previously configured your mongod to run as a standalone replica or with a sets of replicas.
This is super important, and it's a requirement that not should be overlooked (self experience).
Then:
1- I've been noticed that transactions work, but only if they run over MongoDB native functions and not over Laravel models.
Example: User::create($data); will always run, even if you are using the session on this way User::create($data, ['session' => $session]);
After execute: $session->abortTransaction(); the User will be populated to database anyway.
2- When I used it as this way, the transactions control worked as expected:
$collection = $client->{database_name}->{collection_name};
$collection->insertOne($data, ['session' => $session]);
After $session->abortTransaction(); the changes was not made.
After $session->commitTransaction(); changes was made.
3- The horrible thing about this, on this moment, is that you can't create (or at least IDK how to do it) a model with all they fields as timestamps and so on, the others useful things offers by a Laravel Model.
In this way (hypothetical example): $collection->insertOne($data, ['session' => $session]); the array will be saved on they exact form.
4- The other thing (and the only one I think) that I asking for is to get available (and working of course) in this package the Laravel functions as DB::beginTransaction(), DB::commit(), DB::rollBack(), etc... And also, of course, the native Model functions as create, update, remove, etc...
As this functions won't work right now in none of its variants. Or at least I've not been able to make them work (using transactions).
5- If someone has solved this issue (but really solved, with an strongly approach), it would be helpful if could share the solution.
6- If anyone has doubts about my (super long) speech and need more info about it, don't hesitate to contact me or even comment right here, as I think this is not solved yet.
Finally, this is an example of my coding testing ( having a previous $input = $request->all(); by example )
$client = DB::connection('mongodb')->getMongoClient();
$session = $client->startSession();
$session->startTransaction([]);
$collection = $client->administration_schema->users;
$collection->insertOne($input, ['session' => $session]);
// $session->commitTransaction(); // Use it to save your data
$session->abortTransaction(); // You know what it means
$session = DB::connection('mongodb')->getMongoClient()->startSession();
$session->startTransaction();
try {
DB::connection('mongodb')->collection('table1')->updateMany($data1);
$session->commitTransaction();
return true;
} catch (\Exception $e) {
$session->abortTransaction();
return false;
}
MongoDB\Driver\Exception\RuntimeException
Multi-document transactions are not supported by this server version
I get the error like this, please help me
Laravel 8 and "jenssegers/mongodb": "^3.8.0"
$session = DB::connection('mongodb')->getMongoClient()->startSession(); $session->startTransaction(); try { DB::connection('mongodb')->collection('table1')->updateMany($data1); $session->commitTransaction(); return true; } catch (\Exception $e) { $session->abortTransaction(); return false; }MongoDB\Driver\Exception\RuntimeException Multi-document transactions are not supported by this server versionI get the error like this, please help me
Laravel 8 and "jenssegers/mongodb": "^3.8.0"
Hello,
Let me guess, you're using one server? MongoDB transactions does work only with replica sets and sharded clusters.
Thanks!
@divine you are right, thank you.
$input = ['name' => 'aaa', 'status' => 2];
$client = DB::connection('rep')->getMongoClient();
/**@var $session Session */
$session = $client->startSession();
$session->startTransaction([]);
/**@var $collection \MongoDB\Collection */
$collection = $client->test->avatar;
$collection->insertOne($input, ['session' => $session]);
// $session->commitTransaction(); // Use it to save your data
/**@var $user \MongoDB\Collection */
$user = $client->test->user;
$user->updateOne(['age' => 30], ['$set' => ['name' => 'cccc']], ['session' => $session]);
// $session->abortTransaction(); // You know what it means $session->commitTransaction();
database.php
connections => [ 'rep' => [ 'driver' => 'mongodb', 'dsn' => 'mongodb://1.cn:27017,1.cn:27018,1.cn:27019/?replicaSet=mongo_clus' , 'database' => env('MONGO_DB_DATABASE', 'test'), ],
]
it works
@klferreira
I think you would need to change it to:
\DB::beginTransaction(); try { $this->repository->create($data); \DB::commit(); } catch (\Exception $e) { \DB::rollback(); }
Unfortunately you must use the mongo driver syntax, you can't use model eloquent methods, and you must also always pass ['session' => $session] as an option
@fidan-mkdir It seems to be included in the eloquent with jessengers and it seems to work properly with beginTransaction/commit/rollback I tested it with it and transaction seems to be working good.

Just a friendly reminder. If you have multiple database connection, make sure you define it first before you initialize transaction. File : config/database.php
...
'connections' => [
...
'mongodb' => [
// Your mongo db config
]
]
...
Then, you can use @salalaslam's answer
File : app/Controllers/YourController.php
$session = DB::connection('mongodb')->getMongoClient()->startSession();
$session->startTransaction();
try {
// Perform actions.
$session->commitTransaction();
} catch(Exception $e) {
$session->abortTransaction();
}
hello i have issue its not working for me controller: ` $session = DB::connection('mongodb')->getMongoClient()->startSession(); $session->startTransaction(); try {
$db = UserWebsite::create([
'userID' => $dbUser->id,
'categoryID' => $dbCategory->id,
'name' => $request->name,
'website' => $request->website,
'favIcon' => $request->favIcon,
'resourcePath' => null,
'isDelete' => false,
]);
$result = $this->createDirectoryResource2($db->id);
$db->resourcePath = $result;
$db->save();
$session->commitTransaction();
return generateJsonResponse::simpleJson($db , 200 , Environment::storeSuccess);
}catch (\Exception $exception){
$session->abortTransaction();
return generateJsonResponse::simpleJson(null , 500 , $exception->getMessage());
return generateJsonResponse::simpleJson(null , 500 , Environment::storeResponse500);
}
config:
'connections' => [
'mongodb' => [
'driver' => 'mongodb',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', 27017),
'database' => env('DB_DATABASE'),
'username' => env('DB_USERNAME'),
'password' => env('DB_PASSWORD'),
'options' => [
'database' => env('DB_AUTHENTICATION_DATABASE', 'admin'), // required with Mongo 3+
],
],
`
can anyone help me
@julio-mesa Hi, how are you doing? I couldn't get this method to work. I'm getting Call to a member function beginTransaction() on null. Is there something I'm doing wrong?
@julio-mesa Hi, how are you doing? I couldn't get this method to work. I'm getting
Call to a member function beginTransaction() on null. Is there something I'm doing wrong?
MongoDB transactions will only take effect under the replica set architecture
@klferreira
I think you would need to change it to:
\DB::beginTransaction(); try { $this->repository->create($data); \DB::commit(); } catch (\Exception $e) { \DB::rollback(); }
@Justniceone Thanks for your response. I was asking in response to this format. It's really concise and smooth but it gives it this error unless the error is due to the fact its not a replica set. I just think the format is not working for me
@salvationarinze I could be wrong, but the change @julio-mesa is mentioning doesn't seem to be in the main repo, but in a fork. It has a pending pull request...
https://github.com/jenssegers/laravel-mongodb/pull/1904 https://github.com/jenssegers/laravel-mongodb/blob/041d02bbafe71778fb1db8c44cedad32c9a759e6/src/Jenssegers/Mongodb/Connection.php
@alanglaisA4 I really appreciate the information. Thank you so much. In order to use this feature, is it recommended to use the fork directly or do I just stick with traditional method? What do you think?