How can i reduce load on browser? - mysql

I am using multiple databases on cloud and css framework twitter bootstrap to grab the suggession on textfield using "typeahead" with ajax.
now on every keyup event one ajax call get fire and fires a query as below:
public function prod_identifier_typeahead($value) {
$db = ConnectionManager::getDataSource('incident_mgmt');
$list = $db->rawQuery('select id, identifier from products where identifier like "'.$value.'%";');
$options = array();
while ($row = $db->fetchRow()) {
$options[] = array('id' => $row["products"]["id"],'name' => $row["products"]["identifier"]);
}
$this->set('options', $options);
$this->set('_serialize', 'options');
}
Every ajax call uses the connection object .Now, Can anyone help me to reduce load on this ajax call query processing ?

Cake has caching which can be used to store data that has been retrieved from the database. Thus duplicate requests will not hit the database, however, you need to be careful that you don't fill your cache with data that will never be used again.
I would try to optimize for common usage patterns. For example, a user types 'abdc', hits backspace twice, then types 'cd'. In this case, you'll get a cache hit on 'ab' and 'abd' almost immediately but 5 minutes later its probably safe to clear everything associated with this query.

Related

Issue with concurrent requests in CakePHP 2.0

Thanks in advance for attempting to asssist me with this issue.
I'm using CakePHP 2 (2.10.22).
I have a system which creates applications. Each application that gets created has a unique application number. The MySQL database column that stores this application number is set to 'Not null' and 'Unique'. I'm using CakePHP to get the last used application number from the database to then build the next application number for the new application that needs to be created. The process that I have written works without any problem when a single request is received at a given point in time. The problem arises when two requests are received to create an application at the exact same time. The behaviour that I have observed is that the the request that gets picked up first gets the last application number - e.g. ABC001233 and assigns ABC001234 as the application number for the new application it needs to create. It successfully saves this application into the database. The second request which is running concurrently also gets ABC001233 as the last application number and tries to create a new application with ABC001234 as the application number. The MySQL database returns an error saying that the application number is not unique. I then put the second request to sleep for 2 seconds by which time the first application has successfully saved to the database. I then re-attempt the application creation process which first gets the last application number which should be ABC001234 but instead each database read keeps returning ABC001233 even though the first request has long been completed. Both requests have transactions in the controller. What I have noticed is that when I remove these transactions, the process works correctly where for the second request after the first attempt fails, the second attempt works correctly as the system correctly gets ABC001234 as the last application number and assigns ABC001235 as the new application number. I want to know what I need to be doing so as to ensure the process works correctly even with the transaction directives in the controller.
Please find below some basic information on how the code is structured -
Database
The last application number is ABC001233
Controller file
function create_application(){
$db_source->begin(); //The process works correctly if I remove this line.
$result = $Application->create_new();
if($result === true){
$db_source->commit();
)else{
$db_source->rollback();
}
}
Application model file
function get_new_application_number(){
$application_record = $this->find('first',[
'order'=>[
$this->name.'.application_number DESC'
],
'fields'=>[
$this->name.'.application_number'
]
]);
$old_application_number = $application_record[$this->name]['application_number'];
$new_application_number = $old_application_number+1;
return $new_application_number;
}
The above is where I feel the problem originates. For the first request that gets picked up, this find correctly finds that ABC001233 is the last application number and this function then returns ABC001234 as the next application number. For the second request, it also picks up ABC001233 as the last application number but will fail when it tries to save ABC001234 as the application number as the first request has already saved an application with that number. As a part of the second attempt for the second request (which occurs because of the do/while loop) this find is requested again, but instead of returning ABC001234 as the last application number (per the successfuly save of the first request), it keeps returning ABC001233 resulting in a failure to correctly save. If I remove the transaction from the controller, this then works correctly where it will return ABC001234 in the second attempt. I couldn't find any documentation as to why that is and what can be done about the same and is where I need some assistance. Thank you!
function create_new(){
$new_application_number = $this->get_new_application_number();
$save_attempts = 0;
do{
$save_exception = false;
try{
$result = $this->save([$this->name=>['application_number'=>$new_application_number]], [
'atomic'=>false
]);
}catch(Exception $e){
$save_exception = true;
sleep(2);
$new_application_number = $this->get_new_application_number();
}
}while($save_exception === true && $save_attempts++<5);
return !$save_exception;
}
You just have to lock the row with the previous number in a transaction using SELECT ... FOR UPDATE. It's much better than the whole table lock as said in the comments.
According to documentation https://book.cakephp.org/2/en/models/retrieving-your-data.html you just have to add 'lock' => true to get_new_application_number function:
function get_new_application_number(){
$application_record = $this->find('first',[
'order'=>[
$this->name.'.application_number DESC'
],
'fields'=>[
$this->name.'.application_number'
],
'lock'=>true
]);
$old_application_number = $application_record[$this->name]['application_number'];
$new_application_number = $old_application_number+1;
return $new_application_number;
}
How does it work:
The second transaction will wait on that request while the first transaction is ended.
P.S. According to documentation lock option was added in the 2.10.0 version of CakePHP.

Find call returning outdated info immediately after Save

In my application, an action takes some user generated input and uses it to update an entry in the database.
The relevant code resembles the following:
$this->Model->save($data);
$result = $this->Model->findById($id);
The problem is that the contents of $result are outdated. That is, $result contains the record as it was before the save.
I'm assuming that the entry just isn't updated until the function returns. However, I can't do the obvious
$result = $this->Model->save($data);
because this method does not preserve relationships. In this case, the model belongs to another model. I need to be able to get the updated record and the record it belongs to.
See if
$result = $this->Model->findById($id);
is loading from the cache, not the database.
Take a look at:
http://fredericiana.com/2007/09/05/cakephp-delete-cached-models-on-database-change/
http://snook.ca/archives/cakephp/delete_cached_models/
Personally, I've never liked Cake's magic find functions. I find them difficult to add extra conditions/joins/etc to and I much prefer to type a few more lines and get something specific that I can easily adjust.
Sounds in this case like the magic find function is returning from the cache, and you should try a regular find call instead:
$this->Model->save($data);
$result = $this->Model->find('first', array('conditions' => array('id' => $id)));
However, you should try and narrow down your problem and find out exactly what it is for future reference. You could try manually clearing the cache before you do your magic find and see if you get the correct response:
$this->Model->save($data);
Cache::clear();
$result = $this->Model->findById($id);
Another unlikely yet possible option is that your $id variable may not be pointing to the correct model row, and your save might be creating a new one so that when you findById($id) the $id is different to the ID of the row you've just saved/created. In this case, it's worth doing a debug($id) or $this->log('ID is: ' . $id, 'my_test_log'); before and after your safe or at intervals through your code to work out what is happening and where.

Auto update prices in database, mysql

I am currently getting products from one site, storing them in a database, and then having their prices display on another site. I am trying to get the prices from the one site to update daily in my database so the new updated prices can be displayed onto my other site.
Right now I am getting the products using an item number but have to manually go in and update any prices that have changed.
I am guessing I am going to have to use some kind of cronjob but not sure how to do this. I have no experience with cronjobs and am a noob with php.
Any ideas?
Thanks!
I have done some reading on the foreach loop and have written some code. But my foreach loop is only running once for the first item number. The foreach loop runs then goes to the "api.php" page but then stops. It doesn't continually loop for each item number. How do I tell it to go through all of item numbers in my database?
Also if you see anything else wrong in my code please let me know.
Thanks
....
$itemnumber = array("".$result['item_number']."");
foreach ($itemnumber as $item_number) {
echo "<form method=\"post\" action=\"api.php\" name=\"ChangeSubmit\" id=\"ChangeSubmit\">";
echo "<input type=\"text\" name=\"item_number\" value=\"{$item_number}\" />";
echo "<script type=\"text/javascript\">
function myfunc () {
var frm = document.getElementById(\"ChangeSubmit\");
frm.submit();
}
window.onload = myfunc;
</script></form>";
}
}
If you already retrieve the product data from an external site and store it in a local database, updating the prices from the same source should be no problem to you. Just retrieve the data, iterate through it in a foreach loop or similar and update the prices to the database based on the item number.
Once you have created the update script and run it manually, adding it as a cronjob will be as simple as running the command `crontab -e´ and adding this row to execute your script every midnight:
0 0 * * * /usr/local/bin/php /path/to/your/script.php
Don't forget to use the correct path for PHP for your system, running which php in the shell will tell you the path.
If you have cronjob's on your server, it'll be very apparent- You make a PHP script that updates it, and throw it in a daily cronjob.
However, I do it this way:
Method 1: At the beginning of every page request, check the last "update" time (you choose how to store it). If it's been more than a day, do the update and set the "update" time to the current time.
This way, every time someone loads a page and it's been a day since the last update, it updates for them. However, this means it's slower for random users, once a day. If this isn't acceptable, there's a little change:
Method 2: If you need to update (via the above method of checking), start an asyncronous request for the data, handle the rest of the page, flush it to the user, then in a while loop wait until the request finishes and update it.
The downside to method 2 is that the user won't see the updated values, but, the benefit is that it won't be any more of a wait for them.

Last inserted id in cakephp

I use this code but its not working in cakephp and the code is:
$inserted = $this->get_live->query("INSERT INTO myaccounts (fname) values('test');
After this im using:
$lead_id = $this->get_live->query("SELECT LAST_INSERT_ID()");
It's working, but only one time.
Try this. Lots less typing. In your controller, saving data to your database is as simple as:
public function add() {
$data = "test";
$this->Myaccount->save($data);
// $this->set sends controller variables to the view
$this->set("last", $this->Myaccount->getLastInsertId());
}
You could loop through an array of data to save with foreach, returning the insertId after each, or you could use Cake's saveAll() method.
Myaccount is the Model object associated with your controller. Cake's naming convention requires a table called "myaccounts" to have a model class called "Myaccount" and a controller called "Myaccounts_Controller". The view files will live in /app/views/myaccounts/... and will be named after your controller methods. So, if you have a function add()... method in your controller, your view would be /app/Views/Myaccounts/add.ctp.
The save() method generates the INSERT statement. If the data you want to save is located in $this->data, you can skip passing an argument in; it will save $this->data by default. save() even automagically detects whether to generate an UPDATE or an INSERT statement based on the presence of an id in your data.
As a rule of thumb, if you're using raw sql queries at any point in Cake, you're probably doing it wrong. I've yet to run into a query so monstrously complex that Cake's ORM couldn't model it.
http://book.cakephp.org/2.0/en/models/saving-your-data.html
http://book.cakephp.org/2.0/en/models/additional-methods-and-properties.html?highlight=getlastinsertid
HTH :)
You can get last inserted record id by (works for cakePHP 1.3.x and cakePHP 2.x)
echo $this->ModelName->getLastInsertID();
Alternately, you can use:
echo $this->ModelName->getInsertID();
CakePHP 1.3.x found in cake/libs/model/model.php on line 2775
CakePHP 2.x found in lib/Cake/Model/Model.php on line 3167
Note: This function doesn't work if you run the insert query manually
pr($this->Model->save($data));
id => '1'
id is a last inserted value

CakePHP Accessing Dynamically Created Tables?

As part of a web application users can upload files of data, which generates a new table in a dedicated MySQL database to store the data in. They can then manipulate this data in various ways.
The next version of this app is being written in CakePHP, and at the moment I can't figure out how to dynamically assign these tables at runtime.
I have the different database config's set up and can create the tables on data upload just fine, but once this is completed I cannot access the new table from the controller as part of the record CRUD actions for the data manipulate.
I hoped that it would be along the lines of
function controllerAction(){
$this->uses[] = 'newTable';
$data = $this->newTable->find('all');
//use data
}
But it returns the error
Undefined property:
ReportsController::$newTable
Fatal error: Call to a member function
find() on a non-object in
/app/controllers/reports_controller.php
on line 60
Can anyone help.
You need to call $this->loadModel('newTable') to initialize it properly. Cake needs to initialize $this->newTable properly, and call all the callbacks.
Of course, you don't need $this->uses[] = 'newTable';, that doesn't do anything except add another value to the $uses array.
try:
function controllerAction() {
$data = ClassRegistry::init('ModelNameForNewTable')->find('all');
}
If your table is called 'new_tables', your model name should be 'NewTable'