ugrás a tartalomhoz

MySQL táblák tervezése

i · 2014. Feb. 3. (H), 17.59
Sziasztok!

Olyan adatbázist szeretnék amiben minden regisztrált felhasználó adatainak a módosításai visszakereshetőek és a felhasználó szinte minden adata módosítható. Autodidaktaként tanulok programozni. Melyik verziót ajánlott használni ehhez? Egyéb elképzelést is szívesen fogadok.

Első verzió:
create table `users` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp
);

create table `username` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`content` text not null, -- felhasználónév
`user_id` int not null,
foreign key(`user_id`) references `users`(`id`)
);

create table `user_sex` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`content` tinyint(1) not null, -- neme: 1=férfi|2=nő
`user_id` int not null,
foreign key(`user_id`) references `users`(`id`)
);
Második verzió:
create table `users` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`username` text not null, -- regisztrációkor megadott felhasználónév
`sex` tinyint(1) not null, -- regisztrációkor megadott nem
);

create table `username` (
-- a regisztráció utáni esetleges módosítások
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`content` text not null, -- felhasználónév
`user_id` int not null,
foreign key(`user_id`) references `users`(`id`)
);

create table `user_sex` (
-- a regisztráció utáni esetleges módosítások
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`content` tinyint(1) not null, -- neme: 1=férfi|2=nő
`user_id` int not null,
foreign key(`user_id`) references `users`(`id`)
);
Harmadik verzió:
create table `users` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp
);

create table `user_data` (
`id` int not null auto_increment primary key,
`upload` timestamp default current_timestamp,
`key` text not null, -- példa: username
`value` text not null, -- példa: i
`user_id` int not null,
foreign key(`user_id`) references `users`(`id`)
);
Melyiket ajánlott használni? A felhasználói felületen a lekérdezések gyorsasága az elsődleges cél. Ha több munka van a lekérdezések megírásával vagy magával az adatbázis kialakításával az nem baj.
 
1

Hogyan?

Poetro · 2014. Feb. 3. (H), 19.27
felhasználó adatainak a módosításai visszakereshetőek és a felhasználó szinte minden adata módosítható

Melyik fenti megoldás teszi ezt lehetővé? Mert a fenti kitételeket nem látom megvalósítottnak egyikben sem. Amit én tennék, hogy lenne egy mező ami meghatározza, hogy melyik az aktuális, és minden módosítás létrehozna egy új sort a táblában, megjelölve, hogy ez az aktuális, adva hozzá egy időbélyeget, és minden korábbi sort, ami a felhasználóra vonatkozik megjelölném, hogy az nem az aktuális.
2

külön tábla

szabo.b.gabor · 2014. Feb. 4. (K), 09.43
én csinálnék egy user táblát, amiben csak a felhasználó éppen aktuális adatait tárolnám (esetleg az utolsó módosítás dátumával) és csinálnék egy külön user_history táblát, amiben mondjuk lenne egy id, egy text mezo meg egy timestamp és a text mezőben tárolnám json-nal elkódolva a változatás előtti értékeket, vagy a változtatott értékeket.

user tábla nem volna terhelve a history infókkal
adott userhez könnyen és szépen ki lehetne listázni a változásokat
16

Miért strukturálatlanul

Joó Ádám · 2014. Feb. 7. (P), 18.37
Miért strukturálatlanul tárolnád az adatokat?
17

ha változik az alap tábla

szabo.b.gabor · 2014. Feb. 8. (Szo), 11.15
ha változik az alap tábla struktúrája, akkor nem kell itt is menedzselni, ha akarom tárolhatok benne más táblák history-jét is..

nem használja úgysem join-okra stb az adatokat, unique_key-k sem mennének, meg az indexek is feleslegesek.

ha csak diff-et rak bele, az is kisebb.
3

Esetleg hasonlóan, mint ahogy

jgege · 2014. Feb. 4. (K), 10.27
Esetleg hasonlóan, mint ahogy a drupál is csinálja a tartalmak verziókezelését? (amennyiben szükséges lehet, hogy később vissza állj egy előző állapotra)

Elkészíted a user táblát, majd ennek megfelelően egy újabbat (user_history), majdnem azonos szerkezettel. A különbség annyi lenne, hogy hozzá teszel egy datetime mezőt amiben azt tárolod, hogy mikor volt módosítva (userid + ez lehetne az összetett kulcs).

Azonos táblába én azért nem tenném, mert ha a felhasználók száma megugrik és még módosítani is szeretik az adataikat akkor feleslegesen sok lesz a rekord, két tábla összekapcsolásánál ez meg abszolút fájdalmas lehet.

Ennyire - ahogy te tetted - pedig azért nem szedném szét, mert szerintem felesleges. Nagyjából azért lehet tudni, hogy a felhasználó milyen adatait akarod tárolni, nem? :)

Ha nem kifejezetten userekre vonatkozna, hanem tartalmakra is akkor az első verzió egész jó, de a drupál(7) adatbázisát ajánlom tanulmányozásra :)
4

Félelmek

i · 2014. Feb. 4. (K), 12.03
Köszönöm, hogy írtatok! Őszintén szólva én mindig attól félek, hogy valami módosításkor vagy regisztrációkor nem kerül bele az adatbázisba. Csonk lesz az információ. Tehát PHP oldalon csatlakozunk az adatbázishoz, lekezeljük a hibákat, ez eddig rendben:
<?php mysqli = new mysqli (); ?>
Aztán tegyük fel regisztrációs űrlapon megkapjuk a $_POST tömböt amit feldolgozunk.
$username = $mysqli -> real_escape_string ( $_POST [ 'username' ] );
$sex = ( int ) $_POST [ 'sex' ];
A második verziónál regisztrációkor nincsenek félelmeim:
$query = "INSERT INTO `users` ( `username`, `sex` ) VALUES ( '" . $username . "', " . $sex . " )";
Módosításkor viszont már félek, hogy nem kerül be minden a helyére mert mondjuk a felhasználónév felvitelkor még minden rendben, aztán a nemének felvitelekor valami adatbázis hiba lesz és akkor végülis csak a felhasználóneve lesz módosítva hol ott ő mindkét adatot szerette volna. Erre példa:
// Ez sikeresen lefut vagyis történik egy felhasználónév módosítás:
$query = "INSERT INTO `username` ( `content`, `user_id` ) VALUES ( '" . $username . "', " . $_SESSION [ 'user_id' ] . " )";
// Ez már valami hibát jelez így a felhasználó a nemét nem tudta módosítani:
$query = "INSERT INTO `user_sex` ( `content`, `user_id` ) VALUES ( " . $sex . ", " . $_SESSION [ 'user_id' ] . " )";
Tehát ezért félek én több táblában tárolni az adatokat mert regisztrációkor/módosításkor ha több tábla van, akkor az nem biztos, hogy mindig minden bekerül a helyére. Hogyan lehet a biztosra menni vagy fölöslegesen aggódom emiatt?

Történetesen ha mondjuk a jelszót is külön táblában tárolnám és ezzel valami gond lenne a regisztrációs űrlap kitöltése utáni felvitelkor, akkor a felhasználó be se tudna lépni mert a password táblában nem szerepelne a felhasználó azonosítójához tartozó jelszó.

Én nagyon szeretnék mindent külön táblában tárolni mint ahogy az első verzióban van, de ott ugye rengeteg táblát kell létrehozni és ha mondjuk egy felhasználó minden adatát megszeretné változtatni, akkor gyakorlatilag 10 táblába is fel kéne vinni az adatot.

Wordpress adatbázisánál már találkoztam JSON megoldással, de valahogy nem nyerte el a tetszésem pedig tudom, hogy PHP oldalon nagyon könnyű ezt az adatot PHP tömbbé alakítani.

Amit írtatok az user_history pedig azért nem tetszik mert módosításkor itt is több táblához kéne hozzá nyúlni. Egyrészt az aktuális adatok táblában kellene egy UPDATE, másrészt kellene egy INSERT a régiek közé. Gondoljunk csak bele, hogy sikeres az UPDATE, de sikertelen az INSERT, így nem tudnánk már soha többé visszakeresni adatbázisban, hogy mikor mi történt.

Valahogy megkéne oldani, hogy ne féljek a több táblák használatától. Segítsetek ebben! Kezdő vagyok és nincs gyakorlatom. Köszi előre is!
5

tranzakció

szabo.b.gabor · 2014. Feb. 4. (K), 14.33
tranzakció
6

Ha erről van szó akkor a

rrd · 2014. Feb. 4. (K), 16.35
Ha erről van szó akkor a tranzakciókezelésre keress. Máskülönben nem igazán kell aggódnod emiatt.
7

Tranzakciókezelés

i · 2014. Feb. 4. (K), 17.16
Köszönöm!

Azt hiszem ez a tranzakciókezelés a varázsszó minden eddigi kérdésemre.

Tudnátok küldeni linkeket ezzel a témával kapcsolatban ahol az alapoktól példákon át láthatom a tranzakciókezelést? Örülnék ha magyar lenne, de angol is jöhet. Egy PDF-nek örülnék a legjobban.
8

Olvasnivaló

Vilmos · 2014. Feb. 4. (K), 18.46
Tranzakció HU/EN:

http://ade.web.elte.hu/wabp/lecke5_lap1.html#hiv10
http://dev.mysql.com/doc/refman/5.0/en/commit.html

(Ez is megvolt, de...
Tulajdonképpen mi lehet a feladat és a hozzá tartozó elgondolás?)
10

Tranzakciók

i · 2014. Feb. 4. (K), 23.13
Szóval ezek a tranzakciók arra jók, hogy például addig nincs UPDATE még nem volt INSERT? Tehát az alábbi hiba nem következhet be amit írtam?

Amit írtatok az user_history pedig azért nem tetszik mert módosításkor itt is több táblához kéne hozzá nyúlni. Egyrészt az aktuális adatok táblában kellene egy UPDATE, másrészt kellene egy INSERT a régiek közé. Gondoljunk csak bele, hogy sikeres az UPDATE, de sikertelen az INSERT, így nem tudnánk már soha többé visszakeresni adatbázisban, hogy mikor mi történt.
11

Tranzakció működése

Vilmos · 2014. Feb. 5. (Sze), 09.48
1. Akkor indul amikor kiadod a START TRANSACTION-t. Direktben vagy Mysqli... függvénnyel.

2. Ezután az összes INSERT-UPDATE-DELETE végrehajtódik, de visszavonható módon. Ami történik az számodra látható, más számára nem mutatkozik meg. ( A "másik" természetesen login-t, más sql kapcsolatot jelent.) A SELECT csak neked adja vissza a módosításokat menet közben.

Van egy kivétel, az auto increment típusú mezők. Maga az INSERT visszavonható, a mező számláló viszont nem. Az lép egyet, akkor is ha megszakítod a tranzakciót.

3. Befejezni COMMIT paranccsal, vagy függvénnyel tudod az eseménysort.

4. Ha el akarsz dobni mindent, erre a ROLLBACK szolgál. Ez az alapértelmezett parancs. Kijelentkezés, program befejezés kiváltja.
12

Köszönöm!

i · 2014. Feb. 5. (Sze), 14.33
Nagyon szépen köszönöm ezt a részletes leírást! A COMMIT parancs előtt vagy után kell megnézni, hogy volt-e hiba?

1. INSERT, UPDATE, ...
2. COMMIT
3. hibakeresés
4. Ha van hiba ROLLBACK

vagy

1. INSERT, UPDATE, ...
2. hibakeresés
3. ha van hiba, akkor ROLLBACK, ha nincs, akkor COMMIT

És akkor azt jól értem, hogyha nincs COMMIT, akkor minden amit csináltunk érvénytelenné válik – kivéve ha volt auto_increment mező mert bár akkor is elvesznek a módosítások az érték attól még növekedni fog?

Ha ez eddig nekem teljesen újdonság és még sohasem találkoztam ezzel a fogalommal, hogy tranzakciókezelés, akkor kulcsszavakban minek nézhetnék még utána? Amit sohasem tudtam, hogy a MySQL függvény = MySQL trigger?

Egyébként ha létrehozok egy függvényt azt hol/hogyan tárolja adatbázisban?
13

Dokumentáció

Hidvégi Gábor · 2014. Feb. 5. (Sze), 14.52
A kérdéseidre választ kapsz a dokumentációban.
14

Ideje kipróbálni

Vilmos · 2014. Feb. 5. (Sze), 15.13
Második verzió! Vagy COMMIT vagy ROLLBACK az utolsó lépés. Ellenőrzés előtte kell hogy legyen.

Az auto increment-tel az a helyzet, hogy a számláló ugrást a következő INSERT után fogod tapasztalni. Mondjuk van 50 rekordod és az utolsó értéked 50. Felvennél egy rekordot 51.-nek, de eldobod ezt a tranzakciót. Maradt 50 rekordod. Újra próbálkozol. Lesz 51 rekordod, és az utolsónak a számlálója 52-őn fog állni.

A triggert nem tudom hol láttad.
Amennyiben az ősi mysql-t használod, vagy hasonló képességű réteget, akkor paranccsal indíthatod be a tranzakciót.

   mysql_query('START TRANSACTION');
Mysqli esetén már van külön célfüggvény a feladatra. Ez annyiban jobb mint az előző, hogy az indítás sikeréről meggyőződhetsz. Míg az előzőnél lehet tippelni. Ez igaz a tranzakció lezárására is.

   mysqli_begin_transaction();
Egyébként:
Próbálj ki valamit. Nem ér rögtön témát váltani.
15

Annyit tennék hozzá, hogy a

BlaZe · 2014. Feb. 5. (Sze), 22.14
Annyit tennék hozzá, hogy a 2. beállításfüggő, bár nem nagyon láttam még más isolation levelt gyakorlatban használva, mint a read committed.

A 4. szintén (autocommit). Mindig zárd le explicit a tranzakciót, ahogy a te logikád kívánja!
9

Naplózás

i · 2014. Feb. 4. (K), 22.56
Tulajdonképpen mi lehet a feladat és a hozzá tartozó elgondolás?


Egyszerűen csak szeretném naplózni a tevékenységeket. Szeretném tudni ki mikor változtatta meg a felhasználónevét, jelszavát, e-mail címét. Mikor mit mentett el kedvencként, mikor törölte azt, stb. Azt is szeretném tudni, hogy naplóját vagy hozzászólását ha szerkeszti, akkor miért volt szükség a módosításra, stb. Ha valaki panaszkodik valamire vagy valakire, akkor vissza tudjam keresni az aktuális állapotot amiért panaszt tett ami azóta már változhatott, stb.