I need to do 2 query.
Basically it's a
mysql_query("INSERT INTO table ($value1,$value2)");
and
mysql_query("UPDATE table2 SET field1 = '$value1', field2 = '$value2'");
I think I can simply do a
if (mysql_query("INSERT ...") !== false) {
mysql_query("UPDATE ...");
}
In this case should I use a transaction? And how should I use it?
Or can i leave that simple if?
Thanks
You will generally use transactions if you want some "all or nothing" behavior.
Basically, with transactions, you can :
Start a transaction
Do the first query
If it succeeds, do the second query
If it succeed, commit the transaction
Else, rollback the transaction -- cancelling both queries that correspond to that transaction.
If working with mysql_* function, you'll have to :
Start the transaction, with a START TRANSACTION query
Do your queries
Depending on the result of those queries, either do a COMMIT or a ROLLBACK query.
To detect whether a query succeeded or not, you can indeed check the return value of mysql_query() : it will return false in case of an error.
Note : MySQL is the old extension -- and doesn't have functions to deal with transactions ; which means you have to deal with them as regular queries.
Working with MySQLi, you could use :
mysqli::autocommit() to disable autocommit
and mysqli::commit() or mysqli::rollback()
For insert and updates MySQL has a good, alternative solution - "ON DUPLICATE KEY UPDATE". It does what you want safely in a single query:
INSERT .... ON DUPLICATE KEY UPDATE
(also the key must be set as unique in this scenario)
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
Related
I am using InnoDB in MySQL and accessing the table from PHP with PDO.
I need to lock the table, do a select and then, depending on the result of that either insert a row or not. Since I want to have the table locked for as short a time as possible, can I do it like this?
prepare select
prepare insert
begin transaction
lock table
execute select
if reservation time is available then execute insert
unlock table
commit
Or do the prepares have to be inside the transaction? Or do they have to be after the lock?
Should the transaction only include the insert, or does that make any difference?
beginTransaction turns off autocommit mode, so it only affects queries that actually commit changes. This means that prepared statements, SELECT, and even LOCK TABLES are not affected by transactions at all. In fact, if you're only doing a single INSERT there's no need to even use a transaction; you would only need to use them if you wanted to do multiple write queries atomically.
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();
}
I got two tables. One is account, another is Interest.
One account can have multi Interests and It can be edited.
Now, the process is deleting all Interest of this account then insert these insterests.
The QUERY IS:
"DELETE FROM Interests WHERE account_id='$id'"
"INSERT INTO Interests (account_id, interest_name) VALUES('$id', '$name')"
I use the both query when user update their account, but the insert is fail, there is nothing insert into the table (ps. the interests_id is auto_increment and this was be counted) but there is nothing new in the table. When I comment out the delete query. The insert will be successful.
Does any one know what can i do?
If you want to update your table records, you will do update operation.
like this:
UPDATE TABLE_NAME SET FIELD_NAME = 'VARIABLE_NAME'
WHERE PRIMERY_FIELD_NAME = 'VARIABLE_NAME' ;
you did not have to use these two queries, if you want to update data simply use the updat query of mysql.use this:
<?php
$query = "UPDATE Interests SET interest_name = '".$name."' WHERE account_id = '".$id."'" ;
mysql_query($query);
?>
If you want to update your table records then you may execute update operation. It like following
UPDATE Interests
SET
interest_name = '$name'
WHERE
accountno = '$id' ;
Try it. You may solve your problem by this way.
If you have queries failing, you should capture the error and see what went wrong. In all MySQL APIs for PHP, a query that fails returns a status code to indicate this. Examples of checking this status code are easy to find in the docs. But most developers fail to check the status.
Use transactions to ensure that both changes succeed together or neither are applied.
How to Decide to use Database Transactions
Definition of a transaction in MySQL: http://dev.mysql.com/doc/refman/5.5/en/glossary.html#glos_transaction
Syntax for starting and committing transactions in MySQL: http://dev.mysql.com/doc/refman/5.5/en/commit.html
You need to use InnoDB. MyISAM does not support transactions. http://dev.mysql.com/doc/refman/5.5/en/innodb-storage-engine.html
In PHP, you need to stop using the old ext/mysql API and start using MySQLi or PDO.
http://php.net/manual/en/mysqli.quickstart.transactions.php
http://php.net/manual/en/pdo.begintransaction.php
This happens because the query are treated as two single transaction, so the order of execution is not guaranteed.
The effect you are describing is because the insert is processed before delete, so the interests_id is auto-incremented properly, then the row is deleted by delete statement.
You should change the query logic or perform both queries in one single transaction.
I'm curios if this can be achieved as I'm currently facing a bug and would like to see if putting a SELECT and an UPDATE in a transaction would fix it (if you're wondering why I'm not posting the code that causes the bug it's because it's a complex environment and I can't post all the influencing factors).
Something that I'm also interested in, related to this, is if you have ever experienced code that had and UPDATE query written after a SELECT query, yet the UPDATE gets executed before the SELECT (with the possibility that the script might run twice ruled out).
It depends on what do you mean by a transaction.
There are two types of transactions:
Implicit transactons: as in INSERT, UPDATE, SELECT, DELETE statements, and in such statements there is no explicit transaction commands, and the database engine will rollback the whole statement if an error happens.
Explicit Transactions: in such the enclosed statements inside the transaction are executed as a unit and either COMMIT the whole transaction or ROLLBACK .
So you can't have both SELECT and UPDATE inside one query, but you can but them inside a transaction like:
START TRANSACTION;
SELECT * FROM tableName;
UPDATE table SET something = 'other something' WHERE thirdsomething = #s;
COMMIT;
Then Put them in a stored procedure or a UDF.
Note that: SELECT statements do not modify data, so you might not need to enclose it in a transaction, so in your case you will have only UPDATE statement you can just use a stored procedure without a transaction.
Is it possible to insert a row into multiple tables at once? If you do several tables related by an ID; what is the best way to ensure integrity is maintained in case an INSERT fails?
That's exactly what transactions are for. If any of the commands fail, the whole thing since START TRANSACTION is rolled back:
START TRANSACTION;
INSERT INTO sometable VALUES(NULL,'foo','bar');
INSERT INTO someothertable VALUES (LAST_INSERT_ID(),'baz');
COMMIT;
This being MySQL, you can't use transactions with MyISAM tables (you'll need the tables to use some engine that supports this, probably InnoDB).
This will never be inserted into the table (normally you'd have some branching, e.g. an IF):
START TRANSACTION;
INSERT INTO sometable VALUES(NULL,'data','somemoredata');
ROLLBACK;
Caveat: SQL commands which change the database structure (e.g. CREATE,ALTER,DROP) cannot be rolled back!
Use transactions, luke.
MySQL can insert multiple rows (search for 'multiple rows') like this:
INSERT INTO table (field1, field2, ...) VALUES (value1, value2), (value3, value4), etc...
However, there's no way to tell what got inserted and what wasn't due to constraint violations, beyond the query returning a count of records, duplicates, and warnings. You also can't use last_insert_id() to figure out the IDs of the new rows, as that only returns the LAST id that was created, not a set of ids.
If you need to guarantee integrity, then use single row insert statements and transactions.