it is correct for a transaction? - pdo

I create a mysql transaction using pdo.
Please check my code is perfect or not. if its not correct then how i can set transaction correctly.
Do i need to use try block? how can i sort try block in this querys
if(is_null($this->pdo)){
return false;
} else {
$pdo = $this->pdo;
$pdo->beginTransaction();
$stmt = $pdo->prepare("SELECT mallu FROM users WHERE id=? LOCK IN SHARE MODE");
$stmt->execute([$alpharef]);
$reseller = $stmt->fetch();
$stmt = null;
$stmt = $pdo->prepare("UPDATE users SET mallu = mallu - :cost WHERE id=:userid");
$stmt->bindParam(':cost', $cost, PDO::PARAM_STR);
$stmt->bindParam(':userid', $alpharef, PDO::PARAM_INT);
if (stmt->execute() != true) {
$conn->rollBack();
return false
}
$stmt = null;
$dates = date("d-m-Y");
$statos = 0;
$stmt = $pdo->prepare("INSERT INTO request (rtyp, num, amount, cost, typ, usr, refid, tm, dates, status) VALUES (:rtyp, :num, :amount, :cost, :typ, :usr, :refid, NOW(), :dates, :status)");
$stmt->bindParam(':rtyp', $retyp, PDO::PARAM_STR);
............................................................
if (stmt->execute() != true) {
$conn->rollBack();
return false
}
$stmt = null;
$pdo->commit();
$this->msg = 'Request sent successfully';
return true;
}
$pdo = null;

Look at this pseudo-code. Try + catch helps you to handle failed transaction. All you have to do is to throw new exception when one of your sql's fail.
$pdo->beginTransaction();
try{
//DB_operation1
if (result==false){ throw new Exception("...message1...");}
//DB_operation2
if (result==false){ throw new Exception("...message2...");}
$pdo->commit();
}catch(exception $e){
$pdo->rollBack();
//do something with thrown message
}

Related

How to rollback a transaction in EntityFramework?

I have two database tables named Courses and Transactions.Courses stores the details of a particular course and Transactions table stores the details of the transactions performed by a particular user.
My question is how can I make sure that entry in the CourseTable is saved only when transactions(add,edit,delete) regarding that particular course is saved into the TransactionTable
CourseTable is
TransactionTable is
Controller is
POST: /Course/Add
[HttpPost]
public ActionResult Add(CourseVM _mdlCourseVM)
{
string actionName=this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName=this.ControllerContext.RouteData.Values["controller"].ToString();
Course _course = new Course();
_course.Duration = _mdlCourseVM.Course.Duration;
_course.DurationMode = _mdlCourseVM.DurationModeId;
_course.InstalmentFee = _mdlCourseVM.Course.InstalmentFee;
_course.Name = _mdlCourseVM.Course.Name;
_course.SingleFee = _mdlCourseVM.Course.SingleFee;
_db.Courses.Add(_course);
int i = _db.SaveChanges();
if (i > 0)
{
Common _cmn=new Common();
//Add the transaction details
int k=_cmn.AddTransactions(actionName,controllerName,"");
//Want to commit changes to the coursetable here
if(k>0){
_db.commitTransaction()
}
//Want to rollback the committed transaction
else{
_db.rollbackTransaction();
}
}
}
I solved the above scenario by using System.Transactions.Hope anyone with same scenario find it useful.
using (TransactionScope _ts = new TransactionScope())
{
string actionName = this.ControllerContext.RouteData.Values["action"].ToString();
string controllerName = this.ControllerContext.RouteData.Values["controller"].ToString();
Course _course = new Course();
_course.Duration = _mdlCourseVM.Course.Duration;
_course.DurationMode = _mdlCourseVM.DurationModeId;
_course.InstalmentFee = _mdlCourseVM.Course.InstalmentFee;
_course.Name = _mdlCourseVM.Course.Name;
_course.SingleFee = _mdlCourseVM.Course.SingleFee;
_db.Courses.Add(_course);
int i = _db.SaveChanges();
if (i > 0)
{
Common _cmn = new Common();
int k = _cmn.AddTransactions(actionName, controllerName, "",Session["UserId"].ToString());
if (k > 0)
{
_ts.Complete();
return Json(new { message = "success" }, JsonRequestBehavior.AllowGet);
}
else
{
return Json(new { message = "error" }, JsonRequestBehavior.AllowGet);
}
}
else
{
return Json(new { message = "error" }, JsonRequestBehavior.AllowGet);
}
}
}

using clearParameter() even thought PreparedStatement is being closed

private PreparedStatement InsertPS = null;
public boolean InsertInDB(String username, String password, double balance, String secret) {
boolean ans = false;
try {
InsertPS = con.prepareStatement("Insert into BankDB values(?,?,?,?)");
String data[] = AMC.SendtoDB(password, secret);
InsertPS.setString(1, data[0]);
InsertPS.setString(2, username);
InsertPS.setString(3, data[1]);
InsertPS.setDouble(4, balance);
int rows = InsertPS.executeUpdate();
if (rows != 0) {
ans = true;
}
InsertPS.clearParameters();
} catch (SQLException sqlInite) {
System.out.println("SQL Error in InsertInDB method: " + sqlInite);
} finally {
try {
InsertPS.close();
} catch (SQLException sqle) {
System.out.println("SQL Exception in InsertInDB method finally clause : " + sqle);
}
}
return ans;
}
Above is the InsertInDB() method given,
It has a InsertPS PreparedStatement Object.
Here is it necessary to use clearParameters() method even though i am closing the InsertPS object at the end of the method.
(I have provided a separate method to close the connection object)
also another question: Is it a good idea to create PreparedStatement Object's outside any method within a class,initializing using Constructor and Say for example Once all Object's (each in different method) are used, close all PreparedStatement Objects using a separate method.
public class JavatoDB {
Driver DM = null;
Connection con = null;
PreparedStatement InsertPS = null;
PreparedStatement BalancePS = null;
PreparedStatement DeletePS = null;
PreparedStatement UpdatePS = null;
PreparedStatement SearchDB = null;
ResultSet RS = null;
ResultSetMetaData RSMD = null;
AdminControl AMC = null;
public JavatoDB() {
AMC = new AdminControl();
try {
DM = new com.mysql.jdbc.Driver();
con = DriverManager.getConnection("jdbc:mysql://localhost/javadb", "java", "javaaccess");
InsertPS = con.prepareStatement("Insert into BankDB values(?,?,?,?)");
BalancePS = con.prepareStatement("Select BALANCE from BankDB where ACCNAME=? AND ACCPIN = ?");
DeletePS = con.prepareStatement("Delete from BankDB where ACCNAME = ? AND ACCPIN = ? ");
UpdatePS = con.prepareStatement("Update BankDB set BALANCE = (BALANCE + ?) where ACCNAME = ? AND ACCPIN = ?");
SearchDB = con.prepareStatement("Select ID AND ACCPIN from BankDB where ACCNAME = ? ");
} catch (SQLException JavatoDBContrsuctor) {
System.out.println("SQL Error in JavatoDBConstructor: " + JavatoDBContrsuctor);
}
}
public boolean InsertInDB(String username, String password, double balance, String secret) {
boolean ans = false;
try {
String data[] = AMC.SendtoDB(password, secret);
InsertPS.setString(1, data[0]);
InsertPS.setString(2, username);
InsertPS.setString(3, data[1]);
InsertPS.setDouble(4, balance);
int rows = InsertPS.executeUpdate();
if (rows != 0) {
ans = true;
}
InsertPS.clearParameters();
} catch (SQLException sqlInite) {
System.out.println("SQL Error in InsertInDB method: " + sqlInite);
}
return ans;
}
Suggestion's or Criticism on other aspects of code are also welcome.
For the first question, when you call:
con.prepareStatement()
a new preparedStatement is created, then parameters dont survive, i mean you dont need to clear then.
About the second question, in your implementation i cant see where you close your preparedStatement, and if you only add close, next time method will fail. Then, it is usual to create the preparedStatement and close it in the same method.

Oracle columns update not happpening

I am trying to update a few columns in a Oracle table from my C# code.
Here is my method:
private static bool UpdateOracleTable(OracleTable table, string whereClause, List<int> entIDs)
{
try
{
var tableName = table.ToString();
using (OracleConnection conn = new OracleConnection(_oracleConnection))
{
conn.Open();
foreach (var id in entIDs)
{
whereClause = String.Format(whereClause, id);
var query = Resources.UpdateOracle;
query = String.Format(query, tableName, "20", DateTime.Now.ToString("yyyy/MM/dd"), whereClause);
using (OracleCommand cmd = new OracleCommand(query, conn))
{
cmd.ExecuteNonQuery();
}
}
}
return true;
}
catch (Exception ex)
{
Log.Debug(LogType.Error, ex);
return false;
}
}
Here is the Query:
UPDATE
{0}
SET
SYNC_STATUS = '{1}'
,SYNC_DATE = TO_DATE('{2}', 'yyyy/mm/dd')
{3}
And the where clause will look something like:
WHERE ID = {0}
This method updates about 10 records, and the rest stays null. This mehod does return true, and I have debugged, no exception is thrown.
Why does it not update all records?
This isn't an answer but might help debug the problem.
Instead of the like:
cmd.ExecuteNonQuery();
put in this:
int count = cmd.ExecuteNonQuery();
if (count == 0)
{
Console.WriteLine("");
}
Put a break on the Console.WriteLine("") and run it. The debugger will stop if no rows were updated. You can then check the query, and whether or not that ID actually exists.
The problem was with the WHERE clause. Since it contains a place holder {0}, after I I formatted the WHERE clause, the ID always stayed to the value it was formatted with first.
This is what my new method looks like.
private static bool UpdateOracleTable(OracleTable table, string whereClause, List<int> entIDs)
{
try
{
var tableName = table.ToString();
using (OracleConnection conn = new OracleConnection(_oracleConnection))
{
conn.Open();
foreach (var id in entIDs)
{
string originalWhere = whereClause;
originalWhere = String.Format(originalWhere, id);
var query = Resources.UpdateOracle;
query = String.Format(query, tableName, "20", DateTime.Now.ToString("yyyy/MM/dd"), originalWhere);
using (OracleCommand cmd = new OracleCommand(query, conn))
{
bool success = cmd.ExecuteNonQuery() > 0;
}
}
}
return true;
}
catch (Exception ex)
{
Log.Debug(LogType.Error, ex);
return false;
}
}
As can be seen, I added a variable 'originalWhere', that gets formatted, but most importantly, is being set to original WHERE clause parameter passed, so that it will always contain the place holder.

Get raw sql from Phalcon query builder

Is it possible to extract raw sql query from the query builder instance in Phalcon? Something like this?
$queryBuilder = new Phalcon\Mvc\Model\Query\Builder();
$queryBuilder
->from(…)
->where(…);
$rawSql = $queryBuilder->hypotheticalGetRawQueryMethod();
By error and trial the below seems to working. Would be great if someone could confirm if there's a better way.
$queryBuilder = new Builder();
$queryBuilder->from(…)->where(…);
$intermediate = $queryBuilder->getQuery()->parse();
$dialect = DI::getDefault()->get('db')->getDialect();
$sql = $dialect->select($intermediate);
Edit: As of 2.0.3 you can do it super simple, see comment for full details:
$modelsManager->createBuilder()
->from('Some\Robots')
->getQuery()
->getSql()
you can use getRealSqlStatement() (or similar function name) on the DbAdapter. See http://docs.phalconphp.com/en/latest/api/Phalcon_Db_Adapter.html
According to documentation you can get this way the resulting sql query.
Or wait, this might not work on querybuilder. Otherwise you can setup low level query logging: http://docs.phalconphp.com/en/latest/reference/models.html#logging-low-level-sql-statements
$db = Phalcon\DI::getDefault()->getDb();
$sql = $db->getSQLStatement();
$vars = $db->getSQLVariables();
if ($vars) {
$keys = array();
$values = array();
foreach ($vars as $placeHolder=>$var) {
// fill array of placeholders
if (is_string($placeHolder)) {
$keys[] = '/:'.ltrim($placeHolder, ':').'/';
} else {
$keys[] = '/[?]/';
}
// fill array of values
// It makes sense to use RawValue only in INSERT and UPDATE queries and only as values
// in all other cases it will be inserted as a quoted string
if ((strpos($sql, 'INSERT') === 0 || strpos($sql, 'UPDATE') === 0) && $var instanceof \Phalcon\Db\RawValue) {
$var = $var->getValue();
} elseif (is_null($var)) {
$var = 'NULL';
} elseif (is_numeric($var)) {
$var = $var;
} else {
$var = '"'.$var.'"';
}
$values[] = $var;
}
$sql = preg_replace($keys, $values, $sql, 1);
}
More you can read there
The following is the common solution:
$result = $modelsManager->createBuilder()
->from(Foo::class)
->where('slug = :bar:', ['bar' => "some-slug"])
->getQuery()
->getSql();
But you might not expect to see the query without its values, like in:
die(print_r($result, true));
Array
(
[sql] => SELECT `foo`.`id`, `foo`.`slug` FROM `foo` WHERE `foo`.`slug` = :bar
[bind] => Array
(
[bar] => some-slug
)
[bindTypes] =>
)
So, this simple code might be useful:
public static function toSql(\Phalcon\Mvc\Model\Query\BuilderInterface $builder) : string
{
$data = $builder->getQuery()->getSql();
['sql' => $sql, 'bind' => $binds, 'bindTypes' => $bindTypes] = $data;
$finalSql = $sql;
foreach ($binds as $name => $value) {
$formattedValue = $value;
if (\is_object($value)) {
$formattedValue = (string)$value;
}
if (\is_string($formattedValue)) {
$formattedValue = sprintf("'%s'", $formattedValue);
}
$finalSql = str_replace(":$name", $formattedValue, $finalSql);
}
return $finalSql;
}
If you're using query builder then like given below then getPhql function can serve the purpose as per phalcon 3.4.4 version.
$queryBuilder = new Builder();
$queryBuilder->from(…)->where(…)->getQuery();
$queryBuilder->getPhql();
if (!function_exists("getParsedBuilderQuery")) {
/**
* #param \Phalcon\Mvc\Model\Query\BuilderInterface $builder
*
* #return null|string|string[]
*/
function getParsedBuilderQuery (\Phalcon\Mvc\Model\Query\BuilderInterface $builder) {
$dialect = Phalcon\Di::getDefault()->get('db')->getDialect();
$sql = $dialect->select($builder->getQuery()->parse());
foreach ($builder->getQuery()->getBindParams() as $key => $value) {
// For strings work fine. You can add other types below
$sql = preg_replace("/:?\s?($key)\s?:?/","'$value'",$sql);
}
return $sql;
}
}
Simple function that im using for debugging.

PHP PDO dynamically updating db table with multiple records to a specific user ID

/* Newbie need some help; I am creating a class to auto update my apps db record when instructed to, but I am consistently getting this message below, and for the heck of it, I just not seeing what I am doing wrong. Can someone please look at my codes for me? Thank you.
Warning: PDOStatement::bindParam() expects at least 2 parameters, 1 given in……..on line 331; that where the "else if(is_string($val)){" is located.
*/
// vars given
// DBDriver: MySQL
$myTable = 'seeYou';
$loginDate = NULL;
$ip = $_SERVER['REMOTE_ADDR'];
$date = #date('m/d/Y \a\\t h:i a');
$_id =1;
// data array
$idata = array("last_logged_in"=>$loginDate,
"login_date"=>$date,
"ip_addr"=>$ip
);
class name
{
///------------ other methods here---------///
/**
*--------------------------------------------
* Method - PDO: SET FIELD VALUE PLACEHOLDER
*--------------------------------------------
* #return fields with prefix as placeholder
*/
protected function set_fieldValPlaceHolders(array $data)
{
$set = '';
foreach($data as $field => $value)
{
$set .= $field .'= :'.$field . ',';
}
// remove the last comma
$set = substr($set, 0, -1);
return $set;
}
public function save($data=NULL, $_id = NULL, $rows= NULL, $dbTable= NULL)
{
//----------------- some other codes goes here ----------------//
$id = (int)$_id;
// update row with a specific id
if (isset($id) !== NULL && $rows === NULL)
{
$set = $this->set_fieldValPlaceHolders($data);
$sql = "UPDATE {$dbTable} SET {$set} WHERE user_id = :uid";
try
{
// Build the database statement
$_stmt = $this->_dbConn->prepare($sql);
$_stmt->bindValue(':uid',$id, PDO::PARAM_INT);
foreach ($data as $field => $val)
{
if(is_int($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_INT');
}
else if(is_string($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_STR');
}
else if(is_bool($val)){
$_stmt->bindValue(':'.$field.'\', '.$val.', PDO::PARAM_BOOL');
}
else if(is_null($val)){
$_stmt->bindValue(':'.$field.'\', '.$val="null".', PDO::PARAM_NULL');
}
else {
$_stmt->bindValue(':'.$field.'\', '.$val.', NULL');
}
$result = $_stmt->execute();
$num = $_stmt->rowCount();
}
}
catch(PDOException $e)
{
die('Error! The process failed while updating your record. <br /> Line #'.__LINE__ .' '.$e);
}
if ($result === true)
{
return true;
}
}
Check your bindValue calls: You give 1 parameter (a long string). It needs at least two. Check all the '
for example, it should be:
$_stmt->bindValue(':'.$field, $val, PDO::PARAM_INT);