10

I'm very new to PHP/MySQL and I'm learning things as I go. One of the newer things I've learned is that there is a maximum number of connections that can be made to a database for a given username. When I first started building my website on Wordpress, I was using the old mysql_query() commands. I never had to make a connection to the MySQL database because Wordpress keeps an active connection just by being logged in on the website. When I decided to switch all my MySQL queries over to the PDO extension, I could no longer take advantage of Wordpress' active connection, and had to start my own database connections. I did this in a separate PHP config file that I included in every page that ran a script. The PHP code looks like this:

try {
    $DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass);
}
catch(PDOException $e) {  
    echo "Select DB Error: " .$e->getMessage(). "</br>";
}

Unfortunately now, I constantly get the following error:

" SQLSTATE[42000] [1203] User already has more than 'max_user_connections' active connections"

Based on some online research, I tried various different methods to fix this. First, I tried to set the database connection to null at the end of each script (though this should be PHP PDO's default?). Then I tried to set each statement handle to null after each query of the database (this was a hopeless endeavor). And finally, I tried using a persistent connection by changing the following line in my config file:

$DBH = new PDO("mysql:host=$host;dbname=$dbname", $user, $pass, array(PDO::ATTR_PERSISTENT => true));

None of this seems to work and I still get the same exact error. The site, when ready, needs to be able to handle 100-200 people per day entering a myriad of different data. Even if I can figure out how to take advantage of Wordpress' active connection using PDO, that would be a good start. I'd appreciate any help I can get.

UPDATE:

I'm running SHOW FULL PROCESSLIST as a MySQL query in one of my codes and I'm getting very strange behavior. This is the first part of my script (not including the SHOW FULL PROCESSLIST query):

<?php

include 'config.php';

if(isset($_POST['submit']))
{
//Get Current User Login
global $current_user;
$current_user = wp_get_current_user();
$ulog = $current_user->user_login;
$tablename_cc = "cc_".$ulog;
$tablename_db = "db_".$ulog;
$tablename_misc = "misc_".$ulog;
$tablename_cash = "cash_".$ulog;

try {
    $DBH->exec("CREATE TABLE IF NOT EXISTS " .$tablename_cc. " (ID bigint(100) NOT NULL AUTO_INCREMENT, PRIMARY KEY(ID), accnt TEXT(20), cc_num TEXT(4), cc_amnt DECIMAL(8,2), cc_app TEXT(20), cc_date VARCHAR(10), cc_time VARCHAR(10))");            
    $DBH->exec("CREATE TABLE IF NOT EXISTS " .$tablename_db. " (ID bigint(100) NOT NULL AUTO_INCREMENT, PRIMARY KEY(ID), accnt TEXT(20), db_num TEXT(20), db_amnt DECIMAL(8,2), db_date VARCHAR(10), db_time VARCHAR(10))");        
    $DBH->exec("CREATE TABLE IF NOT EXISTS " .$tablename_misc. " (ID bigint(100) NOT NULL AUTO_INCREMENT, PRIMARY KEY(ID), accnt TEXT(20), misc_item TEXT(1000), misc_amnt DECIMAL(8,2), misc_date VARCHAR(10), misc_time VARCHAR(10))");       
    $DBH->exec("CREATE TABLE IF NOT EXISTS " .$tablename_cash. " (ID bigint(100) NOT NULL AUTO_INCREMENT, PRIMARY KEY(ID), accnt TEXT(20), cash_amnt DECIMAL(8,2), cash_time VARCHAR(10))");
}
catch(PDOException $e) {  
    echo "Create Tables Error: " .$e->getMessage();
}
} ?>

If I try to run the SHOW PROCESS LIST query outside of the if statement, I get a result stating that I have one active connection; however, if I try to run the SHOW FULL PROCESSLIST query inside the if statement, I get the error that I have exceeded my number of connections. Based on this result, I figured perhaps my include line on the very top of the page may be causing an issue when the user submits their form (essentially trying to connect to the database twice), so I moved it inside the if statement, but that made no difference either. I'm at a loss as to why this happening.

UPDATE/ANSWER (still some questions):

I figured out what my issue was. Upon completion of one of my scripts, there is a javascript command to pop up a window where another script will print out an invoice for them. That second script also tries to make a connection to the database using the config file. The form the user is working with is dynamic (they can put in as little or as many data sets as they wish), so when the user inserts a small number of data, the PDO queries are performed very fast and there is no conflict between the number of connections; however, if the user inputs a lot of data then it takes a significant more amount of time, and the maximum number of connections is reached by the server. The issue really resides in a combination of poor server environment and inefficient queries on my part (still learning PHP). The only solution I can think of at this point is to put a longer sleep on my second script (already using a 3 second sleep), to let the other script catch up, but at some point, this will just take too long. I'm not sure if you guys have any better suggestions?

Malachi
  • 3,205
  • 4
  • 29
  • 46
user1562781
  • 379
  • 1
  • 9
  • 20
  • 2
    Can you find out what your connection limit is? It's helpful because it's set to something low like 10, you'll probably need to get it changed. If it's something high then we probably have out of control code somewhere. – Levi Morrison Aug 22 '12 at 02:31
  • To be honest, I'm not sure. I'm currently using 000webhost (free account) for testing my PHP/MySQL codes. I've looked all over the website/forum for database connection limitations, but can't seem to find any. The entire website will be installed on its own dedicated server when it's completed, but I need to sort through these sort of errors first. – user1562781 Aug 22 '12 at 02:45
  • Try `ini_get('mysql.max_persistent');` See if it will grab that for you. Also check `mysql.allow_persistent`. – Levi Morrison Aug 22 '12 at 02:49
  • ini_get('mysql.max_persistent'); echos a value of -1? I'm not sure what that means. Also, I just got off of chat with them and they said their paid subscriptions get 10 max connections per user, so I'm assuming a free account is even less. Even still, I'm currently the only user logged in and accessing the site, so I should not be getting any errors whatsoever unless there is an issue with the way I'm handling my connections. There should be a way to make it more efficient. – user1562781 Aug 22 '12 at 02:57
  • I can give sample codes of how I'm utilizing database queries, if it helps display where my inefficiencies are at. – user1562781 Aug 22 '12 at 02:58
  • you talked about a Javascript pop-up. what is the pop-up doing? is it stalling a thread waiting for user input? – Malachi Sep 17 '12 at 21:53
  • Better Question. have you found the solution to your problem yet? – Malachi Sep 17 '12 at 21:54
  • @user1562781 **I would strongly discourage you from sleeping PHP scripts for a longer time**- usually there is a limit of maximum executing PHP scripts at the same time - sleeping script still counts as executing. So it might work for a few users, but for more users at the same time, this would be an app killer. **Anyway** always check if connection does not already exist => **1 script execution should have no more than 1 connection.** – jave.web Jul 03 '15 at 10:06

3 Answers3

2

If you have another tool that can give you a connection to the database you might want to see how many connections you're actually making. In a pinch, phpmyadmin can do this.

Usually you can see all your active queries and connections with:

SHOW PROCESSLIST

If you have made a mistake in your PDO connection routine you may be making a connection for each query you're trying to run rather than one for the duration of the request. You may also need to check that each request is not creating a large pool of connections for you that aren't closed properly. You probably need to experiment with connection options.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • I do have phpmyadmin, but since I can't even make a connection currently, the connection state is shown as 'null'. – user1562781 Aug 22 '12 at 04:02
  • This could be unrelated to your PDO work and instead something else that happened at the same time. Try disabling your app and see if it clears up, or if you can restart the database server somehow. – tadman Aug 22 '12 at 04:13
  • I ran the SHOW FULL PROCESSLIST query inside one of my codes to see the result, and I'm getting some strange behavior. I've updated my initial post with the result. Perhaps you can comment? – user1562781 Aug 22 '12 at 04:32
  • I'm guessing `config.php` makes one connection, `wp_get_current_user` causes WordPress to make a second connection for some reason when populating the WP_User object, and your host is only allowing one connection at a time so that's why you hit the limit when you try to run a query there? This all *seems* like a super overly restrictive web host where the problem would go away in any reasonable environment... – Dan Grossman Aug 22 '12 at 04:37
  • There are two reasons why I suspect that may not be the case. 1) I just moved the wordpress wp_get_current_user() function outside the if statement to see how it behaves and PROCESSLIST shows that it's only making one connection. 2) I managed to use the code a few times earlier today and it was running okay. It only crashed when I tried to input several large arrays. Now it will not work regardless of how small my array is. – user1562781 Aug 22 '12 at 04:42
  • I figured out what my problem is, but not exactly sure on how to fix it. I've updated my original post. I would appreciate any comments/suggestions that you guys have. – user1562781 Aug 22 '12 at 05:12
1

Using include_once('config.php') or require_once('config.php') in the files instead of include 'config.php' may be your solution to avoid duplicate database connections.

khaverim
  • 3,386
  • 5
  • 36
  • 46
0

What you need is called a PDO "singleton" class. Here is an example:

http://tonylandis.com/php/php5-pdo-singleton-class/

It is not the best example because the constructor takes too many arguments. Just hardcode the $dsn,.., args into the constructor ie. _construct(){...} and you can use new sdb() wherever you would have used PDO(). No need for any include or require statements except once for the class.

The $pdo object is stored as a static variable inside the class and so is always accessible.

user1122069
  • 1,767
  • 1
  • 24
  • 52
  • I believe also that "return self::$PDOInstance;" does nothing in this example - the idea is to copy all the class methods, not to return the object and I don't think that you can return anything from __construct(); – user1122069 Sep 15 '12 at 14:22