While running PHPUnit tests, a lot of connections are created but not closed.
I can see this in
mysql> show processlist;
In my database class I create a db connection by implementing PHPUnit_Extensions_Database_TestCase#getConnection().
I make sure that in the teardown the connection gets closed. See snippet:
<?php
abstract class My_Tests_DatabaseTestCase extends \PHPUnit_Extensions_Database_TestCase
{
static private $pdo = null;
private $conn = null;
/**
* #throws RuntimeException
* #return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
final public function getConnection()
{
$iniFilePath = __DIR__ . '/../../../db-config.ini';
$iniFile = parse_ini_file($iniFilePath, true);
$dsn = "mysql:dbname=".$iniFile['phpunit']['dbname'].";host=".$iniFile['phpunit']['host'];
if ( $this->conn === null ) {
if ( self::$pdo == null ) {
self::$pdo = new \PDO($dsn, $iniFile['phpunit']['user'], $iniFile['phpunit']['password']);
}
$this->conn = $this->createDefaultDBConnection(self::$pdo, $iniFile['phpunit']['dbname']);
}
return $this->conn;
}
protected function getSetUpOperation()
{
return new \PHPUnit_Extensions_Database_Operation_Composite(array(
new \TestsExtensions\TruncateDatabaseOperation(),
\PHPUnit_Extensions_Database_Operation_Factory::INSERT()
));
}
protected function getTearDownOperation() {
return \PHPUnit_Extensions_Database_Operation_Factory::TRUNCATE();
}
protected function setUp()
{
parent::setUp();
$em = \ORM\Provider::getInstance()->getEntityManager(\ORM\Provider::DEFAULT_ID);
$em->clear();
}
protected function tearDown()
{
parent::tearDown();
$em = \ORM\Provider::getInstance()->getEntityManager(\ORM\Provider::DEFAULT_ID);
$em->getConnection()->close();
if ($this->conn) {
$this->conn->close();
}
}
}
Debugging showed that the connections were closed, but the processlist showed them with status "sleep".
The amount of connections rises until I get the "too many connections" error.
I do not want to increase the number of connections. I want to close the connection.
What can I modify to make this happen?
Snippet from PDO Connection management:
Upon successful connection to the database, an instance of the PDO
class is returned to your script. The connection remains active for
the lifetime of that PDO object. To close the connection, you need to
destroy the object by ensuring that all remaining references to it are
deleted--you do this by assigning NULL to the variable that holds the
object. If you don't do this explicitly, PHP will automatically close
the connection when your script ends.
Don't store the PDO or set it to null in the teardown:
Remove static private $pdo = null;
or
protected function tearDown()
{
parent::tearDown();
$em = \ORM\Provider::getInstance()->getEntityManager(\ORM\Provider::DEFAULT_ID);
$em->getConnection()->close();
if ($this->conn) {
$this->conn->close();
}
self::$pdo = null;
}
I don't think you need to store the PDO if you are going to pass it into the PHPUnit DB connection
Related
We are creating an extension for the NetConnection object. When we get an error we will retry “n” times. After “n” times we want to call the responder result method returning an error. The responder object contains two properties, both functions, however we cannot seem to see how to access those functions. Is it possible to execute the “result” function of Responder object?
An example might be;
_rspResponder:Responder = new Responder(someFunction);
// lots of code...
_rspResponder.result("Error: Connection timeout failure.\n A network connection error occurred, if needed please try to save work and restart the application.\n Otherwise just restart the application.\n");
Edit:
Based on comments below I created an extended responder like;
package com.fluorinefx
{
import flash.net.Responder;
public class PublicResponder extends Responder
{
/**
* result - Result handler function
*
* #return result
*/
private var _result:Function = null;
public function get result():Function
{
return this._result;
}
public function set result(value:Function):void
{
this._result = value;
}
/**
* status - Status (error) handler function
*
* #return status
*/
private var _status:Function = null;
public function get status():Function
{
return this._status;
}
public function set status(value:Function):void
{
this._status = value;
}
public function PublicResponder(result:Function, status:Function=null)
{
_result = _result;
_status = status;
super(result, status);
}
}
}
When I attempt to use it in my extended NetConnection like;
import com.fluorinefx.PublicResponder;
private var _rspResponder:PublicResponder;
public override function call(strCommand:String, rspResponder:Responder, ...parameters:Array):void
_rspResponder = rspResponder;
I get an implicit coercion error on the "_rspResponder = rspResponder;" line.
After “n” times we want to call the responder result method returning an error.
Is it possible to execute the result function of the Responder object?
Does something like this setup help you?
//# global vars
public var _rspResponder :Responder;
public var try_count :int = 0;
//# test it...
_rspResponder = new Responder( onResult, onError );
//# Since "result" param can be Object or String... using asterix to allow any data-type
private function onResult( result:* ) :void
{
trace( result ); try_count = 0;
}
//# no comment needed here...
private function onError( error:Object ) :void
{
try_count++;
_rspResponder = new Responder( onResult, onError ); //# retry again
//# after N retries, send custom error String to "onResult" function
if ( try_count == 5)
{
onResult( "Error: Connection timeout failure.\n A network connection error occurred, if needed please try to save work and restart the application.\n Otherwise just restart the application.\n" );
}
}
I have an yii2 project with the advanced template and I want to implement notifications using a mosquitto broker.
I already have the publish part done and working, now I'd like to have some help on subscribing to a topic on my frontend app. I already tried, but the page seems to stop working when I subscribe to any topic.
Is there any easy way or tutorial that I can use? If any more information is needed, please ask.
P.S: My idea was: When I open any page on frontend, I check for messages, save them in a array, set them as view param and then render my page.
EDIT: So far i've tried the following
Class
<?php
namespace common\models;
use Yii;
class Notificacoes
{
private $listaNotificacoes;
public function __construct($id, $name)
{
$this->listaNotificacoes = array();
$server = "127.0.0.1";
$port = 1883;
$username = "";
$password = "";
$client_id = $id;
$mqtt = new \common\mosquitto\phpMQTT($server, $port, $client_id);
if(!$mqtt->connect(true, NULL, $username, $password)) {
exit(1);
}
$topics[$name] = array("qos" => 0, "function" => "procmsg");
$mqtt->subscribe($topics, 0);
while($mqtt->proc()){
}
$mqtt->close();
}
function procmsg($topic, $msg)
{
\array_push($this->listaNotificacoes, $msg);
}
public function getAll()
{
return $this->listaNotificacoes;
}
}
SiteController: I tried to get the messages on the beforeAction method
public function beforeAction($action)
{
if (!parent::beforeAction($action)) {
return false;
}
$notifications = array();
if (!Yii::$app->user->isGuest)
{
$notifs = new Notificacoes(Yii::$app->user->identity->getId(), Yii::$app->user->identity->username);
$notifications = $notifs->getAll();
}
$this->view->params['notifications'] = $notifications;
return true;
}
This model is unlikely to work because normally messages are only delivered by MQTT at the instant they are published.
So unless you are using retained messages or persistent subscriptions for a given client id to queue messages. This means your while loop will never have any messages to process
I'm having a problem involving a database transaction in one class that is timing out due to a secondary database connection being opened within the transaction; the problem started occurring when I added a foreign key constraint. And, testing using:
SET foreign_key_checks = 0;
I've been able to confirm this.
My database class looks like this (I've left off all of the methods):
class Db {
function __construct($config) {
$this->config = $config;
}
private function connect($config) {$dsn = 'mysql:host=' . $config['host'] . ';dbname=' . $config['dbname'] . ';charset=utf8';
$options = array(
// PDO::ATTR_PERSISTENT => true,
PDO::ATTR_EMULATE_PREPARES => false,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
);
$dbh = new PDO($dsn, $config['username'], $config['password'], $options);
$dbh->exec("SET NAMES utf8;");
return $dbh;
}
}
My model looks like this:
class Model {
function __construct() {
$this->db = new Db(array('host'=>DB_HOST,'dbname'=>DB_NAME,'username'=>DB_USERNAME,'password'=>DB_PASSWORD));
}
}
The code below then performs a little bit of logic, then an insert into the question_orders table: question_orders has a column question_id, with a foreign key index, which references the parent table questions; I think that the problem is that Assessment_Question_Orders extends the Model and creates a new database connection? Any thoughts on how to maintain both the transaction and foreign key aspects would be appreciated.
class This_Is_A_Problem extends Model() {
public function __construct() {
parent::construct();
}
public function problemFunction() {
/*variable init code left out*/
$this->db->beginTransaction();
$db_result = false;
try {
$db_result = $this->db->insert('questions', $questions_data);
$new_insert_id = $this->db->lastInsertId();
$assessment_question_orders = new Assessment_Question_Orders();
$question_number = $assessment_question_orders->insertSingleQuestionOrder($module_id, $new_insert_id);
$db_result = $this->db->commit();
}
} catch (PDOException $e) {
$this->db->rollBack();
}}}
One thread should (usually) have only one connection to the database. So I recommend one of these patterns:
Plan A: a single $db passed into all classes:
$db = new PDO(...);
$my_obj = new My_Class($db); -- $db is saved in $this->db for use within the methods of My_Class.
Plan B: a singleton Db class with a getter method:
// Singleton (of sorts)
class Db
{
private static $db;
function __construct()
{
self::$db = new PDO(...);
// A variant would include "lazy" instantiation of self::$Db.
}
function Get_Db() { return self::$db; } // All calls get the same `db`
}
class My_class
{
function My_Method()
{
$db = Db::Get_Db();
$db->...
}
}
new Db(); // one time call at start of program
There is only rarely a need to have two db connections in a single program. Plan A easily allows for such. (But see if you can avoid it -- you are in trouble now because of it.)
I am trying to determine if I am actually using JDBC connection pooling. After doing some research, the implementation almost seems too easy. Easier than a regular connection in fact so i'd like to verify.
Here is my connection class:
public class DatabaseConnection {
Connection conn = null;
public Connection getConnection() {
BasicDataSource bds = new BasicDataSource();
bds.setDriverClassName("com.mysql.jdbc.Driver");
bds.setUrl("jdbc:mysql://localhost:3306/data");
bds.setUsername("USERNAME");
bds.setPassword("PASSWORD");
try{
System.out.println("Attempting Database Connection");
conn = bds.getConnection();
System.out.println("Connected Successfully");
}catch(SQLException e){
System.out.println("Caught SQL Exception: " + e);
}
return conn;
}
public void closeConnection() throws SQLException {
conn.close();
}
}
Is this true connection pooling? I am using the connection in another class as so:
//Check data against database.
DatabaseConnection dbConn = new DatabaseConnection();
Connection conn;
ResultSet rs;
PreparedStatement prepStmt;
//Query database and check username/pass against table.
try{
conn = dbConn.getConnection();
String sql = "SELECT * FROM users WHERE username=? AND password=?";
prepStmt = conn.prepareStatement(sql);
prepStmt.setString(1, user.getUsername());
prepStmt.setString(2, user.getPassword());
rs = prepStmt.executeQuery();
if(rs.next()){ //Found Match.
do{
out.println("UserName = " + rs.getObject("username") + " Password = " + rs.getObject("password"));
out.println("<br>");
} while(rs.next());
} else {
out.println("Sorry, you are not in my database."); //No Match.
}
dbConn.closeConnection(); //Close db connection.
}catch(SQLException e){
System.out.println("Caught SQL Exception: " + e);
}
Assuming that it's the BasicDataSource is from DBCP, then yes, you are using a connection pool. However, you're recreating another connection pool on every connection acquirement. You are not really pooling connections from the same pool. You need to create the connection pool only once on application's startup and get every connection from it. You should also not hold the connection as an instance variable. You should also close the connection, statement and resultset to ensure that the resources are properly closed, also in case of exceptions. Java 7's try-with-resources statement is helpful in this, it will auto-close the resources when the try block is finished.
Here's a minor rewrite:
public final class Database {
private static final BasicDataSource dataSource = new BasicDataSource();
static {
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/data");
dataSource.setUsername("USERNAME");
dataSource.setPassword("PASSWORD");
}
private Database() {
//
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
(this can if necessary be refactored as an abstract factory to improve pluggability)
and
private static final String SQL_EXIST = "SELECT * FROM users WHERE username=? AND password=?";
public boolean exist(User user) throws SQLException {
boolean exist = false;
try (
Connection connection = Database.getConnection();
PreparedStatement statement = connection.prepareStatement(SQL_EXIST);
) {
statement.setString(1, user.getUsername());
statement.setString(2, user.getPassword());
try (ResultSet resultSet = preparedStatement.executeQuery()) {
exist = resultSet.next();
}
}
return exist;
}
which is to be used as follows:
try {
if (!userDAO.exist(username, password)) {
request.setAttribute("message", "Unknown login. Try again.");
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response);
} else {
request.getSession().setAttribute("user", username);
response.sendRedirect("userhome");
}
} catch (SQLException e) {
throw new ServletException("DB error", e);
}
In a real Java EE environement you should however delegate the creation of the DataSource to the container / application server and obtain it from JNDI. In case of Tomcat, see also for example this document: http://tomcat.apache.org/tomcat-6.0-doc/jndi-resources-howto.html
Doesn't seem like it's pooled. You should store the DataSource in DatabaseConnection instead of creating a new one with each getConnection() call. getConnection() should return datasource.getConnection().
Looks like a DBCP usage. If so, then yes. It's already pooled. And here is the default pool property value of the DBCP.
/**
* The default cap on the number of "sleeping" instances in the pool.
* #see #getMaxIdle
* #see #setMaxIdle
*/
public static final int DEFAULT_MAX_IDLE = 8;
/**
* The default minimum number of "sleeping" instances in the pool
* before before the evictor thread (if active) spawns new objects.
* #see #getMinIdle
* #see #setMinIdle
*/
public static final int DEFAULT_MIN_IDLE = 0;
/**
* The default cap on the total number of active instances from the pool.
* #see #getMaxActive
*/
public static final int DEFAULT_MAX_ACTIVE = 8;
As a follow up to BalusC's solution, below is an implementation that I can be used within an application that requires more than one connection, or in a common library that would not know the connection properties in advance...
import org.apache.commons.dbcp.BasicDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.concurrent.ConcurrentHashMap;
public final class Database {
private static final ConcurrentHashMap<String, BasicDataSource> dataSources = new ConcurrentHashMap();
private Database() {
//
}
public static Connection getConnection(String connectionString, String username, String password) throws SQLException {
BasicDataSource dataSource;
if (dataSources.containsKey(connectionString)) {
dataSource = dataSources.get(connectionString);
} else {
dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl(connectionString);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSources.put(connectionString, dataSource);
}
return dataSource.getConnection();
}
}
Here's what I'm trying to do: I've got a db.php file that does all the db manipulation.
It has 2 static methods, connect and deconnect.
In my other file i simply use db::connect() and db::deconnect(). The mysql_close($con) in the deconnect method just doesn't know who $con is.
Since I don't want to instantiate my class static is the only way to go.
Declaring 'private $con' in class db doesn't seem to have an effect.
Any ideas?
class db {
public static function connect() {
$dbData = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/config.ini');
$con = mysql_connect($dbData['host'],$dbData['user'],$dbData['pass']);
$db = mysql_select_db($dbData['db']);
if ((!$con) || (!$db))
return 0;
else return 1;
}
public static function deconnect() {
mysql_close($con);
}
}
In deconnect, $con is out of scope.
You should make it a static member, like this:
class db {
static $con;
public static function connect() {
$dbData = parse_ini_file($_SERVER['DOCUMENT_ROOT'].'/config.ini');
self::$con = mysql_connect($dbData['host'],$dbData['user'],$dbData['pass']);
$db = mysql_select_db($dbData['db']);
if ((!self::$con) || (!$db))
return 0;
else return 1;
}
public static function deconnect() {
if( !isset( self::$con ) ) return;
mysql_close( self::$con );
}
}
The message makes sense as $con is out of scope in your deconnect() method (deconnect...?).
Use a static data member
class db {
static $con;
}
Access it through self::$con.
Well, it seems to me that $con is a local variable (local to the method connect). Thus, when you call mysql_close, most likely $con is undefined. Try declaring $con as a private variable in your class. Look here for more info on how to do that.