I want a trigger to fire only when UPDATEs are user-initiated (not me running updates from the MySQL command line).
What's the 'industry standard' for achieving this? I have been trying unsuccessfully to detect a variable passed in with the query (i.e. #user_update=true), but without success. A colleague of mine suggested a way to do it would be to add a new column into the table containing the trigger: 'fire_trigger', for example. And fill this with 'true' when running the SQL from the code, and ensure that this is present in order for the trigger to fire.
Any help much appreciated!
Disable the trigger before doing command-line updates and re-enable it after.
But you're doing this wrong, conceptually.
Why shouldn't the trigger run when you use the command line? I Assume this is some sort of auditing trigger, that captures who updated a row. You at the command line are a "who" too.
Comment from OP:
Yes - good point! :) It is a "dd/mm/yyyy hh:mm - User A changed First name from "Jane" to "Joan"" type thing. I just don't want it to fill the history table during the test phase when I'm potentially updating rows 'manually'.
Then either disable the trigger, or just delete the added history rows after. Even better, do your testing on a separate database, and just don't worry about this at all.
Create 2 mysql users: one that is used by the application(so it will identify your users) and one that you will use when connecting through the mysql client.
In the update trigger, check for the user with CURRENT_USER() and take action only when it's the application user.
Hope it helps!
Related
Overview
Consider the following details:
We have a table named user. In it is a column named wallet.
We have a table named walletAction. We insert a new entry on each wallet action a user is doing. This table acts like some sort of logs in the database with some calculations.
We have a CRON command that does an update every N minutes. Each CRON action gets some data by using a standalone API and 'inserts' a new walletAction entry. At the sime time, it updates the user.wallet's value.
A user can buy stuff from our site. When the user clicks the buy button, we insert a new walletAction entry and change the user.wallet column.
Problem
I am afraid that the CRON update and the action of the user when they click the buy button will happen at the exact same time causing the entries in the walletAction table to have wrong calculations.
I need some kind of 'lock' on the CRON update execution or something along those lines.
Questions
Should I be afraid of this situation?
How can I avoid this problem?
Can I avoid this trouble by using MySQL transactions?
What isolation level should I use and in which case should I use it? (In the CRON command or in the action of the user when they click the buy button?)
It seems that we don't have concurrency on php as is in GO or Java. You can implement some technical trick, but almost of them made new problems for you :). For solving your problem i suggest you to use optimistic lock. For more information you can see http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#optimistic-locks.
Yes, in this case I would recommend to use trasactions with the strongest isolation level yii\db\Transaction::SERIALIZABLE.
This level should prevent "phantom reads" and "non-repetable reads".
Moreover I recommend to use transactions always when you perform more than 1 related changes, because it helps to keep DB consistency.
This may prevents problem when you get some PHP exception after successful inserting new rows into walletAction, but before user.wallet updating.
This one happened to me last night. I am quite familiar with the nature of the error but still I cannot figure out what could have caused it. I might have a hunch, but I am not sure. I'll begin with some basic app's info:
My app has 3 entities: Loan, SystemPage and TextPage. Whenever someone adds a loans, one or more system pages is being added to the DB. Basically, it goes something like this:
if ( $form->isValid()){
$this->em->getConnection()->beginTransation();
$this->em->persist($loan);
$this->em->flush();
while ($someCondition){
$page = new SystemPage();
//... Fill the necessary data into page
$page->setObject($loan);
$this->em->persist($page);
}
$this->em->flush();
$this->em->getConnection()->commit();
}
Please ignore potential typos, I am writing this literally by remembering
Entity Loan is mapped to table loans and SystemPage is mapped (via inheritance mapping) to system_pages and base_pages. Both of later one have id field which is set to AUTO_INCREMENT.
My hunch: There is another table called text_pages. Given that text_pages and base_pages on one hand and system_pages and base_pages on another share IDs, I am thinking that it could easily cause this:
User1: Create BasePage, acquire autoincrement ID (value = 1)
User2: Create BasePage, acquire autoincrement ID (value = 1)
User1: Create TextPage, use the ID from step 1
User2: Create SystemPage, use the ID from step 2
Two problems with this theory:
Transactions. That's why I used them in the first place
In the time of error there was no other activity on app by another user
Important: After waiting for a minute, resubmitting passed OK.
Could this be some weird MySQL transaction isolation bug? Any hint would be greatly appreciated...
Edit:
Part of DB Schema:
Please ignore the columns names which are in Serbian language
flush() operation flushes all changes in one single transaction, so you have redundant code here...
You didn't stated if you can reproduce this bug and it would be convenient if you can provide db schema.
It seems there is no right answer to this question, only speculation, so I will provide some troubleshooting ideas based on my own experiences with a problem like this:
You mention there was no other activity on the app, but I would triple check that by looking at the query logs. There must be a duplicate query that was executed.
Maybe the form was submitted twice accidentally. The user double-clicked on the submit button, or they clicked again if the UI did not respond. You can check this idea by looking at the Apache log files for POST requests on your form around the same timestamp. You may need to implement some javascript code to prevent double-clicks on your form page submit button.
Your hunch is probably quite close to correct, in that there is some kind of race condition. Using transactions won't prevent race conditions, but they do provide the means to gracefully rollback. Wrap your code in a try/catch block so that you can catch the Mysql exception and present the user with a friendly error and the option to retry.
I am working on a custom MVC application.
Its an ERP system where we need to set restriction that if a record is opened by admin1 then other user (admin2) can view but cannot change the record.
I have read about locking table and about transactions but didn't get much cleared idea.
Can someone give exact idea with some sample code.
Thanks
Whatever db lock you acquire while the php script is running will be released upon script completion. A workaround is to add a column that will serve as a flag indicating that the record is being updated. Alternatively, you can use a timestamp that is updated via a trigger when the row is updated. You can then use that timestamp to check if someone else has updated that record.
See http://www.akadia.com/services/ora_update_guide.html examples of concurrency control.
Question is following: I have an oracle trigger after row insert. From trigger, I want to call a php script and pass just inserted row fields as parameters.
Insert is coming from very old legacy application with a very little chance of looking at the source code. Rows are inserted frequently, could be batches of ~1000 rows at a time or could be one row in 30minutes, so checking this table every, let's say, 5 seconds is not an option.
So, Idea is to have oracle trigger, which would be triggered every time on insert and call my php script? Any ideas?
Thanks in advance...
When you say "php script" do you literally mean a command line script, or a chunk of php being run through apache/etc.
If its the former, then go with OMG Ponies. Otherwise I'd use UTL_HTTP to make the call to Apache/PHP. Actually, I'd probably consider going with this anyway ( updating your php/c# if needed ).
Just remember though.. Triggers are transactional... if you absolutely MUST call out from a trigger be aware that your trigger may run several times ( due to query restart ) and may rollback completely, resulting in your external (presumably non-transactional) php call now being invalid. If your php can't handle this then perhaps have your trigger creating a job or even a message into an AQ or something, this would also speed up handling, you probably don't really want your insert to be waiting on an external web call.
I want to call a php script when some row is inserted or updated in some table via oracle triggers . Currently I m using this but its not much of help.
CREATE OR REPLACE TRIGGER test_script
BEFORE INSERT OR UPDATE OR DELETE ON STATES
FOR EACH ROW
BEGIN
-- Flags are booleans and can be used in any branching construct.
CASE
WHEN INSERTING THEN
:'/! echo C:/wamp/bin/php/php5.3.5/php.exe C:/wamp/www/csv.php >> C:/wamp/www/log.txt'
WHEN UPDATING THEN
-- Include any code specific for when the trigger is fired from an UPDATE.
WHEN DELETING THEN
-- Include any code specific for when the trigger is fired from an DELETE.
END CASE;
END;
/
I was wondering how to trigger a notification if a new record is inserted into a database, using PHP and MySQL.
You can create a trigger than runs when an update happens. It's possible to run/notify an external process using a UDF (user defined function). There aren't any builtin methods of doing so, so it's a case of loading a UDF plugin that'll do it for you.
Google for 'mysql udf sys_exec' or 'mysql udf ipc'.
The simplest thing is probably to poll the DB every few seconds and see if new records have been inserted. Due to query caching in the DB this shouldn't effect DB performance substantially.
MySQL does now have triggers and stored procedures, but I don't believe they have any way of notifying an external process, so as far as I know it's not possible. You'd have to poll the database every second or so to look for new records.
Even if it were, this assumes that your PHP process is long-lived, such that it can afford to hang around for a record to appear. Given that most PHP is used for web sites where the code runs and then exits as quickly as possible it's unclear whether that's compatible with what you have.
If all your database changes are made by PHP I would create a wrapper function for mysql_query and if the query type was INSERT, REPLACE, UPDATE or DELETE I would call a function to send the respective email.
EDIT: I forgot to mention but you could also do something like the following:
if (mysql_affected_rows($this->connection) > 0)
{
// mail(...)
}
One day I ask in MySQL forum if event like in Firebird or Interbase exist in MySQL and I see that someone answer Yes (I'm really not sure)
check this : http://forums.mysql.com/read.php?84,3629,175177#msg-175177
This can be done relatively easily using stored procedures and triggers. I have created a 'Live View' screen which has a scrolling display which is updated with new events from my events table. It can be a bit fiddly but once its running its quick.