如何在Kohana/PHP中优雅地管理DB事务

如何在Kohana/PHP中优雅地管理DB事务,php,database,transactions,kohana,kohana-orm,Php,Database,Transactions,Kohana,Kohana Orm,我是Kohana的新手,但有Spring/Java的背景 在春季,我习惯于所有的服务方法都自动应用数据库事务。我只是标记该方法以指示它是只需要读事务还是读/写事务 在科哈纳,人们在这方面做了什么?我正在使用的一个新应用程序除了在一些他们知道有必要的地方手动进行交易外,没有其他交易。对我来说,这似乎有点冒险,很容易忽略一些事务一致性要求,在春季全球实施这一要求总是很好的。在Kohana中,事务需要手动完成,没有办法在春季这样做。 下面您可以找到一些处理方法: 使用数据库方法: $db = Data

我是Kohana的新手,但有Spring/Java的背景

在春季,我习惯于所有的服务方法都自动应用数据库事务。我只是标记该方法以指示它是只需要读事务还是读/写事务


在科哈纳,人们在这方面做了什么?我正在使用的一个新应用程序除了在一些他们知道有必要的地方手动进行交易外,没有其他交易。对我来说,这似乎有点冒险,很容易忽略一些事务一致性要求,在春季全球实施这一要求总是很好的。

在Kohana中,事务需要手动完成,没有办法在春季这样做。
下面您可以找到一些处理方法:
使用
数据库
方法:

$db = Database::instance();
$db->begin();

try
{
    // do your stuff here

    $db->commit();
}
catch(Database_Exception $e)
{
    $db->rollback();
}
使用查询生成器:

DB::query('START TRANSACTION');
// do your stuff here

If (no errors)
    DB::query('COMMIT');
else
    DB::query('ROLLBACK');

我是这样处理的:

  • 为所有服务方法类创建基类:

    abstract class Base
    {
    
        public function __call($method,$arguments)
        {
                // Start transaction here
                echo 'start';
    
                try
                {                    
                    call_user_func_array(array($this, $method), $arguments);
    
                    // Commit
                    echo ' commit';
                }
                catch ($e)
                {
                    // Roll back
                }                       
        }
    
    }
    
  • 创建包含所有“受保护”函数的子类:

    class Member extends Base
    {
            protected function test()
            {
                echo 'test';
            }
    }
    
  • 呼叫服务方式:

    $member = new Member();
    
    $member->test();
    
  • 它将显示:“开始测试提交”


    这里的诀窍是,您必须对所有函数使用“protected”,否则它将不再运行(它将直接调用“test”函数,而不是通过_call()。

    我创建了一个Kohana模块(受Spring启发),它使事务的使用变得更加简单:

    添加模块后,您只需添加

    public $_transactional = true;
    
    对于控制器,所有操作都在事务中自动执行,当操作出现异常失败时,事务将回滚。在我看来,这是最有用的实现,因为在PHP项目中,使用单独的服务层似乎并不常见


    我可能最终会实现对只读事务的支持(如果可以以独立于供应商的方式实现)。

    手动实现,并针对您的具体情况:

    $db = Database::instance();
    $db->begin();
    try{
        // do your stuff
        $db->commit();
    }catch(ORM_Validation_Exception $e){
        // ceep care WHAT you catch
        $db->rollback();
    }catch(Exception $e){
        // and catch whatever exceptions too
        // or your rollback is blown in the wind
        $db->rollback();
        throw $e;
    }
    

    你的kohana文档对此有何评论?据我所知,它是codeigniter框架的一个分支,因此如果有任何帮助,你可以查看codeigniter的文档。kohana没有这样做。但是,在我看来,它应该这样做。如果PHP最终有了
    ,这可以写得更优雅。儿子,你建议的解决方案是多么棒,它是alm不过有一点,spring事务允许我们将它们设置为只读或读/写(例如,对于innodb表很有用)。我可能建议使用[FunctionMe_RW]之类的命名方案来指示txn是以只读还是读写方式启动。请注意,当服务方法调用die或exit时,此解决方案将失败-您需要注册一个关机函数来处理这种情况。