How to lock a table during an operation use php/yii - php

My table:
CREATE TABLE IF NOT EXISTS `detail_transaction` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`created_date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`code` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`id_product` int(11) NOT NULL,
`id_store` int(11) NOT NULL,
`input_quality` int(11) NOT NULL,
`output_quality` int(11) NOT NULL,
`quality_in_store` int(11) NOT NULL,
PRIMARY KEY (`id`)
)
I have the problem is below:
I get record have max_id, and then before i insert new record, having
another process insert new record was inserted.
I think: I will lock table during "I select a record have max_id" to "I completed to insert new next record"(don't run any task work with this table). And to do this method. Please help me! How to do this by php code or Yii.

You could use transactions:
$transaction = Yii::app()->db->beginTransaction();
try {
foreach ($items as $item) {
$item->attr = value;
$item->save();
}
$transaction->commit();
// actions to do on success (redirect, alert, etc.)
} catch (Exception $e) {
$transaction->rollBack();
// other actions to perform on fail (redirect, alert, etc.)
}
This source code is from this post: using transaction in a loop in yii

I'm not exactly sure what you want to achieve, but I'm sure it will work out if you just use transactions - http://www.yiiframework.com/doc-2.0/yii-db-transaction.html. Otherwise, you can always call a LOCK TABLE query - http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html.
$connection = Yii::app()->db;
$lock = $connection-> createCommand('LOCK TABLES `detail_transactions` WRITE');
// do your magic
$unlock = $connection-> createCommand('UNLOCK TABLES');

In Yii2, you can lock/unlock a table like this
$db = Yii::$app->getDb();
$db ->createCommand('LOCK TABLES `YOUR_TABLE` WRITE')->execute();
// access YOUR_TABLE here
// something like YOUR_TABLE_MODEL::find()->where(["something" => "blah"])->one()
$db ->createCommand('UNLOCK TABLES')->execute();

Related

How to reinstall database on Prestahop Module?

I'm trying to customize a Prestashop module and I need to add two new colonnes in a table.
The problem is that the database is already created, I guess it did when the module initializing. So if I change the code now, changes does not appear and I keep receiving this mistake:
There is no way to do it in configuration and I suppose if I delete the module my code will dissepear.
How can I do ?
Maybe asking the delete and the create method in a common method (just one time).
I'm new with Smarty and PHP, I see it's not a usual method where the table is created.
Could you help me ?
I'm new with Smarty, how can I do that ?
It looks like it's not a method where the table is created.
$sql = array();
$sql[] =
'CREATE TABLE IF NOT EXISTS `'._DB_PREFIX_.'opartdevis` (
`id_opartdevis` int(10) NOT NULL AUTO_INCREMENT,
`id_shop` int(10) NOT NULL,
`id_cart` int(10) NOT NULL,
`id_customer` int(10) NOT NULL,
`name` varchar(128),
`message_visible` TEXT,
`id_customer_thread` int(10),
`date_add` DATETIME NOT NULL,
`status` int(2) DEFAULT 0,
`id_order` int(10) NULL,
`id_ordered_cart` int(10) NULL,
`remise` int(10),
`delivery` int(10),
PRIMARY KEY (`id_opartdevis`)
) ENGINE='._MYSQL_ENGINE_.' DEFAULT CHARSET=utf8';
//1.6.1.0 specific price bug fix
if (version_compare(_PS_VERSION_, '1.6.1.0', '=')) {
$sql[] = "ALTER TABLE "._DB_PREFIX_."specific_price DROP INDEX id_product_2";
$sql[] = "ALTER TABLE "._DB_PREFIX_."specific_price ADD INDEX id_product_2 (id_product,id_shop,id_shop_group,id_currency,id_country,id_group,id_customer,id_product_attribute,from_quantity,id_specific_price_rule,id_cart,`from`,`to`)";
}
foreach ($sql as $s) {
if (!Db::getInstance()->execute($s)) {
return false;
}
}
Thanks in advance
Malaury
You need to revert all DB changes when you're uninstalling the module.
Define (or append to existing) uninstall() function in your base module file and run DROP TABLE query on the created table. Example:
public function uninstall() {
if (!parent::uninstall()) {
return false;
}
$sql = 'DROP TABLE IF EXISTS `'._DB_PREFIX_.'opartdevis`';
if (!Db::getInstance()->execute($sql)) {
return false;
}
return true;
}
This way, when you're uninstalling the module, the table is going to be deleted (and recrteated when you install it again).

MYSQL delete statement deletes too many rows

I have a table for users in my MYSQL db like so:
CREATE TABLE `myDatabase`.`user` (
`id` INT NOT NULL AUTO_INCREMENT ,
`login` VARCHAR(250) NOT NULL ,
`uid` VARCHAR(250) NOT NULL ,
`email` VARCHAR(250) NOT NULL ,
`user_type` VARCHAR(250) NOT NULL ,
PRIMARY KEY (`id`)) ENGINE = InnoDB;
uid is provided by firebase when a user logs in (strings such as 3LmgcBeCUNW1lfMKCQcoI8Xkxai1
or DrFblVatVdacokhcQCuwb8DK13q1.
My project has a delete user option that calls the query:
public function deleteProfile($uid) {
$memberDelete = $this->_db->prepare("DELETE FROM user WHERE uid = :uid");
$memberDelete->bindParam(':uid',$uid,PDO::PARAM_INT);
$resp = $memberDelete->execute();
if(!$resp) {
throw new PDOException('member couldn't be removed');
}
$memberDelete->closeCursor();
return "member successfully removed";
}
When I do this, it deletes way too many users. I tried deleting based on email instead of UID and it deleted all of the users.
Here:
$memberDelete->bindParam(':uid', $uid, PDO::PARAM_INT);
You are binding your param as an integer, while obviously it's a string. This generates a chain of implicit conversions that ends up deleting more rows that you intend.
Instead, you want:
$memberDelete->bindParam(':uid', $uid, PDO::PARAM_STR);

PHP SQL query slow?

Here is my function which i am using to un-follow users.It first DELETE the relationship between users and all the notifications that are related to this relationship.Then it INSERT a new notification for user which we are going to un-follow and then UPDATE his followers count (as one follower has left).I am using multi_query and this query seems to be bit slower on large database and i want to know whether it's a good practice or not or is there is any more complex form of query to get the job done.
PHP Function
// 'By' is the array that hold logged user and 'followed' is the user id which we are going to unfollow
function unFollowUser($followed,$by) {
$following = $this->getUserByID($followed);// Return fetch_assoc of user row
if(!empty($following['idu'])) { // if user exists
// return user followers as number of rows
$followers = $this->db->real_escape_string($this->numberFollowers($following['idu'])) - 1;
$followed_esc = $this->db->real_escape_string($following['idu']);
$by_user_esc = $this->db->real_escape_string($by['idu']);
// delete relationship
$query = "DELETE FROM `relationships` WHERE `relationships`.`user2` = '$followed_esc' AND `relationships`.`user1` = '$by_user_esc' ;" ;
// delete notification (user started following you )
$query.= "DELETE FROM `notifications` WHERE `notifications`.`not_from` = '$by_user_esc' AND `notifications`.`not_to` = '$followed_esc' ;" ;
// Insert a new notification( user has unfollowed you)
$query.= "INSERT INTO `notifications`(`id`, `not_from`, `not_to`, `not_content_id`,`not_content`,`not_type`,`not_read`, `not_time`) VALUES (NULL, '$by_user_esc', '$followed_esc', '0','0','5','0', CURRENT_TIMESTAMP) ;" ;
// update user followers (-1)
$query .= "UPDATE `users` SET `followers` = '$followers' WHERE `users`.`idu` = '$followed_esc' ;" ;
if($this->db->multi_query($query) === TRUE) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
}
Table structures
--
-- Table structure for table `notifications`
--
CREATE TABLE IF NOT EXISTS `notifications` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`not_from` int(11) NOT NULL,
`not_to` int(11) NOT NULL,
`not_content_id` int(11) NOT NULL,
`not_content` int(11) NOT NULL,
`not_type` int(11) NOT NULL,
`not_read` int(11) NOT NULL,
`not_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `id` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Table structure for table `relationships`
--
CREATE TABLE IF NOT EXISTS `relationships` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user1` int(11) NOT NULL,
`user2` int(11) NOT NULL,
`status` int(11) NOT NULL,
`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- Table structure for table `users`
--
CREATE TABLE IF NOT EXISTS `users` (
`idu` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(32) NOT NULL,
`password` varchar(256) NOT NULL,
`email` varchar(256) NOT NULL,
`first_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`last_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_unicode_ci NOT NULL,
`verified` int(11) NOT NULL,
`posts` text CHARACTER SET utf32 NOT NULL,
`photos` text CHARACTER SET utf32 NOT NULL,
`followers` text CHARACTER SET utf32 NOT NULL,
UNIQUE KEY `id` (`idu`),
UNIQUE KEY `idu` (`idu`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
In my testing, multi_query has been the fastest way to execute multiple different queries. Why do you feel it's running slow? Compared to what?
Anyway, improvements could come from adding indexes to some of the columns you search frequently:
relationships.users2
relationships.users1
notifications.not_from
notifications.not_to
users.idu
Adding indexes makes searching faster, but it has at least two downsides:
Makes the DB a lot more resource hungry, which could affect your server performance
Makes writing operations take longer
I don't see any problem with your current queries. Really consider whether the slow performance you're seeing comes from the DB queries themselves, or from the rest of your PHP process. Try measuring the script time with the queries, then skipping the queries and taking another measurement (you could hardcode query results). It will give you an idea of whether the slowness is attributable to something else.
Either way, benchmark.
Try creating index on user where deletes are running , this may speed up query

php database table creation fails

I use the following gist to make an OOP attempt to create a database connection:
https://gist.github.com/jonashansen229/4534794
It seems to work so far.
But the creation of the database table passed_exams fails.
Edit:
After recent comments and suggestions i updated my code:
require_once 'Database.php'; // the gist 4534794
class DatabaseSchema {
public function createStudents() {
$db = Database::getInstance();
$mysqli = $db->getConnection();
$create_students = 'CREATE TABLE IF NOT EXISTS students (
id INT(6) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
firstname VARCHAR(40) NOT NULL,
lastname VARCHAR(40) NOT NULL,
university VARCHAR(50)
)';
$result = $mysqli->query($create_students);
}
public function createPassedExams() {
$db = Database::getInstance();
$mysqli = $db->getConnection();
$create_passed_exams = 'CREATE TABLE IF NOT EXISTS passed_exams (
id INT(6) UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(40) NOT NULL,
student_id INT(6),
FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE
)';
$result = $mysqli->query($create_passed_exams);
}
}
$db_student = new DatabaseSchema();
$db_student->createStudents();
$db_student->createPassedExams();
When i look in the mysql console, only table students is created.
Why is table passed_exams missing?
You create the string to check $query_students = 'SELECT ID FROM STUDENTS';
but you never actually run this. Then u check the string if it is Empty, it will never be empty in your code.
What you should do is use the CREATE ... IF NOT EXISTS syntax of mysql, and not what you do here.
First example show the syntax https://dev.mysql.com/doc/refman/5.5/en/create-table.html
The id column on your students table is INT(6) UNSIGNED but the student_id column on the passed_exams table is a signed INT(6). Therefore the FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE clause will fail with "Error Code: 1215. Cannot add foreign key constraint".
I advise you to implement some error handling so that you would see this error message rather than blindly continue executing code.

Get a record with maxid and condition in mysql in yii, but sometime it get second record?

my table:
CREATE TABLE IF NOT EXISTS `the_kho_chi_tiet_with_id` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`ngay_thang` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ma_phieu` varchar(100) COLLATE utf8_unicode_ci NOT NULL,
`id_san_pham` int(11) NOT NULL,
`id_kho` int(11) NOT NULL,
`khoi_luong_nhap` double NOT NULL,
`so_luong_nhap` int(11) NOT NULL,
`khoi_luong_xuat` double NOT NULL,
`so_luong_xuat` int(11) NOT NULL,
`khoi_luong_ton` double NOT NULL,
`so_luong_ton` int(11) NOT NULL,
`kho_du_tru` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
)
PHP code:
$sql = "SELECT so_luong_ton, khoi_luong_ton, kho_du_tru FROM the_kho_chi_tiet_with_id WHERE id_kho = $id_kho and id_san_pham = $id_san_pham ORDER by id DESC LIMIT 1";
$command=$connection->createCommand($sql);
$dataReader=$command->queryAll();
if($dataReader!=null)
{
foreach($dataReader as $row)
{
.................
}
}
**Get a record with maxid and condition in mysql in yii, *but sometime it get second record* !?**
Please check with the below, hope it works!..if not please tell...
$id_kho=373;//sample value declaration
$id_san_pham=1;//sample value declaration
$select="select max(id) as id,so_luong_ton, khoi_luong_ton, kho_du_tru from
the_kho_chi_tiet_with_id where users_ref_id=".$id_kho." and
status=".$id_san_pham;
$command = Yii::app()->db->createCommand($select)->queryRow();
$Maxid=$command['id'];
$so_luong_ton=$command['so_luong_ton'];
$khoi_luong_ton=$command['khoi_luong_ton'];
$kho_du_tru=$command['kho_du_tru'];
I think, the problem is conflict. It mean that when I get record have max_id, and then before i insert new record, having another process insert new record was inserted.
if such cases happen, so how to handle to fix above problem?
My solution:
$lock = $connection->createCommand('LOCK TABLES `the_kho_chi_tiet_with_id` READ');
$lock->execute();
$sql = "SELECT so_luong_ton, khoi_luong_ton, kho_du_tru FROM the_kho_chi_tiet_with_id WHERE id_kho = $id_kho and id_san_pham = $id_san_pham ORDER by id DESC LIMIT 1";
$command=$connection->createCommand($sql);
$dataReader=$command->queryAll();
if($dataReader!=null)
{
foreach($dataReader as $row)
{
.................
}
}
//Insert new record here
TheKhoChiTietWithId::model()->InsertNewRecord(1,300,1,333,1);
$unlock = $connection->createCommand('UNLOCK TABLES');
$unlock->execute();
I lock table to keep no other session work to this table.

Categories