Transactions in php function or in mysql stored procedure? - php

What is better way to begin a transaction?
Inside procedures or PHP functions?
For example I calling MySQL procedure like this:
function sendLeaguesToDb(){
$leagues = "";
try{
$this->PDO->beginTransaction();
$stmt = $this->PDO->prepare("call insupd_Leagues(:id,:name,:country,:sport_id,:his_data,:fixtures,:livescore,
:numofmatches,:latestmatch)");
$leagues=$this->soccer->GetAllLeagues();
foreach($leagues as $key=>$value){
$stmt->bindParam(':id',$value->Id);
$stmt->bindParam(':name',$value->Name);
$stmt->bindParam(':country',$value->Country);
$stmt->bindParam(':sport_id',$value->Sport_Id);
$stmt->bindParam(':his_data',$value->Historical_Data);
$stmt->bindParam(':fixtures',$value->Fixtures);
$stmt->bindParam(':livescore',$value->Livescore);
$stmt->bindParam(':numofmatches',$value->NumberOfMatches);
$stmt->bindParam(':latestmatch',$value->LatestMatch);
$stmt->execute();
$this->PDO->commit();
}
}
catch(XMLSoccerException $e){
echo "XMLSoccerException: ".$e->getMessage();
}
catch(PDOException $e){
echo "PDOException: ".$e->getMessage();
$this->PDO->rollback();
}
}
Is this good way if I want to send/get data fastest possible every minute/hour?

It depends on what you're trying to achieve.
If you want to see all the inserts as an 'atomic operation' you are doing right, as if one call to the SP fails, the rollback will undo all the changes made from the previous calls
If, otherwise, you want to "isolate" every single SP call, assuring that if it succedes the results are stored in the DB, you have to start and end the transaction inside the SP
I think the preferred solution is the first
EDIT: one thing i'm noting now: the commit should be after the for :
try{
$this->PDO->beginTransaction();
$stmt = $this->PDO->prepare("call insupd_Leagues(:id,:name,:country,:sport_id,:his_data,:fixtures,:livescore,
:numofmatches,:latestmatch)");
$leagues=$this->soccer->GetAllLeagues();
foreach($leagues as $key=>$value){
$stmt->bindParam(':id',$value->Id);
$stmt->bindParam(':name',$value->Name);
$stmt->bindParam(':country',$value->Country);
$stmt->bindParam(':sport_id',$value->Sport_Id);
$stmt->bindParam(':his_data',$value->Historical_Data);
$stmt->bindParam(':fixtures',$value->Fixtures);
$stmt->bindParam(':livescore',$value->Livescore);
$stmt->bindParam(':numofmatches',$value->NumberOfMatches);
$stmt->bindParam(':latestmatch',$value->LatestMatch);
$stmt->execute();
}
//move your commit here
$this->PDO->commit();
}

Related

How to print drop table result through PDO

$droptable = 'DROP TABLE cars';
$resultd = $db->prepare($droptable);
$resultd->execute();
$printresult = $resultd->fetchAll();
echo "<pre>";
print_r($printresult);
echo "</pre>";
I am trying to test something with PDO and created an execute query for the drop table query, but I could not see anything on the screen. Am I making some fundamental programming fundamental or there will be a way around?
fetchAll will not work, as there are not records generated.
$resultd->debugDumpParams(); // print to screen
/* to push the debug to a var */
ob_start();
$content = ob_get_contents();
ob_end_clean();
/* or to just get the error message */
if($resultd->execute())
echo " Table deleted ";
else
print_r($sql->errorInfo());
DROP is a DDL (Data Definition Language) statement, it can't possibly return anything.
The statement can succeed or fail. You could manually check the result of every database method call, but you're better off configuring PDO to throw exceptions on error.
It's also unnecessary to prepare the statement since there aren't parameters to bind.
Putting all this together:
$db = new \PDO($dsn, $user, $pass, [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]);
$droptable = 'DROP TABLE cars';
$db->query($droptable);
You'll get PDOException if something goes wrong or the code will just continue running otherwise. If you really expect the removal to fail now and then during normal operations, you can capture the exception as usual:
try {
$db->query($droptable);
echo 'Table dropped successfully';
} catch(\PDOException $e) {
echo 'Could not drop table: ', $e->getMessage();
}

A stored procedure that doesn't work in my PHP code but it works with a SQL Client

I'm working on a business monitor (a pannel that presents some metrics).
To get that data I do a sql request. By the way, I used a stored procedure.
My code is :
public function execErrorWarnLogs($id){
try {
$sql = "exec [BUSINESS_MONITOR_LOGS] #id='".$id."'";
$req = $this->_bdd->prepare($sql);
$req->execute();
$res = $req->fetchAll(PDO::FETCH_ASSOC);
$req->closeCursor();
return $res;
} catch (Exception $e) {
echo $e->getMessage();
}
}
When I'm trying to get some data indexed by $id, I get some troubles. I got an array that has null values... However, if I execute that stored procedure with an SQL client I get results.
Is that already happened to someone here ? Can someone explain me why I get that ?
If you want more information, please let me know.
Thanks.
Is $id an integer or a string?
Try using bound parameter instead. This is a example how it is working perfectly in my code:
public function execErrorWarnLogs($id){
try {
$sql = "exec BUSINESS_MONITOR_LOGS #id=:id";
$req = $this->_bdd->prepare($sql);
$req->execute([
'id' => $id
]);
$res = $req->fetchAll(PDO::FETCH_ASSOC);
$req->closeCursor();
return $res;
} catch (Exception $e) {
echo $e->getMessage();
}
}
You should use parameters for security reasons, too!
Two site notes:
If you do string interpolation you don't need to prepare the statement. Then you could just do:
$req = $this->_bdd->query($sql);
$res = $req->fetchAll(PDO::FETCH_ASSOC);
But the recommendet approach (for security) is to provide values as bound parameters and prepare the query.
As far as I know, you don't need $req->closeCursor() if you use Microsofts latest pdo driver for MSSQL. Whether you need closeCursor depends on the driver you use.
My stored procedure :
CREATE PROCEDURE BUSINESS_MONITOR #id VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
SELECT e.METRIC_NAME, e.METRIC_VALUE
FROM MONITOR_EVENTS e
WHERE e.MAIN_ID = #id
END
There are two more possible reasons:
Encoding issue
I would assume, that you have an encoding issue. If $id contains chars, that are out of the ascii-range, and you have another encoding, this could cause the query to fail. So check the encoding of $id and of you db connection
Whitespaces in $id
Maybe you have whitespaces in you id.

Transactions using PDO

My understanding is the InnoDB is now the default engine for MySQL. With that knowledge, I am beginning to delve into transactions.
Here is what I have so far...
try{
$pdo->beginTransaction();
$stmnt = $pdo->prepare ("delete from playing where uniq = :uniq");
$stmnt->bindParam (':uniq',$uniq);
$stmnt->execute();
$stmnt = $pdo->prepare ("insert into removals (playdate, time, vid) values (:playdate, :time, :vid");
$stmnt->bindParam (":playdate",$playdate);
$stmnt->bindParam (":time", $time);
$stmnt->bindParam (":vid", $vid);
$stmnt->execute();
$pdo->commit();
echo "1"; // success
return;
}
catch (PDOException $e){
$pdo->rollback();
echo $e->getMessage();
}
This is called by jQuery with a result of "1" indicating a success.
If I understand this correctly, if bot statements execute successfully, they will both be "committed" however it either fails, no database activity will take place and an error message will be generated detailing the first statement execution that fails.
My real question is whether the begin transaction and commit should reside within or outside the try...catch block.
Thanks,
-dmd-
For readability and cleanliness, yes it should be inside the try block. But it really does not matter. It just declares what to commit or rollback if you call roll back.

can I make multiple transactional updates with CI and if one fails rollback them all?

I am making an update for multiple entries with CodeIgniter, my doubt is if I am using the transaction correctly... right now I have this
$this->db->trans_begin();
foreach ($query->result_array() as $b){
try{
$querystring = "somemysql to update... pure mysql";
$query = $this->db->query($querystring);
}catch(Exception $e){
$this->db->trans_rollback();
}
}
$this->db->trans_commit();
At the moment, i havent get any error... and seems to be working fine, what I dont know is this:
If im for the update 4/100 lets say, will this rollback the #4 only? or the #1,#2,#3 as well?
Any idea?
Thanks.
The way you have written this, if there is an exception on 4; 1,2,3 will be rolled back..
BUT it will continue on with 5+, presumably this is not what you want!
I also assume trans_rollback() ends the transaction so the next queries will be run outside of the transaction and won't be rolled back if another exception occurs. You may even get an uncaught exception on trans_commit() or another attempted trans_rollback().
I am guessing what you want is:
$this->db->trans_begin();
try{
foreach ($query->result_array() as $b){
$querystring = "somemysql to update... pure mysql";
$query = $this->db->query($querystring);
}
$this->db->trans_commit();
}
catch(Exception $e){
$this->db->trans_rollback();
}

how to find record insert to mysql using commit()

Sorry for this beginners question and i'm not a PHP developer, but now i'm trying to learn it.
i want to add record in MySQL data base and i'm using transactions lock.
my code is as below.
$SqlQuery="INSERT INTO tab_photo VALUES('$PhotoID','$ProjectId','$Day','$barCode','$photoName','$PhotoXml')";
$waiting = true;
while($waiting) {
try {
// save border data
$stmt = $conn->prepare($SqlQuery);
$conn->beginTransaction();
$stmt->execute();
sleep(1);
$x=$conn->commit();
echo "x value-".$x;
echo "Success";
$waiting = false;
}
catch (PDOException $e){
echo "Failled :".$PhotoID."-".$PhotoID;
if(stripos($e->getMessage(), 'DATABASE IS LOCKED') !== false) {
// This should be specific to SQLite, sleep for 0.25 seconds
// and try again. We do have to commit the open transaction first though
$conn->commit();
usleep(250000);
} else {
$conn->rollBack();
throw $e;
}
}
}
in here as output it gives,
x value-1 Success
but actually this record doesn't add to the database.
My Questions:
Even the commit is successful(output 1) how does it not added to the database?
how can i check whether record is added to database? ( Is there any way to find it without write select statement?
As I understand, you expect that PDOException will be thrown when statement is failed to execute. But as I can see, exception is not thrown by default in such cases.
See how you can change that here
Suppose in your case you should have a code like this:
$conn = new PDO($connection_string);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // this will force PDO to throw exception when SQL statement fails instead of simply setting an error.
Suppose this will work fine for you.
Please note that you should not use
$SqlQuery="INSERT INTO tab_photo VALUES('$PhotoID','$ProjectId','$Day','$barCode','$photoName','$PhotoXml')";
Instead of that, you should use parameters binding:
$SqlQuery="INSERT INTO tab_photo VALUES(:PhotoID,:ProjectId,:Day,:barCode,:photoName,:PhotoXml)";
$stmt = $conn->prepare($SqlQuery);
$conn->beginTransaction();
$stmt->execute(array(':PhotoID' => $PhotoID, ':ProjectId' => $ProjectId, ....));
sleep(1);
See this for more details.

Categories