سؤال

لدي حبة عديمة الجنسية شيء مثل:

@Stateless
public class MyStatelessBean implements MyStatelessLocal, MyStatelessRemote {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.SUPPORTED)
    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.process(obj);
        }
    }

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

الاستخدام المعتاد إذن هو أن العميل سوف يستدعي ProcessObjects(...)، والذي لا يتفاعل فعليًا مع مدير الكيان.يقوم بما يجب عليه القيام به ويستدعي العملية (...) بشكل فردي لكل كائن ليتم معالجته.مدة العملية (...) قصيرة نسبيًا، لكن عملية الكائنات (...) قد تستغرق وقتًا طويلاً جدًا لتشغيل كل شيء.لذلك لا أريد أن تحتفظ بمعاملة مفتوحة.أنا يفعل تحتاج العمليات الفردية (...) للعمل ضمن معاملاتها الخاصة.يجب أن تكون هذه معاملة جديدة لكل مكالمة.أخيرًا، أود إبقاء الخيار مفتوحًا للعميل للاتصال بالعملية (...) مباشرةً.

لقد جربت عددًا من أنواع المعاملات المختلفة:أبدًا، غير مدعوم، مدعوم (في ProcessObjects) ومطلوب، يتطلب جديدًا (قيد المعالجة) ولكني أحصل على TransactionRequiredException في كل مرة يتم فيها استدعاء merge().

لقد تمكنت من إنجاح الأمر عن طريق تقسيم الطرق إلى قسمين مختلفين:

@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessBean2 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }
}

@Stateless
public class MyStatelessBean2 implements MyStatelessLocal2, MyStatelessRemote2 {
    @PersistenceContext(unitName="myPC")
    private EntityManager mgr;

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

ولكن ما زلت أشعر بالفضول إذا كان من الممكن تحقيق ذلك في فصل دراسي واحد.يبدو لي أن مدير المعاملات يعمل فقط على مستوى الفول، حتى عندما يتم إعطاء الطرق الفردية تعليقات توضيحية أكثر تحديدًا.لذا، إذا قمت بوضع علامة على إحدى الطرق بطريقة تمنع المعاملة من بدء استدعاء طرق أخرى داخل نفس المثيل، فلن تقوم أيضًا بإنشاء معاملة، بغض النظر عن كيفية وضع علامة عليها؟

أنا أستخدم JBoss Application Server 4.2.1.GA، لكن الإجابات غير المحددة مرحب بها/مفضلة.

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

المحلول

هناك طريقة أخرى للقيام بذلك وهي في الواقع وجود كلا الطريقتين على نفس الحبة - والحصول على @EJB إشارة إلى نفسها!شئ مثل هذا:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(Object obj) {
        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();
    }
}

بهذه الطريقة تقوم في الواقع "بإجبار". process() طريقة يمكن الوصول إليها عبر مجموعة ejb من الوكلاء، وبالتالي أخذ @TransactionAttribute في الواقع - وما زال يحتفظ بفئة واحدة فقط.أوف!

نصائح أخرى

مات، السؤال الذي تطرحه هو سؤال كلاسيكي جدًا، وأعتقد أن حل المرجع الذاتي الذي قدمه Herval/Pascal هو حل أنيق.هناك حل أكثر عمومية لم يتم ذكره هنا.

هذا هو الحال بالنسبة لمعاملات "مستخدم" EJB.نظرًا لأنك في جلسة العمل، يمكنك الحصول على معاملة المستخدم من سياق الجلسة.إليك كيف سيبدو الرمز الخاص بك مع معاملات المستخدم:

// supposing processObjects defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {

    @Resource
    private SessionContext ctx;

    @EJB
    private MyStatelessLocal1 myBean2;

    public void processObjects(List<Object> objs) {
        // this method just processes the data; no need for a transaction
        for(Object obj : objs) {
            this.myBean2.process(obj);
        }
    }


    public void process(Object obj) {

        UserTransaction tx = ctx.getUserTransaction();

        tx.begin();

        // do some work with obj that must be in the scope of a transaction

        this.mgr.merge(obj);
        // ...
        this.mgr.merge(obj);
        // ...
        this.mgr.flush();

        tx.commit();
    }
}

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

ولكن عندما تستدعي إحدى الفولات أسلوبًا على نفسها بسمة معاملة مختلفة، فإن الاستدعاء لا يمر عبر الوكيل، وبالتالي لا يتغير السلوك.

مات، لما يستحق الأمر، لقد توصلت إلى نفس النتيجة تمامًا مثلك.

يتم أخذ TransactionAttributeTypes في الاعتبار فقط عند عبور حدود Bean.عند استدعاء الأساليب داخل نفس الحبة، لا يكون لـ TransactionAttributeTypes أي تأثير، بغض النظر عن الأنواع التي يتم وضعها على الأساليب.

بقدر ما أستطيع أن أرى، لا يوجد شيء في مواصفات استمرار EJB يحدد السلوك الذي يجب أن يكون في ظل هذه الظروف.

لقد واجهت هذا أيضًا في Jboss.سأجربها أيضًا في Glassfish وأخبرك بالنتائج.

في حال واجه شخص ما هذا يومًا ما:

لتجنب التبعيات الدائرية (السماح بالإشارة الذاتية على سبيل المثال) في JBoss، استخدم التعليق التوضيحي "IgnoreDependency" على سبيل المثال:

ignoredependency @ejb نفسي نفسي ؛

لم أجربه بعد (أنا على وشك القيام بذلك)، ولكن هناك بديل لحقن مرجع ذاتي عبر @EJB الشرح هو SessionContext.getBusinessObject() طريقة.ستكون هذه طريقة أخرى لتجنب احتمالية قيام مرجع دائري بتفجير الأشياء عليك - على الرغم من أن حقن الفاصوليا عديمة الجنسية يبدو ناجحًا على الأقل.

أنا أعمل على نظام كبير يتم فيه استخدام كلتا التقنيتين (من قبل مطورين مختلفين على الأرجح)، لكنني لست متأكدًا من الطريقة "الصحيحة" للقيام بذلك.

أعتقد أن له علاقة ب @TransationAttribute(TransactionAttributeType.Never) على الطريقة كائنات العملية.

TransactionAttributeType.Never

http://docs.sun.com/app/docs/doc/819-3669/6n5sg7cm3?a=view

إذا كان العميل يعمل ضمن معاملة ويحتج على طريقة Bean Enterprise ، فإن الحاوية ترمي عن بعد.إذا لم يكن العميل مرتبطًا بالمعاملة ، فلن تبدأ الحاوية معاملة جديدة قبل تشغيل الطريقة.

أفترض أنك عميل الطريقة كائنات العملية من كود العميللأنه من المحتمل أن عميلك غير مرتبط بمعاملة تستدعي الطريقة بها TransactionAttributeType.Never سعيد في المقام الأول.ثم تتصل ب عملية الطريقة من كائنات العملية على الرغم من وجود TransactionAttributeType.Required لم يكن التعليق التوضيحي عبارة عن استدعاء لطريقة الفول ولم يتم فرض سياسة المعاملة.عندما تتصل دمج تحصل على الاستثناء لأنك لا تزال غير مرتبط بالمعاملة.

جرب استخدام TransactionAttributeType.Required لكلا طريقتي الفاصوليا لمعرفة ما إذا كانت تؤدي الغرض.

لقد واجهت مشكلات التبعية الدائرية التي ذكرها كيفن.ومع ذلك، فإن التعليق التوضيحي المقترح @IgnoreDependency هو تعليق توضيحي خاص بـ jboss ولا يوجد نظير له على سبيل المثال Glassfish.

نظرًا لأنه لا يعمل مع مرجع EJB الافتراضي، فقد شعرت بعدم الارتياح قليلاً تجاه هذا الحل.

لذلك، أعطيت حل بلوكربون فرصة، وبالتالي بدأت المعاملة الداخلية "يدويًا".

بجانب هذا، لا أرى أي حل سوى تنفيذ العملية الداخلية () في حبة أخرى وهو أمر قبيح أيضًا لأننا نريد ببساطة إزعاج نموذج صفنا لمثل هذه التفاصيل الفنية.

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