Programmering

Vedvar data med Java Data Objects, del 1

"Alt skal gjøres så enkelt som mulig, men ikke enklere."

Albert Einstein

Behovet for å vedvare data som er opprettet ved kjøretid, er like gammelt som databehandling. Og behovet for å lagre objektorientert data dukket opp når objektorientert programmering ble gjennomgripende. For tiden bruker de fleste moderne, ikke-private applikasjoner et objektorientert paradigme for å modellere applikasjonsdomener. I kontrast er databasemarkedet mer delt. De fleste databasesystemer bruker relasjonsmodellen, men objektbaserte datalagre er uunnværlige i mange applikasjoner. I tillegg har vi også eldre systemer som vi ofte trenger å grensesnitt mot.

Denne artikkelen identifiserer problemene knyttet til datautholdenhet i transaksjonelle mellomvaremiljøer, for eksempel J2EE (Java 2 Platform, Enterprise Edition), og viser hvordan Java Data Objects (JDO) løser noen av disse problemene. Denne artikkelen gir en oversikt, ikke en detaljert opplæring, og er skrevet fra synspunktet til en applikasjonsutvikler, ikke en JDO-implementeringsdesigner.

Les hele serien på Java Data Objects:

  • Del 1. Ta tak i kvalitetene bak et ideelt utholdenhetslag
  • Del 2. Sun JDO vs. Castor JDO

De Java-utviklerne, designerne og J2EE-arkitektene som jobber med systemer som må lagre data i relasjons- eller objektdatabaser eller andre lagringsmedier, bør lese denne artikkelen. Jeg antar at du har grunnleggende kunnskap om Java og litt kjennskap til objektsammenhengende problemstillinger og terminologi.

Gjennomsiktig utholdenhet: Hvorfor bry seg?

Mer enn et tiår med kontinuerlige forsøk på å bygge bro over objektorientert kjøretid og utholdenhet peker på flere viktige observasjoner (oppført i rekkefølge etter betydning):

  1. Det er viktig å abstrakte bort utholdenhetsdetaljer og ha en ren, enkel, objektorientert API for å utføre datalagring. Vi ønsker ikke å håndtere utholdenhetsdetaljer og intern datarepresentasjon i datalagre, det være seg relasjonelle, objektbaserte eller noe annet. Hvorfor skal vi håndtere konstruksjoner på lavt nivå av datalagringsmodellen, for eksempel rader og kolonner, og hele tiden oversette dem frem og tilbake? I stedet må vi konsentrere oss om den kompliserte applikasjonen vi var pålagt å levere innen i går.
  2. Vi ønsker å bruke plug-and-play-tilnærmingen med datalagrene våre: Vi vil bruke forskjellige leverandører / implementeringer uten å endre en linje i applikasjonens kildekode - og kanskje uten å endre mer enn noen få linjer i riktig konfigurasjonsfil ( s). Med andre ord trenger vi en industristandard for tilgang til data basert på Java-objekter, en som spiller en rolle som den JDBC (Java Database Connectivity) spiller som en industristandard for tilgang til SQL-baserte data.
  3. Vi vil bruke plug-and-play-tilnærmingen med forskjellige databaseparadigmer - det vil si at vi vil bytte fra en relasjonsdatabase til en objektorientert med minimale endringer i applikasjonskoden. Selv om det er hyggelig å ha, er denne evnen ofte ikke nødvendig.

    En kommentar her: Selv om relasjonsdatabaser har den største markedstilstedeværelsen, gir det et enhetlig persistens-API og tillater datalagringsleverandører å konkurrere på implementeringsstyrker, men uansett hvilket paradigme disse leverandørene bruker. Denne tilnærmingen kan til slutt bidra til å utjevne spillereglene mellom de to dominerende databaseleverandørgruppene: den godt forankrede relasjonsleiren og den objektorienterte leiren som kjemper for markedsandelen.

De tre oppdagelsene som er oppført ovenfor, får oss til å definere a utholdenhetslag, et rammeverk som gir et Java-API på høyt nivå for objekter og relasjoner for å overleve levetiden til kjøretidsmiljøet (JVM). Et slikt rammeverk må inneholde følgende egenskaper:

  • Enkelhet
  • Minimal inntrenging
  • Åpenhet, noe som betyr at rammeverket skjuler implementeringen av datalager
  • Konsekvente, konsise APIer for lagring / henting / oppdatering av objekter
  • Transaksjonsstøtte, som betyr at rammeverket definerer transaksjonell semantikk assosiert med vedvarende objekter
  • Støtte for både administrerte (f.eks. Applikasjonsserverbaserte) og ikke-administrerte (frittstående) miljøer
  • Støtte for nødvendige tilleggsutstyr, som hurtigbufring, spørsmål, generering av primærnøkkel og kartverktøy
  • Rimelige lisensavgifter - ikke et teknisk krav, men vi vet alle at dårlig økonomi kan dømme et utmerket prosjekt

Jeg beskriver de fleste av de ovennevnte egenskapene i de følgende avsnittene.

Enkelhet

Enkelhet er høyt på listen over nødvendige egenskaper for ethvert programvarerammeverk eller bibliotek (se denne artikkels åpningstilbud). Å utvikle distribuerte applikasjoner er allerede vanskelig nok, og mange programvareprosjekter mislykkes på grunn av dårlig kompleksitet (og, i forlengelse, risiko). Enkel er ikke synonymt med forenklet; programvaren skal ha alle nødvendige funksjoner som gjør at en utvikler kan gjøre jobben sin.

Minimal inntrenging

Hvert vedvarende lagringssystem introduserer en viss mengde innbrudd i applikasjonskoden. Det ideelle utholdenhetslaget skal minimere innbrudd for å oppnå bedre modularitet og dermed plug-and-play-funksjonalitet.

I denne artikkelen definerer jeg innbrudd som:

  • Mengden utholdenhetsspesifikk kode sprøytet over applikasjonskoden
  • Behovet for å modifisere applikasjonsobjektmodellen ved enten å måtte implementere noe utholdenhetsgrensesnitt - for eksempel Vedvarende eller lignende - eller ved etterbehandling av den genererte koden

Inntrenging gjelder også objektorienterte databasesystemer, og selv om det vanligvis er mindre av et problem der sammenlignet med relasjonelle datalagre, kan det variere betydelig blant ODBMS (objektorientert databasestyringssystem) leverandører.

Åpenhet

Det vedvarende lagets gjennomsiktighetskonsept er ganske enkelt: applikasjonen bruker samme API uavhengig av datalagringstypen (datalagringstypen), eller datalagringsleverandøren (datalagring-leverandørtransparens). Gjennomsiktighet forenkler applikasjoner i stor grad og forbedrer vedlikeholdsevnen ved å skjule implementeringsdetaljer for datalager i størst mulig grad. Spesielt for de vanlige relasjonsdatalagrene, i motsetning til JDBC, trenger du ikke å hardkode SQL-setninger eller kolonnenavn, eller huske kolonneordren som returneres av et spørsmål. Faktisk trenger du ikke å vite SQL eller relasjonsalgebra, fordi de er for implementeringsspesifikke. Åpenhet er kanskje utholdenhetslagets viktigste trekk.

Konsistent, enkel API

Persistenslag API koker ned til et relativt lite sett med operasjoner:

  • Elementær CRUD (opprett, les, oppdater, slett) operasjoner på førsteklasses objekter
  • Transaksjonsstyring
  • Søknads- og utholdenhetsobjektidentiteters ledelse
  • Cache-administrasjon (dvs. forfriskende og kaste ut)
  • Spørring og utføring

Et eksempel på en PersistenceLayer API:

 offentlig tomrom vedvarer (Objekt obj); // Lagre obj til datalageret. offentlig objektbelastning (klasse c, objekt pK); // Les obj med en gitt primærnøkkel. offentlig ugyldig oppdatering (Object obj); // Oppdater det modifiserte objektobjektet. sletting av offentlig tomrom (Objekt obj); // Slett obj fra databasen. offentlig samling finne (spørring q); // Finn objekter som tilfredsstiller vilkårene i spørringen vår. 

Transaksjonsstøtte

Et godt utholdenhetslag trenger flere grunnleggende funksjoner for å starte, begå eller rulle tilbake en transaksjon. Her er et eksempel:

// Transaksjon (tx) avgrensning. offentlig ugyldig startTx (); public void commitTx (); offentlig ugyldig rollbackTx (); // Velg å gjøre et vedvarende objekt tross alt forbigående. public void makeTransient (Object o) 

Merk: APIer for transaksjonsavgrensning brukes primært i ikke-administrerte miljøer. I administrerte miljøer antar den innebygde transaksjonslederen ofte denne funksjonaliteten.

Administrerte miljøer støtter

Administrerte miljøer, som J2EE applikasjonsservere, har blitt populære blant utviklere. Hvem vil skrive mellomnivåer fra bunnen av i disse dager når vi har gode applikasjonsservere tilgjengelig? Et anstendig utholdenhetslag skal kunne fungere i en hvilken som helst større applikasjonsserveres EJB (Enterprise JavaBean) -beholder og synkronisere med tjenestene, som JNDI (Java Naming and Directory Interface) og transaksjonsadministrasjon.

Spørringer

API-en skal kunne utstede vilkårlige spørsmål for datasøk. Den skal inneholde et fleksibelt og kraftig, men brukervennlig språk - API-et skal bruke Java-objekter, ikke SQL-tabeller eller andre datalagringsrepresentasjoner som formelle spørsmålsparametere.

Cache-administrasjon

Cache-administrasjon kan gjøre underverker for applikasjonsytelsen. Et godt vedvarende lag skal gi full datakurring samt passende API-er for å angi ønsket oppførsel, for eksempel låsenivåer, utkastelsespolicyer, lat belastning og distribuert caching-støtte.

Primær nøkkelgenerering

Å tilby automatisk generering av identitet for data er en av de vanligste utholdenhetstjenestene. Hvert anstendig utholdenhetslag skal gi identitetsgenerering, med støtte for alle viktige primære nøkkelgenereringsalgoritmer. Generering av primærnøkkel er et godt undersøkt problem, og det finnes mange primære nøkkelalgoritmer.

Kartlegging, kun for relasjonsdatabaser

Med relasjonsdatabaser oppstår et datakartingsproblem: behovet for å oversette objekter til tabeller, og å oversette forhold, som avhengigheter og referanser, til flere kolonner eller tabeller. Dette er et ikke-trivielt problem i seg selv, spesielt med komplekse objektmodeller. Temaet for objektrelasjonsmodell impedans mismatch når utover denne artikkelen, men er godt publisert. Se Ressurser for mer informasjon.

Følgende liste over tillegg knyttet til kartlegging og / eller relasjonsdatalager er ikke nødvendig i utholdenhetslaget, men de gjør utviklernes liv mye lettere:

  • Et GUI-kartverktøy (grafisk brukergrensesnitt)
  • Kodegeneratorer: Autogenerering av DDL (databeskrivelsesspråk) for å lage databasetabeller, eller autogenerering av Java-kode og kartleggingsfiler fra DDL
  • Primære nøkkelgeneratorer: Støtter flere nøkkelgenereringsalgoritmer, som UUID, HIGH-LOW og SEQUENCE
  • Støtte for binære store objekter (BLOB) og karakterbaserte store objekter (CLOBs)
  • Selvreferanseforhold: Et objekt av typen Bar refererer til et annet objekt av typen Bar, for eksempel
  • Rå SQL-støtte: Pass-through SQL-spørsmål

Eksempel

Følgende kodebit viser hvordan du bruker persistenslag API. Anta at vi har følgende domenemodell: Et selskap har en eller flere lokasjoner, og hvert sted har en eller flere brukere. Følgende kan være et eksempel på programmets kode:

PersistenceManager pm = PMFactory.initialize (..); Company co = nytt selskap ("MyCompany"); Sted l1 = ny Sted1 ("Boston"); Sted l2 = ny plassering ("New York"); // Opprett brukere. Bruker u1 = ny bruker ("Mark"); Bruker u2 = ny bruker ("Tom"); Bruker u3 = ny bruker ("Mary"); // Legg til brukere. En bruker kan bare "tilhøre" ett sted. L1.addUser (u1); L1.addUser (u2); L2.addUser (u3); // Legg til lokasjoner til selskapet. co.addLocation (l1); co.addLocation (l2); // Og til slutt, lagre hele treet i databasen. pm.persist (c); 

I en annen økt kan du slå opp selskaper som bruker brukeren Tom:

PersistenceManager pm = PMFactory.initialize (...) InnsamlingsselskaperEmployingToms = pm.find ("company.location.user.name = 'Tom'"); 

For relasjonsdatalager må du opprette en ekstra kartfil. Det kan se slik ut:

    Bruker av selskapslokasjoner 

Persistenslaget tar seg av resten, som omfatter følgende:

  • Finne avhengige objektgrupper
  • Administrere applikasjonsobjektidentitet
  • Administrere vedvarende objektidentiteter (primære nøkler)
  • Holde hvert objekt i riktig rekkefølge
  • Tilbyr cache-administrasjon
  • Å gi den riktige transaksjonelle konteksten (vi vil ikke bare ha en del av objekttreet vedvarende, gjør vi?)
  • Tilbyr brukervalgbare låsemodi
$config[zx-auto] not found$config[zx-overlay] not found