Else Lervik 13.04.2004 Opphavsrett: Forfatter og Stiftelsen TISIP Lærestoffet er utviklet for faget LV192D Web-programmering med ASP 11. Resymé: Vi skali denne leksjonen se litt på hva vi må ta hensyn til ved utvikling av profesjonelle løsninger. Med utgangspunkt i at de aller fleste web-applikasjonene jobber mot databaser, skal vi se på: 1. hva som ligger i begrepet databasetransaksjon, og hvorfor det er viktig. 2.hvordan vi med relativt enkle midler kan lage raskere databaseapplikasjoner.endelig tar vi med et par ord om sikkerhet. Innhold 11.1. TRANSAKSJONSHÅNDTERING... 1 11.2. SKALERBARHET OG YTELSE... 4 11.3. HVA MENES MED YTELSEN TIL EN WEB-APPLIKASJON... 5 11.4. Å BEDRE YTELSEN PÅ APPLIKASJONEN... 6 11.4.1. En pool av databaseforbindelser... 6 11.4.2. Å frigjøre ressurser... 6 11.4.3. Å lagre resultatene fra en databaseforespørsel... 7 11.4.4. Å bruke lagrede prosedyrer... 7 11.5. SIKKERHET... 7 Referanse til læreboka Disse emnene er dårlig behandlet i boka. Vi tar med referanser i teksten der det er aktuelt. 11.1. Transaksjonshåndtering Ved endring av innholdet i en database er det ofte et krav at flere tabellrader må oppdateres for at databaseinnholdet skal forbli korrekt. La oss se på en tabell som inneholder en kontooversikt. Se figur 1. Figur 1: En tabell med kontoinformasjon
La oss si at Ole skal overføre 500 kroner til Jonny. To rader må oppdateres: update konto set saldo = saldo - 500 where kontonr = '123456'; update konto set saldo = saldo + 500 where kontonr = '678909'; // Ole sin konto // Jonny sin konto Vi må for enhver pris unngå systemkræsj mellom disse to oppdateringene. Da er det bedre at ingen av setningene ble utført. Systemkræsj vil føre til at de 500 kronene er forsvunnet. Vi kan også oppnå underlige resultater dersom andre brukere får tilgang til dataene mellom de to setningene. De vil kunne foreta beslutninger basert på feil grunnlag. En transaksjon er en enhet med arbeid som må utføres i sin helhet for å gi konsistente resultater. Svært mange transaksjoner består av bare én SQL-setning. Foran har vi imidlertid et eksempel på en transaksjon som består av mer enn én SQL-setning. Det er fire ting som karakteriserer en transaksjon: - Databasetransaksjonen må utføres i sin helhet (den er atomisk, ordet atom stammer fra gresk, og det betyr helt og udelelig). Hvis det ikke er mulig å utføre transaksjonen i sin helhet, må den rulles tilbake slik at databasen er i den tilstanden den var i før oppdateringen. - En transaksjon forlater aldri en database som ikke er konsistent. Alle integritetskrav som gjelder for databasen gjelder også etter at en transaksjon er utført. Med integritetskrav mener vi krav som er satt opp for å sikre at dataene er mest mulig korrekte, et eksempel er kravet til entydige primærnøkler, et annet er for eksempel at et årstall skal være mellom 1950 og 2000. - Andre brukere må ikke ha tilgang til en database der halvparten av oppdateringene i en transaksjon er utført. Det vil si at en transaksjon oppfører seg isolert fra de andre transaksjonene i systemet. - Dersom eksempelvis maskinen der databasesystemet kjører går ned, skal databasesystemet sikre at ingen fullførte og bekreftede transaksjoner forsvinner. Delvis fullførte transaksjoner skal rulles tilbake, det vil si eventuelle halvgjorte oppdateringer skal angres. Databasen skal overleve slike systemkræsj, på engelsk sier vi at den skal ha durability. Hvorfor i all verden disse ordene som atomisk, konsistent, isolert og durability? Selvfølgelig beskriver de viktige egenskaper ved transaksjoner, men på engelsk danner forbokstavene til disse fire ordene en viktig og velkjent forkortelse i databaseverden: Atomic, Consistency, Isolation, Duarabiblity ACID. Databasesystemer med støtte for transaksjoner sørger for at disse egenskapene er oppfylt, vi må bare fortelle når transaksjonen starter og når den slutter. Dersom transaksjonen avsluttes på normal måte, sender vi meldingen bekreft ( commit ) til databasesystemet, og dataene lagres fysisk i databasen. Hvis det skjer noe unormalt vil databasesystemet få meldingen rull tilbake ( rollback ). Ingen endringer registreres i databasen. Vanligvis er en SQL-setning en transaksjonsenhet. Dersom noe annet skal gjelde bruker vi setningen BeginTrans: Set objdbforbindelse = Server.CreateObject("ADODB.Connection") objdbforbindelse.open. objdbforbindelse.begintrans Så utfører vi de aktuelle SQL-setningene som transaksjonen består av, og bekrefter at vi er ferdige på følgende måte: side 2 av 8
objdbforbindelse.committrans Ved utførelse av en transaksjon vil tabellrader 1 som berøres låses etter hvert som transaksjonen prøver å oppdatere dem. Det vanlige er at radene låses eksklusivt, slik at andre brukere verken får lese- eller skrivetilgang. Denne låsen holdes inntil transaksjonen avsluttes. Det er derfor viktig at en transaksjon avsluttes så fort som mulig. Eksempelvis bør ikke en transaksjon inneholde kommunikasjon med brukeren. Det kan fort ta veldig lang tid De vanligste årsakene til tilbakerulling er en ytre hendelse, for eksempel at web-tjeneren og dermed programmet vårt stopper. Det hender imidlertid at det skjer ting innefor vår kontroll som gjør at vi ønsker transaksjonen tilbakerullet. Da kan vi sende meldingen RollBackTrans til databaseforbindelsen: objdbforbindelse.rollbacktrans Eksemplet nedenfor viser de to oppdateringene av konto-tabellen satt inn i en transaksjon med utskrift av begge saldoene før og etter transaksjonen: <% ' OppdateringAvSaldo.asp E.L. 2001-11-13 ' Eksempel på databasetransaksjon Option Explicit %> <HTML><HEAD><TITLE>Oppdatering av saldo</title></head> <BODY BGCOLOR="wheat" TEXT="darkgreen" LINK="brown" VLINK="steelblue" ALINK="darkblue"> Overfører 500 kroner fra Ole til Jonny <P> <% Dim objdbforbindelse, objresultat, iantrader1, iantrader2, strsqlsetn strsqlsetn = "select * from konto where kontonr = " Set objdbforbindelse = Server.CreateObject("ADODB.Connection") objdbforbindelse.open "dsn=konto" Set objresultat = objdbforbindelse.execute(strsqlsetn & "'123456'") Response.Write "<BR>Saldo, konto 123456 før overføring " & _ objresultat("saldo") Set objresultat = objdbforbindelse.execute(strsqlsetn & "'678909'") Response.Write "<BR>Saldo, konto 678909 før overføring " & objresultat("saldo") ' Overfører 500 kroner fra en konto til en annen objdbforbindelse.begintrans objdbforbindelse.execute _ 1 Dette er det vanligste. Enkelte databasesystemer setter imidlertid lås på større (for eksempel hele tabellen) eller mindre (det aktuelle feltet) områder. Som databaseadministrator kan du ofte styre dette. side 3 av 8
"update konto set saldo = saldo - 500 where kontonr = '123456'", _ iantrader1 objdbforbindelse.execute _ "update konto set saldo = saldo + 500 where kontonr = '678909'", _ iantrader2 objdbforbindelse.committrans %> <P>Oppdatering utført. <BR>Antall rader berørt i den første setningen <%=iantrader1%> <BR>Antall rader berørt i den andre setningen <%=iantrader2%> <P> <% Set objresultat = objdbforbindelse.execute(strsqlsetn & "'123456'") Response.Write "<BR>Saldo, konto 123456 etter overføring " & objresultat("saldo") Set objresultat = objdbforbindelse.execute(strsqlsetn & "'678909'") Response.Write "<BR>Saldo, konto 678909 etter overføring " & objresultat("saldo") objdbforbindelse.close Set objdbforbindelse = Nothing %> </BODY> </HTML> Prøvekjør denne ASP en og se at resultatene stemmer. 11.2. Skalerbarhet og ytelse Med unntak av avsnittet om databaseforbindelser (kap. 11.4.1), så bygger dette kapitlet i hovedsak på en generalisering av utdrag fra kap. 34 i Esposito, et.al.: Professional ASP Data Access. Wrox Press Ltd. 2000. ISBN 1-861003-92-7 Skalerbarhet defineres (Dictionary.com) som hvor godt en løsning på et problem vil fungere når størrelsen på problemet øker. Skalerbarhet er direkte relatert til ytelse. I web-løsninger er for eksempel antall samtidige klienter et kritisk mål. Vi ønsker oss stor trafikk, men klarer de løsningene vi lager å håndtere det? MS Access er ikke et databasesystem for profesjonell bruk. Web-tjeneren som mange i kurset bruker, PersonalWebServer, er heller ikke egnet for den typen bruk. Det første du bør bytte ut er dermed databasesystemet og web-tjenerprogramvaren. Det er vel mest aktuelt å holde seg til Microsoft-plattformen, da er SQLServer som databasesystem og Internet Information Server som web-tjener de mest nærliggende alternativene. Men det er også mange andre forbedringsmuligheter. ADO er et stort komponentbibliotek. Vi har i dette kurset kun brukt en liten del av dette biblioteket. Det er verdt å studere dette nærmere. Se for eksempel boka nevnt i begynnelse av dette kapitlet, samt Microsoft sine web-sider. side 4 av 8
11.3. Hva menes med ytelsen til en Web-applikasjon En spesifikasjon av en Web-applikasjon bør inneholde krav til ytelsen. Hvilke kvalitative mål kan vi sette opp for en web-applikasjon? Eksempler: Antall sekunder det tar å laste ned en side, gitt en viss båndbredde. Den tiden det tar å utføre en tjeneste, for eksempel å kredittsjekke en person eller hente data fra en database. Antall samtidige forespørsler som vi skal kunne håndtere. Skal tjenesten være tilgjengelig 24 timer i døgnet, sju dager per uke hele året? Hvor stor er feiltoleransen? Og hva gjør vi dersom den applikasjonen vi lager ikke tilfredsstiller de kravene som er satt opp. Vi kan selvfølgelig revidere kravene, men aktuelle spørsmål vi bør stille oss kan være: Er maskinvaren god nok? Er for eksempel nettverkskortene raske nok, og er minnekapasiteten på tjener-maskinen stor nok? Bruk av flere maskiner og kanskje også flere web-tjenere kan være aktuelt. Det er for eksempel sjelden fornuftig å kjøre så vidt tungt belastede program som web-tjenere og databasetjenere på samme maskin. Kan operativsystemet konfigureres på en bedre måte? Kan tjenerprogramvaren (web-tjeneren) konfigureres på en bedre måte? Er databasen bygd opp på fornuftig vis? Her handler det om datamodellering som vi så vidt var inne på i leksjon 8. Såkalt normalisering (og faktisk også denormalisering av effektivitetshensyn) er også nøkkelord her. Implementerer vi sikkerheten på en lite effektiv måte? Er applikasjonen bygget opp lagvis? Lagvis oppbygging av applikasjoner er et velkjent prinsipp i programvareutvikling. Prinsippet går ut på å lage en applikasjon som består av flere lag, der grensesnittet mellom lagene er veldefinert. Samtidig skal lagene være mest mulig uavhengig av hverandre. I ASP er bruk av komponenter sentralt. I dette kurset har vi kun brukt noen få ferdiglagede komponenter, ved profesjonell bruk bør nok bruken av komponenter utvides betraktelig. Se for eksempel følgende bok: S. Powers: Developing ASP Components. O Reilly 1999. ISBN 1-56592-446-0. Boka inneholder mange nyttige komponenter skrevet i både Visual Basic, C++ og J++. Den gir også mange andre nyttige tips for utvikling av større systemer, blant annet bruk av Microsoft Transaction Server. Er koden skrevet slik at den fungerer effektivt? Effektivisering av kode er sjelden tema i grunnkurs av denne typen. Vi holder det derfor utenfor også i dette kurset. Det nevnes bare at bruken av Option Explicit gjør koden raskere, så det er enda en god grunn til å ha med denne i alle programmer du har ikke glemt den andre grunnen? (Se side 63 i boka.) side 5 av 8
Klarer vi å peke på ett sted der roten til problemet ligger? 11.4. Å bedre ytelsen på applikasjonen Listen foran krever høy kompetanse på mange fagområder. Vi velger å fokusere på det som dette kurset handler om, nemlig utvikling av web-applikasjoner. De aller fleste webapplikasjoner jobber mot databaser, og her er det mye å hente. 11.4.1. En pool av databaseforbindelser Å sette opp en forbindelse til en database er noe av det mest tidkrevende en ASP kan gjøre. I våre eksempler er hver eneste ASP som jobber mot en database bygget opp på følgende måte: 1.Sett opp databaseforbindelsen 2. Utfør en databaseoperasjon 3. Kople ned forbindelsen En mulig løsning er å lagre databaseforbindelsen i et sesjons-objekt. Dette reduserer antall oppkoplinger til én per sesjon, men det kan fort føre til veldig mange samtidige oppkoplinger mot databasen, og hver oppkopling kan lett holdes unødvendig lenge. Det er vanlig å løse dette problemet ved å vedlikeholde en pool av forbindelser. En slik pool er en samling med databaseforbindelser. Når en ASP trenger kontakt med databasen henvender den seg til poolen og spør om det er noen ledig forbindelse. Dersom det er det, får den tildelt en slik forbindelse. Dersom det ikke er flere ledige forbindelser, kan det opprettes en ny, eller ASP en må vente til en blir ledig. Akkurat hva som praktiseres varierer. ASP en holder på forbindelsen så lenge som nødvendig, men ikke lenger. Hvem skal så ha ansvaret for å vedlikeholde denne poolen? Vi kan i prinsippet gjøre det selv på en særdeles enkel måte: Ved oppstart av web-tjeneren kan vi opprette en tabell med for eksempel 10 databaseforbindelser. Denne tabellen legger vi i applikasjonsobjektet, slik at alle klientene får tilgang til den. Ved å lage metoder for å reservere en forbindelse og å frigjøre en forbindelse, har vi poolen klar. Pass på at databaseforbindelsene koples ned når web-tjeneren tas ned. Mer profesjonelle løsninger er nok å foretrekke. Og løsningen er snublende nær: ODBC har innebygd støtte for såkalt Tilkoplingspooling, forutsatt at databasesystemet som brukes støtter dette. Se fanen med dette navnet i ODBC Datakildeadministrator. 11.4.2. Å frigjøre ressurser I eksemplene i de siste leksjonene har vi vært påpasselige med å lukke databaseforbindelsene når de ikke trengs lenger. Dersom vi bruker en pool, vil vi på tilsvarende måte frigi den forbindelsen vi har brukt slik at andre kan benytte den. I praksis skjer dette når vi lukker Connection-objektet. I tillegg til å lukke RecordSet- og Connection-objekter, må vi også frigjøre den plassen disse (og andre) objekter bruker i minnet: objdbforbindelse.close() Set objdbforbindelse = Nothing side 6 av 8
11.4.3. Å lagre resultatene fra en databaseforespørsel Det er ofte vi trenger resultatene fra en databaseforespørsel over flere ASP-sider, ofte en hel sesjon eller kanskje hele tiden. Vi bør ikke lagre hele RecordSet-objektet som del av sesjonsobjektet eller applikasjonsobjektet, for dette objektet kan være stort! Vi lagrer i stedet de dataene i dette objektet som er av interesse for oss. Vi henter dem ut på vanlig måte og lagrer dem for eksempel i en tabell eller annen type samling. 11.4.4. Å bruke lagrede prosedyrer Lagrede prosedyrer er prosedyrer (funksjoner/metoder/subrutiner, eller hva du måtte ønske å kalle en slik kodesnutt; i Java kalles det metoder) som lagres hos databasetjeneren. Eksempel: En bank ønsker å tilby gode kunder et spesielt godt tilbud. Kunden logger seg på nettbanken og ønsker å vite om han eller hun kan nyte godt av dette tilbudet. ASP en sender en passende SELECT-setning til databasesystemet, og får tilbake alle registrerte data om den aktuelle kunden. En komplisert algoritme analyserer disse dataene og sender svaret til kunden. Mer effektivt er det om databasesystemet kan foreta analysen, og så sende JA eller NEI til ASP en. Det kan databasesystemet gjøre dersom det eksisterer en lagret prosedyre som foretar denne analysen. Slike prosedyrer programmeres i tilknytning til databasen. Se side 648-655 i læreboka. 11.5. Sikkerhet Sikkerhet er et enormt tema, det strekker seg fra fysisk sikkerhet i form av avlåste maskinrom, via brannmurer til kryptering og sertifikater og videre til brukerautentisering. Og mye, mye mer. En ansatt på en avdeling som nettopp var blitt utsatt for et alvorlig virusangrep sa: Jeg har ikke installert virusprogramvare, jeg mener at sikkerhet er noe man har i hodet, ikke på arbeidsstasjonen. Vel, vedkommende var ikke angrepet, angivelig fordi han hadde vært påpasselig med å laste ned alle Microsoft sine patcher og service packs. Vedkommende har rett i at sikkerhet sitter i hodet, det har med holdninger å gjøre. Og det er nok det viktigste. Men som en følge av riktige holdninger kan og bør vi gjøre nytte av den programvare som tilbys. Som utviklere vil sikkerhet i hovedsak være noe som ligger utenfor det vi holder på med: Web-tjener og database-tjener må kjøre i sikre miljøer. Her gjelder de vanlige forholdsreglene: Hvem har tilgang til filene, pass på passordene!, sørg for oppdateringer av programvaren, rutiner for sikkerhetskopiering, for overvåking av systemet og nettverket, osv. Autentisering betyr at brukeren må bevise at han/hun er den han/hun gir seg ut for. Brukernavn og passord er en vanlig måte. Sertifikater blir imidlertid mer og mer brukt til autentisering. Skandiabanken, for eksempel, benytter digitale sertifikater i all sin kommunikasjon med kundene. Denne metoden benytter en pålitelig tredje part, en såkalt Certificate Authority (CA) til å autentisere en bruker overfor web-tjeneren, eller motsatt, å autentisere tjeneren overfor brukeren. Med sertifikat vil kommunikasjonen være sikker og kryptert. Krypteringen skjer i henhold til en protokoll som side 7 av 8
kalles Secured Sockets Layer (SSL). SSL bygger på et par nøkler, en offentlig og en privat. Meldinger som sendes kodes med den private nøkkelen og kan bare dekodes dersom mottakeren bruker den tilhørende offentlige nøkkelen. Nøklene deles ut i form av såkalte sertifikater. Både klient og tjener kan ha sertifkater. I nettleseren din, under Sikkerhet, vil du finne en liste over de CA s som du aksepterer sertifikater fra. Brukeren vil se at han/hun jobber over en sikker forbindelse ved at URL en i adressefeltet i nettleseren begynner med https, og ikke http. Autorisering er neste skritt. Når det er bevist at brukeren er den han/hun gir seg ut for å være, handler det om at ulike brukere kan ha ulike rettigheter. Her vil web-tjeneren kunne sette opp ulike rettigheter for ulike brukergrupper. Databasesystemer har i tillegg også vanligvis omfattende muligheter for autorisering av brukergrupper. side 8 av 8