Oracle Multiple queries with locked row - php

I'm using ORACLE version 11g.
I would like to execute three queries "at the same time" and take care that if one or more of theses queries fails must return both tables to the previous state. These queries are one select to know if the selected row still being possible the make the action, and one update and one insert to do the action.
In my case I need to make an update on the same locked row (obviously no one else should be able to do the action to the same row) and later and insert on another table, only if the result of the select query confirm that the selected row still having the option to execute the action, so the queries will be like these approximately:
//this is the row I want to execute the action
$selectedIdFromTable1 = "1";
$query="SELECT attr1 FROM table1 WHERE attr1 = 'oldValueAttr1' AND id = selectedIdFromTable1";
$stmt = $this->oracleDB->prepare($query);
$stmt->bindValue(1, $attr1, "string");
$stmt->execute();
$result = $stmt->fetchColumn();
if($result->num_rows == 1){ //I'm still being able to do the action to the row because the row still having the oldValue
//So here the row must be locked to execute the update and the insert only once. Only one user should execute the update and the insert.
$query="UPDATE table1 SET attr1 = ? WHERE id == $selectedIdFromTable1";
$stmt = $this->oracleDB->prepare($query);
$stmt->bindValue(1, 'newValueAttr1', "string");
$stmt->execute();
$query="INSERT INTO table2 (attr2) VALUES (?)";
$stmt = $this->oracleDB->prepare($query);
$stmt->bindValue(1, 'newValueAttr2', "string");
$stmt->execute();
}
//here the lock can release the row for future actions (but not this one, because if any one tries the previous select should not find anymore the selected row)
Also I'm using the binding system to send the variables more safety. Not sure If can affect the answer.
I'm quite sure that a transaction with locking row is the answer and if it's the answer, I will really appreciate to receive your help with an example of a transaction with Oracle with an example of this situation.
All of that, will be in a Symfony 3.3 project. Probably is not necessary this last information, but the transaction code must be in the symfony project and not in the oracle database for different reasons.
Thank you very much.

If you will use symfony you will most likely use the DBAL connection.
Transactions are handled as described in its documentation
(To me it seems more a transaction feature than a locking one)
Transactions:
$conn->beginTransaction();
try{
// do stuff
$conn->commit();
} catch (\Exception $e) {
$conn->rollBack();
throw $e;
}
Locking is not handled by DBAL

Related

Multiple query PHP Mysql [duplicate]

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

MySQL Statement is not working in PHP but works perfectly fine in MySQL Workbench [duplicate]

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

How to run multiple insert query in SQL using PHP in one go?

I want to run mysql queries to insert data from a custom html form.
Here I have to insert multiple set of data, some data to one table and some to other. Currently I am using the simple approach to send data to php page using jquery ajax and run multiple mysqli_query() functions one after another. But I guess when there will be large number of users, there will be problems related to speed. So can anyone suggest me a better way to do the same.
There are 5 tables in the database and each table has 7 to 10 columns that need to get different set of data, every time.
I want to run each query only if the previous insert query is successfully completed.
That's why I am checking for the result every time and then running the next query, which makes me feel the issue of speed on large user base.
The problem is, I need to insert data to first table and if its successfully inserted then only run query for the second table.
This means you need a transaction.
A transaction is a set of queries that either all execute ok or if one fails - they all fail. This is to ensure you don't end up with crap data in your tables.
Do not
Do not use multiquery.
Do not use mysql_* function(s).
Do not use bulk inserts.
People telling you to do that just have absolutely no clue what they're doing, ignore them.
Do
Use PDO
Use prepared statements
Prepare the statement(s) ONCE, use them MULTIPLE times
Sample code - do NOT copy paste
$dsn = 'mysql:dbname=testdb;host=127.0.0.1;charset=utf8mb4';
$user = 'dbuser';
$password = 'dbpass';
$pdo = new PDO($dsn, $user, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$insert['first'] = $pdo->prepare("INSERT INTO table SET col1 = :val, col2 = :val2");
$insert['second'] = $pdo->prepare("INSERT INTO another_table SET col1 = :val, col2 = :val2");
$pdo->beginTransaction();
$insert['first']->bindValue(':val', 'your value');
$insert['first']->bindValue(':val2', 'anothervalue');
$insert['first']->execute();
$insert['second']->bindValue(':val', 'your value');
$insert['second']->bindValue(':val2', 'anothervalue');
$insert['second']->execute();
$pdo->commit();
The code above will save the data in two tables ONLY if both inserts are successful.
To paraphrase the accepted answer but with accent on mysqli.
The key is to configure mysqli to throw exceptions and to use a transaction.
A transaction will ensure that all operations either complete in their entirety or have no effect whatsoever. Another important advantage of using a transaction is that it makes multiple inserts faster, eliminating all possible delays that could be caused by separate query execution.
To use transactions with mysqli you need to do as follows:
First of all, make sure you have a proper mysqli connection, which, among other things, tells mysqli to throw an exception in case of error. Then just prepare your queries, start a transaction, execute the queries and commit the transaction - just like it is shown in the accepted answer, but with mysqli:
include 'mysqli.php';
$stmt1 = $mysqli->prepare("INSERT INTO table SET col1 = ?, col2 = ?");
$stmt2 = $mysqli->prepare("INSERT INTO another_table SET col1 = ?, col2 = ?");
$mysqli->begin_transaction();
$stmt1->bind_param("ss", $col1, $col2);
$stmt1->execute();
$stmt2->bind_param("ss", $col1, $col2);
$stmt2->execute();
$mysqli->commit();
Thanks to exceptions and transactions there is no need to verify the result of each query manually.

Updating multiple table records in 1 query with PDO

Im trying to figure out how to update my table using PDO - I need to update 2 records simultaneously only im unsure how this works.
I have my session user, and my "befriended user".
My befriended user will have 10 credits or so in my table and he can offer other users X credits when they befriend him.
// $uid is my logged in session user
// $follow_id is the id of the person were trying to befriend
// Im confused by the whole process of this do i write 2 queries? 1 that minuses credits from the befirended user, and then one that adds the credits to the current session users column?
$upd_stmt = $conn->prepare('SELECT * FROM users WHERE user_id=? ');
$upd_stmt->bindParam(1, $uid, PDO::PARAM_INT);
$upd_stmt->execute();
while( $row = $upd_stmt->fetch(PDO::FETCH_ASSOC) ) {
$row['credits_offered'];
}
The short answer is, yes, you will need to write two queries, one to subtract and the other to add.
You could probably do it in one query, but I would recommend doing it in two for better readability. I would also recommend doing it via a transaction, if the first query executes successfully but the second doesn't, you would want to roll it back.
PHP + MySQL transactions examples
This is what transactions were made for. You don't need to do this in one query to make sure they are both executed succefully.
$dbh->beginTransaction();
$addQuery = "UPDATE ...";
$subtractQuery = "UPDATE ...";
$sth = $dbh->exec($addQuery);
$sth = $dbh->exec($subtractQuery);
$dbh->commit(); // or $dbh->rollback();
Read more about transactions here: http://en.wikipedia.org/wiki/Database_transaction
Short version - they ensure that either all your queries are executed succefully, or none.

Rollback multiple update query if one fails

So what I am doing is am having multiple UPDATE queries, which changes the group name in the tbl_groups table and then updates all the users in tbl_users which belongs to that group, but if the user update query fails, it updates group, but I want to update both together or none, am using PHP and MySQL.
It sounds like all you need to do is use transactions.
You must use InnoDB tables to use transactions (actually, some other DB engines have transactions, but InnoDB is most common with MySQL).
Issue the "BEGIN TRANSACTION" query before the first update.
If any query fails, issue the "ROLLBACK" query to undo everything.
It's really pretty simple.
And if you ever decide you want to do a partial rollback (back to some point after the beginning of the transaction), then you can use "ROLLBACK TO SAVEPOINT savepoint_name". You will have had to issue the "SAVEPOINT savepoint_name" query 1st.
E.g., in PHP
mysql_query("BEGIN TRANSACTION");
$result1 = mysql_query("UPDATE `tbl_groups` SET `user_id` = 5 WHERE `group_id` = 3");
if($result1 === false) {
mysql_query("ROLLBACK");
}
mysql_query("SAVEPOINT savepoint1");
$result2 = mysql_query("UPDATE `tbl_users` SET `group_id` = 3 WHERE `user_id` = 5");
if($result === false) {
ROLLBACK TO SAVEPOINT savepoint1;
}
// COMMIT saves the changes to the db, making them visible to other sessions
// if the ROLLBACK TO SAVEPOINT statement executed, then only changes up to that SAVEPOINT will be saved
// if no ROLLBACK statements were executed, then all changes will be saved (assuming no MySQL errors that cause implicit ROLLBACK)
mysql_query('COMMIT');
use transactions with the best isolation level
i prefer "repeatable read"( you cannot view others data and vise verse until you committed the transaction ) is always good and it is default for innodb storage engine
if you are not using innodb then change the isolation level with
SET GLOBAL tx_isolation='REPEATABLE-READ'; or
SET SESSION tx_isolation='REPEATABLE-READ';
the rest of details are given by #Buttle Butkus
Set the relation between tbl_groups and tbl_users to ON DELETE CASCADE. Then just update tbl_groups and the changes will cascade to related records in tbl_users. If you have to update your parent keys like this very often then you could maybe think about using a surrogate key instead.
Following example is based on object oriented style, make sure your Required database table Type is InnoDB as it supports transaction statement
Here i just want delete multiple record based on ids
$this->link_id->autocommit(FALSE);
// This above statement start the transaction by disabling auto commit where link_id refers to your MySQLi database connection
for($i=1; $i<=5; $i++){
$tSql = "DELETE FROM your_table"
. " WHERE id=" . $i;
$rs = $this->link_id->query($tSql);// execute the query
if($this->link_id->affected_rows == -1) // check if it fails
{
$_SESSION["error"] = "Sorry ! cant be deleted ! ";
$this->link_id->rollback(); // rollback the transaction
break; // break the loop
}
}
//check if there is some error or not, if no error then commit the transaction
if(empty($_SESSION["error"])){
$this->link_id->commit();
}

Categories