1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

Help! MySQL

Discussion in 'Ajutor: Software și sisteme de operare' started by Marius '95, Feb 4, 2014.

  1. Marius '95

    Marius '95 Membru Senior

    Am senzatia ca acea corupere a survenit din cauza unui bug in program: s-a facut un alter table pe 3 tabele, fara tranzactie (care, btw, nu stiu daca e posibila cu un alter table), si care nu s-a executat decat pe doua tabele. Cred ca nici mama arhitecturilor nu ar fi detectat problema asta.
     
  2. miahi

    miahi Wizzard

    În myisam nu există tranzacții. Iar dacă ar exista tranzactii, by default orce DDL face commit la orice tranzacție aveai în curs (chiar dacă nu vrei :biggrin:), adică nu poți avea mai multe DDL-uri înlănțuite într-o tranzacție normală* (dacă sunt alter-uri separate).

    Problema ta e că faci DDL-uri în program și nemonitorizate/netestate. Așa ceva faci în program dacă ai integrată o sculă de db refactoring capabilă (gen liquibase - că tot ziceai de mama arhitecturilor, în java e absolut banal de integrat liquibase, ia juma' de oră cu teste cu tot și pe urmă ai siguranța că ai sincronizare între versiunea de aplicație și structura DB). Altfel apar probleme ca mai sus.

    * în db-uri avansate există posibilități de rulat cu "versiuni" diferite de DB în paralel, cu structuri kindof diferite, cât faci o migrare live de la o versiune la alta; cu costuri de performanță, complexitate a codului și costuri pur și simplu (la oracle opțiunea era vreo $20k/CPU parcă, la pachet cu alte chestii dar oricum), dar se poate.
     
  3. AdrianB1

    AdrianB1 Membru Senior

    Si cica eu eram ala rau :tongue:
     
  4. puterfixer

    puterfixer Administrator

    Staiașea... Deci în mod normal, structura bazei de date e construită pre-deployment, iar programul doar o folosește pentru a insera/modifica date din ea. Vrei să zici că programul tău face modificări structurale ale bazei de date ca activitate curentă?!
     
  5. Marius '95

    Marius '95 Membru Senior

    Nu chiar ca activitate curenta, doar cand se modifica lista de analize disponibile. In speta, s-a cerut modificarea codului unei analize. =>crash intre doua alter table. Datele pre-crash au disparut. De fapt, cred ca rezultatele sunt inca acolo, doar ca intr-o coloana-fantoma care nu mai e citita. Ce vrei, eram prea "green" pe vremea aia (2003-2004).
     
  6. Marius '95

    Marius '95 Membru Senior

    S-a rezolvat.

    Alta:
    Daca folosesc prepared statement, mai am nevoie sa folosesc mysql_escape_string sau echivalent? Cand ar fi bine sa folosesc htmlspecialchars? Inainte de stocare in baza de date sau inainte de afisare?
     
  7. AdrianB1

    AdrianB1 Membru Senior

    Daca folosesti PDO prepared statements nu mai e nevoie de alte manevre, oricum functia aia e scoasa la pensie de mult timp (php 4.x, in 7 nici nu mai exista si versiunea curenta/stabila e 7.1.8).
    htmlspecialchars se foloseste pentru afisare, baza de date e imuna la taguri html.
     
  8. Marius '95

    Marius '95 Membru Senior

    Sa presupunem urmatoarea situatie:
    Utilizatorul #1 deschide un rezultat la analize "A" si il modifica.
    Utilizatorul #2 deschide acelasi rezultat "A" si face si el modificari.
    Utilizatorul #1 salveaza.
    Utilizatorul #2 salveaza.
    Cum ar fi mai bine sa gestionez situatia?

    Varianta 1:
    Cel care salveaza ultimul suprascrie rezultatul. Asta e varianta curenta si o vreau modificata.

    Varianta 2:
    Rezultatul are timestamp. Cand user#2 salveaza, programul observa ca timestamp-ul de cand a deschis el rezultatul s-a modificat intre timp => eroare si nu salveaza. Asta e varianta folosita la Synevo, doar ca functioneaza per buletin, nu per rezultat individual. Enervant.

    Varianta 3:
    La fiecare salvare, se introduc rezultatele modificate pe un rand nou cu timestamp: A ramane pe loc, user #1 salveaza A1, user #2 salveaza A2. La validare apar toate: A, A1, A2, si se poate valida oricare din ele.

    As folosi varianta 3. Alte variante mai sunt?
     
  9. AdrianB1

    AdrianB1 Membru Senior

    Ca varianta mai exista si notiunea de "deschis pentru scriere", primul utilizator deschide pentru scriere si marcheaza asta, al doilea poate deschide doar read-only pana cand primul inchide sau pana cand al doilea foloseste butonul "nuclear override" daca vrei sa aibe o asemenea optiune, caz in care aplici 2 sau 3 dupa cum doresti.
     
  10. miahi

    miahi Wizzard

    Ceea ce descrii tu în 1 și 2 se numește locking optimist, în diferite forme de implementare.

    Varianta 2 e cea uzuală în ORM-uri (cu câmp de versiune sau pur și simplu verificat toate câmpurile/cele modificate când se face update). Poți folosi varianta 3 dacă ai nevoie, dar trebuie ca utilizatorii să știe bine ce fac (sau să-i forțezi să valideze una din ele până la urmă).

    Uită-te și la același lucru la nivel de bază de date (select for update), pentru că poți avea aceeași problemă de concurență la versiunea 2 dacă nu faci lock și salvarea U1 și U2 se face în același timp (tu citești "versiunea" 1 în ambele sesiuni, după care ambele încearcă să facă update la versiunea 2 - folosești locking pe rândul din DB când citești o valoare, să fii sigur că nu o mai modifică nimeni până nu o faci tu).

    Mai există locking pesimist, ce zice Adi, unde zici de la început "pe asta lucrez eu și nu se atinge nimeni", pe tot parcursul modificării (de când ai intrat în modificare rezultat, e al lui până salvează sau iese). În aplicații web asta presupune tratarea multor probleme (ex: cineva face lock și închide browser-ul, când deschide iar trebuie să poată face override sau să aibă în continuare lock-ul, sau pui sesiune cu expirare rapidă și pierderea lock-ului la expirare... astea trebuie tratate).
     
    Last edited: Aug 14, 2017 at 6:38 PM
    puterfixer likes this.
  11. Marius '95

    Marius '95 Membru Senior

    Din motive de HTTP, varianta asta ar da numai batai de cap. Daca user#1 deschide pentru scriere si apoi inchide browserul, buletinul ramane blocat. Nici cu timeout nu e bine, pentru ca mie, spre exemplu, mi se intampla foarte des sa fiu intrerupt in timp ce bag rezultate si sa lipsesc 30-180 minute, apoi sa continui de unde am ramas.

    N-am inteles prea bine ce ai vrut sa zici... Un singur rezultat poate fi validat din fiecare analiza. Exista si altceva la care trebuie sa mai fiu atent?
    Asta cu locking pesimist mi se pare foarte foarte complicat de implementat. Si dupa ce ca e complicat, va fi si foarte greu de explicat utilizatorilor.

    Deci inclin spre varianta 3. N-o sa folosesc versiune, ci timestamp. Din ce vad, in Firebird timestamp-ul are miimi de secunda, deci sansele sa se nimereasca doua INSERT-uri simultane sunt nule.
     
  12. miahi

    miahi Wizzard

    În varianta 3 cineva va trebui să aleagă din cele N versiuni ale aceluiași rezultat varianta corectă (pentru că dacă vrei doar să folosești ultima versiune întotdeauna, ar fi echivalentă cu varianta 1). Iar pentru versionări vezi secvențe (îți dau numere diferite și crescătoare no matter what); asta pentru că șansele ca timestamp-ul să fie în aceeași miime de secundă nu-s nule, doar foarte mici (și depind de implementare, poate că e cu 3 zecimale dar are sampling mai rar, se poate). În stilul ăsta de "șanse nule" introduci bug-uri care te mușcă de fund peste 5 ani, cum a fost ăla cu alter table.
     
    puterfixer likes this.
  13. AdrianB1

    AdrianB1 Membru Senior

    E una si aceeasi varianta si e folosita si de altii mai destepti ca mine, de ex. Microsoft in SharePoint. Daca ai utilizatori concurenti care lucreaza pe aceeasi inregistrare si esti optimist poti sa o dai in gard foarte usor.
     
  14. Marius '95

    Marius '95 Membru Senior

    Am index unic pe (cod proba, cod analiza, timestamp creat, timestamp modificat). In cel mai pesimist caz, ar da o eroare. Suficient?
     
  15. AdrianB1

    AdrianB1 Membru Senior

    Si nu scrie, pentru ca un index de genul asta nu va permite scrierea.
     
  16. puterfixer

    puterfixer Administrator

    Ideea din spatele programării *bune* este să 1) *previi* prin design *orice* eroare posibil identificată din faza de design/implementare, și 2) eviți crash-ul aplicației sau pierderile de date prin tratarea elegantă a erorilor.

    Ce faci tu acum este:
    - să permiți existența unui caz care va produce o eroare
    - să reduci acea situație la "ar da o eroare", fără probabil să implementezi în soft o rutină care face try și, în caz de eroare la bd, are o cale de error recovery elegantă (nu afișarea unui mesaj cu care userul se șterge la fund, ci efectuarea unor pași suplimentari care să producă rezultatul dorit fără eroare și fără pierderea datelor)
    - să crezi că abordarea ta e perfect coerentă.

    Și mai e ceva care mi-a atras atenția - lași sesiunea deschisă timp de 30-120 minute și vrei să continui fără ca aplicația să dea eroare... Asta e o situație foarte dubioasă, fiindcă sesiunile pe server expiră după un timp, altfel se umple de sesiuni și crapă. Și e treaba ta să gestionezi sesiunile: le salvezi și le redeschizi în funcție de cookie, faci keep-alive prin AJAX ca să nu expire cât timp browserul încă e conectat, etc. Altfel, o aplicație web nu "ține în memorie" datele nedefinit, ca o aplicație standalone, să continui după 3 zile exact de unde ai lăsat-o, fără să faci un efort în acest sens.
     
  17. AdrianB1

    AdrianB1 Membru Senior

    E adecvat un termen numit "mariusisme"? Nefiind substantiv propriu nu necesita capitalizare.
     
    Thor, Styr and ipman like this.