【问题标题】:PHP/PDO how reuse connection started in a class to resolve "There is no active transaction" errorPHP/PDO 如何在类中启动重用连接以解决“没有活动事务”错误
【发布时间】:2014-05-08 08:10:48
【问题描述】:

我有一个封装 PDO 的类,定义为该示例:

class db{
       private $conn=null;

       function __construct(){
          getConn();
       }

       function getConn(){
        $this->conn = new PDO("mysql:host=localhost;dbname=database", 'username', 'password'); 
       }

    }

我想在不同的类实例之间重用相同的数据库连接,这样我就可以在复杂的操作中使用事务,例如:

function getDataFromAnotherTable(){
 $db = new dbClass;
 $data = execute('select * from table2');
 return $data;
}

//main code start here...
$db = new db; //here i will instantiate class defined above
$db->beginTrans();
$db->execute(insert into table1);

//here transaction still active
$data = getDataFromAnotherTable()

//now transaction has been closed by previous call!

$db->execute('insert into table1');

 //here i receive "There is no active transaction" error because transaction is closed inside
 // getDataFromAnotherTable()
 $db->endTransaction();

我想改变我的班级:

       function __construct(){
         if(empty($this->conn){             
          getConn();
         }             
        }

所以如果一个连接已经存在,将被重用并且不会创建新的连接。 我已经尝试过这种方法,但是类的每个实例都会获得新的连接,所以我不能重用相同的连接来维护我对不同类和函数的事务。

请记住,这只是一个简化的示例!我的情况真的更复杂,所以我不能使用类似的东西做一个插入语句:

select x from table1 insert into table2

提前感谢您的支持!

【问题讨论】:

  • 这种封装没有多大意义。
  • 嗨,感谢您的评论,但正如我在帖子中所说,这只是一个真正的简化示例。我的 DB 类不仅用于连接,还涵盖了许多其他问题。那么,您需要更多信息来帮助我,或者您认为这不可能实现我的目标?
  • 恐怕它主要解决不存在的问题,就像大多数 PHP 代码一样
  • 您的问题有非常简单的解决方案。只需启动一次数据库连接,然后一直使用它。就是这样

标签: php pdo transactions


【解决方案1】:

您可以将 $conn 设为静态变量...

class myClass
{
    private $conn = NULL;

    function __construct()
    {
        static $nDB = false;

        if ($nDB === false)
        {
            echo "INIT DB\n";
            $nDB = true;
        }

        $this->conn = $nDB;
    }
}

class myOne
{
    private $oDB = NULL;

    function __construct()
    {
        $this->oDB = new myClass();
    }
}

class myTwo
{
    private $oDB = NULL;

    function __construct()
    {
        $this->oDB = new myClass();
    }

}

$f1 = new myOne();
$f2 = new myTwo();

应该只给你一个回声

INIT DB

这是因为 $conn 在所有加载的 myClass 版本之间共享。

【讨论】:

  • 嗨,谢谢你的建议,但实际上我的问题是我必须在具有共同父级的不同类之间调用构造函数,但每个类都单独调用 db 类
  • 我认为这不是问题。更改我的答案以澄清。鉴于这种变化——您可以有两个不同的类,它们都创建“myClass”的属性,并且“myClass”使用的连接将被共享。允许每个对象(myOne、myTwo)访问它们自己的指向 $this->oDB(或任何你想调用它的名称)的私有指针——但它们都使用与你的数据库相同的连接。
  • 你是个天才 :) 非常感谢!所有工作都非常出色,非常感谢您!这对我来说是完美的解决方案!
  • 没问题,乐于助人=)
【解决方案2】:

你基本上有两个选择。

首先,如果您在所有地方都专门使用 OOP,则必须将 PDO 连接作为类属性传递。

// having no class at hand I am passing $db into function as well
function getDataFromAnotherTable($db){
 $data = $db->execute('select * from table2');
 return $data;
}
$db = new db; //here i will instantiate class defined above
$db->beginTransaction();
$db->execute(insert into table1);
$data = getDataFromAnotherTable($db);
$db->execute('insert into table1');
$db->commit();

其次,您主要使用旧的普通程序样式,那么单例将是最好的答案。您只需将 -> 更改为 :: 并摆脱这个 new dbClass; 东西:

function getDataFromAnotherTable(){
    return DB::query('select * from table2')->fetchAll();
}

DB::beginTransaction();
DB::prepare("insert into table1 VALUES(?,?)")->execute([1,2]);
$data = getDataFromAnotherTable()
DB::prepare("insert into table1 VALUES(?,?)")->execute([3,4]);
DB::commit();

【讨论】:

    猜你喜欢
    • 2017-05-14
    • 1970-01-01
    • 2011-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-18
    相关资源
    最近更新 更多