محاولة غير قانونية لربط مجموعة مع جلستين مفتوحتين

StackOverflow https://stackoverflow.com/questions/221079

سؤال

أحاول إضافة pojo إلى مجموعة في Pojo آخر. أنا متأكد من أنني أرتكب خطأً غبيًا حقًا في مكان ما على طول الخطوط ، لكن لا يمكنني معرفة كيفية حلها.

لديّ pojo lookuptable يحتوي على قائمة من الأعمدة:

public class LookupTable {
  private long id;
  // More properties go here...
  private List<Column> columns;

  public void addColumn(Column column) {
    this.columns.add(column);
  }

  // More methods go here...
}

في تكوين السبات لدي:

<class name="LookupTable" table="ARR_LOOKUP_TABLE">
  <id name="id" column="ID">
    <generator class="native"/>
  </id>
  <!-- Some properties here -->
  <bag name="columns" cascade="all,delete-orphan" access="field">
    <key column="LOOKUP_TABLE" not-null="true"/>
    <one-to-many class="Column"/>
  </bag>
</class>

<class name="Column" table="ARR_LOOKUP_COLUMN">
  <id name="id" column="ID">
    <generator class="native"/>
  </id>
  <!-- Some properties here -->
</class>

في ملف تكوين الربيع لدي:

<tx:advice id="txAdvice" transaction-manager="txManager">
  <tx:attributes>
    <tx:method name="*" propagation="REQUIRED"/>
  </tx:attributes>
</tx:advice>
<aop:config>
  <aop:pointcut id="managers" expression="execution(public * com.foo.*Manager.*(..))"/>
  <aop:advisor advice-ref="txAdvice" pointcut-ref="managers"/>
</aop:config>

وأخيراً ، فإن الكود الذي يفشل فيه كل شيء ضمن فئة مديري (com.foo.lookuptableManager):

public void addColumnToTable(Column column, long tableId) {
  LookupTable lookupTable = this.lookupTableDao.findById(tableId);
  lookupTable.addColumn(column);
  this.lookupTableDao.saveOrUpdate(lookupTable);
}

يشير المتغير Lookuptabledao هنا إلى فئة DAO بسيطة تمتد إلى heibernatedaoSupport.

الخطأ الذي أحصل عليه هو:

org.hibernate.HibernateException: Illegal attempt to associate a collection with two open sessions
  at org.hibernate.collection.AbstractPersistentCollection.setCurrentSession(AbstractPersistentCollection.java:410)
  at org.hibernate.event.def.OnUpdateVisitor.processCollection(OnUpdateVisitor.java:43)
  at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
  at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
  at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
  at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
  at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:293)
  at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:223)
  at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:89)
  at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
  at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
  at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
  at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
  at com.foo.AbstractDao.saveOrUpdate(AbstractDao.java:29)
  at com.foo.LookupTableManager.addColumnToTable(LookupTableManager.java:338)
... etc ...

حسنًا ، أفهم الرسالة الأساسية التي أحصل عليها. لكن ما لا أفهمه هو المكان الذي أحصل فيه على الجلسة الثانية .... هل يمكن لأي شخص مساعدتي في هذا؟

أنا أستخدم Hibernate 3.2.6.ga ، Spring 2.5.5 و Tomcat 6.0

هل كانت مفيدة؟

المحلول

اتضح أنه لم يكن لدي معاملة على الإطلاق. لقد استخدمت نفس تكوين المعاملة تقريبًا في أحد ملفات التكوين الأخرى الخاصة بي.

كان يسمى النقطة الموجودة هناك أيضًا "المديرين" ، لذلك كان مستشاري هنا يشير إلى نقطة النقاط في الملف الآخر.

إعادة تسمية Pointcut حل مشكلتي.

نصائح أخرى

أظن أن lookupTableDao.findById المكالمة هي الحصول على كائنك في جلسة واحدة ، ولكن lookupTableDao.saveOrUpdate هو واحد مختلف - كيف تحصل على Session كائن ، عبر الربيع؟

اين ال Column كائن قادم من - هل هذا بالفعل على DB أو جديد؟

كانت المشكلة مع الجلسة المفتوحة في رسم تصفية عرض. كان إنشاء جلسة على getSession وغيرها على حفظ.

يمكنك تغيير الفردي فقط باعتباره افتراضيًا كاذبًا صحيحًا

من المحتمل أن استخدام الدمج سيصلح المشكلة على الأرجح

myInstance = (myInstanceClass) Session.merge(myInstance);

واجهت نفس المشكلة في الكود التالي: أردت تحديث متجر كيان معين. كنت استرجعها من هذه الطريقة:

@Override
public Store getStoreByStoreId(final long storeId) {
    getHibernateTemplate().execute(new HibernateCallback<Store>() {
        @Override
        public StoredoInHibernate(Session session) throws HibernateException, SQLException {
            return (Store) session.createCriteria(Store.class)
                    .add(Restrictions.eq(Store.PROP_ID, storeId))
                    .uniqueResult();
        }
    });
}

ثم ، كنت أقوم بتحديث المتجر بالطريقة التالية:

@Override
public void updateStoreByStoreId(final long storeId) {
    getHibernateTemplate().execute(new HibernateCallback<Void>() {
        @Override
        public Void doInHibernate(Session session) throws HibernateException, SQLException {
            Store toBeUpdated =  getStoreByStoreId(storeId);

            if (toBeUpdated != null){
                // ..change values for certain fields
                session.update(toBeUpdated);
            }
            return null;
        }
    });
} 

اتضح أنني حصلت على خطأ "المحاولة غير القانونية ..." لأن الجلسة الأولى من طريقة GET لم تكن مغلقة ، وكنت أحاول التحديث مع الجلسة الأخرى المتجر. كان الحل بالنسبة لي هو نقل المكالمة لاسترداد المتجر ليتم تحديثه في طريقة التحديث.

@Override
public void updateStoreByStoreId(final long storeId) {
    getHibernateTemplate().execute(new HibernateCallback<Void>() {
        @Override
        public Void doInHibernate(Session session) throws HibernateException, SQLException {
            Store toBeUpdated =  (Store) session.createCriteria(Store.class)
                    .add(Restrictions.eq(Store.PROP_ID, storeId))
                    .uniqueResult();

            if (toBeUpdated != null){
                // ..change values for certain fields
                session.update(toBeUpdated );
            }
            return null;
        }
    });
} 

إذا كنت تريد فقط معاملة على جزء من الكود الخاص بك ، فيمكنك استخدام شيء مثل هذا:

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

وفي الفصل:

@Autowired private SessionFactory sessionFactory;

في وقت لاحق ، حول الكود الذي يجب أن يفعل الأشياء في نفس المعاملة:

Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();

Stuff stuff = getStuff();
manipulate(stuff);
send(stuff);
save(stuff);

tx.commit();

أستخدم هذا داخل حلقة في بعض وظائف الدُفعات طويلة الأجل.

كنت أستخدم Windows Server IIS وتغيير وضع خط أنابيب AppPool المدار من AppPool المدمج إلى كلاسيكي حل مشكلتي.

شكرًا

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top