Introduktion
Att använda en databas för att hantera dina applikationsdata är ett av de vanligaste valen för databeständighet. Databaser tillåter snabb informationslagring och hämtning, ger dataintegritetsgarantier och erbjuder beständighet utöver livslängden för en enskild applikationsinstans. Det finns otaliga typer av databaser tillgängliga för att möta ditt projekts krav och dina preferenser.
Men att arbeta direkt med databaser från din applikation är inte alltid lätt. Skillnader i hur datastrukturer representeras leder ofta till utmaningar. Svårigheten att uttrycka subtiliteter om relationer mellan olika enheter kan också orsaka problem. För att hantera detta har många olika verktyg skapats för att fungera som ett gränssnitt mellan kärnapplikationen och datalagret.
I den här guiden kommer vi att titta på några av skillnaderna som uppstår mellan tre vanliga tillvägagångssätt:rå SQL, frågebyggare och ORM:er (objektrelationsmappare). Vi jämför några av fördelarna och nackdelarna med varje tillvägagångssätt och avslutar sedan med en ordlista med vanliga termer för att hjälpa dig att bekanta dig med några nyckelbegrepp.
Som en förenklad sammanfattning, här är en allmän bild av varje tillvägagångssätts styrkor och svagheter:
Tillvägagångssätt | Databas-/programmeringsfokuserad | Praktisk hantering | Abstraktionsnivå | Komplexitetsnivå |
---|---|---|---|---|
Raw SQL | databasorienterad | hög | ingen | låg |
Frågebyggare | blandat | låg | låg | låg |
ORM | programmeringsorienterad | låg | hög | hög |
Hantera data med rå SQL eller annat databasinbyggt frågespråk
Vissa applikationer gränssnitt direkt med databasen genom att skriva och köra frågor med det modersmål som stöds av databasmotorn. Ofta är en databasdrivrutin allt som behövs för att ansluta, autentisera och kommunicera med databasinstansen.
Utvecklare kan skicka frågor skrivna på databasens modersmål via anslutningen. I gengäld kommer databasen att tillhandahålla frågeresultaten, även i ett av dess ursprungliga format. För många relationsdatabaser är det valda språket SQL.
De flesta relationsdatabaser, såväl som vissa icke-relationella databaser, stöder strukturerat frågespråk, även känt som SQL, för att bygga och exekvera kraftfulla frågor. SQL har använts för att hantera data sedan 1970-talet, så det stöds väl och till viss del standardiserat.
Fördelar med native querying
Att använda SQL eller ett annat databasspråk har några tydliga fördelar.
En fördel är att utvecklare skriver och hanterar databasfrågorna och hanterar resultaten explicit. Även om detta kan vara en hel del extra arbete, betyder det att det finns få överraskningar när det gäller vad databasen lagrar, hur den representerar din data och hur den kommer att tillhandahålla den informationen när den hämtas senare. Bristen på abstraktion gör att det finns färre "rörliga delar" som kan leda till osäkerhet.
Ett exempel på detta är prestanda. Medan sofistikerade abstraktionslager genererar SQL-frågor genom att översätta programmeringssatser, kan den genererade SQL-en vara mycket ineffektiv. Onödiga klausuler, alltför breda frågor och andra missöden kan leda till långsamma databasoperationer som kan vara ömtåliga och svåra att felsöka. Genom att skriva inbyggt i SQL kan du använda all din domänkunskap och sunt förnuft för att undvika många klasser av frågeproblem
Ett annat skäl till att använda databasbaserade frågor är flexibilitet. Ingen abstraktion kommer sannolikt att kunna vara så flexibel som det inhemska databasens frågespråk. Högre abstraktionsnivåer försöker överbrygga klyftan mellan två olika paradigm, vilket kan begränsa de typer av operationer de kan uttrycka. När du skriver i rå SQL kan du dock dra nytta av alla funktioner i din databasmotor och uttrycka mer komplexa frågor.
Nackdelar med native querying
Även om native querying har vissa starka sidor, är det inte utan problem.
När du interagerar med en databas från en applikation med vanlig SQL måste du förstå den underliggande datastrukturen för att kunna skapa giltiga frågor. Du är helt ansvarig för att översätta mellan de datatyper och strukturer som din applikation använder och de konstruktioner som finns tillgängliga inom databassystemet.
En annan sak att tänka på när du arbetar med rå SQL är att det är helt upp till dig att hantera säkerheten för din input. Detta gäller särskilt om du lagrar data från externa användare, där specialgjorda indata kan få din databas att exponera information som du inte hade tänkt tillåta.
Denna typ av utnyttjande kallas SQL-injektion och är ett potentiellt problem när användarinmatning kan påverka databastillståndet. Verktyg för högre abstraktion rengör ofta användarinmatning automatiskt, vilket hjälper dig att undvika den här typen av problem.
Att arbeta med inhemska frågespråk innebär nästan alltid att skriva frågor med vanliga strängar. Detta kan vara en smärtsam process i fall där du måste undvika inmatning och sammanfoga strängar för att skapa en giltig fråga. Dina databasoperationer kan lindas in i många lager av strängmanipulation som har stor potential att oavsiktligt mangla data.
Native querying summary
Även om vi i första hand har pratat om SQL i det här avsnittet, gäller det mesta av informationen här lika väl för alla inhemska databasfrågor. För att sammanfatta, rå SQL eller direkt användning av något motsvarande frågespråk kommer dig närmast abstraktionerna som används av databasen för att lagra och hantera data, men tvingar dig att göra allt det tunga arbetet med att hantera dina data manuellt.
Hantera data med frågebyggare
Ett alternativt tillvägagångssätt för att använda databasbaserade frågespråk som SQL är att använda ett verktyg eller bibliotek som kallas frågebyggare för att prata med din databas.
Vad är SQL-frågebyggare?
En SQL-frågebyggare lägger till ett lager av abstraktion ovanför råa databasbaserade frågespråk. De gör detta genom att formalisera frågemönster och tillhandahålla metoder eller funktioner som lägger till ingångshygien och automatiskt undviker objekt för enklare integrering i applikationer.
Strukturerna och åtgärderna som stöds av databaslagret är fortfarande ganska igenkännbara när du använder SQL-frågebyggare. Detta gör att du kan arbeta med data programmatiskt samtidigt som du fortfarande är relativt nära data.
Vanligtvis tillhandahåller frågebyggare ett gränssnitt som använder metoder eller funktioner för att lägga till ett villkor till en fråga. Genom att kedja ihop metoder kan utvecklare komponera kompletta databasfrågor från dessa individuella "klausuler".
Fördelar med SQL-frågebyggare
Eftersom frågebyggare använder samma konstruktioner (metoder eller funktioner) som resten av din applikation, tycker utvecklare ofta att de är lättare att hantera på lång sikt än rådatabasfrågor skrivna som strängar. Det är enkelt att se skillnaden mellan operatorer och data och det är lätt att dekomponera frågor i logiska bitar som hanterar specifika delar av en fråga.
För vissa utvecklare är en annan fördel med att använda en SQL-frågebyggare att den inte alltid döljer det underliggande frågespråket. Även om operationerna kan använda metoder istället för strängar, kan den vara ganska transparent, vilket gör det lättare för dem som är bekanta med databasen att förstå vad en operation kommer att göra. Detta är inte alltid fallet när man använder högre abstraktionsnivåer.
SQL-frågebyggare stöder ofta också flera databackends, och abstraherar några av de subtila skillnaderna i olika relationsdatabaser, till exempel. Detta gör att du kan använda samma verktyg för projekt som använder olika databaser. Det kan till och med göra migreringen till en ny databas något lättare.
Nackdelar med SQL-frågebyggare
SQL-frågebyggare lider av några av samma nackdelar som inhemska frågespråk.
En populär kritik är att SQL-frågebyggare fortfarande kräver att du förstår och redogör för databasens strukturer och möjligheter. Detta är inte en tillräckligt användbar abstraktion för vissa utvecklare. Detta innebär att du måste ha ett ganska bra grepp om SQL utöver den specifika syntaxen och kapaciteten hos själva frågebyggaren.
Dessutom kräver SQL-frågebyggare fortfarande att du definierar hur data du hämtar relaterar till din applikationsdata. Det finns ingen automatisk synkronisering mellan dina minnesobjekt och de i databasen.
Även om frågebyggare ofta emulerar frågespråket som de är designade för att fungera med, kan det extra lagret av abstraktion innebära att vissa operationer ibland inte är möjliga med de tillhandahållna metoderna. Vanligtvis finns det ett "rå"-läge för att skicka frågor direkt till backend, som kringgår frågebyggarens typiska gränssnitt, men detta kringgår problemet snarare än att lösa det.
Sammanfattning av SQL-frågebyggare
Sammantaget erbjuder SQL-frågebyggare ett tunt lager av abstraktion som specifikt inriktar sig på några av de största smärtpunkterna med att arbeta direkt med databasspråk. SQL-frågebyggare fungerar nästan som ett mallsystem för frågor, vilket gör att utvecklare kan gå på gränsen mellan att arbeta direkt med databasen och lägga till ytterligare abstraktionslager.
Hantera data med ORM
Ett steg längre upp i abstraktionshierarkin finns ORM. ORM:er siktar i allmänhet på en mer fullständig abstraktion med hopp om att integreras med applikationsdata mer flytande.
Vad är ORM?
Objektrelationsmappare, eller ORM:er, är programvaror dedikerade till att översätta mellan datarepresentationer i relationsdatabaser och representationen i minnet som används med objektorienterad programmering (OOP). ORM tillhandahåller ett objektorienterat gränssnitt till data i databasen, och försöker använda välbekanta programmeringskoncept och minska mängden standardkod som krävs för att påskynda utvecklingen.
I allmänhet fungerar ORM:er som ett abstraktionslager avsett att hjälpa utvecklare att arbeta med databaser utan att drastiskt ändra det objektorienterade paradigmet. Detta kan vara till hjälp genom att minska den mentala belastningen av att anpassa sig till detaljerna i en databas lagringsformat.
Särskilt objekt i objektorienterad programmering tenderar att koda mycket tillstånd inom dem och kan ha komplexa relationer med andra objekt genom arv och andra OOP-koncept. Att kartlägga denna information tillförlitligt till ett tabellorienterat relationsparadigm är ofta inte okomplicerat och kan kräva en god förståelse för båda systemen. ORM försöker lätta denna börda genom att automatisera en del av denna mappning och genom att tillhandahålla uttrycksfulla gränssnitt till data i systemet.
Är utmaningarna med ORM specifika för objektorienterad programmering och relationsdatabaser?
Per definition är ORM:er specifikt utformade för att samverka mellan objektorienterade applikationsspråk och relationsdatabaser. Men att försöka kartlägga och översätta mellan datastrukturabstraktionerna som används inom programmeringsspråk och de som används av databasbutiker är ett mer allmänt problem som kan uppstå när abstraktioner inte stämmer överens.
Beroende på programmeringsparadigmet (objektorienterat, funktionellt, procedurmässigt, etc.) och databastypen (relationellt, dokument, nyckel-värde, etc.), kan olika mängder abstraktion vara till hjälp. Ofta dikterar komplexiteten i datastrukturerna i applikationen hur lätt det är att samverka med datalagret.
Objektorienterad programmering tenderar att producera många strukturer med betydande tillstånd och relationer som måste redovisas. Vissa andra programmeringsparadigm är mer explicita om var tillstånd lagras och hur det hanteras. Till exempel tillåter inte rent funktionella språk föränderligt tillstånd, så tillstånd är ofta en indata för funktioner eller objekt som matar ut ett nytt tillstånd. Denna rena separering av data från åtgärder, såväl som tydligheten i tillståndets livscykler kan hjälpa till att förenkla interaktionen med databasen.
Hur som helst, möjligheten att gränssnitta med en databas genom programvara som mappar mellan två olika representationer är ofta tillgänglig. Så även om ORM beskriver en specifik delmängd av dessa med unika utmaningar, kräver kartläggning mellan applikationsminne och beständig lagring ofta övervägande oavsett detaljer.
Active record vs data mapper ORMs
Olika ORM använder olika strategier för att kartlägga mellan applikations- och databasstrukturer. De två huvudkategorierna är det aktiva postmönstret och datamappningsmönstret .
Det aktiva postmönstret försöker kapsla in databasens data i strukturen av objekt i din kod. Objekt innehåller metoder för att spara, uppdatera eller ta bort från databasen och ändringar av dina objekt är avsedda att enkelt återspeglas i databasen. I allmänhet representerar ett aktivt postobjekt i din applikation en post i en databas.
Aktiva postimplementeringar låter dig hantera din databas genom att skapa och ansluta klasser och instanser i din kod. Eftersom dessa generellt mappar klassinstanser direkt till databasposter är det lätt att begreppsualisera vad som finns i din databas om du förstår vilka objekt som används i din kod.
Tyvärr kan detta också komma med några stora nackdelar. Applikationer tenderar att vara mycket tätt kopplade till databasen, vilket kan orsaka problem när du försöker migrera till en ny databas eller till och med när du testar din kod. Din kod tenderar att förlita sig på databasen för att fylla i luckor som har laddats bort från dina objekt. Den "magiska" översättningen mellan dessa två domäner kan också leda till prestandaproblem eftersom systemet sömlöst försöker mappa komplexa objekt till den underliggande datastrukturen.
Datamappningsmönstret är det andra vanliga ORM-mönstret. Liksom det aktiva postmönstret försöker datakartläggningen fungera som ett oberoende lager mellan din kod och din databas som förmedlar mellan de två. Men istället för att försöka integrera objekt och databasposter sömlöst, fokuserar den på att försöka frikoppla och översätta mellan dem samtidigt som de låter var och en existera oberoende. Detta kan hjälpa till att skilja din affärslogik från databasrelaterade detaljer som handlar om mappningar, representation, serialisering etc.
Så istället för att låta ORM-systemet ta reda på hur man mappar mellan objekten och databastabellerna, är utvecklaren ansvarig för att explicit kartlägga mellan de två. Detta kan hjälpa till att undvika tät koppling och operationer bakom kulisserna på bekostnad av betydligt mer arbete med att ta reda på lämpliga mappningar.
Fördelar med ORM
ORM är populära av många anledningar.
De hjälper till att abstrahera den underliggande datadomänen till något som är lätt att resonera kring inom ramen för din applikation. Istället för att tänka på datalagring som ett oberoende system, hjälper ORM dig att komma åt och hantera datasystem som en förlängning av ditt nuvarande arbete. Detta kan hjälpa utvecklare att arbeta snabbare med kärnverksamhetens logik istället för att fastna i nyanserna i deras lagringsbackends.
En annan bieffekt av detta är att ORM:er tar bort en hel del av den konstruktion som krävs för att gränssnittet med databaser. ORM:er kommer ofta med migreringsverktyg som hjälper dig att hantera databasschemaändringar baserat på ändringar som gjorts i din kod. Du behöver inte nödvändigtvis ta reda på det perfekta databasschemat i förväg om din ORM kan hjälpa till att hantera ändringar i databasstrukturen. Dina applikations- och databasändringar är ofta samma sak eller nära relaterade, vilket hjälper till att spåra ändringar i din databas när du gör ändringar i din kod.
Nackdelar med ORM
ORM är inte utan sina brister. I många fall härrör dessa från samma beslut som gör ORM användbara.
Ett av de grundläggande problemen med ORM är försöket att dölja detaljerna i databasens backend. Denna förvirring gör det lättare att arbeta med ORM:er i enkla fall eller på små tidsskalor, men leder ofta till problem i takt med att komplexiteten växer.
Abstraktionen är aldrig 100 % komplett och försök att använda en ORM utan att förstå det underliggande frågespråket eller databasstrukturen leder ofta till problematiska antaganden. Detta kan göra felsökning och prestandajustering svår eller omöjlig.
Det kanske mest välkända problemet med att arbeta med ORM är objektrelationell impedansmismatch, en term som används för att beskriva svårigheten att översätta mellan objektorienterad programmering och det relationsparadigm som används av relationsdatabaser. Inkompatibiliteten mellan datamodellerna som används av dessa två teknologikategorier innebär att ytterligare, ofullkomlig abstraktion är nödvändig med varje ökning av komplexiteten. Objektrelationell impedansmissanpassning har kallats datavetenskapens Vietnam (med hänvisning till Vietnamkriget) på grund av dess tendens att öka komplexiteten över tid och leda till situationer där vägarna till antingen framgång eller att ändra kurs är svåra eller omöjliga.
I allmänhet tenderar ORM:er att vara långsammare än alternativ, särskilt med komplexa frågor. ORM genererar ofta komplicerade frågor för relativt enkla databasoperationer, eftersom de använder allmänna mönster som måste vara tillräckligt flexibla för att hantera andra fall. Att förlita sig på att ORM gör det rätta under alla omständigheter kan leda till kostsamma misstag som kan vara svåra att komma ikapp.
Sammanfattning av ORM
ORM:er kan vara användbara abstraktioner som gör arbetet med databaser mycket enklare. De kan hjälpa dig att designa och iterera snabbt och överbrygga de konceptuella skillnaderna mellan applikationslogik och databasstrukturer. Men många av dessa fördelar fungerar som ett tveeggat svärd. De kan hindra dig från att förstå dina databaser och kan göra det utmanande att felsöka, ändra paradigm eller öka prestanda.
Ordlista
När du arbetar med teknologier som samverkar mellan databaser och applikationer kan du stöta på terminologi som du inte är bekant med. I det här avsnittet kommer vi kortfattat att gå igenom några av de vanligaste termerna du kan stöta på, av vilka några behandlades tidigare i den här artikeln och några inte.
- Datamappare: En datamapper är ett designmönster eller en mjukvara som mappar programmeringsdatastrukturer till de som är lagrade i en databas. Datakartare försöker synkronisera ändringar mellan de två källorna samtidigt som de håller dem oberoende av varandra. Kartläggaren själv ansvarar för att upprätthålla en fungerande översättning, vilket gör att utvecklare kan iterera applikationens datastrukturer utan att behöva bry sig om databasrepresentationen.
- Databasdrivrutin: En databasdrivrutin är en mjukvara utformad för att kapsla in och möjliggöra anslutningar mellan en applikation och en databas. Databasdrivrutiner abstraherar lågnivådetaljerna om hur man gör och hanterar anslutningar och tillhandahåller ett enhetligt, programmatiskt gränssnitt till databassystemet. Databasdrivrutiner är vanligtvis den lägsta abstraktionsnivån som utvecklare använder för att interagera med databaser, med verktyg på högre nivå som bygger på de funktioner som drivrutinen tillhandahåller.
- Injektionsattack: En injektionsattack är en attack där en illvillig användare försöker utföra oönskade databasoperationer med hjälp av specialgjorda indata i användarvänliga applikationsfält. Ofta används detta för att hämta data som inte borde vara tillgängligt eller för att radera eller mangla information i databasen.
- ORM: ORM:er, eller objektrelationsmappare, är abstraktionslager som översätter mellan de datarepresentationer som används i relationsdatabaser och representationen i minnet som används med objektorienterad programmering. ORM tillhandahåller ett objektorienterat gränssnitt till data i databasen, och försöker minska mängden kod och använda välbekanta arketyper för att påskynda utvecklingen.
- Obalans i objektrelationell impedans: Objektrelationell impedansmissanpassning hänvisar till svårigheten att översätta mellan en objektorienterad applikation och en relationsdatabas. Eftersom datastrukturerna varierar avsevärt kan det vara svårt att troget och effektivt mutera och transkribera de programmatiska datastrukturerna till formatet som används av lagringsbackend.
- Ramverk för uthållighet: Ett persistensramverk är ett abstraktionslager för middleware som utvecklats för att överbrygga gapet mellan programdata och databaser. Persistensramverk kan också vara ORM:er om abstraktionen de använder mappar objekt till relationsenheter.
- Frågebyggare: En frågebyggare är ett abstraktionslager som hjälper utvecklare att komma åt och kontrollera databaser genom att tillhandahålla ett kontrollerat gränssnitt som lägger till funktioner för användbarhet, säkerhet eller flexibilitet. Vanligtvis är frågebyggare relativt lätta, fokuserar på att underlätta dataåtkomst och datarepresentation och försöker inte översätta data till ett specifikt programmeringsparadigm.
- SQL: SQL, eller strukturerat frågespråk, är ett domänspecifikt språk utvecklat för att hantera relationsdatabashanteringssystem. Den kan användas för att fråga, definiera och manipulera data i en databas såväl som deras organisationsstrukturer. SQL finns överallt bland relationsdatabaser.
Slutsats
I den här artikeln tittade vi på några olika alternativ för gränssnitt med din databas från din applikation. Vi undersökte de olika abstraktionsnivåerna och den flexibilitet som erbjuds genom att använda databasbaserade frågespråk som SQL, använda en frågebyggare för att hjälpa till att skapa frågor på ett säkert sätt och ORM för att ge en mer komplett abstraktionsnivå.
Var och en av dessa tillvägagångssätt har sina användningsområden och vissa kan vara väl lämpade för vissa typer av tillämpningar än andra. Det är viktigt att förstå dina applikationskrav, din organisations databaskunskap och kostnaderna för de abstraktioner (eller bristen på sådana) som du väljer att implementera. Genom att förstå varje tillvägagångssätt får du den bästa chansen att välja det alternativ som passar dina projekt.