מסד נתונים והקמת MySQL: טבלאות, מפתחות, Docker ו-Driver
- להסביר למה צריך Database ומה הבעיות של שמירה בקובץ JSON במערכת אמיתית
- להגדיר Table, Row, Column ו-Primary Key ולזהות אותם בדוגמה
- להכיר את טיפוסי הנתונים הבסיסיים — INT, VARCHAR, DECIMAL — ואת NOT NULL
- לתרגם מודל Python (Class או dict) לתכנון של טבלה
- להסביר מה זה שרת מסד נתונים, ולמה מריצים אותו בקונטיינר של Docker
- להריץ את MySQL עם docker run, ולהפעיל אותו מחדש עם docker start
- להתחבר למסד מ-VS Code עם התוסף Database Client ולהריץ בו SQL
- להתקין את ה-Driver, להתחבר מ-Python, ולדעת למה הסיסמה לא נכתבת בקוד
מה בשיעור
השיעור הזה בנוי משני פרקים, באותו סדר כמו במצגת:
- פרק ראשון — מהו Database: טבלה, שורה, עמודה, Primary Key וטיפוסי נתונים
- פרק שני — הקמת MySQL: Docker, Database Client ו-Driver
פרק ראשון: מהו Database — טבלה, שורה, עמודה, Primary Key וטיפוסי נתונים
מה נלמד?
- למה צריך Database (מסד נתונים).
- מה זה Relational Database (מסד נתונים רלציוני).
- Table (טבלה), Row (שורה), Column (עמודה).
- Primary Key (מפתח ראשי).
- Data Types (טיפוסי נתונים) בסיסיים.
השבוע לומדים רק את הבסיס הדרוש ל-CRUD: חיבור, טבלה אחת, ויצירה, קריאה, עדכון ומחיקה. לא נלמד JOIN, GROUP BY, HAVING, Sub-Queries, נרמול מתקדם, אינדקסים או Stored Procedures. את אלה תלמדו לעומק בהמשך המסלול.
למה צריך את זה?
בנושא הקבצים שמרנו נתונים בקובץ JSON. זה עבד לתוכנית אחת שרצה אצלנו. בשרת אמיתי, זה נשבר:
| בעיה בקובץ JSON | מה קורה |
|---|---|
| הכול או כלום בקריאה | כדי למצוא סטודנט אחד מתוך מיליון, טוענים את כל הקובץ ל-RAM. |
| הכול או כלום בכתיבה | כדי לשנות שדה אחד, כותבים את כל הקובץ מחדש. |
| שני משתמשים בבת אחת | שתי בקשות קוראות את הקובץ, כל אחת משנה משהו, וכל אחת כותבת. השינוי של הראשונה נמחק. |
| קריסה באמצע כתיבה | הקובץ נשאר חצי כתוב, ופגום. |
| אין כללים | שום דבר לא מונע שני סטודנטים עם אותו אימייל, או שדה חסר. |
| שאילתות | “כל הסטודנטים מחיפה מעל גיל 20” = לולאה בקוד שלנו, על כל הנתונים. |
Database פותר את כל אלה: קריאה וכתיבה של בדיוק מה שצריך, טיפול בהרבה משתמשים בו-זמנית, הגנה מפני קריסות, כללים שנאכפים במסד עצמו, ושפה (SQL) לשאילתות.
הסבר מהבסיס
מהו Database?
Database (מסד נתונים) = מערכת לשמירה מאורגנת של נתונים, שמאפשרת לשמור, למצוא, לעדכן ולמחוק אותם ביעילות ובאמינות. התוכנה שמנהלת אותו נקראת DBMS (Database Management System): MySQL, PostgreSQL, SQLite…
Relational Database — טבלאות
הסוג הנפוץ ביותר הוא מסד נתונים רלציוני: הנתונים מאורגנים בטבלאות, כמו גיליון Excel עם כללים נוקשים.
Table: students
┌────┬────────┬─────┬────────────────┐
│ id │ name │ age │ email │ ← columns (the structure)
├────┼────────┼─────┼────────────────┤
│ 1 │ Dana │ 24 │ dana@mail.com │ ← row = one student
│ 2 │ Avi │ 31 │ avi@mail.com │ ← row
│ 3 │ Noa │ 22 │ noa@mail.com │ ← row
└────┴────────┴─────┴────────────────┘
↑
primary key| מושג | מה זה | ב-Python (מה שכבר מכירים) |
|---|---|---|
| Table (טבלה) | אוסף של רשומות מאותו סוג | Class (התבנית) + רשימה של כל האובייקטים |
| Column (עמודה) | שדה אחד, עם שם וטיפוס קבועים | Attribute |
| Row (שורה / רשומה / Record) | פריט אחד | אובייקט אחד / dict אחד |
| Primary Key | עמודה שמזהה כל שורה באופן ייחודי | student_id |
Database = הארון. Table = מגירה אחת (“סטודנטים”). Columns = הטופס המודפס שכל תיק בנוי עליו (שם, גיל, אימייל), זהה לכל התיקים. Row = תיק אחד, של סטודנט אחד. Primary Key = המספר על גב התיק: אף פעם לא חוזר, ולפיו מוציאים תיק בלי לעבור על כולם.
Primary Key — מפתח ראשי
Primary Key = עמודה (בדרך כלל id) שערכה:
- ייחודי — אין שתי שורות עם אותו ערך.
- לא ריק — לכל שורה חייב להיות ערך.
- לא משתנה — מזהה הוא לכל חיי השורה.
למה לא להשתמש בשם? כי יש שתי “דנה”. ובאימייל? כי אנשים מחליפים אימייל. מזהה מספרי שהמסד מייצר לבד הוא הבחירה הבטוחה. (זוכרים את Shop שייצרה מזהים עם max + 1? המסד עושה את זה בשבילנו, ובצורה בטוחה יותר.)
וזה בדיוק ה-{student_id} שבנתיב של ה-API: GET /students/7 = “תביא את השורה שה-Primary Key שלה הוא 7”.
Data Types — טיפוסי נתונים בסיסיים
לכל עמודה יש טיפוס. ב-MySQL (המסד שנשתמש בו) יש הרבה טיפוסים, אבל זה מה שנצטרך:
| טיפוס SQL | מה שומרים | Python | דוגמה |
|---|---|---|---|
| INT | מספר שלם | int | id, age, quantity |
| DECIMAL(10, 2) | מספר עשרוני מדויק — 2 ספרות אחרי הנקודה | Decimal (כמו float, אבל מדויק) | price |
| VARCHAR(100) | טקסט — עד 100 תווים | str | name, email |
| (אין BOOLEAN אמיתי) | שומרים 0/1 ב-INT | bool | is_active |
| NULL | “אין ערך” | None | שדה אופציונלי ריק |
אילוצים (Constraints) בסיסיים
כללים שהמסד אוכף. גם אם יש באג בקוד, המסד יסרב:
| אילוץ | משמעות |
|---|---|
PRIMARY KEY | מזהה ייחודי של השורה. |
AUTO_INCREMENT | המסד מייצר את ה-id לבד, בסדר עולה. |
NOT NULL | חובה למלא. |
UNIQUE | אין שתי שורות עם אותו ערך (למשל אימייל). |
זה כמו ולידציה ב-__init__ (נושא OOP), רק שהמסד עצמו אוכף אותה: שכבת הגנה נוספת.
SQL — השפה
SQL (Structured Query Language, נקרא “סיקוול” או “אס-קיו-אל”) = השפה שבה מדברים עם מסד רלציוני. Query (שאילתה) = פקודה אחת ב-SQL. נכיר רק ארבע-חמש פקודות:
CREATE TABLE → create the structure (day 3)
INSERT → C - add a row (day 3)
SELECT → R - read rows (day 3)
UPDATE → U - change rows (day 4)
DELETE → D - remove rows (day 4)תחביר
תכנון טבלה (תוצר של שלב התכנון, לפני כל קוד). כך נראה תכנון של טבלת students:
Table: students
| column | type | constraints |
|--------|--------------|-----------------------------|
| id | INT | AUTO_INCREMENT PRIMARY KEY |
| name | VARCHAR(100) | NOT NULL |
| age | INT | NOT NULL |
| email | VARCHAR(100) | NOT NULL UNIQUE |וזו פקודת ה-SQL שמייצרת אותה (נכתוב ונריץ אותה בנושא מסדי נתונים ו-MySQL, כאן רק לראות לאן מתכנסים):
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INT NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);דוגמת קוד ראשונה
מ-Class של Python לתכנון טבלה. ה-Class Product מנושא OOP:
class Product:
def __init__(self, sku, name, price, stock=0):
...התרגום:
| Attribute ב-Python | עמודה | טיפוס | אילוצים | למה |
|---|---|---|---|---|
| — | id | INT | AUTO_INCREMENT PRIMARY KEY | מזהה פנימי יציב |
sku | sku | VARCHAR(20) | NOT NULL UNIQUE | ייחודי, חובה |
name | name | VARCHAR(100) | NOT NULL | חובה |
price | price | DECIMAL(10, 2) | NOT NULL | מספר עשרוני מדויק |
stock | stock | INT | NOT NULL DEFAULT 0 | מספר שלם, ברירת מחדל 0 |
פירוק הקוד שורה אחר שורה
| החלטה | נימוק |
|---|---|
הוספת id למרות שיש sku | sku הוא מזהה עסקי שעלול להשתנות (מיתוג מחדש). id הוא מזהה טכני שלא משתנה לעולם. מקובל להחזיק את שניהם. |
sku עם UNIQUE | הכלל “SKU ייחודי” נאכף במסד, גם אם קוד אחר ישכח לבדוק. |
price כ-DECIMAL(10, 2) | מחיר עם אגורות. DECIMAL שומר את המספר בדיוק — בלי בעיות העיגול של float (0.1 + 0.2). |
| מה לא נכנס לטבלה | מתודות (take, restock) הן התנהגות, וחיות בקוד. המסד שומר נתונים בלבד. |
דוגמה נוספת
מ-dicts לטבלה, וטיפוסים “מבולגנים”. נתונים שהגיעו מקובץ JSON:
students = [
{"name": "Dana", "age": 24, "email": "dana@mail.com", "phone": "050-1234567"},
{"name": "Avi", "age": "31", "email": "avi@mail.com"},
{"name": "Noa", "age": 22, "email": "dana@mail.com", "phone": None},
]שאלות תכנון:
phoneמופיע רק בחלק מהשורות. ← עמודה בליNOT NULL. כשאין ערך, נשמר NULL (Noneב-Python).ageשל אבי הוא"31"(מחרוזת). ← העמודהINT. בקוד נמירint(...)לפני השמירה (או ש-Pydantic ימיר, בנושא Students API – שרת עם מסד נתונים).- לנועה ולדנה אותו אימייל. ← עם
UNIQUEעלemail, המסד יסרב לשמור את נועה. זה בדיוק מה שאנחנו רוצים (ונטפל בשגיאה הזו בנושא מסדי נתונים ו-MySQL). - אין
id. →AUTO_INCREMENT: המסד ייתן 1, 2, 3.
| column | type | constraints |
|--------|--------------|----------------------------|
| id | INT | AUTO_INCREMENT PRIMARY KEY |
| name | VARCHAR(100) | NOT NULL |
| age | INT | NOT NULL |
| email | VARCHAR(100) | NOT NULL UNIQUE |
| phone | VARCHAR(20) | (nullable) |למה phone הוא VARCHAR ולא INT? כי 050-1234567 מכיל מקף, ומספר טלפון שמתחיל ב-0 יאבד את האפס כ-INT. כלל: “מספר” שלא עושים עליו חשבון (טלפון, מיקוד, ת"ז) ← VARCHAR.
טעות נפוצה
הטעות 1: Primary Key “טבעי” שעלול להשתנות או לחזור. שם, אימייל, מספר טלפון. ביום שדנה מחליפה אימייל, כל מי שהצביע עליה לפי אימייל “מאבד” אותה. id מספרי של המסד.
הטעות 2: לשמור רשימה בתוך עמודה אחת.
| id | name | grades |
| 1 | Dana | "90,85,70" |אי אפשר לחשב ממוצע ב-SQL, אי אפשר לחפש “כל מי שקיבל 90”, וקשה לעדכן ציון אחד. בעולם הרלציוני, ציונים הם טבלה נפרדת (grades, עם student_id). את זה תלמדו לעומק בהמשך המסלול (קשרים בין טבלאות ו-JOIN). השבוע נעבוד עם טבלה אחת ושדות פשוטים.
הטעות 3: לוותר על NOT NULL ו-UNIQUE, “כי הקוד בודק”. הקוד בודק היום. מחר מישהו יכתוב סקריפט ייבוא שעוקף את הקוד, או שיהיה באג. המסד הוא קו ההגנה האחרון.
הטעות 4: לחשוב ש-SQL “תוכנית”. SQL הוא שפה הצהרתית (Declarative): אומרים מה רוצים (“כל הסטודנטים מחיפה”), ולא איך למצוא (בלי לולאות). המסד מחליט איך לבצע ביעילות.
סיכום
- Database פותר את בעיות קובץ ה-JSON: קריאה וכתיבה ממוקדות, הרבה משתמשים בו-זמנית, עמידות לקריסות, כללים ושאילתות.
- מסד רלציוני = טבלאות. Table ≈ Class + כל האובייקטים. Column ≈ Attribute (עם טיפוס). Row ≈ אובייקט אחד.
- Primary Key = מזהה ייחודי, לא ריק ולא משתנה. בדרך כלל
id INT AUTO_INCREMENT PRIMARY KEY. - טיפוסים ב-MySQL: INT, DECIMAL, VARCHAR, ו-NULL (=
None). bool נשמר כ-0/1. טלפון ומיקוד נשמרים כ-VARCHAR. - אילוצים: NOT NULL, UNIQUE. המסד אוכף כללים גם כשהקוד טועה.
- SQL = שפה הצהרתית. השבוע: CREATE TABLE, INSERT, SELECT, UPDATE, DELETE, וזהו.
דוקומנטציה רשמית
- MySQL — Creating and Using a Database — מסד, טבלה ושורות
- MySQL — Data Types — INT, VARCHAR ועוד
- MySQL — CREATE TABLE — הגדרת עמודות ו-PRIMARY KEY
פרק שני: הקמת MySQL — Docker, Database Client ו-Driver
מה נלמד?
- מה זה שרת מסד נתונים, ולמה נעבוד עם MySQL.
- מה זה קונטיינר, ואיך מריצים את MySQL ב-Docker — בפקודה אחת.
- איך רואים את המסד מ-VS Code עם התוסף Database Client.
- מה זה Driver, ואיך Python מתחבר ל-MySQL.
- איפה שומרים את פרטי החיבור — ולמה לא בקוד.
למה צריך את זה?
לפני שכותבים INSERT אחד, צריך לענות על שאלות “צנרת”: איפה המסד רץ? איך הקוד שלנו מגיע אליו? מה פרטי החיבור? בעבודה אמיתית, הדבר הראשון שמקבלים בפרויקט חדש הוא בדיוק זה: “הנה פרטי החיבור למסד”. צריך לדעת מה לעשות איתם.
הסבר מהבסיס
מסד נתונים הוא שרת
MySQL הוא שרת מסד נתונים: תוכנה נפרדת (תהליך — Process, נושא מחשב, מערכת הפעלה ורשת!) שרצה כל הזמן ומאזינה על פורט — ב-MySQL זה פורט 3306. הקוד שלנו לא פותח קובץ — הוא מתחבר ברשת לשרת, בדיוק כמו דפדפן שמתחבר לאתר (נושא רשתות: IP + Port).
| MySQL (שרת מסד נתונים) | |
|---|---|
| איפה | תהליך נפרד שמאזין על פורט 3306 |
| איך מתחברים | ברשת: Host, Port, משתמש, סיסמה ושם המסד |
| מי מתחבר | כמה תוכנות ושרתים — בבת אחת |
| איפה זה בעולם | אתרים ומערכות בכל גודל. גם PostgreSQL ו-SQL Server עובדים כך |
למה Docker?
להתקין MySQL ישירות על המחשב זה תהליך ארוך: אשף התקנה, סיסמאות, שירות שרץ ברקע, והגדרות ששונות בין Windows ל-Mac. ומה שעובד אצל אחד — לא תמיד עובד אצל השני.
Docker (שהתקנו בשבוע הראשון) פותר את זה: הוא מריץ תוכנות מוכנות בתוך קונטיינר.
- Image — התבנית: “MySQL בגרסה 8.4, מוכן לעבודה”. מורידים אותו פעם אחת.
- Container — עותק שרץ מה-Image. מבודד משאר המחשב, עם כל מה שהתוכנה צריכה.
מכולה (Container) נראית אותו דבר בכל אונייה ובכל נמל — לא משנה מה בתוכה. כך גם קונטיינר של Docker: אותו MySQL, עם אותן הגדרות, רץ בדיוק אותו דבר אצל כל הסטודנטים, בכל מערכת הפעלה.
Database Client — המסד עם ממשק
את MySQL אפשר לראות ולתפעל בלי שורת קוד אחת, עם תוסף ל-VS Code בשם Database Client (של Weijan Chen). הוא מציג עץ של מסדים וטבלאות, פותח טבלה כמו גיליון, ומריץ SQL ומציג את התוצאה כטבלה. נשתמש בו כל השבוע כדי לראות מה הקוד שלנו עשה במסד.
Driver — המתורגמן
הקוד שלנו כתוב ב-Python. MySQL מדבר ב"פרוטוקול" משלו (נושא רשתות: פרוטוקול = כללי תקשורת). צריך מתווך שמתרגם: Driver (נקרא גם Database Connector) = ספרייה שיודעת:
- להתחבר לשרת מסד מסוג מסוים.
- לשלוח אליו פקודות SQL.
- להחזיר את התוצאות כנתונים של Python (tuples, int, str).
ל-MySQL נשתמש ב-Driver הרשמי: mysql-connector-python. מתקינים אותו עם pip, ובקוד כותבים import mysql.connector.
המכשיר שלכם (קוד Python) עם תקע ישראלי, והשקע בקיר (המסד) אמריקאי. Driver = המתאם. לכל סוג שקע מתאם משלו, אבל המכשיר עצמו לא משתנה.
פרטי החיבור — ולא בקוד!
כדי להתחבר ל-MySQL צריך חמישה פרטים:
| פרט | אצלנו | מה זה |
|---|---|---|
host | localhost | איפה השרת — המחשב שלנו |
port | 3306 | הפורט של MySQL |
user | root | שם המשתמש |
password | kodkod | הסיסמה שהגדרנו בקונטיינר |
database | school | איזה מסד בתוך השרת |
בפרויקט אמיתי יש כאן סיסמה אמיתית. אם היא כתובה בקוד והקוד עלה ל-GitHub, היא דלפה (נושא Python!). הנוהג המקצועי:
- פרטי החיבור נשמרים במשתני סביבה (Environment Variables), או בקובץ
.envשנמצא ב-.gitignore. - הקוד קורא אותם:
os.environ.get("DB_PASSWORD").
תחביר
הרצת MySQL בקונטיינר — פקודה אחת, פעם אחת (ב-PowerShell; ב-Mac מחליפים את ` ב-\):
docker run --name kodkod-mysql `
-e MYSQL_ROOT_PASSWORD=kodkod `
-e MYSQL_DATABASE=school `
-p 3306:3306 -d mysql:8.4| חלק | משמעות |
|---|---|
docker run | יוצר ומפעיל קונטיינר חדש |
--name kodkod-mysql | שם לקונטיינר, כדי שנוכל לפנות אליו |
-e MYSQL_ROOT_PASSWORD=kodkod | משתנה סביבה: הסיסמה של המשתמש root |
-e MYSQL_DATABASE=school | משתנה סביבה: מסד בשם school שנוצר אוטומטית |
-p 3306:3306 | הפורט 3306 במחשב שלנו מוביל ל-MySQL שבתוך הקונטיינר |
-d | רץ ברקע (detached), וה-Terminal נשאר פנוי |
mysql:8.4 | ה-Image: MySQL בגרסה 8.4 |
פקודות שימושיות:
docker ps # which containers are running now
docker start kodkod-mysql # start it again (after a restart of the computer)
docker stop kodkod-mysql # stop it (the data is kept)חיבור מ-Python:
import mysql.connector
connection = mysql.connector.connect(
host="localhost",
port=3306,
user="root",
password="kodkod",
database="school",
)
connection.close()mysql.connector.connect(...)— פותח חיבור רשת לשרת. אם השרת לא רץ — שגיאה.port=3306הוא ברירת המחדל, ואפשר לוותר עליו.
דוגמת קוד ראשונה
הקמת מסד הנתונים של השבוע, צעד אחר צעד.
1. מריצים את MySQL (Docker Desktop צריך להיות פתוח):
docker run --name kodkod-mysql `
-e MYSQL_ROOT_PASSWORD=kodkod `
-e MYSQL_DATABASE=school `
-p 3306:3306 -d mysql:8.4
docker psבהרצה הראשונה Docker מוריד את ה-Image (כמה דקות). docker ps מראה שהקונטיינר רץ:
CONTAINER ID IMAGE STATUS PORTS NAMES
ffaa661f5047 mysql:8.4 Up 10 seconds 0.0.0.0:3306->3306/tcp kodkod-mysql2. מתחברים מ-VS Code:
- לשונית Extensions ← מחפשים Database Client (של Weijan Chen) ← Install.
- בסרגל הצד מופיע אייקון של מסד נתונים. לוחצים עליו ← + (Create Connection) ← בוחרים MySQL.
- ממלאים: Host
127.0.0.1, Port3306, Usernameroot, Passwordkodkod, Databaseschool→ Connect. - בעץ מופיע החיבור, ובתוכו המסד
school— עדיין בלי טבלאות.
3. פרויקט Python:
mkdir ~\dev\kodkod6\week-4\school-db
cd ~\dev\kodkod6\week-4\school-db
git init
python -m venv .venv
.venv\Scripts\Activate.ps1
pip install mysql-connector-python.gitignore:
__pycache__/
.venv/
.envsetup_db.py:
import os
import mysql.connector
connection = mysql.connector.connect(
host="localhost",
port=3306,
user="root",
password=os.environ.get("DB_PASSWORD", "kodkod"),
database="school",
)
print("Connected:", connection.is_connected())
print("Server version:", connection.server_info)
connection.close()
print("Connected after close:", connection.is_connected())פלט:
Connected: True
Server version: 8.4.11
Connected after close: Falseפירוק הקוד שורה אחר שורה
| קוד | הסבר |
|---|---|
import mysql.connector | ה-Driver. הותקן עם pip install mysql-connector-python. |
host="localhost", port=3306 | איפה השרת: המחשב שלנו, בפורט שפתחנו עם -p 3306:3306. |
user="root" | המשתמש הראשי של MySQL. |
os.environ.get("DB_PASSWORD", "kodkod") | הסיסמה — ממשתנה סביבה אם הוגדר, ואחרת ברירת המחדל של סביבת הלימוד. |
database="school" | המסד שנוצר עם -e MYSQL_DATABASE=school. |
connection.is_connected() | True — החיבור פתוח. |
connection.server_info | גרסת שרת ה-MySQL. אצלכם המספר עשוי להיות שונה. |
connection.close() | סוגר את החיבור (בשיעור הבא: למה זה חשוב). |
אין *.db ב-.gitignore | הנתונים יושבים בקונטיינר, לא בתיקיית הפרויקט. ל-Git נכנס רק הקוד שיוצר את המבנה. |
דוגמה נוספת
הקונטיינר אחרי הפעלה מחדש של המחשב
אחרי Restart, Docker Desktop עולה — אבל הקונטיינר לא רץ. מריצים שוב docker run? לא — השם kodkod-mysql כבר תפוס:
docker: Error response from daemon: Conflict. The container name "/kodkod-mysql" is already in use by container ...הקונטיינר קיים, רק עצור. מפעילים אותו:
docker start kodkod-mysqlכל הנתונים נשמרו — הטבלאות והשורות נשארות בקונטיינר עד שמוחקים אותו (docker rm).
כשהשרת לא רץ
אם Docker Desktop סגור או הקונטיינר עצור, החיבור מ-Python נכשל:
mysql.connector.errors.InterfaceError: 2003: Can't connect to MySQL server on 'localhost:3306' (Errno 10061: No connection could be made because the target machine actively refused it)Can't connect = אין מי שמאזין בפורט 3306. בודקים עם docker ps, ומפעילים עם docker start kodkod-mysql.
טעות נפוצה
הטעות 1: Docker Desktop לא פתוח.
failed to connect to the docker API ... The system cannot find the file specified.פקודות docker מדברות עם Docker Desktop. פותחים אותו, מחכים שיסיים לעלות, ומנסים שוב.
הטעות 2: הפורט תפוס.
Bind for 0.0.0.0:3306 failed: port is already allocatedכבר רץ משהו בפורט 3306 — בדרך כלל MySQL שהותקן בעבר ישירות על המחשב. אפשר להשתמש בפורט אחר במחשב שלנו: -p 3307:3306, ואז מתחברים עם port=3307.
הטעות 3: סיסמה של מסד בקוד שעולה ל-GitHub.
connection = mysql.connector.connect(host="prod-db.company.com", user="admin", password="MyRealPassword123")גם אם מוחקים ב-Commit הבא, הסיסמה נשארת בהיסטוריה (נושא Python!). משתני סביבה / .env ב-.gitignore. (הסיסמה kodkod שלנו היא של סביבת לימוד מקומית בלבד.)
סיכום
- MySQL = שרת מסד נתונים: תהליך שמאזין על פורט 3306, ומתחברים אליו ברשת.
- Docker מריץ את MySQL בתוך קונטיינר — בפקודה אחת, ואצל כולם אותו דבר.
docker runפעם אחת, ואחר כךdocker start kodkod-mysql. - Database Client (תוסף ל-VS Code) = ממשק למסד: עץ טבלאות, הרצת SQL ותוצאות כטבלה.
- Driver = ספרייה שמתרגמת בין Python למסד. ל-MySQL:
mysql-connector-python(import mysql.connector). - חמישה פרטי חיבור:
host,port,user,password,database. - סיסמאות לא נכתבות בקוד: משתני סביבה או
.envב-.gitignore.
דוקומנטציה רשמית
- Docker Hub — MySQL official image — docker run ומשתני הסביבה של MySQL
- Database Client for VS Code — התוסף לצפייה במסד
- Connector/Python — Installation — התקנת ה-Driver, כולל התקנה עם pip
תרגול
התרגילים מבוססים רק על מה שנלמד בשיעור הזה ובשיעורים שלפניו. נסו לבד, ורק אז פתחו את הפתרון.
תרגיל 1: טבלה, שורה, עמודה
id | name | age | email
---+------+-----+---------------
1 | Dana | 24 | dana@mail.com
2 | Avi | 31 | avi@mail.com- כמה שורות וכמה עמודות יש בטבלה?
- מה מתאר כל שורה, ומה מתארת כל עמודה?
- איזו עמודה מתאימה להיות Primary Key, ולמה לא
name?
הצג פתרון
- 2 שורות ו-4 עמודות.
- כל שורה (Row) היא סטודנט אחד — רשומה. כל עמודה (Column) היא שדה אחד, עם טיפוס קבוע, שיש לכל הסטודנטים.
id— הוא ייחודי, לא משתנה אף פעם, ונוצר אוטומטית.nameלא מתאים: יכולים להיות שני סטודנטים בשם דנה, ושם יכול להשתנות.
תרגיל 2: טיפוסים ואילוצים
כתבו את פקודת ה-SQL שיוצרת טבלת students עם:
id— מספר שלם, Primary Key, שנוצר אוטומטית;name— טקסט, חובה;age— מספר שלם, חובה;email— טקסט, חובה וייחודי.
הצג פתרון
CREATE TABLE students (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100) NOT NULL,
age INT NOT NULL,
email VARCHAR(100) NOT NULL UNIQUE
);INT/VARCHAR(100)— הטיפוס של כל עמודה: מספר שלם, וטקסט של עד 100 תווים.NOT NULL— אי אפשר להשאיר ריק.UNIQUE— אין שני סטודנטים עם אותו אימייל.AUTO_INCREMENT— המסד בוחר את ה-idלבד.
תרגיל 3: מה המסד היה תופס?
students = [
{"name": "Dana", "age": 24, "email": "d@x.com"},
{"name": "Avi", "age": 24, "email": None},
{"name": "Noa", "age": 22, "email": "d@x.com"},
]אילו מהנתונים האלה טבלת students מהתרגיל הקודם הייתה דוחה, ובגלל איזה אילוץ? ולמה ברשימה של Python אף אחד לא עצר אותם?
הצג פתרון
- Avi — אימייל
None← נדחה בגללNOT NULL. - Noa — אותו אימייל כמו דנה ← נדחה בגלל
UNIQUE. - Dana — תקינה.
ברשימה של Python אין כללים: כל ערך נכנס. במסד הנתונים הכללים מוגדרים פעם אחת, בטבלה, וחלים על כל מי שכותב אליה — מכל תוכנה.
תרגיל 4: להרים את MySQL
- מה עושה כל חלק בפקודה הבאה?
- איך בודקים שהקונטיינר רץ?
- איך מפעילים אותו שוב אחרי הפעלה מחדש של המחשב — בלי ליצור חדש?
docker run --name kodkod-mysql -e MYSQL_ROOT_PASSWORD=kodkod -e MYSQL_DATABASE=school -p 3306:3306 -d mysql:8.4הצג פתרון
| חלק | משמעות |
|---|---|
docker run | יוצר ומפעיל קונטיינר חדש |
--name kodkod-mysql | שם לקונטיינר, כדי שנוכל לפנות אליו |
-e MYSQL_ROOT_PASSWORD=kodkod | הסיסמה של המשתמש root |
-e MYSQL_DATABASE=school | מסד בשם school שנוצר אוטומטית |
-p 3306:3306 | הפורט 3306 במחשב שלנו מוביל ל-MySQL שבקונטיינר |
-d | רץ ברקע, וה-Terminal נשאר פנוי |
mysql:8.4 | ה-Image: MySQL בגרסה 8.4 |
docker ps— מציג את הקונטיינרים שרצים כרגע.docker start kodkod-mysql— מפעיל את הקונטיינר הקיים. הנתונים שלו נשמרים.docker runשוב היה נכשל, כי השם כבר תפוס.
תרגיל 5: חיבור ראשון
כתבו קוד שמתחבר למסד school שבקונטיינר, מדפיס אם החיבור פעיל, סוגר אותו, ומדפיס שוב.
פלט צפוי:
Connected: True
Connected after close: Falseהצג פתרון
import mysql.connector
connection = mysql.connector.connect(
host="localhost",
port=3306,
user="root",
password="kodkod",
database="school",
)
print("Connected:", connection.is_connected())
connection.close()
print("Connected after close:", connection.is_connected())Connected: True
Connected after close: Falsemysql.connector.connect פותח חיבור רשת לשרת ה-MySQL שבקונטיינר. אם הקונטיינר לא רץ — מקבלים שגיאה: Can't connect to MySQL server.