Ачааллж байна...
Түвшин 3-ын төгсгөлд бид нэг зүйлийг өөрийн нүдээр харсан: серверээ унтраахад бүх тэмдэглэл алга болно. Таны API мэргэжлийн бүтэцтэй, хамгаалалттай, тохируулж болдог — гэхдээ санах ой түр зуурынх.
Энэ бүлэг тэр асуудлыг шийдэх замын эхлэл юм. Гэхдээ бид шууд шийдэл рүү үсрэхгүй. Эхлээд яагаад гэдгийг ойлгоно.
Учир нь энд ойлгомжтой мэт харагддаг завсрын шийдэл байна: файлд хадгалах. Курс 2-ын Бүлэг 6-т та JSON файлд бичиж, уншиж сурсан. Тэр мэдлэгээ ашиглаад тэмдэглэлүүдээ notes.json файлд хадгалж болох юм шиг санагдана.
Тэр нь ажиллана — тодорхой хэмжээнд. Дараа нь эвдэрнэ. Энэ хичээл нь хаана, яагаад эвдэрдгийг тайлбарлана. Код бичихгүй; зөвхөн ойлгоно. Дараагийн хичээлүүдэд бид зөв шийдэл рүү орно.
Файлаар хадгалахыг шууд буруутгаж эхлэх нь шударга биш. Тодорхой нөхцөлд файл бол зөв сонголт юм.
Хэрэв танд:
цөөн өгөгдөл байгаа (хэдэн зуун мөр),
нэг л программ түүнд ханддаг,
нэг л хүн ашигладаг,
нарийн хайлт хэрэггүй бол —
файл бол хамгийн энгийн, хамгийн ойлгомжтой шийдэл. Тохиргооны файл, жижиг жагсаалт, түр зуурын тэмдэглэл — бүгд файлд байж болно.
Курс 2-ын Бүлэг 6-ын "Зарлагын бүртгэл" бүтээн байгуулалт нь JSON файлд хадгалдаг байсан бөгөөд тэр нь бүрэн зөв байсан. Тэр программ нэг хүний компьютер дээр, нэг удаад нэг л ажилладаг байсан.
Гэхдээ API бол өөр. API нь олон хэрэглэгчид зэрэг үйлчилдэг, өсдөг, хайлт хийдэг. Тэр гурван шинж чанар нь файлыг эвдэдэг. Тус бүрийг харъя.
Барааны агуулах төсөөлье. Бараа орж, гарч байдаг. Бүртгэл хөтлөх ёстой.
Эхний арга: нэг том дэвтэр. Нярав ширээн дээрээ дэвтэр тавьж, бараа орох бүрд нэг мөр бичдэг, гарах бүрд нэг мөр бичдэг.
Жижиг агуулахад энэ нь төгс ажиллана. Нярав дэвтрээ мэднэ, юу хаана байгааг санана, өдөрт хэдэн бичлэг хийнэ.
Одоо агуулах өсье.
Хоёр нярав ажиллаж эхлэв. Хоёулаа нэг дэвтэрт бичих ёстой. Гэхдээ дэвтэр нэг л ширээн дээр байна. Нэг нь бичиж байхад нөгөө нь хүлээх ёстой. Хоёулаа зэрэг бичих гэвэл — мөр давхардаж, хуудас урагдаж, бичлэг алдагдана.
Дэвтэр зузаарлаа. Тавин мянган мөр болов. Одоо "энэ бараа хаана байна?" гэсэн асуултад хариулахын тулд нярав дэвтрийн эхнээс дуустал унших ёстой. Нэг асуултад хэдэн цаг.
Дэвтэр гар дээр багтахаа болив. Тавин мянган мөртэй дэвтрийг ширээн дээр бүхэлд нь дэлгэж чадахгүй. Гэтэл ганц мөр өөрчлөхийн тулд бүхэлд нь нээх ёстой.
Нэг өдөр гал гарлаа. Нярав дэвтэрт бичиж байх зуур цахилгаан тасарлаа. Хагас бичсэн мөр үлдэв. Тэр мөр одоо утгагүй — бүтэн ч биш, хоосон ч биш.
Эдгээр нь зүйрлэл биш. Эдгээр нь яг тэр асуудлууд, зөвхөн цаасан дээр биш, файл дээр тохиолддог.
Энэ бол хамгийн ноцтой асуудал бөгөөд эхлээд ойлгоход хамгийн хэцүү нь.
Таны API нэг л хүнд үйлчилдэггүй. Хоёр хүн яг нэг мөчид тэмдэглэл нэмэхийг оролдож болно. Хэрэв таны программ файлд хадгалдаг бол юу болох вэ?
Файлд бичих үйлдэл нь ойролцоогоор ийм алхмуудаас бүрддэг:
Файлыг нээж, бүх өгөгдлийг уншина.
Шинэ тэмдэглэлийг жагсаалтад нэмнэ.
Бүх жагсаалтыг файлд буцаан бичнэ.
Одоо хоёр хүсэлт зэрэг ирлээ гэж бодъё. Дараалал ийм болж болно:
Хүсэлт А файлыг уншив. Дотор нь 5 тэмдэглэл байна.
Хүсэлт Б файлыг уншив. Дотор нь мөн 5 тэмдэглэл байна (А хараахан бичээгүй).
Хүсэлт А 6 дахь тэмдэглэлээ нэмж, 6 мөртэй файл бичив.
Хүсэлт Б өөрийн 6 дахь тэмдэглэлээ нэмж, 6 мөртэй файл бичив.
Үр дүн: 6 тэмдэглэл, гэтэл 7 байх ёстой байсан. А-гийн тэмдэглэл алга болсон — Б түүнийг дарж бичсэн.
Хамгийн аймшигтай нь: ямар ч алдаа гараагүй. Программ унаагүй, log-д юу ч бичигдээгүй, хэрэглэгч хоёулаа "амжилттай" гэсэн хариу авсан. Гэтэл нэг тэмдэглэл байхгүй болсон.
Ийм алдааг чимээгүй өгөгдөл алдагдал гэж нэрлэдэг бөгөөд энэ нь программ хангамжийн хамгийн аюултай төрлийн алдаа юм. Учир нь та мэдэхгүй. Хэрэглэгч хэдэн долоо хоногийн дараа "би тэмдэглэл бичсэн шүү дээ, хаачив?" гэж гомдоллоно, та шалтгааныг олохгүй.
Файлын систем энэ асуудлыг шийддэггүй. Түүнийг гараар шийдэх боломжтой (түгжээ ашиглах), гэхдээ тэр нь хэцүү, алдаатай, удаан.
Өгөгдлийн сан энэ асуудлыг үндсэн чадвар болгон шийддэг. Тэр нь зэрэг бичих үйлдлийг зохицуулах зориулалттай бүтээгдсэн.
Таны API-д мянган тэмдэглэл байна гэж бодъё. Хэрэглэгч ?search=тайлан гэж хайв.
Файлаар бол таны код ийм зүйл хийнэ:
Файлыг бүхэлд нь уншина (мянган тэмдэглэл)
Тэдгээрийг Python объект болгож хувиргана
Мянган тэмдэглэлийг нэг нэгээр нь шалгана
Тохирохыг нь буцаанаМянган мөрд энэ нь хурдан. Сая мөрд энэ нь удаан. Арван сая мөрд энэ нь боломжгүй.
Асуудлын мөн чанар: та хэрэгтэй мөрөө олохын тулд бүх мөрийг унших ёстой. Хэрэв та "id 500-тай тэмдэглэлийг өгөөч" гэж асуувал ч гэсэн бүх файлыг унших ёстой — учир нь тэр мөр хаана байгааг мэдэхгүй.
Агуулахын зүйрлэлээр: барааг олохын тулд дэвтрийг эхнээс нь уншиж байна.
Өгөгдлийн сан үүнийг index ашиглан шийддэг. Index бол номын арын хэлхээ шиг зүйл: "тайлан" гэсэн үг ямар мөрүүдэд байгааг урьдчилан бүртгэсэн жагсаалт. Хайхад бүх номыг уншихгүй — хэлхээнээс хараад шууд зөв хуудас руу очно.
Сая мөртэй хүснэгтээс index-тэй хайлт нь секундын мянганы нэгээр хариу өгдөг. Index-гүй бол хэдэн секунд. Ялгаа нь мянга дахин.
Файлын нэг үндсэн хязгаарлалт: бүхэлд нь эсвэл юу ч биш.
Нэг тэмдэглэлийн текстийг өөрчлөхийн тулд:
Бүх файлыг уншина.
Санах ойд өөрчилнө.
Бүх файлыг буцаан бичнэ.
Сая тэмдэглэлтэй файлд нэг үг өөрчлөхийн тулд сая мөр уншиж, сая мөр бичих ёстой. Утгагүй.
Түүнчлэн: сая тэмдэглэл нь санах ойд багтах ёстой. Хэрэв файл нь таны серверийн RAM-аас том бол — уншиж ч чадахгүй.
Өгөгдлийн сан хэсэгчлэн ажилладаг. "500 дугаартай мөрийн текстийг өөрчил" гэж хэлэхэд зөвхөн тэр мөрд хүрдэг. Бусад сая мөр хөдлөхгүй. Санах ойд бүхэлд нь ачаалах шаардлагагүй.
Файлд бичих явцад цахилгаан тасарвал, эсвэл программ унавал юу болох вэ?
Хагас бичигдсэн файл үлдэнэ. JSON файлын хувьд энэ нь бүр ноцтой: JSON бол бүтэцтэй формат бөгөөд хагас бичигдсэн JSON нь уншигдахгүй. Дараагийн удаа программ асахад:
json.decoder.JSONDecodeError: Expecting ',' delimiterБүх өгөгдөл алдагдана — зөвхөн сүүлийн бичлэг биш, файл бүхэлдээ уншигдахгүй болно.
Өгөгдлийн сан үүнийг transaction гэсэн ойлголтоор шийддэг. Transaction бол "бүгд болно, эсвэл юу ч болохгүй" гэсэн баталгаа юм. Хэрэв дунд нь тасалдвал өгөгдлийн сан өөрөө өмнөх бүрэн байдалдаа буцдаг. Хагас төлөв гэж байдаггүй.
Энэ бол банкны системд яагаад өгөгдлийн сан ашигладгийн шалтгаан: мөнгө нэг данснаас хасагдаж, нөгөөд нэмэгдэх ёстой. Дунд нь тасалдвал мөнгө алга болох ёсгүй.
Энэ асуудал нь бага мэдэгддэг ч бодит төсөлд хамгийн их тохиолддог нь юм.
Тэмдэглэл бүр хэрэглэгчид харьяалагддаг гэж бодъё. Файлаар бол:
notes.json:
json
[{"id": 1, "text": "Сүү авах", "user_id": 3}]users.json:
json
[{"id": 3, "name": "Дулгуун"}]Одоо "тэмдэглэл бүрийг эзэмшигчийнх нь нэртэй хамт үзүүлэх" гэсэн асуулт гарлаа. Кодоор:
notes.json-ыг унших
users.json-ыг унших
Тэмдэглэл бүрд тохирох хэрэглэгчийг хайх
Хоёрыг нийлүүлэхХоёр файл, гар аргын нийлүүлэлт. Мянган тэмдэглэл, мянган хэрэглэгчтэй бол энэ нь удаан.
Түүнчлэн: хэрэглэгч 3-ыг устгавал яах вэ? Түүний тэмдэглэлүүд одоо байхгүй хүн рүү заана. Программ тэдгээрийг харуулах гэж оролдоод унана. Энэ асуудлыг орphaned data (өнчин өгөгдөл) гэж нэрлэдэг.
Өгөгдлийн сан холбоог үндсэн чадвар болгон дэмждэг. "Хэрэглэгчийг устгавал түүний тэмдэглэлийг ч устга" эсвэл "тэмдэглэлтэй хэрэглэгчийг устгаж болохгүй" гэсэн дүрэм тогтоож болно. Мөн хоёр хүснэгтийг нэг асуултаар нийлүүлж (join) чадна.
Энэ курсын capstone-д (Номын сангийн API) яг ийм холбоо гарч ирнэ: ном, гишүүн, зээл.
Асуудал | Файл | Өгөгдлийн сан |
|---|---|---|
Зэрэг бичих | Өгөгдөл алдагдана | Зохицуулагдана |
Хайлт | Бүгдийг унших | Index ашиглана |
Нэг мөр өөрчлөх | Бүхэлд нь дахин бичих | Зөвхөн тэр мөр |
Тасалдал | Файл эвдэрнэ | Transaction сэргээнэ |
Холбоо | Гараар нийлүүлэх | Join, дүрэм |
Хэмжээ | RAM-д багтах ёстой | Диск дээр, хязгааргүй |
Одоо тодорхойлолт өгье.
Өгөгдлийн сан (database) бол өгөгдлийг зохион байгуулж, хадгалж, хайж, өөрчлөхөд зориулагдсан тусгай программ юм.
Гол үгс нь "тусгай программ". Өгөгдлийн сан бол файлын өөр нэр биш — тэр нь ажиллаж байдаг систем. Түүнд асуулт илгээж, хариу авдаг.
Өгөгдлийн сан нь өгөгдлөө эцсийн дүндээ диск дээр файлд хадгалдаг. Гэхдээ тэр файлыг та шууд уншдаггүй. Оронд нь өгөгдлийн санд "надад ийм өгөгдөл хэрэгтэй" гэж хэлдэг, тэр өөрөө хамгийн үр дүнтэй аргаар олж өгдөг.
Ялгаа нь энэ: файл бол хадгалах газар; өгөгдлийн сан бол хадгалах газар дээр ажилладаг ухаалаг систем.
Өгөгдлийн сангийн үндсэн ойлголтууд гурав байна. Тэдгээрийг одоо танилцуулъя, учир нь бид тэднийг байнга ашиглана.
Хүснэгт (table) — нэг төрлийн зүйлийн цуглуулга. Тэмдэглэлийн хүснэгт, хэрэглэгчийн хүснэгт, номын хүснэгт.
Мөр (row) — нэг тодорхой зүйл. Нэг тэмдэглэл, нэг хэрэглэгч, нэг ном.
Багана (column) — зүйл бүрийн нэг шинж. Тэмдэглэлийн текст, priority, төлөв.
Excel-тэй ажиллаж байсан бол энэ бүтэц танил байх ёстой. Хүснэгт бол хуудас, мөр бол эгнээ, багана бол багана.
Жишээ нь тэмдэглэлийн хүснэгт ойролцоогоор ийм харагдана:
id | text | priority | done
---|-------------------|-----------|------
1 | Сүү авах | чухал | false
2 | Номоо буцаах | энгийн | true
3 | Тайлан бичих | яаралтай | falseГурван мөр, дөрвөн багана.
Курс 2-оос танил бүтэцтэй харьцуулъя: хүснэгт нь dictionary-үүдийн жагсаалт шиг. Мөр бүр нь dictionary, багана нь түлхүүр. Таны notes: list[dict] жагсаалт яг ийм хэлбэртэй байсан:
python
notes = [
{"id": 1, "text": "Сүү авах", "priority": "чухал", "done": False},
{"id": 2, "text": "Номоо буцаах", "priority": "энгийн", "done": True},
]Энэ нь санамсаргүй биш. Та аль хэдийн хүснэгтийн хэлбэрээр бодож ирсэн; зөвхөн одоо тэр хэлбэр нь санах ойд биш, өгөгдлийн санд амьдрах болно.
Гэхдээ нэг чухал ялгаа бий. Python жагсаалтад та юу ч хийж болно:
python
notes = [
{"id": 1, "text": "Сүү авах"},
{"id": 2, "title": "Өөр түлхүүр!", "extra": [1, 2, 3]},
]Хоёр dictionary огт өөр бүтэцтэй. Python юу ч хэлэхгүй.
Өгөгдлийн сангийн хүснэгт ийм байж чадахгүй. Хүснэгт үүсгэхдээ та түүний schema-г зарладаг: ямар багана байх, багана бүр ямар төрөлтэй байх. Дараа нь бүх мөр тэр бүтцийг дагах ёстой.
Хүснэгт: notes
id — бүхэл тоо
text — текст
priority — текст
done — үнэн/худалХэрэв та done баганад текст хийхийг оролдвол өгөгдлийн сан татгалзана.
Танил санагдаж байна уу? Энэ бол яг Pydantic model-ын хийдэг зүйл. Талбарын нэр, төрөл зарлаж, буруу өгөгдлийг татгалзах.
Тэр төстэй байдал нь санамсаргүй биш. Бүлэг 11-т бид SQLModel сурах бөгөөд тэр нь яг энэ хоёрыг нэгтгэдэг: нэг class бичээд, тэр нь Pydantic model ч мөн, өгөгдлийн сангийн хүснэгт ч мөн болдог. Type hint дахин ажиллана — гурав дахь удаагаа.
Сүүлийн ойлголт. Өгөгдлийн сангууд хоёр том гэр бүлд хуваагддаг бөгөөд нэрийг нь мэдэж байх нь зүйтэй.
SQL (харилцан хамааралтай) өгөгдлийн сан. Хүснэгт, мөр, багана. Хатуу schema. Хүснэгт хоорондын холбоо. SQL гэсэн хэлээр асуулт тавьдаг. Жишээ: SQLite, PostgreSQL, MySQL.
NoSQL өгөгдлийн сан. Хүснэгтгүй, илүү уян хатан бүтэц (ихэвчлэн JSON шиг). Schema заавал биш. Жишээ: MongoDB, Redis.
Аль нь дээр вэ? Тухайн ажлаас шалтгаална — энэ бол шударга хариу. Хоёулаа өргөн ашиглагддаг.
Гэхдээ энэ сургалтад бид SQL сонгоно, гурван шалтгаанаар. Нэгд, SQL нь илүү түгээмэл — ажлын байранд тааралдах магадлал өндөр. Хоёрт, хатуу schema нь суралцахад илүү тодорхой. Гуравт, FastAPI-ийн ертөнцөд SQL хэрэгслүүд (SQLModel) маш сайн хөгжсөн.
Тодруулбал бид SQLite ашиглана. Дараагийн хичээл бүхэлдээ түүнд зориулагдана.
Шударга дүгнэлт хийе. Дээрх бүх асуудлыг уншаад "тэгвэл үргэлж өгөгдлийн сан хэрэгтэй юм байна" гэж бодох нь буруу.
Өгөгдлийн сан нь нэмэлт төвөг авчирдаг: суулгах, тохируулах, шинэ ойлголт сурах, нэмэлт код бичих. Жижиг зүйлд энэ нь илүүц.
Файл хангалттай:
Тохиргооны утга (.env — та үүнийг Бүлэг 9-т хийсэн).
Нэг удаагийн скрипт.
Зөвхөн уншдаг тогтмол өгөгдөл.
Log файл.
Ганц хэрэглэгчийн дотоод хэрэгсэл.
Өгөгдлийн сан хэрэгтэй:
Олон хэрэглэгч зэрэг ханддаг (бүх вэб API).
Өгөгдөл өсдөг.
Хайлт, шүүлт хийдэг.
Өгөгдөл хоорондоо холбоотой.
Өгөгдөл алдагдвал ноцтой.
Таны Тэмдэглэлийн API нь эхний жагсаалтын бүх шинжтэй. Тиймээс өгөгдлийн сан руу шилжих нь зөв.
Файл тодорхой нөхцөлд зөв сонголт — цөөн өгөгдөл, нэг хэрэглэгч, нарийн хайлтгүй.
API нь өөр: олон хэрэглэгч, өсөлт, хайлт — гурвуулаа файлыг эвдэнэ.
Зэрэг бичих — хамгийн ноцтой: өгөгдөл чимээгүй алдагдана, ямар ч алдаа гарахгүй.
Хайлт — файлаас олохын тулд бүгдийг унших ёстой; өгөгдлийн сан index ашиглана.
Нэг мөр өөрчлөхөд файлыг бүхэлд нь дахин бичдэг; өгөгдлийн сан зөвхөн тэр мөрд хүрнэ.
Тасалдал файлыг эвдэж, бүх өгөгдлийг алдагдуулна; өгөгдлийн санд transaction сэргээнэ.
Холбоо — файлаар гараар нийлүүлдэг; өгөгдлийн санд join болон дүрэм байдаг.
Өгөгдлийн сан = хадгалах газар дээр ажилладаг ухаалаг систем, зүгээр нэг файл биш.
Бүтэц: хүснэгт (нэг төрлийн зүйл), мөр (нэг зүйл), багана (нэг шинж) — dictionary-үүдийн жагсаалттай төстэй.
Schema нь баганын нэр, төрлийг тогтооно — Pydantic model-тэй яг ижил санаа.
Хоёр гэр бүл: SQL (хүснэгттэй, хатуу schema) ба NoSQL (уян хатан). Бид SQL, тодруулбал SQLite ашиглана.
Одоо та яагаад гэдгийг ойлголоо. Дараагийн хичээлд бид юуг гэдгийг үзнэ: SQLite гэж юу болох, яагаад тэр нь суралцахад болон жижиг бодит программд төгс тохирдог, .db файл гэж юу болохыг ойлгоно. Тэнд бид эхний удаа өгөгдлийн сантай гар дээрээ танилцах бөгөөд түүний хамгийн гайхалтай онцлогийг харна: тэр нь суулгах шаардлагагүй, аль хэдийн таны Python дотор байгаа.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.