resetting CDbConnection in Yii - php

I am running a php gearman worker which establishes the connection to the database. However, the problem is that after around 8 hours, the mysql connection disconnects, and my worker crashes. So, I wanted to disconnect and make a new connection to the database again.
I am using CDbConnection to connect to the database in Yii, and was expecting "setActive(false)" to do the trick for me. Here below I am "explicitly disconnecting" and the making a db query....expecting my query to throw an exception, but I am surprised to see that "setActive" makes no impact at all and my query goes successfully.
//if it fails then reconnect to the database
Yii::app()->db->setActive(false);
try {
$model = MyModel::model()->findByPk(10);
var_dump($model);
} catch (exception $e) {
echo "got exception -- ".$e->getMessage()."\n";
Yii::app()->db->setActive(false);
Yii::app()->db->setActive(true);
// I also tried Yii::app()->db->active = true/false
$model = MyModel::model()->findByPk(10);
var_dump($model);
}
How do I disconnect and reconnect to my database with CdbConnection?

Try looking in the trace log, I'm pretty sure it actually closes the connection, but then reopens it in CDbConnection->createCommand() when you execute a query.

Related

Laravel 5.1 - Checking a Database Connection

I am trying to check if a database is connected in Laravel.
I've looked around the documentation and can't find anything. The closest thing I've found is this, but this doesn't solve my problem.
I have three instances of MySQL that are set up on different machines. Below is a simplified version of what I am trying to achieve.
If database 1 is connected, save data to it
If database 1 is not connected, check if database 2 is connected
If database 2 is connected save data to it
If database 2 is not connected, check if database 3 is connected
If database 3 is connected, save data to it
To be clear, is there a way to check that a database is connected in Laravel 5.1?
Try just getting the underlying PDO instance. If that fails, then Laravel was unable to connect to the database!
use Illuminate\Support\Facades\DB;
// Test database connection
try {
DB::connection()->getPdo();
} catch (\Exception $e) {
die("Could not connect to the database. Please check your configuration. error:" . $e );
}
You can use alexw's solution with the Artisan. Run following commands in the command line.
php artisan tinker
DB::connection()->getPdo();
If connection is OK, you should see
CONNECTION_STATUS: "Connection OK; waiting to send.",
near the end of the response.
You can use this, in a controller method or in an inline function of a route:
use Illuminate\Support\Facades\DB;
//....
try {
DB::connection()->getPdo();
if(DB::connection()->getDatabaseName()){
echo "Yes! Successfully connected to the DB: " . DB::connection()->getDatabaseName();
}else{
die("Could not find the database. Please check your configuration.");
}
} catch (\Exception $e) {
die("Could not open connection to database server. Please check your configuration.");
}
You can also run this:
php artisan migrate:status
It makes a db connection connection to get migrations from migrations table. It'll throw an exception if the connection fails.
You can use this query for checking database connection in laravel:
use Illuminate\Support\Facades\DB;
// ...
$pdo = DB::connection()->getPdo();
if($pdo)
{
echo "Connected successfully to database ".DB::connection()->getDatabaseName();
} else {
echo "You are not connected to database";
}
For more information, you can check out this page https://laravel.com/docs/5.0/database.
I don't know if this worked in that version of laravel, but at least on newer ones you can run
php artisan db
and if your app can access the database then you should see a cli repl for it, for postgres you will see a psql instance
Another Approach:
When Laravel tries to connect to database, if the connection fails or if it finds any errors it will return a PDOException error. We can catch this error and redirect the action
Add the following code in the app/filtes.php file.
App::error(function(PDOException $exception)
{
Log::error("Error connecting to database: ".$exception->getMessage());
return "Error connecting to database";
});
Hope this is helpful.

Laravel handle nested exceptions and keep going

I have a question regarding PHP's way to handle exceptions and Laravel 5.
Here's a snippet of what I'm trying to accomplish
try
{
//set up webservices
saveData();
} catch(exception $e)
{
Log:error('stuff went bananas')
}
saveData(){
//record stuff through DB with eloquent
//in case some data is missing connect to a second DB
try
{
connect()
query to get data
}catch(exception $e)
{
//log error again
}
In other words, I'm calling webservices that receive data. I'm then inserting these into my own DB inside the Model.
At this stage I'm trying to see if I know the user ID that I just received. In case I don't I have to connect to a second database to request that same user.
There are two issues though
the second database I'm trying to connect isn't likely to be up
it will often not hold the information I need (I have to try again the next day)
There's nothing I can do against these issues. But what I want is for my code to try and connect, and in case it fails, log the errors and keep moving inserting the data.
Thanks in advance.

PHP OCI: how to roll back ANY open connections

I'm using PHP's OCI library to communicate with Oracle. In every function there is a try...catch to catch any exceptions. In the catch part I call my own error handling function.
When an exception occurs I want to rollback ALL open connections to oracle, preferably in my error handling function. Is this possible?
Thanks
#
#
It's a bit hacky, but here's how I solved the problem.
In my connect() function which connects to Oracle, I put this code:
if(!isset($GLOBALS['OPEN_CONNECTIONS'])){
$GLOBALS['OPEN_CONNECTIONS'] = array();
$GLOBALS['OPEN_CONNECTIONS'][] = $this;
}else{
$GLOBALS['OPEN_CONNECTIONS'][] = $this;
}
This stores a list of all open connections in the global scope.
In my error handling function, I do this:
//rollback all open connections
if(isset($GLOBALS['OPEN_CONNECTIONS'])){
foreach($GLOBALS['OPEN_CONNECTIONS'] as $con){
$con->rollback();
}
}
This way, I can rollback all open connections without having to pass them into my error handler.

How to treat Database_Exception with Kohana 3 ORM

Here is the problem
There is a script that after X amount of time (unknown amount between 5 and 40 minutes) throws the following error: MySQL server has gone away which Kohana turns into a Database_Exception 2006 As a result some of the information is not saved to the DB.
Here is what I think might work
class Model_Bar extends ORM {
protected $_belongs_to = array(
'foo' => array()
);
public function save(){ //Extends the save method
try {
$result = parent::save(); //Try parent save
} catch (Database_Exception $e) { //Catch exception
if ($e->getCode() == 2006) { //If exception code == 2006 then DB has gone away
mysqli_ping(); //Try to refresh DB link
$result = parent::save(); //Try parent save again
} else { //Exception code != 2006
throw new Exception($e); //Throw new DB exception
}
}
return $result; // Return the result from parent::save()
}
}
The Question: How can I refresh the link to the DB in Kohana's ORM?
More Info:
Using Kohana 3.0.8
Possible solution (I dont know how to try it in Kohana)
Thanks!
That's a problem of either
Reached the MYSQL configured timeout
Exceeded packet size
Loss of packets
If you are executing a long insert, like a bulk insert, if your DB isn't configured for that, no change in your code will have any effect. You may try to reconfigure your MYSQL instance, then rule out the MYSQL blame, then after you try to amend your code (which I doubt is the source of the problem). Retrying saving won't help much, but to make the DB even busier.
Another thing, if you are using a proxy (like HAProxy), check the timeouts on that as well.

Why the following PDO transaction is committing?

I think the question itself is pretty self-explanatory. The code is given below -
<?php
$PDO = NULL;
$pdo_dsn = 'mysql:host=localhost;dbname=pdo_test';
$pdo_persistence = array( PDO::ATTR_PERSISTENT => true );
$db_user = 'root';
$db_pass = '';
$db_query = "INSERT INTO person(name, address)
VALUES ('Mamsi Mamsi', 'Katabon')";
try
{
$PDO = new PDO($pdo_dsn, $db_user, $db_pass,
$pdo_persistence);
}
catch(PDOException $e)
{
echo "Error occured: ". $e->getMessage();
die();
}
$PDO->setAttribute(PDO::ATTR_ERRMODE,
PDO::ERRMODE_EXCEPTION);
$PDO->setAttribute(PDO::ATTR_AUTOCOMMIT, false);
try
{
$PDO->beginTransaction();
$PDO->exec($db_query);
throw new PDOException('Generated Exception');
$PDO->commit();
}
catch(PDOException $e)
{
echo "An error occured while doing a database transaction. The
error message is : ".$e->getMessage();
$PDO->rollBack();
die();
}
?>
Even if I am rolling back the transaction inside the catch block, data are still being inserted into the database. Why?
EDIT
I am adding the following few lines from the documentation for further clarification -
Unfortunately, not every database supports transactions, so PDO needs
to run in what is known as "auto-commit" mode when you first open the
connection. Auto-commit mode means that every query that you run has
its own implicit transaction, if the database supports it, or no
transaction if the database doesn't support transactions. If you need
a transaction, you must use the PDO::beginTransaction() method to
initiate one. If the underlying driver does not support transactions,
a PDOException will be thrown (regardless of your error handling
settings: this is always a serious error condition). Once you are in
a transaction, you may use PDO::commit() or PDO::rollBack() to finish
it, depending on the success of the code you run during the
transaction.
Also, the following lines from this page -
bool PDO::beginTransaction ( void )
Turns off autocommit mode. While autocommit mode is turned off,
changes made to the database via the PDO object instance are not
committed until you end the transaction by calling PDO::commit().
Calling PDO::rollBack() will roll back all changes to the database
and return the connection to autocommit mode.
Some databases, including MySQL, automatically issue an implicit
COMMIT when a database definition language (DDL) statement such as
DROP TABLE or CREATE TABLE is issued within a transaction. The
implicit COMMIT will prevent you from rolling back any other changes
within the transaction boundary.
You should check that you are using INNODB as your database type. MyISAM does not support transactions.

Categories