Avatar billede stenmadsen Nybegynder
23. april 2005 - 00:48 Der er 2 kommentarer

Problemer med RequiresNew trans-attribute

I bogen EJB design patterns, som kan downloades fra www.theserverside.com, er jeg faldet over en CMPløsning til generering af primærnøgler. Jeg har forsøgt benytte dette 'pattern'  i Netbeans4.1 og Sun's applicationserver 8.11, men er løbet ind i et transaktionsproblem. I bogen fremhæves det, at CMP-metoden getValueAfterIncrementingBy(int blockSize), som henter og reserverer en portion primærnøgleværdier, skal registreres i ejb-jar.xml med transaktionsattributen RequiresNew, så metoden ikke risikere at blive en del af en langvarig transaktion.

Kort fortalt kan problemet beskrives sådan:
Jeg ønsker at genere primærnøgleværdier for tabellen MYTABLE.
Tabellen MYPRIMKEY_TBL, som holder styr på nøgleværdier, har to kolonner, en primærnøgle 'NAME'  (CHAR(20)) og INDEX (INTEGER).
Hvis tabellen MYPRIMKEY_TBL allerede har en række med NAME = 'MYTABLE'  virker følgende korrekt

String name = "MYTABLE";
MyPrimkeyTblLocalHome meHome = lookupMeEntityTblBean();
MyPrimkeyTblLocal me = meHome.findByPrimaryKey(name);
int primKeyVal = me.getValueAfterIncrementingBy(blockSize);

Indeholder tabellen MYPRIMKEY_TBL ikke en række med NAME = 'MYTABLE', så skal rækken oprettes. Men følgende kode kaster en exception com.sun.jdo.api.persistence.support.JDOObjectNotFoundException: JDO76210: Object does not exist in the data store.
FailedObjectArray:

String name = "MYTABLE";
MyPrimkeyTblLocalHome meHome = lookupMeEntityTblBean();
MyPrimkeyTblLocal me = meHome.create(name);
int primKeyVal = me.getValueAfterIncrementingBy(blockSize);

Sætter jeg derimod transaction attributen til Required, så virker begge kodeeksempler.

Min egen fornemmelse er, at da transaktionen med meHome.create(name) ikke committes før metoden me.getValueAfterIncrementingBy(blockSize) på grund af 'RequiresNew' , kan me.getValueAfterIncrementingBy(blockSize) ikke læse entity-bønnen dannet ved create. Når der blot slås op med meHome.findByPrimaryKey(name) opstår dette problem ikke. Mon det er sådan det hænger sammen? og kan jeg gøre noget for at omgå problemet?
Sten
Avatar billede arne_v Ekspert
23. april 2005 - 10:21 #1
Hvordan bruges de 2 stykker kode ?

(umiddelbart skulle jeg da mene at den første fejlede hvis den ikke eksisterede
og den anden fejlede hvsi den eksisterede - uanset transaction attribute)
Avatar billede stenmadsen Nybegynder
23. april 2005 - 11:10 #2
Undskyld hvis jeg ikke var helt knivskarp. Ja, den første kodestump kører hvis rækken allerede findes. Den anden kodestump SKAL køre i stedet for den første, hvis rækken ikke findes. Men det entity object der dannes ved create metoden kan åbenbart ikke ses af metoden me.getValueAfterIncrementingBy(blockSize), hvis denne metoden markeres som RequiresNew. Markerer jeg den istedet som Required virker den!

Metoden med den nævnte kode er i en stateless sessionbean (facade) og ser sådan ud

      public int getNextPrimaryKeyNumber(java.lang.String name) {
        try {
            Entry entry = (Entry) this.entries.get(name);
            if (entry == null) {
                entry = new Entry();
                try {
                    ejb.PrimkeysTblPK pk = new ejb.PrimkeysTblPK();
                    pk.name = name;
                    entry.primKeys = this.primKeysHome.findByPrimaryKey(pk);
                } catch (javax.ejb.FinderException e) {
                    // if we couldn't find it, then create it...
                    entry.primKeys = this.primKeysHome.create(name);
                }
                this.entries.put(name, entry);
            }
            if (entry.last % this.blockSize == 0) {
                for (int retry = 0; true; retry++) {
                    try {
                        entry.last = entry.primKeys.getValueAfterIncrementingBy(this.blockSize);
                        entry.last = entry.last - this.blockSize;
                        break;
                    } catch (javax.ejb.TransactionRolledbackLocalException e) {
                        if (retry < this.retryCount) {
                            // we hit a concurrency exception, so try again...
                            System.out.println("PrimaryKeysFacadeBean    RETRYING");
                            continue;
                        } else {
                            // we tried too many times, so fail...
                            throw new javax.ejb.EJBException(e);
                        }
                    }
                }
            }
            return entry.last++ ;
        } catch (javax.ejb.CreateException e) {
            throw new javax.ejb.EJBException(e);
        }
    }

me.getValueAfterIncrementingBy(blockSize) er en CMP-entitybean og ser sådan ud
    public int getValueAfterIncrementingBy(int blockSize) {
        this.setIndex(this.getIndex()+ blockSize);
        return this.getIndex();
    }
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester