EntityManager बंद है


85
[Doctrine\ORM\ORMException]   
The EntityManager is closed.  

डेटा डालने पर मुझे DBAL अपवाद मिलने के बाद, EntityManager बंद हो जाता है और मैं इसे फिर से जोड़ने में सक्षम नहीं हूं।

मैं इस तरह की कोशिश की, लेकिन यह एक कनेक्शन नहीं मिला।

$this->em->close();
$this->set('doctrine.orm.entity_manager', null);
$this->set('doctrine.orm.default_entity_manager', null);
$this->get('doctrine')->resetEntityManager();
$this->em = $this->get('doctrine')->getEntityManager();

किसी को भी एक विचार कैसे फिर से कनेक्ट करने के लिए?


इकाई प्रबंधक बंद क्यों करता है?
Jay Sheth

2
@JaySheth इकाई प्रबंधक एक DBAL अपवाद के बाद बंद कर सकता है, या यदि आप एक फ्लश से पहले EntityManager-> स्पष्ट () कर रहे हैं। मैंने कुछ लोगों को निष्पादन प्रवाह को शाखा करने के लिए DBAL अपवादों का उपयोग करते हुए देखा है, और फिर एक EntityManager बंद त्रुटि के साथ समाप्त हो रहा है। यदि आपको यह त्रुटि हो रही है, तो आपके कार्यक्रम में निष्पादन प्रवाह में कुछ गड़बड़ है।
ILikeTacos

5
@AlanChavez - मुझे यह त्रुटि इसलिए मिल रही है क्योंकि मैं एक टेबल पर एक सेमाफोर झंडा लिखने के लिए डॉक्ट्रिन का उपयोग कर रहा हूं जिसे एक साथ कई थ्रेड द्वारा एक्सेस किया जा रहा है। MySQL सेमीफोर बनाने की कोशिश कर रहे दो प्रतिस्पर्धी थ्रेड्स में से एक में त्रुटि करेगा, क्योंकि मुख्य बाधा का मतलब है कि उनमें से केवल एक ही सफल हो सकता है। IMO डॉक्ट्रिन में एक दोष है जो आपको अपेक्षित MySQL त्रुटियों को सुरक्षित रूप से संभालने की अनुमति नहीं देता है । पूरे INSQL कनेक्शन को डिस्कनेक्ट क्यों किया जाना चाहिए क्योंकि एक INSERT स्टेटमेंट में विरोध है?
स्टैम्पकोड

2
यदि आप किसी डेटाबेस में अपवादों को लॉग इन करने का प्रयास कर रहे हैं, तो आपको यह त्रुटि भी दिखाई देगी, app.exception_listenerलेकिन अपवाद (जैसे कि एक बाधा का उल्लंघन) ने कनेक्शन बंद कर दिया।
Lg102

जवाबों:


24

यह एक बहुत ही मुश्किल समस्या है, कम से कम सिम्फनी 2.0 और डॉक्ट्रिन 2.1 के लिए, यह बंद होने के बाद एंटिटीमैन को फिर से खोलना किसी भी तरह से संभव नहीं है।

इस समस्या को दूर करने का एकमात्र तरीका मुझे अपना डीबीएएल कनेक्शन वर्ग बनाना है, डॉक्ट्रिन को लपेटना है और अपवाद हैंडलिंग प्रदान करना है (जैसे कि एंटिटीमैन के लिए अपवाद को पॉप करने से पहले कई बार पुनः प्रयास करना)। यह थोड़ा हैकी है और मुझे डर है कि यह लेन-देन के वातावरण में कुछ असंगति पैदा कर सकता है (यानी अगर लेनदेन के बीच में फेल होने वाली क्वेरी होती है तो वास्तव में मुझे यकीन नहीं है कि क्या होता है)।

इस तरह से जाने के लिए एक उदाहरण विन्यास है:

doctrine:
  dbal:
    default_connection: default
    connections:
      default:
        driver:   %database_driver%
        host:     %database_host%
        user:     %database_user%
        password: %database_password%
        charset:  %database_charset%
        wrapper_class: Your\DBAL\ReopeningConnectionWrapper

वर्ग को कम या ज्यादा इस तरह से शुरू करना चाहिए:

namespace Your\DBAL;

class ReopeningConnectionWrapper extends Doctrine\DBAL\Connection {
  // ...
}

एक बहुत ही कष्टप्रद बात यह है कि आपको अपने अपवाद-हैंडलिंग आवरण को प्रदान करने वाले कनेक्शन के प्रत्येक तरीके को ओवरराइड करना होगा। क्लोजर के इस्तेमाल से वहां कुछ दर्द कम हो सकता है।


71

मेरा समाधान।

कुछ भी करने से पहले जाँच करें:

if (!$this->entityManager->isOpen()) {
    $this->entityManager = $this->entityManager->create(
        $this->entityManager->getConnection(),
        $this->entityManager->getConfiguration()
    );
}

सभी संस्थाओं को बचाया जाएगा। लेकिन यह विशेष वर्ग या कुछ मामलों के लिए उपयोगी है। यदि आपके पास इंजेक्टेड यूनिटमैन के साथ कुछ सेवाएं हैं, तो यह अभी भी बंद है।


यह बेहतर है जब डि कंटेनर खुद उपलब्ध नहीं है। धन्यवाद।
हरी केटी

1
आप $ 3 - पैरामीटर में यह भी प्राप्त कर सकते हैं- unitManager-> getEventManager ()।
मेधाट गेयड

34

सिम्फनी 2.0 :

$em = $this->getDoctrine()->resetEntityManager();

सिम्फनी 2.1+ :

$em = $this->getDoctrine()->resetManager();

6
चेतावनी: resetEntityManager सिम्फनी 2.1 के बाद से पदावनत किया गया है। resetManagerइसके बजाय का उपयोग करें
फ्रांसेस्को Casula

क्या यह कार्य की इकाई को भी रीसेट करता है?
फ्लू

@flu EntityManager वर्ग को देखते हुए UnitOfWork वर्ग का प्रबंधन करता है, मुझे संदेह है कि यह होगा। हालाँकि, मैंने इसका परीक्षण नहीं किया है इसलिए यह सुनिश्चित नहीं किया जा सकता है।
रयाल

26

इस तरह मैंने डॉक्ट्रिन को हल किया "एंटिटी मैनजर बंद है।" मुद्दा। मूल रूप से हर बार एक अपवाद (यानी डुप्लिकेट कुंजी) या अनिवार्य कॉलम के लिए डेटा प्रदान नहीं करना डोक्ट्रीन को एंटिटी मैनेजर को बंद करने का कारण होगा। यदि आप अभी भी डेटाबेस के साथ बातचीत करना चाहते हैं तो आपको JGrinonresetManager() द्वारा बताए गए तरीके से कॉल करके Entity Manger को रीसेट करना होगा

मेरे आवेदन में मैं कई RabbitMQ उपभोक्ताओं को चला रहा था जो सभी एक ही काम कर रहे थे: अगर कोई इकाई डेटाबेस में थी, तो जाँच करें कि यदि हाँ, तो इसे वापस लौटाएँ, यदि नहीं बनाते हैं और फिर इसे वापस करते हैं। जाँच के बीच कुछ मिलीसेकंड में अगर वह इकाई पहले से मौजूद थी और इसे बनाने वाला एक अन्य उपभोक्ता भी ऐसा ही करता था और लापता इकाई को एक नकली कुंजी अपवाद ( दौड़ की स्थिति ) में अन्य उपभोक्ता को उकसाता है ।

इससे सॉफ्टवेयर डिजाइन की समस्या पैदा हो गई। मूल रूप से मैं जो करने की कोशिश कर रहा था, वह सभी संस्थाओं को एक लेन-देन में पैदा कर रहा था। यह सबसे स्वाभाविक लग सकता है लेकिन निश्चित रूप से मेरे मामले में वैचारिक रूप से गलत था। निम्नलिखित समस्या पर विचार करें: मुझे एक फुटबॉल मैच इकाई को स्टोर करना था जिसमें ये निर्भरताएं थीं।

  • एक समूह (जैसे समूह A, समूह B ...)
  • एक दौर (जैसे सेमीफाइनल ...)
  • एक स्थान (यानी जहां मैच हो रहा है स्टेडियम)
  • एक मैच की स्थिति (जैसे आधा समय, पूर्णकालिक)
  • मैच खेलने वाली दो टीमें
  • मैच ही

अब, स्थल का निर्माण मैच के समान लेनदेन में क्यों होना चाहिए? यह हो सकता है कि मुझे सिर्फ एक नया स्थान प्राप्त हुआ है जो कि मेरे डेटाबेस में नहीं है इसलिए मुझे इसे पहले बनाना होगा। लेकिन यह भी हो सकता है कि वह स्थान किसी अन्य मैच की मेजबानी कर सकता है इसलिए एक अन्य उपभोक्ता शायद उसी समय इसे बनाने की कोशिश करेगा। इसलिए मुझे जो करना था वह अलग-अलग लेन-देन में पहले निर्भरता पैदा करना था, जिससे मुझे पता चला कि मैं डुप्लिकेट कुंजी अपवाद में इकाई प्रबंधक को रीसेट कर रहा था। मैं कहूंगा कि मैच के बगल में मौजूद सभी संस्थाओं को "साझा" के रूप में परिभाषित किया जा सकता है क्योंकि वे संभवतः अन्य उपभोक्ताओं में अन्य लेनदेन का हिस्सा हो सकते हैं। कुछ ऐसा है जो "साझा" नहीं है, यह मैच ही है जो संभवतः एक ही समय में दो उपभोक्ताओं द्वारा नहीं बनाया जाएगा।

इस सब के कारण एक और मुद्दा भी बन गया। यदि आप इकाई प्रबंधक को रीसेट करते हैं, तो रीसेट करने से पहले आपके द्वारा पुनर्प्राप्त सभी ऑब्जेक्ट पूरी तरह से नए हैं। तो सिद्धांत उन पर एक अद्यतन चलाने की कोशिश नहीं करेंगे, लेकिन एक INSERT ! इसलिए सुनिश्चित करें कि आप अपने सभी निर्भरता को तार्किक रूप से सही लेनदेन में बनाते हैं और फिर लक्ष्य इकाई में स्थापित करने से पहले अपनी सभी वस्तुओं को डेटाबेस से वापस प्राप्त करते हैं। एक उदाहरण के रूप में निम्नलिखित कोड पर विचार करें:

$group = $this->createGroupIfDoesNotExist($groupData);

$match->setGroup($group); // this is NOT OK!

$venue = $this->createVenueIfDoesNotExist($venueData);

$round = $this->createRoundIfDoesNotExist($roundData);

/**
 * If the venue creation generates a duplicate key exception
 * we are forced to reset the entity manager in order to proceed
 * with the round creation and so we'll loose the group reference.
 * Meaning that Doctrine will try to persist the group as new even
 * if it's already there in the database.
 */

तो यह है कि मुझे लगता है कि यह किया जाना चाहिए।

$group = $this->createGroupIfDoesNotExist($groupData); // first transaction, reset if duplicated
$venue = $this->createVenueIfDoesNotExist($venueData); // second transaction, reset if duplicated
$round = $this->createRoundIfDoesNotExist($roundData); // third transaction, reset if duplicated

// we fetch all the entities back directly from the database
$group = $this->getGroup($groupData);
$venue = $this->getVenue($venueData);
$round = $this->getGroup($roundData);

// we finally set them now that no exceptions are going to happen
$match->setGroup($group);
$match->setVenue($venue);
$match->setRound($round);

// match and teams relation...
$matchTeamHome = new MatchTeam();
$matchTeamHome->setMatch($match);
$matchTeamHome->setTeam($teamHome);

$matchTeamAway = new MatchTeam();
$matchTeamAway->setMatch($match);
$matchTeamAway->setTeam($teamAway);

$match->addMatchTeam($matchTeamHome);
$match->addMatchTeam($matchTeamAway);

// last transaction!
$em->persist($match);
$em->persist($matchTeamHome);
$em->persist($matchTeamAway);
$em->flush();

मुझे उम्मीद है यह मदद करेगा :)


शानदार व्याख्या। मुझे कुछ ऐसा मिला जो समान है और सोचा कि आपके उत्तर में योगदान करना अच्छा होगा। आपका बहुत बहुत धन्यवाद।
अंजना सिल्वा

17

आप अपना EM रीसेट कर सकते हैं

// reset the EM and all aias
$container = $this->container;
$container->set('doctrine.orm.entity_manager', null);
$container->set('doctrine.orm.default_entity_manager', null);
// get a fresh EM
$em = $this->getDoctrine()->getManager();

10

में Symfony 4.2+ आप पैकेज का उपयोग करने के लिए है:

composer require symfony/proxy-manager-bridge

अन्य अपवाद आपको मिलते हैं:

Resetting a non-lazy manager service is not supported. Declare the "doctrine.orm.default_entity_manager" service as lazy.  

आप इस तरह से UnitManager को रीसेट कर सकते हैं:

services.yaml:

App\Foo:
    - '@doctrine.orm.entity_manager'
    - '@doctrine'

Foo.php:

use Doctrine\Bundle\DoctrineBundle\Registry;
use Doctrine\DBAL\DBALException;
use Doctrine\ORM\EntityManagerInterface;


 try {
    $this->entityManager->persist($entity);
    $this->entityManager->flush();
} catch (DBALException $e) {
    if (!$this->entityManager->isOpen()) {
        $this->entityManager = $this->doctrine->resetManager();
    }
}

4

नियंत्रक में।

अपवाद एंटिटी मैनेजर को बंद कर देता है। यह बल्क इंसर्ट के लिए परेशानी खड़ी करता है। जारी रखने के लिए, इसे फिर से परिभाषित करने की आवश्यकता है।

/** 
* @var  \Doctrine\ORM\EntityManager
*/
$em = $this->getDoctrine()->getManager();

foreach($to_insert AS $data)
{
    if(!$em->isOpen())
    {
        $this->getDoctrine()->resetManager();
        $em = $this->getDoctrine()->getManager();
    }

  $entity = new \Entity();
  $entity->setUniqueNumber($data['number']);
  $em->persist($entity);

  try
  {
    $em->flush();
    $counter++;
  }
  catch(\Doctrine\DBAL\DBALException $e)
  {
    if($e->getPrevious()->getCode() != '23000')
    {   
      /**
      * if its not the error code for a duplicate key 
      * value then rethrow the exception
      */
      throw $e;
    }
    else
    {
      $duplication++;
    }               
  }                      
}


1

यह क्या है इसके लिए मैंने पाया कि यह समस्या एक बैच आयात कमांड में हो रही थी क्योंकि किसी SQL त्रुटि को पकड़ने की कोशिश / पकड़ने वाले लूप के साथ (जिसके साथ em->flush()) मैंने कुछ भी नहीं किया। मेरे मामले में ऐसा इसलिए था क्योंकि मैं एक गैर-अशक्त संपत्ति के साथ एक रिकॉर्ड डालने की कोशिश कर रहा था जिसे अशक्त छोड़ दिया गया था।

आमतौर पर यह एक महत्वपूर्ण अपवाद होता है और कमांड या कंट्रोलर को रोकने के लिए, लेकिन मैं सिर्फ इस समस्या को लॉग ऑन कर रहा था और ले जा रहा था। SQL त्रुटि के कारण इकाई प्रबंधक बंद हो गया था।

dev.logइस तरह से किसी भी मूर्ख SQL त्रुटियों के लिए अपनी फ़ाइल की जाँच करें क्योंकि यह आपकी गलती हो सकती है। :)


1

मुझे सिम्फनी 4.3.2 में बदलावों का परीक्षण करते समय एक ही समस्या का सामना करना पड़ा

मैंने जानकारी के लिए लॉग स्तर को कम किया

और दोबारा परीक्षा दी

और लॉग ने यह दिखाया:

console.ERROR: Error thrown while running command "doctrine:schema:create". Message: "[Semantical Error] The annotation "@ORM\Id" in property App\Entity\Common::$id was never imported. Did you maybe forget to add a "use" statement for this annotation?" {"exception":"[object] (Doctrine\\Common\\Annotations\\AnnotationException(code: 0): [Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation? at C:\\xampp\\htdocs\\dirty7s\\vendor\\doctrine\\annotations\\lib\\Doctrine\\Common\\Annotations\\AnnotationException.php:54)","command":"doctrine:schema:create","message":"[Semantical Error] The annotation \"@ORM\\Id\" in property App\\Entity\\Common::$id was never imported. Did you maybe forget to add a \"use\" statement for this annotation?"} []

इसका मतलब है कि कोड में कुछ त्रुटि का कारण बनता है:

Doctrine\ORM\ORMException: The EntityManager is closed.

इसलिए लॉग को चेक करना एक अच्छा विचार है


क्या आप इस बारे में अतिरिक्त जानकारी प्रदान कर सकते हैं कि पहला दूसरे से कैसे संबंधित है?
जॉर्ज नोविक

1

सिम्फनी v4.1.6

सिद्धांत v2.9.0

रिपॉजिटरी में डुप्लिकेट डालने की प्रक्रिया

  1. अपने रेपो में एक रजिस्ट्री का उपयोग करें


    //begin of repo
    
    /** @var RegistryInterface */
    protected $registry;
    
    public function __construct(RegistryInterface $registry)
    {
        $this->registry = $registry;
        parent::__construct($registry, YourEntity::class);
    }

  1. जोखिम कोड को लेनदेन में लपेटें और अपवाद के मामले में प्रबंधक को रीसेट करें


    //in repo method
    $em = $this->getEntityManager();
    
    $em->beginTransaction();
    try {
        $em->persist($yourEntityThatCanBeDuplicate);
        $em->flush();
        $em->commit();
    
    } catch (\Throwable $e) {
        //Rollback all nested transactions
        while ($em->getConnection()->getTransactionNestingLevel() > 0) {
            $em->rollback();
        }
        
        //Reset the default em
        if (!$em->isOpen()) {
            $this->registry->resetManager();
        }
    }


0

मेरे पास यह मुद्दा था। यह मैंने इसे कैसे तय किया।

कनेक्शन फ्लश करने या बने रहने की कोशिश करते हुए बंद होने लगता है। इसे फिर से खोलने की कोशिश करना एक बुरा विकल्प है क्योंकि इससे नए मुद्दे पैदा होते हैं। मैंने यह समझने की कोशिश की कि कनेक्शन क्यों बंद किया गया और पाया गया कि मैं दृढ़ता से पहले बहुत सारे संशोधन कर रहा था।

persist () ने पहले इस मुद्दे को हल किया।


0

प्रयोग करके देखें:

$em->getConnection()->[setNestTransactionsWithSavepoints][1](true);

लेन-देन शुरू करने से पहले।

पर Connection::rollbackविधि इसके लिए जाँच करता है nestTransactionsWithSavepointsसंपत्ति।


3
क्या आपके द्वारा इसे विस्तार दिया जा सकता है?
paul.ago

0

यह वास्तव में पुराना मुद्दा है, लेकिन मुझे सिर्फ इसी तरह की समस्या थी। मैं कुछ इस तरह कर रहा था:

// entity
$entityOne = $this->em->find(Parent::class, 1);

// do something on other entites (SomeEntityClass)
$this->em->persist($entity);
$this->em->flush();
$this->em->clear();

// and at end I was trying to save changes to first one by
$this->em->persist($entityOne);
$this->em->flush();
$this->em->clear();

समस्या यह थी कि पहले एक सहित सभी संस्थाओं को अलग करें और त्रुटि को समाप्त करें EntityManager बंद है।

मेरे मामले में समाधान केवल विभिन्न प्रकार की इकाई पर स्पष्ट करना और $entityOneईएम के तहत अभी भी छोड़ना था :

$this->em->clear(SomeEntityClass::class);

0

एक ही समस्या, एक सरल कोड रीफैक्टरिंग के साथ हल। समस्या कुछ समय के लिए मौजूद होती है जब एक आवश्यक क्षेत्र शून्य होता है, एंथिंग करने से पहले, अपने कोड को फिर से भरने की कोशिश करें। एक बेहतर वर्कफ़्लो समस्या को हल कर सकता है।


-1

मुझे Symfony 5 / Doctrine 2 का उपयोग करने में एक ही त्रुटि हुई थी। मेरे एक फ़ील्ड को MySQL आरक्षित शब्द "आदेश" का उपयोग करके नाम दिया गया था, जिससे DBALException पैदा हुई। जब आप किसी आरक्षित शब्द का उपयोग करना चाहते हैं, तो आपको बचकर निकले हुए नाम का उपयोग करना होगा। एनोटेशन फॉर्म में:

@ORM\Column(name="`order`", type="integer", nullable=false)


-2

मैंने उसी समस्या का सामना किया। यहां कई जगहों को देखने के बाद मैंने इसे कैसे निपटाया।

//function in some model/utility
function someFunction($em){
    try{
        //code which may throw exception and lead to closing of entity manager
    }
    catch(Exception $e){
        //handle exception
        return false;
    }
    return true;
}

//in controller assuming entity manager is in $this->em 
$result = someFunction($this->em);
if(!$result){
    $this->getDoctrine()->resetEntityManager();
    $this->em = $this->getDoctrine()->getManager();
}

आशा है कि यह किसी की मदद करता है!

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.