Programmering

Vedhold data med Java Data Objects, del 1

"Alt skal gøres så simpelt som muligt, men ikke enklere."

Albert Einstein

Behovet for at vedvare data oprettet ved kørsel er lige så gammelt som computing. Og behovet for at gemme objektorienterede data dukkede op, når objektorienteret programmering blev udbredt. I øjeblikket bruger de fleste moderne, ikke-private applikationer et objektorienteret paradigme til at modellere applikationsdomæner. I modsætning hertil er databasemarkedet mere opdelt. De fleste databasesystemer bruger relationsmodellen, men objektbaserede datalagre er uundværlige i mange applikationer. Plus, vi har også ældre systemer, som vi ofte har brug for at interface til.

Denne artikel identificerer de problemer, der er forbundet med vedvarende data i transaktionsmæssige mellemvaremiljøer, såsom J2EE (Java 2 Platform, Enterprise Edition), og viser, hvordan Java Data Objects (JDO) løser nogle af disse problemer. Denne artikel giver en oversigt, ikke en detaljeret vejledning, og er skrevet fra en applikationsudviklers synspunkt, ikke en JDO-implementeringsdesigner.

Læs hele serien om Java Data Objects:

  • Del 1. Tag fat i kvaliteterne bag et ideelt persistenslag
  • Del 2. Sun JDO vs. Castor JDO

De Java-udviklere, designere og J2EE-arkitekter, der arbejder på systemer, der skal gemme data i relations- eller objektdatabaser eller andre lagringsmedier, bør læse denne artikel. Jeg antager, at du har en grundlæggende viden om Java og en vis fortrolighed med objektrelationelle problemer og terminologi.

Gennemsigtig vedholdenhed: Hvorfor gider?

Mere end et årti med kontinuerlige forsøg på at bygge bro over objektorienteret køretid og vedholdenhed peger på flere vigtige observationer (angivet i rækkefølge efter betydning):

  1. Det er altafgørende at abstrakte alle persistensdetaljer og have en ren, enkel, objektorienteret API til at udføre datalagring. Vi ønsker ikke at håndtere persistensdetaljer og intern datarepræsentation i datalagre, hvad enten de er relationelle, objektbaserede eller noget andet. Hvorfor skal vi håndtere konstruktioner på lavt niveau af datalagermodellen, såsom rækker og kolonner, og konstant oversætte dem frem og tilbage? I stedet skal vi koncentrere os om den komplekse ansøgning, som vi skulle levere i går.
  2. Vi vil bruge plug-and-play-tilgangen med vores datalagre: Vi ønsker at bruge forskellige udbydere / implementeringer uden at ændre en linje i applikationens kildekode - og måske uden at ændre mere end et par linjer i den relevante konfigurationsfil ( s). Med andre ord har vi brug for en industristandard for at få adgang til data baseret på Java-objekter, en der spiller en rolle svarende til den, JDBC (Java Database Connectivity) spiller som en industristandard for adgang til SQL-baserede data.
  3. Vi vil bruge plug-and-play-tilgangen med forskellige databaseparadigmer - det vil sige, at vi vil skifte fra en relationsdatabase til en objektorienteret med minimale ændringer i applikationskoden. Selvom det er rart at have, er denne evne ofte ikke nødvendig.

    En kommentar her: Mens relationsdatabaser har langt den største tilstedeværelse på markedet, giver det en fornuftig persistens-API og giver datalagerudbydere mulighed for at konkurrere om implementeringsstyrker, uanset hvilket paradigme disse udbydere bruger. Denne tilgang kan i sidste ende hjælpe med at skabe lige vilkår for de to dominerende databaseleverandørgrupper: den velforankrede relationelle lejr og den objektorienterede lejr, der kæmper for markedsandele.

De tre opdagelser, der er anført ovenfor, får os til at definere en persistenslag, en ramme, der giver et Java-API på højt niveau for objekter og relationer til at overleve runtime-miljøets (JVM) levetid. En sådan ramme skal have følgende kvaliteter:

  • Enkelhed
  • Minimal indtrængen
  • Gennemsigtighed, hvilket betyder at rammen skjuler implementeringen af ​​datalager
  • Konsistente, kortfattede API'er til objektlagring / hentning / opdatering
  • Transaktionsunderstøttelse, hvilket betyder, at rammen definerer transaktionsemantik forbundet med vedvarende objekter
  • Support til både administrerede (fx applikationsserverbaserede) såvel som ikke-administrerede (enkeltstående) miljøer
  • Støtte til de nødvendige ekstraudstyr, såsom caching, forespørgsler, generering af primær nøgle og kortlægningsværktøjer
  • Rimelige licensafgifter - ikke et teknisk krav, men vi ved alle, at dårlig økonomi kan dømme et fremragende projekt

Jeg beskriver de fleste af de ovennævnte kvaliteter i de følgende afsnit.

Enkelhed

Enkelhed satser højt på min liste over krævede træk til enhver software ramme eller bibliotek (se denne artikels åbningstilbud). Udvikling af distribuerede applikationer er allerede hårdt nok, og mange softwareprojekter fejler på grund af dårlig kompleksitet (og i forlængelse heraf risikostyring). Enkel er ikke synonymt med forenklet; softwaren skal have alle de nødvendige funktioner, der gør det muligt for en udvikler at udføre sit job.

Minimal indtrængen

Hvert vedvarende lagersystem introducerer en vis indtrængen i applikationskoden. Det ideelle persistenslag skal minimere indtrængen for at opnå bedre modularitet og dermed plug-and-play-funktionalitet.

Med henblik på denne artikel definerer jeg indtrængen som:

  • Mængden af ​​persistensspecifik kode spredt over applikationskoden
  • Behovet for at ændre din applikationsobjektmodel ved enten at skulle implementere en eller anden persistensgrænseflade - f.eks Vedholdende eller lignende - eller ved efterbehandling af den genererede kode

Indtrængen gælder også for objektorienterede databasesystemer, og selvom det normalt er mindre et problem der sammenlignet med relationelle datalagre, kan det variere betydeligt blandt ODBMS (objektorienteret databasestyringssystem) leverandører.

Gennemsigtighed

Det vedvarende lag gennemsigtighedskoncept er ret simpelt: applikationen bruger den samme API uanset datalagertypen (datalagringstypens gennemsigtighed) eller datalagringsleverandøren (datalagring-leverandørtransparens). Gennemsigtighed forenkler applikationer i høj grad og forbedrer deres vedligeholdelsesevne ved at skjule implementeringsoplysninger for datalager i størst muligt omfang. Især for de udbredte relationelle datalagre, i modsætning til JDBC, behøver du ikke at hardcode SQL-sætninger eller kolonnenavne eller huske kolonneordren returneret af en forespørgsel. Faktisk behøver du ikke kende SQL eller relationel algebra, fordi de er for implementeringsspecifikke. Gennemsigtighed er måske persistenslagets vigtigste træk.

Konsistent, enkel API

Persistenslag API koger ned til et relativt lille sæt operationer:

  • Elementær CRUD (opret, læs, opdater, slet) operationer på førsteklasses objekter
  • Transaktionsstyring
  • Administration- af applikations- og persistens-objekt-identiteter
  • Cache-styring (dvs. forfriskende og udsættelse)
  • Forespørgsel oprettelse og udførelse

Et eksempel på en PersistenceLayer API:

 offentlig tomrum vedvarer (Objekt obj) // Gem obj til datalageret. offentlig objektbelastning (klasse c, objekt pK); // Læs obj med en given primærnøgle. offentlig ugyldig opdatering (Objekt obj) // Opdater det modificerede objekt obj. offentlig tomrumslet (Objekt obj); // Slet obj fra databasen. offentlig samling finde (forespørgsel q); // Find objekter, der opfylder betingelserne i vores forespørgsel. 

Transaktionsunderstøttelse

Et godt persistenslag har brug for flere elementære funktioner for at starte, begå eller rulle en transaktion tilbage. Her er et eksempel:

// Afgrænsning af transaktion (tx). offentlig ugyldig startTx (); public void commitTx (); offentlig ugyldig rollbackTx (); // Vælg alligevel at gøre et vedvarende objekt kortvarigt. public void makeTransient (Object o) 

Bemærk: API til transaktionsafgrænsning anvendes primært i ikke-administrerede miljøer. I administrerede miljøer antager den indbyggede transaktionsmanager ofte denne funktionalitet.

Administrerede miljøer understøtter

Administrerede miljøer, såsom J2EE-applikationsservere, er blevet populære blandt udviklere. Hvem ønsker at skrive mellemniveauer fra bunden i disse dage, når vi har fremragende applikationsservere til rådighed? Et anstændigt persistenslag skal kunne arbejde inden for enhver større applikationsservers EJB (Enterprise JavaBean) -container og synkronisere med dets tjenester, såsom JNDI (Java Naming and Directory Interface) og transaktionsadministration.

Forespørgsler

API'en skal kunne udstede vilkårlige forespørgsler til datasøgninger. Det skal indeholde et fleksibelt og kraftfuldt, men let at bruge sprog - API'en skal bruge Java-objekter, ikke SQL-tabeller eller andre repræsentationer af datalager som formelle forespørgselsparametre.

Cache-administration

Cache-administration kan gøre underværker for applikationsydelse. Et sundt persistenslag skal give fuld datacaching samt passende API'er til at indstille den ønskede adfærd, såsom låseniveauer, bortkastningspolitikker, doven indlæsning og distribueret caching-understøttelse.

Primær nøglegenerering

At levere automatisk identitetsgenerering til data er en af ​​de mest almindelige vedholdenhedstjenester. Hvert anstændigt persistenslag skal give identitetsgenerering med støtte til alle større primære nøglegenerationsalgoritmer. Generering af primærnøgle er et velundersøgt emne, og der findes adskillige primære nøglealgoritmer.

Kortlægning, kun til relationsdatabaser

Med relationsdatabaser opstår der et datakortingsproblem: behovet for at oversætte objekter til tabeller og at oversætte relationer, såsom afhængigheder og referencer, til yderligere kolonner eller tabeller. Dette er et ikke-problematisk problem i sig selv, især med komplekse objektmodeller. Emnet for objektrelationel model impedans uoverensstemmelse når ud over denne artikels anvendelsesområde, men er godt offentliggjort. Se Ressourcer for mere information.

Følgende liste over ekstramateriale relateret til kortlægning og / eller relationelle datalagre er ikke påkrævet i persistenslaget, men de gør udviklerens liv meget lettere:

  • Et kortlægningsværktøj til GUI (grafisk brugergrænseflade)
  • Kode generatorer: Autogeneration af DDL (databeskrivelsessprog) for at oprette databasetabeller eller autogeneration af Java-kode og kortlægning af filer fra DDL
  • Primære nøglegeneratorer: Understøtter flere algoritmer til generering af nøgler, såsom UUID, HIGH-LOW og SEQUENCE
  • Støtte til binære store objekter (BLOB) og karakterbaserede store objekter (CLOBs)
  • Selvrefererende relationer: Et objekt af typen Bar der henviser til et andet objekt af typen Bar, for eksempel
  • Raw SQL support: Pass-through SQL-forespørgsler

Eksempel

Følgende kodestykke viser, hvordan man bruger persistenslag API. Antag, at vi har følgende domænemodel: En virksomhed har en eller flere placeringer, og hver placering har en eller flere brugere. Følgende kan være et eksempel på applikationens kode:

PersistenceManager pm = PMFactory.initialize (..); Company co = nyt firma ("MyCompany"); Placering l1 = ny Location1 ("Boston"); Placering l2 = ny placering ("New York"); // Opret brugere. Bruger u1 = ny bruger ("Marker"); Bruger u2 = ny bruger ("Tom"); Bruger u3 = ny bruger ("Mary"); // Tilføj brugere. En bruger kan kun "tilhøre" én placering. L1.addUser (u1); L1.addUser (u2); L2.addUser (u3); // Tilføj placeringer til virksomheden. co.addLocation (l1); co.addLocation (l2); // Og til sidst skal du gemme hele træet i databasen. pm.persist (c); 

I en anden session kan du slå op på virksomheder, der ansætter brugeren Tom:

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

For relationelle datalagre skal du oprette en ekstra kortfil. Det kan se sådan ud:

    Virksomhedslokationsbruger 

Persistenslaget tager sig af resten, som omfatter følgende:

  • Finde afhængige objektgrupper
  • Håndtering af applikationsobjektidentitet
  • Håndtering af vedvarende objektidentiteter (primære nøgler)
  • Vedligeholdelse af hvert objekt i den passende rækkefølge
  • Tilvejebringelse af cacheadministration
  • Tilvejebringelse af den korrekte transaktionskontekst (vi vil ikke kun have en del af objekttræet vedvarende, gør vi?)
  • Tilbyder brugervalgbare låsningstilstande