Gå til innhold

Check Constraint i MySQL? Er det mulig?


Anbefalte innlegg

Videoannonse
Annonse
Jobber med ein MySQL database og skal lage ein check constraint, men eg ettersom eg leser etter litt googling er at dette ikkje støttes? Den nyaste siden eg fant var frå jula 2007, er dette støtta per dags dato?

 

Når du begynner å ta i bruk slik ting er det kanskje bedre å vurdere PostgreSQL. Den støtter slike ting lett, god støtte for stored procedures for mer avanserte ting, og *mye* lettere å finne frem i dokumentasjonen, for å finne svar på spørsmål som dette.

Lenke til kommentar

Det hadde eg gjort om eg kunne velge database som eg ikkje kan i dette tilfellet. Det er nok krangling å få bytta frå MyISAM til INNODB :p

 

Men det er mulig eg kan få dette til med å bruke triggers istaden, litt ekstra arbeid, men men.

Endret av siDDIs
Lenke til kommentar

Finner eksempler på at ein må bruke after insert trigger for å sjekke om raden som er satt inn er 'valid' om ikkje så fjerner ein raden. Problemet her er jo kva om det skjer eit straumbrudd mens dette pågår?

 

Er det mogleg å starte ein transaksjon med before insert også commite med after insert?

Lenke til kommentar
Finner eksempler på at ein må bruke after insert trigger for å sjekke om raden som er satt inn er 'valid' om ikkje så fjerner ein raden. Problemet her er jo kva om det skjer eit straumbrudd mens dette pågår?

 

Er det mogleg å starte ein transaksjon med before insert også commite med after insert?

 

Burde være mulig, men da har du muligens en race-condition.

 

Du sjekker om raden finnes, den slettes, og så gjør du committ.

 

Ikke nødvendigvis noe problem, men greit å være obs på.

Lenke til kommentar
nei

commit blir kjørt etter eg har sjekka om raden er valid eller ikke. Det burde jo gå.

 

Ja, men som sagt:

 

a) Du sjekker om raden finnes.

b) Noen sletter raden.

c) Du kjører commit.

 

I mange tilfeller er nok dette sikkert helt trygt og greit, men det er en mulig race-condition, så greit å være klar over.

Lenke til kommentar
argh, helvete, det er jo sant, då må eg låse tabellen i såfall :/

 

En annen ting som er litt apropos er at om du sjekker at raden eksisterer gir jo fremdeles ingen beskyttelse mot at den ikke slettes etter transksjonen er ferdig.

 

dvs, det gir deg jo bare en rask sjekk når du setter inn raden. Ofte bruker man jo contstraints/referanser for å hindre at raden det pekes til blir slettet, eller at andre rader følger med i dragsuget om den slettes.

Lenke til kommentar
Finner eksempler på at ein må bruke after insert trigger for å sjekke om raden som er satt inn er 'valid' om ikkje så fjerner ein raden. Problemet her er jo kva om det skjer eit straumbrudd mens dette pågår?

 

Er det mogleg å starte ein transaksjon med before insert også commite med after insert?

 

Kjenner lite til MySQL (og blir mer og mer overbevist om at jeg ikke ønsker noe nærmere bekjentskap heller :p ),

men i SQL Server så er det bare å kjøre ROLLBACK i after triggeren hvis du skulle finne uønskede data. Alt blir selvfølgelig rullet tilbake. Triggeren trenger selvfølgelig ikke å kjøre COMMIT. Dette gjøres enten eksplisitt av caller, eller implisitt for statementet.

 

Hvis InnoDB er ACID-compliant så trenger du heller ikke å bekymre deg for strømbrudd. Databasemotoren vil ta seg av recovery ved oppstart.

 

nei

commit blir kjørt etter eg har sjekka om raden er valid eller ikke. Det burde jo gå.

 

Ja, men som sagt:

 

a) Du sjekker om raden finnes.

b) Noen sletter raden.

c) Du kjører commit.

 

I mange tilfeller er nok dette sikkert helt trygt og greit, men det er en mulig race-condition, så greit å være klar over.

 

Men det er vel ikke mulig? Du inserter en ny rad og det plasseres en write-lock på denne. Ingen får lest denne raden (og iallefall ikke slettet den) før du ha kjørt commit.

Lenke til kommentar
Hvis InnoDB er ACID-compliant så trenger du heller ikke å bekymre deg for strømbrudd. Databasemotoren vil ta seg av recovery ved oppstart.

 

Det er bare delvis riktig.

 

a) Connection 1 setter inn rad #18

b) Connection 2 sjekker om rad #18 finnes

c) Connection 2 legger in rad som depender på rad #18

d) Connection 2 committer

e) Strømmen går, uten at Connection 1 committer

 

Spørs litt på hvordan MySQL isolerer transactions, men dersom en insertet rad er synlig før den er committed, så vil ikke ACID redde deg ved en slik situasjon og strømbrudd.

Lenke til kommentar
Hvis InnoDB er ACID-compliant så trenger du heller ikke å bekymre deg for strømbrudd. Databasemotoren vil ta seg av recovery ved oppstart.

 

Det er bare delvis riktig.

 

a) Connection 1 setter inn rad #18

b) Connection 2 sjekker om rad #18 finnes

c) Connection 2 legger in rad som depender på rad #18

d) Connection 2 committer

e) Strømmen går, uten at Connection 1 committer

 

Spørs litt på hvordan MySQL isolerer transactions, men dersom en insertet rad er synlig før den er committed, så vil ikke ACID redde deg ved en slik situasjon og strømbrudd.

 

Connection2 ser ikke rad #18 før connection 1 har committet, ergo er dette ikke noe problem.

Lenke til kommentar
Connection2 ser ikke rad #18 før connection 1 har committet, ergo er dette ikke noe problem.

 

Meget mulig at dette stemmer. Jeg husker som sagt ikke MySQL som stort mer enn ett vondt minne, så en del slike detaljer har gått tapt.

 

Ville bare påpeke det, siden ikke alle databaser som er ACID-complient vil gjør det på denne måten.

 

Ta PostgreSQL for eksempel.

 

Avhengig av hvordan transaction isolation er satt opp vil du kunne se raden fra Connection 1 i Connection 2, før den er committet. Hvis du da bruker en referanse fra Connection 2 til raden satt inn av Connection 1, så vil (hvis jeg husker rett) COMITT på Connection 2 kunne blokke til Connection 1 er COMMITTed.

 

Hvis du derimot implementerer dette som en stored procedure for å sjekke om raden satt inn av Connection 1 er tilstedet, så vil det jo ikke legge til en referanse, og du vil kunne få problemer.

 

Terje

Lenke til kommentar
argh, helvete, det er jo sant, då må eg låse tabellen i såfall :/

 

En annen ting som er litt apropos er at om du sjekker at raden eksisterer gir jo fremdeles ingen beskyttelse mot at den ikke slettes etter transksjonen er ferdig.

 

dvs, det gir deg jo bare en rask sjekk når du setter inn raden. Ofte bruker man jo contstraints/referanser for å hindre at raden det pekes til blir slettet, eller at andre rader følger med i dragsuget om den slettes.

Det du meiner at når eg finner ut at raden ikkje er korrekt og skal slettes også går strømmen før den fekk begynt på slettinga vil den da ikkje slette den når databasen starter opp på nytt?

Lenke til kommentar
Det du meiner at når eg finner ut at raden ikkje er korrekt og skal slettes også går strømmen før den fekk begynt på slettinga vil den da ikkje slette den når databasen starter opp på nytt?

 

Hvofor skal du DELETE raden? Du sjekker om raden er "good to go" i en insert trigger, og da trenger du jo bare å kjøre en ROLLBACK. Og siden siden du bruker InnoDb, og denne visstnok skal være ACID compliant, så trenger du ikke å bekymre deg over slikt. Sjekk gjerne ACID på Wikipedia

Lenke til kommentar

aha, ja sjølvsagt!

Så lenge triggeren kan skrive rollback så er jo alt fint :)

 

Då blir det noko ala dette

 

Python miljø:

start transaction

insert into.....

 

MySQL miljø:

after insert trigger runs

if data inserted is invalid then rollback

else commit

 

Det burde vell gå?

Endret av siDDIs
Lenke til kommentar
Avhengig av hvordan transaction isolation er satt opp vil du kunne se raden fra Connection 1 i Connection 2, før den er committet. Hvis du da bruker en referanse fra Connection 2 til raden satt inn av Connection 1, så vil (hvis jeg husker rett) COMITT på Connection 2 kunne blokke til Connection 1 er COMMITTed.erje

 

At du kan lese dirty data ved å bruke f.eks. READ UNCOMMITTED isolasjonsnivået er greit nok, men dette begrenser seg KUN til lesing. Du kan ikke referere (foreign key constraints) til en insertet rad som ikke er committed fra en annen connection, uansett hvilket isolasjonsnivå du bruker. Den connectionen som prøver å gjøre det vil vente på å kunne sette en shared/read lock på raden satt inn av connection1 (som holder en exclusive/write lock).

 

Hvis PostgreSql lar deg gjøre dette så havner dessverre denne rett i søpla også. Men jeg tviler veldig sterkt på at det du sier er tillfelle.

Lenke til kommentar
MySQL miljø:

after insert trigger runs

if data inserted is invalid then rollback

else commit

 

Det burde vell gå?

 

Jepp. Hva som skjer i Python når MySql kjører ROLLBACK vet jeg ikke. Vil det kastes en exception?

Bare sørg for å håndtere slikt så går det nok bra.

 

Du trenger forsåvid ikke å kjøre COMMIT i triggeren. COMMIT kan du kjøre i Python hvis alt går bra. Regner med at ROLLBACK vil kaste en exception i Python. Eller?

Lenke til kommentar
At du kan lese dirty data ved å bruke f.eks. READ UNCOMMITTED isolasjonsnivået er greit nok, men dette begrenser seg KUN til lesing. Du kan ikke referere (foreign key constraints) til en insertet rad som ikke er committed fra en annen connection, uansett hvilket isolasjonsnivå du bruker. Den connectionen som prøver å gjøre det vil vente på å kunne sette en shared/read lock på raden satt inn av connection1 (som holder en exclusive/write lock).

 

Hvis PostgreSql lar deg gjøre dette så havner dessverre denne rett i søpla også. Men jeg tviler veldig sterkt på at det du sier er tillfelle.

 

Med en foreign key constraint burde både MySQL med InnoDB og PostgreSQL være helt greie.

 

Som jeg skrev i ett annet innlegg, dersom du bruker foreign key constraint vil nok PostgreSQL vente.

 

Dersom du derimot bare sjekker at raden finnes i en trigger, uten å bruke noen constraints, så havner du fort på dypt vann. ;)

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...