I want to know if mysqli->rollback will rollback all the queries that have been committed before the rollback.
For example, in the code below, the first query will be committed, but the second query will fail because of misspelling 'username'. Does that mean that the query before the rollback will or will not get executed?
$mysqli->autocommit(FALSE);
$query = "INSERT INTO users (username, password) VALUES ('user123', '1apple')";
$query2 = "INSERT INTO users (**usernam**, password) VALUES ('user987', '2apple')";
if($resrouce = $mysqli->query($query)){
$mysqli->commit();
if($resource2 = $mysqli->query($query2)){
$mysqli->commit();
}else{
$mysqli->rollback();
}
}else{
$mysqli->rollback();
}
Once you commit the transaction , you can not rollback it , you can only rollback the statement which is not comited yet
modify line 8 and add a line in the end in your code:
$mysqli->autocommit(FALSE);
$query = "INSERT INTO users (username, password) VALUES ('user123', '1apple')";
$query2 = "INSERT INTO users (**usernam**, password) VALUES ('user987', '2apple')";
if($resrouce = $mysqli->query($query)){
//$mysqli->commit(); this not necesary
if($resource2 = $mysqli->query($query2)){
$mysqli->commit();
}else{
$mysqli->rollback();
}
}else{
$mysqli->rollback();
}
$mysqli->close();
Personally I find the PDO library better for database access than mysqli. You can check:
http://php.net/manual/en/pdo.begintransaction.php
which does exactly what you need... Hope that helps
Related
I have two tables, one 'comment' and the other 'pendingcomment'. I want when I copy the data of the 'pendingcomment' in the 'comment' table then that data should be deleted from the 'pendingcomment' table.
This is my code.
<?php
include '../conn.php';
$id = $_GET['id'];
// sql to Insert and delete a record
$sql = "INSERT INTO comment (blogid, name, email, subject, message, date) SELECT blogid, name, email, subject, message, date FROM pendingcomment WHERE id= $id";
$sql .= "DELETE FROM pendingcomment WHERE id=$id";
if (mysqli_multi_query($conn, $sql)) {
// mysqli_close($conn);
header('Location: ../pendingcomments.php'); //redirect to the pending page
exit;
}
else {
echo "Error deleting record ";
}
?>
Result: Error deleting record
NEVER USE mysqli_multi_query()!!!
This function is extremely unsafe and causes a lot more problems than it solves. In fact, it doesn't solve any problems, it just creates more. You can't run queries at the same time from PHP! It is impossible to do so without threading or parallelization. If you need something like this then you can check out Swoole or ReactPHP but it's probably not needed in your case.
When executing queries you need to execute them one after another using prepared statements. This is how it should be done properly:
<?php
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
$conn = new mysqli('localhost', 'user', 'password', 'test');
$conn->set_charset('utf8mb4'); // always set the charset
$id = $_GET['id'];
// begin atomic transaction
$stmt = $conn->begin_transaction();
// prepare statement for insert
$stmt = $conn->prepare('INSERT INTO comment (blogid, name, email, subject, message, date) SELECT blogid, name, email, subject, message, date FROM pendingcomment WHERE id= ?');
$stmt->bind_param('s', $id);
$stmt->execute();
// prepare statement for delete
$stmt = $conn->prepare('DELETE FROM pendingcomment WHERE id=?');
$stmt->bind_param('s', $id);
$stmt->execute();
// commit transaction
$conn->commit();
header('Location: ../pendingcomments.php'); //redirect to the pending page
exit;
The transaction ensures atomicity of the operations as long as your DB engine is InnoDB or a similar transaction engine. MyISAM is not. Remember to enable mysqli error reporting or it won't work.
I have the following two queries. Second query is dependent on first one.
$query1 = mysql_query("Insert into table_one set ---- ");
if($query1)
{
$query2 = mysql_query("delete from table_two where condition---");
if($query2)
{
$message = "both queries executed successfully";
}
else
{
$del = mysql_query("delete record inserted by $query1");
}
}
Can we execute these two queries in a single statement so that both queries depend on each other.If INSERT query fail, DELETE query also fail it's execution as well as if DELETE query fail INSERTION in query first fail.
Thanks
If I good understand what you need, simply use transactions.
Run this query before your insertion:
mysql_query('begin');
And then, if everything went fine, commit the transaction:
mysql_query('commit');
In case of any failures, you may rollback every change you made:
mysql_query('rollback');
Note that in case of MySQL, the MyISAM engine does not support rollback in transactions, so use InnoDB.
Read more about transactions here: https://dev.mysql.com/doc/refman/5.0/en/commit.html
Example with your code:
<?PHP
mysql_query('begin'); //start transaction
$query1 = mysql_query("Insert into table_one set ---- ");
if($query1)
{
$query2 = mysql_query("delete from table_two where condition---");
if($query2)
{
mysql_query('commit'); //both queries went fine, so let's save your changes and end the transaction
$message = "both queries executed successfully";
}
else
{
mysql_query('rollback'); //query2 failed, so let's rollback changes made by query1 and end the transaction
}
}
else
mysql_query('rollback'); //query1 failed, so let's end the transaction
If query2 fails it doesn't check query1.
$query1 = mysql_query("Insert into table_one set ---- ");
$query2 = mysql_query("delete from table_two where condition---");
if( $query2 && $query1)
{
$message = "both queries executed successfully";
}
else if(!$query2)
{
$del = mysql_query("delete record inserted by $query1");
}
You can use transaction, if any query fails then call rollback, otherwise commit
I found a best solution.
Extending idea of #Luki i wrote the following code and it give me too much satisfied answer. First use the following function.
function multi_statement()
{
global $conn;
$total_args = func_get_args();
$args = implode($total_args,";");
$args = "begin;".$args.";commit;";
$number = 0;
if($conn->multi_query($args))
{
do
{
if ($conn->more_results())
{
$number++;
}
}
while($conn->next_result());
}
if($number < (count($total_args)+1))
{
$conn->query('rollback');
echo "Sorry..!!! Error found in Query no:".$number;
}
else
{
echo "All queries executed successfully";
}
}
Then I called the function with number of statements, all these statements are dependent on each other. In-case there is error in any query, no one query occur any changes in database.
$statement1 = "INSERT INTO `pic_gall`.`admin` (`admin_id`, `username`, `password`) VALUES (NULL, 'as1', 'as1')";
$statement2 = "INSERT INTO `pic_gall`.`admin` (`admin_id`, `username`, `password`) VALUES (NULL, 'as2', 'as2')";
$statement3 = "INSERT INTO `pic_gall`.`admin` (`admin_id`, `username`, `password`) VALUES (NULL, 'as3', 'as3')";
$statement4 = "INSERT INTO `pic_gall`.`admin` (`admin_id`, `username`, `password`) VALUES (NULL, 'as4', 'as4')";
$statement5 = "DELETE from user where user_id = '12'";
multi_statement($statement1,$statement2,$statement3,$statement4,$statement5);
this is the tables
tbl_one
id---int
name-var
tbl_tow
id----int
name--var
this is how it will insert with php pdo,
public function insert() {
$stmt9 = $this->conn->prepare("INSERT into tbl_one (name) VALUES (:name)");
$stmt9->bindParam(':name' ,$this->name);
$stmt9->execute();
if($stmt9){
echo "Added";
} else {
echo "error";
}
}
here the idia is to insert in both tables in one time, and delete from both tables in one time.
is it possible here
NOTE: i can not use trigger as i have already setup in other case so mysql is not supporting multi trigger in one time or action.
regards
Is this not what you're after?
public function insert() {
$stmt9 = $this->conn->prepare("INSERT into tbl_one (name) VALUES (:name)");
$stmt9->bindParam(':name' ,$this->name);
$stmt9->execute();
$stmt10 = $this->conn->prepare("INSERT into tbl_one (name) VALUES (:name)");
$stmt10->bindParam(':name' ,$this->name);
$stmt10->execute();
if($stmt9 && $stmt10){
echo "Added";
} else {
echo "error";
}
}
Basically you double up the queries inside your function, so you can "manually" insert trails to your log table. Sorry if I've misunderstood you.
I assume that you are looking for a transaction.
All changes performed by queries will be live only when you commit a transaction, if something fails you may simply do a rollback and nothing will happen at all.
This is useful if you have inserts in multiple tables and want to be sure that changes are only made when all queries were a success!
Example:
public function insert() {
//This will start a transaction and turn-off auto-commit of queries.
$this->conn->beginTransaction();
$stmt9 = $this->conn->prepare("INSERT into tbl_one (name) VALUES (:name)");
$stmt9->bindParam(':name' ,$this->name);
$stmt9->execute();
$stmt10 = $this->conn->prepare("INSERT into tbl_two (name) VALUES (:name)");
$stmt10->bindParam(':name' , $someOtherName);
$stmt10->execute();
if($stmt9 && $stmt10){
$this->conn->commit(); //This will save your changes
} else {
$this->conn->rollBack(); //This will undo your changes
}
}
Simple as that.
So I have this exercise where i need to insert (and do various other actions, i did those successfully) data into a very basic database through php insertion, but I don't seem to be able to do so, and I have absolutely no idea why.
Here is my code (disclaimer, i'm only at the beginning of learning php, so any advice would be really appreciated!):
<?php
include 'Connect.php';
$query = "INSERT INTO game ( product_id, product_name, multiplayer, pegi, genre, release_date, dis_id, dev_name)
VALUES ('"
.$_POST['product_id']."','"
.$_POST['product_name']."','"
.$_POST['multiplayer']."','"
.$_POST['pegi']."','"
.$_POST['genre']."',"
.$_POST['release_date'].",'"
.$_POST['publisher'].",'"
.$_POST['developer']."')";
//execute query
$queryexe = mysql_query($query);
if ($queryexe) {
mysql_query("COMMIT");
print("<p><font size=\"+1\">Success!</font></p>");
} else {
print("<p><font size=\"+1\">Error</font></p>");
}
//disconnect from database
mysql_close($connectionstring);
?>
It connects to the db, as I'm able to see what's in the game table, but i don't know why i'm getting a constant error.
Thanks in advance!
Here is your code modified since that transaction was incomplete
include 'Connect.php';
mysql_query("START TRANSACTION");
$query = "INSERT INTO game ( product_id, product_name, multiplayer, pegi, genre, release_date, dis_id, dev_name)
VALUES ('"
.$_POST['product_id']."','"
.$_POST['product_name']."','"
.$_POST['multiplayer']."','"
.$_POST['pegi']."','"
.$_POST['genre']."','"
.$_POST['release_date']."','"
.$_POST['publisher']."','"
.$_POST['developer']."')";
//execute query
$queryexe = mysql_query($query);
if ($queryexe) {
mysql_query("COMMIT");
print("<p><font size=\"+1\">Success!</font></p>");
} else {
mysql_query("ROLLBACK");
print("<p><font size=\"+1\">Error</font></p>");
}
//disconnect from database
mysql_close($connectionstring);
You were doing a commit, without beggining a transaction, and no rollback in case of mysql error or failure,
As a recommendation, start working with mysqli and don't use your values concatenated in the insert statement.
Edit
You are missing a quote after the double quote in publisher field
.$_POST['release_date'].",'"
.$_POST['publisher']."' // <--- this one
I have the following table:
ID: bigint autoinc
NAME: varchar(255)
DESCRIPTION: text
ENTRYDATE: date
I am trying to insert a row into the table. It executes without error but nothing gets inserted in database.
try {
$query = "INSERT INTO mytable (NAME, DESCRIPTION, ENTRYDATE) VALUES(?,?,?)";
$stmt = $conn->prepare($query);
$name= 'something';
$desc = 'something';
$curdate = "CURDATE()";
$stmt->bind_param("sss", $name, $desc, $curdate);
$stmt->execute();
$stmt->close();
$conn->close();
//redirect to success page
}
catch(Exception $e) {
print $e;
}
It runs fine and redirects to success page but nothing can be found inside the table. Why isn't it working?
What about replacing DESCTIPTION with DESCRIPTION inside the $query?
Edit
Just out of curiosity, I created a table called mytable and copy-pasted your code into a PHP script.
Here everything worked fine and rows got inserted, except that the binded parameter CURDATE() did not execute properly and the ENTRYDATE cell was assigned 0000-00-00.
Are you sure you are monitoring the same database and table your script is supposedly inserting to?
What happens when going with error_reporting(E_ALL); ?
Have you verified that the script actually completes the insertion?
The following appears to be working as expected:
error_reporting(E_ALL);
try {
$query = "INSERT INTO mytable (NAME, DESCRIPTION, ENTRYDATE) VALUES (?, ?, CURDATE())";
$stmt = $conn->prepare($query);
$name= 'something';
$desc = 'something';
$stmt->bind_param("ss", $name, $desc);
$stmt->execute();
if ($conn->affected_rows < 1) {
throw new Exception('Nothing was inserted!');
}
$stmt->close();
$conn->close();
//redirect to success page
}
catch(Exception $e) {
print $e->getMessage();
}
Are you sure there is no error? There seems to be a typo in your column name for example.
Note that PDO is extremely secretive about errors by default.
See How to squeeze error message out of PDO? on how to fix this.
Try preparing this query instead:
"INSERT INTO mytable (NAME, DESCRIPTION, ENTRYDATE) VALUES(?,?,CUR_DATE())"
And check the results of $stmt->execute(). It would have given you a warning that "CUR_DATE()" (sic) is not a valid DATE.
You can check if a statement was correctly executed by checking the return value of execute() and querying the errorInfo() method:
if (!$stmt->execute()) {
throw new Exception($stmt->errorInfo(), stmt->errorCode());
}
Be aware that upon failure, execute() does not throw an exception automagically. You'll have to check for successful operation and failure for yourself.
Is it possible that autocommit is OFF?
If so then you have to commit your insert like so
/* commit transaction */
$conn->commit();
Regards