2012-12-19 33 views
2

我有一個教條實體正在被持久保存到數據庫中,我沒有調用persist或flush。爲什麼空的事務會持續我的實體(原則)?

我設法在下面簡單地重現了這個問題。正如你將會看到的,這個腳本從一個名爲MyEntity的數據庫表中加載一行,並獲得一個包含行字段作爲屬性的php對象。該腳本然後更改其中一個屬性,但不會調用persist或flush。然後腳本創建一個空的事務,它什麼都不做。奇怪的是,這使得對象堅持不變,因爲對php對象所做的更改也是在數據庫中進行的。我不希望這個腳本對數據庫進行任何更改。

這裏發生了什麼?

請注意,如果我刪除空事務,則問題消失並且不會更改數據庫。

下面是代碼(test.php的):

<?php 

    use Doctrine\ORM\Tools\Setup; 

    require_once("Doctrine/ORM/Tools/Setup.php"); 
    Setup::registerAutoloadPEAR(); 

    $classloader = new Doctrine\Common\ClassLoader('testEntities', __DIR__); 
    $classloader->register(); 

    $paths = array(); 
    $isDevMode = true; 
    $config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode); 
    $dbParams = array("driver" => "pdo_mysql", 
     "host" => "localhost", 
     "user" => "username", 
     "password" => "password", 
     "dbname" => "databaseName", 
     "charset" => "utf8"); 

    $em = \Doctrine\ORM\EntityManager::create($dbParams, $config); 
    $em->getConnection()->exec("SET NAMES UTF8"); 

    $matches = $em->getRepository('testEntities\\MyEntity')->findBy(array('ID' => 1)); 
    echo("<pre>"); 

    if (!empty($matches)) { 
     $object = $matches[0]; 
     print_r($object); 
     $object->Content = "WILL IT BLEND?"; 
     print_r($object); 
    } 
    $em->transactional(function($em) { 
     // Nothing happens here, but if I comment out the call to transactional, the behaviour of the script changes. 
    }); 

    echo("</pre>Done!"); 
?> 

創建和數據庫myEntity所填寫表:

CREATE TABLE `MyEntity` (
    `ID` int(11) NOT NULL AUTO_INCREMENT, 
    `Content` varchar(500) COLLATE utf8_swedish_ci NOT NULL, 
    PRIMARY KEY (`ID`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci; 

INSERT INTO MyEntity (ID, Content) VALUES (NULL, "Hello World"); 

myEntity所創建學說實體(testEntities \ MyEntity.php):

<?php 

    namespace testEntities; 

    /** @Entity @Table(name="MyEntity")*/ 
    class MyEntity 
    { 
     /** 
     * @Id @GeneratedValue(strategy="AUTO") @Column(type="integer") 
     */ 
     public $ID; 

     /** 
     * @Column(type="string", length=500) 
     */ 
     public $Content; 
    } 

?> 

回答

2

學說手冊:9.事務和併發 - >9.1.2. Approach 2: Explicitly(在部分底部):

連接#事務($ FUNC)和 的EntityManager#事務($ FUNC)之間的區別是,後者抽象 刷新事務提交之前的EntityManager,並且當發生異常時(除了回滾事務的 ),還會正確關閉 EntityManager。

因此:EntityManager#transactional($func)刷新事務提交之前的EntityManager(如果$func調用成功 - 您的情況)。

+0

這可能會讓EntityManager浮躁,但是如果我從來沒有調用persist,它應該不會將任何內容保存到數據庫,如果它? – Shawn

+0

不,你錯了。這取決於跟蹤策略。閱讀手冊中的[Tracking Policies](http://docs.doctrine-project.org/en/latest/reference/change-tracking-policies.html#change-tracking-policies)。默認策略是Deferred Implicit。 _有了這個策略,Doctrine在提交時通過屬性和屬性的比較來檢測變化,並且還檢測對其他被管理實體引用的實體或新實體的變化(「通過可達性持久化」)_。 –

+0

如果您將'@ChangeTrackingPolicy(「DEFERRED_EXPLICIT」)'註釋添加到'class MyEntity',那麼您的較高評論將變爲true,Doctrine必須停止保存您示例的更改。 –

相關問題