LOCK TABLES inside TRANSACTION does not ROLLBACK - mysql

I have a problem and it is that I need to lock tables within a transaction to prevent data from being inserted into it, but when I do this when I have an error the transaction rollback does not work.
I read in mysql articles that table locks break a transaction, but is there any other way to lock tables to prevent data from being inserted into it temporarily?
https://dev.mysql.com/doc/refman/8.0/en/lock-tables.html
try {
DB::beginTransaction();
DB::unprepared('LOCK TABLES table_name WRITE');
//
DB::unprepared('UNLOCK TABLES');
DB::commit();
} catch (\Exception $e){
DB::rollBack();
}

You can lock the tables in the outer scope, outside of the transaction.
Then, your example code would look like:
try
{
DB::unprepared('LOCK TABLES table_name WRITE');
try
{
DB::beginTransaction();
//...
DB::commit();
}
catch (\Exception $e)
{
DB::rollBack();
}
}
finally
{
DB::unprepared('UNLOCK TABLES');
}

Related

Laravel getQueryLog not print if query was executed as a transaction

Currently I'm testing a execution of a query using laravel 5.4.
I'm trying to print is a query was executed on a transaction, for example:
\DB::enableQueryLog();
try {
\DB::beginTransaction();
$item = new Item();
$item->name = 'some name';
// ...
$item->save();
\DB::commit();
dump(\DB::getQueryLog());
} catch (\Exception $e) {
But query log only show the information of the sql statement, but not tells me complete transaction sql:
I want to print the execution with the transaction.

Execute second statement only after the first statement finished

From mysql table at first want to delete row. Only after the row deleted, i want to select sum(certain_column). Want to be sure that until row deleted, i do not execute select.
Decided to use such code like this:
try{
$db->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
$db->beginTransaction();
try{
$stmt_delete = $db->prepare('DELETE FROM `table` WHERE `Id` = 1;');
$stmt_delete_items->execute( );
}
catch (PDOException $e){
echo "DataBase Error: " .htmlspecialchars( $e->getMessage() , ENT_QUOTES, "UTF-8").'<br>';
$db->rollBack();
exit;
}
try{
$stmt_select = $db->prepare('SELECT SUM(`Quantity`) AS `SumQuantity` FROM `table` WHERE `some_column` = 234;');
$stmt_select->execute( );
$arr_select = $stmt_select->fetchAll(PDO::FETCH_ASSOC);
}
catch (PDOException $e){
echo "DataBase Error: " .htmlspecialchars( $e->getMessage() , ENT_QUOTES, "UTF-8").'<br>';
}
$db->commit();
}
Expecting at first execute $stmt_delete and only then $stmt_select. In usual case i get such execution order. But is it guaranteed 100%? Somewhere read that delete may take more time than select... with exit; i prevent next execution only in case of error. But i need to delay $stmt_select until $stmt_delete.
Or may be better to use START TRANSACTION; ... COMMIT;. Or may be for DELETE to use LOCK TABLES ... UNLOCK TABLES.
Please advice solution to be 100% sure that select executes only after delete is finished.

Eloquent delete and MySQL foreign key cascade

I have these tables in MySQL database:
users['id', 'name'],
roles['id', 'title'] and
user_role ['user_id', 'role_id'] where both are foreign keys, CASCADE.
When it catches an exception the user remains in the table as wanted, while the row from the relation table is deleted.
try{
$user->delete();
}
catch (\Exception $e){
throw new \Dingo\Api\Exception\DeleteResourceFailedException('Error.');
}
Is this eloquent's mistake?
Now, I figured out a way to fix this but I'm not sure that it's the best practise. Is there a better way to do it?
try{
$roleId = $user->roles[0]->id;
$user->delete();
}
catch (\Exception $e){
$user->roles()->attach($roleId);
throw new \Dingo\Api\Exception\DeleteResourceFailedException('Error.');
}
If i understood your question, transactions are what you need.
Database Transactions
DB::transaction(function () {
$user->delete();
});
and in case you face a deadlock use this one
DB::transaction(function () {
$user->delete();
},5);

How to handle Integrity constraint violation on delete?

I have rows, which some rows can't be delete because it referenced to other table, and the other can be delete.
What I want is delete rows which can be delete and leave the other rows which can't be delete
so far my code is
$tkota = TbKota::find()->all();
foreach($tkota as $kota){
if($kota->delete()){
echo "del success<br/>";
}else{
echo "fail ".$kota['api_id']."<br/>";
}
}
my above code produce this error
SQLSTATE[23503]: Foreign key violation: 7 ERROR: update or delete on table "tb_kota" violates foreign key constraint "fk_tb_produ_reference_tb_kota" on table "tb_produk_ekspedisi_by_vendor"
DETAIL: Key (kota_id)=(1771) is still referenced from table "tb_produk_ekspedisi_by_vendor".
The SQL being executed was: DELETE FROM "tb_kota" WHERE "kota_id"=1771
instead of show success when record deleted and show fail if record can't be delete.
what's wrong with my code?
thanks in advance.
This one will be better
use yii\db\IntegrityException;
use yii\web\NotFoundHttpException;
foreach($tkota as $kota){
$connection = \Yii::$app->db;
$transaction = $connection->beginTransaction();
try {
$kota->delete();
$transaction->commit();
return $this->redirect(['user/view', 'id' => $model->id]);
}catch (IntegrityException $e) {
$transaction->rollBack();
throw new \yii\web\HttpException(500,"YOUR MESSAGE.", 405);
}catch (\Exception $e) {
$transaction->rollBack();
throw new \yii\web\HttpException(500,"YOUR MESSAGE", 405);
}
}
foreach($tkota as $kota){
try {
if($kota->delete()){
echo "del success<br/>";
}
} catch (\Exception $e) {
echo "fail ".$kota['api_id']."<br/>";
}
}

KO3, PostgreSQL, Transactions, and PDOException

I've run into an issue that I'm hoping to get a little help on. I'm using the following:
Kohana 3.0.7
PostgreSQL 8.4
Transactions in PostgreSQL using
$db->query(NULL, 'BEGIN', FALSE)
$db->query(NULL, 'ROLLBACK', FALSE);
$db->query(NULL, 'COMMIT', FALSE);
The issue is that when I send a query to the database that results in a postgres error within a transaction my system freezes up. When I send the same query to the database without wrapping it in a transaction the PDO error is reported back just as expected. Here is an exmaple:
This first example works fine and duplicate key value violates unique constraint "pk_test_table" error is returned:
$query = DB::query(Database::INSERT, 'INSERT INTO test_table (test_table_id, test_table_val) VALUES (:id, :value)';
$query->param(':id', 1);
$query->param(':value', "test value");
try
{
$result = $query->execute($db);
}
catch (Exception $e)
{
echo 'Caught exception: ', $e->getMessage(), "\n";
}
This second example causes my system to freeze (I can't tell if it's an infinite loop, or some other freeze):
$db->query(NULL, 'BEGIN', FALSE);
$query = DB::query(Database::INSERT, 'INSERT INTO test_table (test_table_id, test_table_val) VALUES (:id, :value)';
$query->param(':id', 1);
$query->param(':value', "test value");
try
{
$result = $query->execute($db);
}
catch (Exception $e)
{
echo 'Caught exception: ', $e->getMessage(), "\n";
}
$db->query(NULL, 'ROLLBACK', FALSE);
As you can see the only difference is that the second example is wrapped in a transaction.
Any ideas on what is going on? Any suggestions for things to try?
I found a way to work around the issue. Not sure if this is a bug in PDO or some other part of the tool set but what I'm doing to work around is the following:
$exception_exists = FALSE;
$db->query(NULL, 'BEGIN', FALSE);
$query = DB::query(Database::INSERT, 'INSERT INTO test_table (test_table_id, test_table_val) VALUES (:id, :value)';
$query->param(':id', 1);
$query->param(':value', "test value");
try
{
$result = $query->execute($db);
}
catch (Exception $e)
{
echo 'Caught exception: ', $e->getMessage(), "\n";
$exception_exists = TRUE;
}
if (!$exception_exists)
{
$db->query(NULL, 'ROLLBACK', FALSE);
}
By adding the variable $exception_exists in the catch I can then act of that if there is no exception. If there is an exception and I try to ROLLBACK or COMMIT then I get the freezing behavior.
This works for now but I wouldn't call it elegant.