ЛЕКЦ 08: МЭДЭЭЛЛИЙН САНГИЙН ДИЗАЙН (Database Design & SQL)
Хичээлийн зорилго: Мэдээллийн сангийн суурь ойлголт, харилцааны мэдээллийн сан (RDBMS), хүснэгтийн дизайн, нормалчлал, SQL хэл, индекс, гүйлгээ (transaction), JPA/Hibernate-ийн суурь мэдлэгийг Java жишээнүүдтэйгээр эзэмшүүлэх.
Хамрах хүрээ: Мэдээллийн сангийн төрлүүд, ER диаграм, хүснэгтийн бүтэц, Primary Key, Foreign Key, нормалчлал (1NF-3NF), SQL (DDL, DML, DQL), JOIN, индекс, гүйлгээ (ACID), JPA Entity Mapping, харилцааны төрлүүд, N+1 асуудал, NoSQL ойлголт.
ХЭСЭГ 1: ОНОЛЫН СУУРЬ (Theory & Foundations)
1.1 Мэдээллийн сан гэж юу вэ?
Мэдээллийн сан (Database) — Зохион байгуулагдсан, хадгалагдсан, удирдагддаг өгөгдлийн цуглуулга. Програмын өгөгдлийг бүтэцтэй хэлбэрээр хадгалж, хайлт, шинэчлэлт, устгалт хийх боломжийг олгоно.
💡 Зүйрлэл: Номын сан шиг — номууд (өгөгдөл) ангилагдаж, тавиур дээр (хүснэгт) байрлаж, каталог (индекс)-аар хурдан олддог.
DBMS (Database Management System) — Мэдээллийн сангийн удирдлагын систем. Өгөгдөл хадгалах, хайх, өөрчлөх, аюулгүй байдлыг хангах програм хангамж.
| # | DBMS | Төрөл | Тайлбар |
|---|---|---|---|
| 1 | PostgreSQL | RDBMS | Нээлттэй эх, дэвшилтэт, enterprise-д тохиромжтой |
| 2 | MySQL | RDBMS | Түгээмэл, вэб хөгжүүлэлтэд |
| 3 | Oracle | RDBMS | Томоохон байгууллагын стандарт |
| 4 | SQL Server | RDBMS | Microsoft-ийн RDBMS |
| 5 | H2 | RDBMS | In-memory, Java хөгжүүлэлт/тестэд |
| 6 | MongoDB | NoSQL (Document) | JSON-д суурилсан |
| 7 | Redis | NoSQL (Key-Value) | Кэш, session хадгалалт |
| 8 | Cassandra | NoSQL (Wide Column) | Олон тооны бичлэг, өндөр хүрэлцээ |
1.2 Харилцааны мэдээллийн сан (RDBMS)
RDBMS (Relational Database Management System) — Өгөгдлийг хүснэгт (table) хэлбэрээр хадгалж, хүснэгтүүд хоорондоо харилцаа (relationship)-аар холбогддог.
Суурь нэр томьёо:
| Нэр | Англи | Тайлбар |
|---|---|---|
| Хүснэгт | Table | Өгөгдлийн бүтэц (оюутнууд, хичээлүүд) |
| Мөр | Row / Record | Нэг бичлэг (нэг оюутан) |
| Багана | Column / Field | Нэг шинж чанар (нэр, имэйл) |
| Анхдагч түлхүүр | Primary Key (PK) | Мөр бүрийг давтагдашгүй тодорхойлох |
| Гадаад түлхүүр | Foreign Key (FK) | Өөр хүснэгттэй холбох |
| Схем | Schema | Хүснэгтүүдийн бүтцийн тодорхойлолт |
┌─────────────────────────────────────────────┐
│ students (хүснэгт) │
├─────┬──────────┬─────────────────┬──────────┤
│ id │ name │ email │ gpa │ ← Баганууд (Columns)
├─────┼──────────┼─────────────────┼──────────┤
│ 1 │ Батболд │ bat@example.com │ 3.75 │ ← Мөр (Row)
│ 2 │ Сараа │ sar@example.com │ 3.90 │ ← Мөр (Row)
│ 3 │ Дорж │ dor@example.com │ 3.20 │ ← Мөр (Row)
└─────┴──────────┴─────────────────┴──────────┘
↑ PK
1.3 Түлхүүрүүд (Keys)
1.3.1 Primary Key (PK) — Анхдагч түлхүүр
- Хүснэгтийн мөр бүрийг давтагдашгүй тодорхойлох
- NULL байж болохгүй
- Хүснэгтэд ганц PK байна
- Ихэвчлэн auto-increment тоо (1, 2, 3...) эсвэл UUID
CREATE TABLE students (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE
);
1.3.2 Foreign Key (FK) — Гадаад түлхүүр
- Өөр хүснэгтийн PK-г заах → Хүснэгт хоорондын ХОЛБООС
- Мэдээллийн бүрэн бүтэн байдал (Referential Integrity) хангах
CREATE TABLE enrollments (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
student_id BIGINT NOT NULL,
course_id BIGINT NOT NULL,
enrolled_at DATE DEFAULT CURRENT_DATE,
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
students enrollments courses
┌─────┬─────────┐ ┌─────┬─────┬─────┐ ┌─────┬──────────┐
│ id │ name │ │ s_id│ c_id│ date │ │ id │ name │
├─────┼─────────┤ ├─────┼─────┼─────┤ ├─────┼──────────┤
│ 1 │ Батболд │◄────│ 1 │ 101 │ 9/1 │────►│ 101 │ Java │
│ 2 │ Сараа │◄────│ 2 │ 101 │ 9/1 │ │ 102 │ Python │
│ │ │ │ 1 │ 102 │ 9/5 │────►│ │ │
└─────┴─────────┘ └─────┴─────┴─────┘ └─────┴──────────┘
PK FK FK PK
1.3.3 Бусад түлхүүрүүд
| Түлхүүр | Тайлбар |
|---|---|
| Composite Key | 2+ баганаас бүрдсэн PK: (student_id, course_id) |
| Unique Key | Давтагдашгүй, гэхдээ NULL байж болно |
| Natural Key | Бизнесийн утгатай PK (жишээ: email, ИД-ийн дугаар) |
| Surrogate Key | Бизнесийн утгагүй PK (жишээ: auto-increment id) |
Зөвлөмж: Surrogate Key (auto-increment ID) ашиглах нь илүү уян хатан, бизнес дүрэм өөрчлөгдөхөд эвдрэхгүй.
1.4 Харилцааны төрлүүд (Relationships)
1.4.1 Нэг-Олон (One-to-Many / 1:N)
Хамгийн түгээмэл. Нэг тал → Олон тал.
Нэг тэнхим → Олон оюутан
┌─────────────┐ ┌──────────────┐
│ departments │ │ students │
├─────────────┤ ├──────────────┤
│ id (PK) │───┐ │ id (PK) │
│ name │ │ │ name │
└─────────────┘ └───►│ dept_id (FK) │
└──────────────┘
CREATE TABLE departments (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL
);
CREATE TABLE students (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
department_id BIGINT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
1.4.2 Олон-Олон (Many-to-Many / M:N)
Завсрын хүснэгт (Junction Table) шаардлагатай.
Олон оюутан ↔ Олон хичээл
┌──────────┐ ┌──────────────┐ ┌──────────┐
│ students │ │ enrollments │ │ courses │
├──────────┤ ├──────────────┤ ├──────────┤
│ id (PK) │◄───│ student_id │ │ id (PK) │
│ name │ │ course_id │───►│ name │
└──────────┘ │ grade │ │ credits │
└──────────────┘ └──────────┘
CREATE TABLE enrollments (
student_id BIGINT NOT NULL,
course_id BIGINT NOT NULL,
grade VARCHAR(2),
enrolled_at DATE DEFAULT CURRENT_DATE,
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id),
FOREIGN KEY (course_id) REFERENCES courses(id)
);
1.4.3 Нэг-Нэг (One-to-One / 1:1)
Нэг оюутан → Нэг профайл
┌──────────┐ ┌──────────────────┐
│ students │ │ student_profiles │
├──────────┤ ├──────────────────┤
│ id (PK) │───┐ │ id (PK) │
│ name │ └───►│ student_id (FK) │ ← UNIQUE
└──────────┘ │ bio │
│ avatar_url │
└──────────────────┘
CREATE TABLE student_profiles (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
student_id BIGINT NOT NULL UNIQUE,
bio TEXT,
avatar_url VARCHAR(500),
FOREIGN KEY (student_id) REFERENCES students(id)
);
1.5 ER диаграм (Entity-Relationship Diagram)
ER диаграм = Мэдээллийн сангийн бүтцийг зурагаар илэрхийлэх. Хүснэгтүүд, баганууд, харилцаануудыг харуулна.
┌──────────────┐ ┌───────────────┐ ┌──────────────┐
│ departments │ │ students │ │ courses │
├──────────────┤ ├───────────────┤ ├──────────────┤
│ * id │ │ * id │ │ * id │
│ name │───1:N─│ name │──M:N──│ name │
│ code │ │ email │ │ credits │
└──────────────┘ │ gpa │ │ code │
│ dept_id (FK)│ └──────────────┘
│ status │ │
└───────────────┘ │
│ │
│ 1:1 │
┌──────▼────────┐ ┌──────▼───────┐
│student_profiles│ │ enrollments │
├───────────────┤ ├──────────────┤
│ * id │ │ student_id │
│ student_id │ │ course_id │
│ bio │ │ grade │
│ avatar_url │ │ enrolled_at │
└───────────────┘ └──────────────┘
Зурагласны ашиг тус:
- Хүснэгтүүдийн холбоосыг визуалаар харах
- Баг хамтран ажиллахад ойлголт нэгтгэх
- Дизайны алдааг эрт олох
- Шинэ хөгжүүлэгчид системийг хурдан ойлгох
Хэрэгслүүд: dbdiagram.io, Lucidchart, draw.io, IntelliJ Database Diagrams, DBeaver.
1.6 Нормалчлал (Normalization)
Нормалчлал = Давхардлыг арилгаж, өгөгдлийн бүрэн бүтэн байдлыг хангахын тулд хүснэгтийг зөв хуваах.
1.6.1 Нормалчлалгүй (Unnormalized)
┌─────┬─────────┬─────────────────────┬──────────────┐
│ id │ name │ courses │ dept │
├─────┼─────────┼─────────────────────┼──────────────┤
│ 1 │ Батболд │ Java, Python, DB │ CS │
│ 2 │ Сараа │ Java, Web │ CS │
│ 3 │ Дорж │ Math, Statistics │ Mathematics │
└─────┴─────────┴─────────────────────┴──────────────┘
⚠️ Асуудал: courses баганад олон утга, dept давхардаж байна.
1.6.2 Эхний нормал хэлбэр (1NF)
Дүрэм: Багана бүрт ганц утга (atomic). Олон утга → Тусдаа мөр.
┌─────┬─────────┬───────────┬──────┐
│ id │ name │ course │ dept │
├─────┼─────────┼───────────┼──────┤
│ 1 │ Батболд │ Java │ CS │
│ 1 │ Батболд │ Python │ CS │
│ 1 │ Батболд │ DB │ CS │
│ 2 │ Сараа │ Java │ CS │
│ 2 │ Сараа │ Web │ CS │
└─────┴─────────┴───────────┴──────┘
✅ Багана бүрт ганц утга. ⚠️ Гэхдээ name, dept давхардаж байна.
1.6.3 Хоёрдугаар нормал хэлбэр (2NF)
Дүрэм: 1NF + PK-ийн бүх хэсэгт хамааралтай (Partial Dependency арилгах).
students enrollments courses
┌─────┬─────────┬──┐ ┌─────┬─────┐ ┌─────┬─────────┐
│ id │ name │dp│ │ s_id│ c_id│ │ id │ name │
├─────┼─────────┼──┤ ├─────┼─────┤ ├─────┼─────────┤
│ 1 │ Батболд │CS│ │ 1 │ 1 │ │ 1 │ Java │
│ 2 │ Сараа │CS│ │ 1 │ 2 │ │ 2 │ Python │
└─────┴─────────┴──┘ │ 2 │ 1 │ │ 3 │ DB │
└─────┴─────┘ └─────┴─────────┘
✅ Давхардал арилсан. Оюутны мэдээлэл нэг л газар.
1.6.4 Гуравдугаар нормал хэлбэр (3NF)
Дүрэм: 2NF + PK-аас шууд бус хамааралтай (Transitive Dependency) арилгах.
// ❌ 2NF: dept_name нь dept_id-аас хамааралтай (шууд бус)
students: id, name, dept_id, dept_name
→ dept_name нь id-аас шууд бус → dept_id-аар дамжуулж
// ✅ 3NF: dept_name тусдаа хүснэгтэд
students: id, name, dept_id (FK)
departments: id, name
Нормалчлалын дүрэм (Товч):
| Хэлбэр | Дүрэм |
|---|---|
| 1NF | Багана бүрт ГАНЦ утга (atomic) |
| 2NF | 1NF + Partial Dependency арилгах |
| 3NF | 2NF + Transitive Dependency арилгах |
Бодит байдал: Ихэвчлэн 3NF хүрэлцээтэй. Зарим тохиолдолд performance-ийн тулд denormalize (давхардуулах) хийж болно.
1.7 SQL хэл (Structured Query Language)
1.7.1 SQL-ийн төрлүүд
| Төрөл | Нэр | Командууд | Зорилго |
|---|---|---|---|
| DDL | Data Definition Language | CREATE, ALTER, DROP, TRUNCATE | Бүтэц тодорхойлох |
| DML | Data Manipulation Language | INSERT, UPDATE, DELETE | Өгөгдөл өөрчлөх |
| DQL | Data Query Language | SELECT | Өгөгдөл хайх |
| DCL | Data Control Language | GRANT, REVOKE | Эрх удирдах |
| TCL | Transaction Control Language | COMMIT, ROLLBACK, SAVEPOINT | Гүйлгээ удирдах |
1.7.2 DDL — Хүснэгт үүсгэх, өөрчлөх
-- Хүснэгт үүсгэх
CREATE TABLE students (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL,
email VARCHAR(150) NOT NULL UNIQUE,
gpa DECIMAL(3,2) CHECK (gpa >= 0.00 AND gpa <= 4.00),
status VARCHAR(20) DEFAULT 'ACTIVE',
department_id BIGINT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
-- Багана нэмэх
ALTER TABLE students ADD COLUMN phone VARCHAR(20);
-- Багана устгах
ALTER TABLE students DROP COLUMN phone;
-- Хүснэгт устгах (бүх өгөгдөлтэй)
DROP TABLE IF EXISTS students;
-- Бүх мөр устгах (бүтэц хадгалах)
TRUNCATE TABLE students;
1.7.3 DML — Өгөгдөл нэмэх, шинэчлэх, устгах
-- INSERT — Шинэ мөр нэмэх
INSERT INTO students (name, email, gpa, department_id)
VALUES ('Батболд', 'bat@example.com', 3.75, 1);
-- Олон мөр нэмэх
INSERT INTO students (name, email, gpa, department_id) VALUES
('Сараа', 'sar@example.com', 3.90, 1),
('Дорж', 'dor@example.com', 3.20, 2),
('Оюуна', 'oyu@example.com', 3.60, 1);
-- UPDATE — Мөр шинэчлэх
UPDATE students SET gpa = 3.80 WHERE id = 1;
UPDATE students SET status = 'GRADUATED' WHERE gpa >= 3.5;
-- DELETE — Мөр устгах
DELETE FROM students WHERE id = 1;
DELETE FROM students WHERE status = 'INACTIVE';
-- ⚠️ WHERE-гүй бол БҮГДИЙГ устгана!
-- DELETE FROM students; ← Бүх оюутан устана! АЮУЛТАЙ!
1.7.4 DQL — Өгөгдөл хайх (SELECT)
-- Бүх оюутан
SELECT * FROM students;
-- Тодорхой баганууд
SELECT name, email, gpa FROM students;
-- Нөхцөлтэй (WHERE)
SELECT * FROM students WHERE gpa >= 3.5;
SELECT * FROM students WHERE status = 'ACTIVE' AND department_id = 1;
SELECT * FROM students WHERE name LIKE 'Бат%';
SELECT * FROM students WHERE gpa BETWEEN 3.0 AND 3.5;
SELECT * FROM students WHERE department_id IN (1, 2, 3);
SELECT * FROM students WHERE email IS NOT NULL;
-- Эрэмбэлэх (ORDER BY)
SELECT * FROM students ORDER BY gpa DESC;
SELECT * FROM students ORDER BY name ASC, gpa DESC;
-- Хязгаарлах (LIMIT + OFFSET)
SELECT * FROM students ORDER BY gpa DESC LIMIT 10; -- Шилдэг 10
SELECT * FROM students ORDER BY id LIMIT 10 OFFSET 20; -- 3-р хуудас
-- Агрегат функцүүд
SELECT COUNT(*) FROM students; -- Нийт тоо
SELECT AVG(gpa) FROM students; -- Дундаж GPA
SELECT MAX(gpa) FROM students; -- Хамгийн өндөр GPA
SELECT MIN(gpa) FROM students; -- Хамгийн бага GPA
SELECT SUM(gpa) FROM students; -- GPA нийлбэр
-- Бүлэглэх (GROUP BY)
SELECT department_id, COUNT(*) as student_count, AVG(gpa) as avg_gpa
FROM students
GROUP BY department_id;
-- Бүлэглэсний дараа шүүх (HAVING)
SELECT department_id, AVG(gpa) as avg_gpa
FROM students
GROUP BY department_id
HAVING AVG(gpa) > 3.5;
-- DISTINCT — Давтагдашгүй утгууд
SELECT DISTINCT status FROM students;
SELECT DISTINCT department_id FROM students;
1.7.5 JOIN — Хүснэгт холбох
-- INNER JOIN — Хоёр хүснэгтэд ХОЁУЛАНГД нь байгаа мөрүүд
SELECT s.name, d.name as department
FROM students s
INNER JOIN departments d ON s.department_id = d.id;
-- LEFT JOIN — Зүүн хүснэгтийн БҮХ мөр + баруунаас тохирох
SELECT s.name, d.name as department
FROM students s
LEFT JOIN departments d ON s.department_id = d.id;
-- Тэнхимгүй оюутнууд ч гарна (department = NULL)
-- RIGHT JOIN — Баруун хүснэгтийн БҮХ мөр
SELECT s.name, d.name as department
FROM students s
RIGHT JOIN departments d ON s.department_id = d.id;
-- Оюутангүй тэнхимүүд ч гарна
-- Олон хүснэгт холбох
SELECT s.name as student, c.name as course, e.grade
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id
WHERE s.id = 1;
INNER JOIN: LEFT JOIN: RIGHT JOIN:
A ∩ B A (бүгд) B (бүгд)
┌───┬───┐ ┌───┬───┐ ┌───┬───┐
│ │███│ │███│███│ │ │███│
│ │███│ │███│███│ │ │███│
└───┴───┘ └───┴───┘ └───┴───┘
Зөвхөн тохирох Зүүн бүгд + Баруун бүгд +
тохирох тохирох
1.8 Индекс (Index)
Индекс гэж юу вэ?
Индекс = Номын сангийн каталог шиг — хайлтыг хурдасгах тусгай бүтэц. Индексгүй бол хүснэгтийн БҮХ мөрийг шалгана (Full Table Scan).
// Индексгүй: Бүх 1,000,000 мөр шалгана
SELECT * FROM students WHERE email = 'bat@example.com';
⏱️ Удаан (Full Scan)
// Индекстэй: B-Tree бүтцээр хурдан олно
CREATE INDEX idx_students_email ON students(email);
SELECT * FROM students WHERE email = 'bat@example.com';
⏱️ Хурдан (Index Scan)
Индексийн төрлүүд
| Төрөл | Тайлбар | Жишээ |
|---|---|---|
| B-Tree | Ерөнхий зориулалт (default) | =, <, >, BETWEEN, ORDER BY |
| Hash | Яг тэнцүү хайлт | = шалгалт |
| GIN | Массив, Full-text search | ARRAY, tsvector |
| Partial | Зөвхөн нөхцөлтэй мөрүүдэд | WHERE status = 'ACTIVE' |
| Composite | Олон баганат | (department_id, gpa) |
-- Нэг баганат индекс
CREATE INDEX idx_students_email ON students(email);
-- Олон баганат (Composite) индекс
CREATE INDEX idx_students_dept_gpa ON students(department_id, gpa);
-- Partial индекс (зөвхөн идэвхтэй оюутнууд)
CREATE INDEX idx_active_students ON students(email)
WHERE status = 'ACTIVE';
-- UNIQUE индекс
CREATE UNIQUE INDEX idx_students_email_unique ON students(email);
Хэзээ индекс ашиглах вэ?
| ✅ Ашиглах | ❌ Ашиглахгүй |
|---|---|
| WHERE-д байнга ашигладаг багана | Бага тооны мөр (<1000) |
| JOIN-д ашигладаг FK | INSERT/UPDATE маш олон хүснэгт |
| ORDER BY багана | Бараг бүх утга ижил багана |
| UNIQUE шаардлагатай багана | Хүснэгтийн ихэнх баганыг SELECT хийдэг |
⚠️ Анхаарах: Индекс нь READ хурдасгана, гэхдээ WRITE (INSERT/UPDATE/DELETE) удаашруулна — индексийг ч шинэчлэх шаардлагатай учраас.
1.9 Гүйлгээ (Transaction) ба ACID
Transaction гэж юу вэ?
Transaction = Нэг логик нэгж болох олон үйлдлийн багц. Бүгд амжилттай бол COMMIT, нэг ч алдаа бол ROLLBACK.
-- Мөнгө шилжүүлэх (2 үйлдэл = 1 transaction)
BEGIN TRANSACTION;
UPDATE accounts SET balance = balance - 100000 WHERE id = 1; -- Батаас -100,000
UPDATE accounts SET balance = balance + 100000 WHERE id = 2; -- Дорж руу +100,000
-- Хоёулаа амжилттай бол:
COMMIT;
-- Аль нэг нь алдаатай бол:
ROLLBACK; -- ХОЁУЛАНГ нь буцаах!
ACID зарчим
| Зарчим | Англи | Тайлбар | Жишээ |
|---|---|---|---|
| A | Atomicity | Бүгд эсвэл юу ч ҮГҮ | Мөнгө хасагдсан + нэмэгдсэн, эсвэл хоёулаа буцна |
| C | Consistency | Бүрэн бүтэн байдал хангагдсан | Баланс < 0 болохгүй |
| I | Isolation | Зэрэг ажиллаж буй transaction бие биедээ нөлөөлөхгүй | А ба Б зэрэг шилжүүлсэн ч зөв |
| D | Durability | COMMIT хийсний дараа өгөгдөл ХАДГАЛАГДСАН | Сервер унтарсан ч өгөгдөл алдагдахгүй |
Isolation Level
| Түвшин | Dirty Read | Non-Repeatable Read | Phantom Read |
|---|---|---|---|
| READ UNCOMMITTED | ✅ Болно | ✅ Болно | ✅ Болно |
| READ COMMITTED | ❌ Болохгүй | ✅ Болно | ✅ Болно |
| REPEATABLE READ | ❌ Болохгүй | ❌ Болохгүй | ✅ Болно |
| SERIALIZABLE | ❌ Болохгүй | ❌ Болохгүй | ❌ Болохгүй |
PostgreSQL default: READ COMMITTED. MySQL default: REPEATABLE READ.
1.10 JPA / Hibernate Entity Mapping
1.10.1 Entity ба Table холбох
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name", nullable = false, length = 100)
private String name;
@Column(name = "email", nullable = false, unique = true)
private String email;
@Column(precision = 3, scale = 2)
private BigDecimal gpa;
@Enumerated(EnumType.STRING)
@Column(length = 20)
private StudentStatus status = StudentStatus.ACTIVE;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "department_id")
private Department department;
@OneToOne(mappedBy = "student", cascade = CascadeType.ALL)
private StudentProfile profile;
@ManyToMany
@JoinTable(
name = "enrollments",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
@Column(name = "created_at")
private LocalDateTime createdAt = LocalDateTime.now();
}
1.10.2 Харилцааны Annotation
| Annotation | Харилцаа | FK байршил |
|---|---|---|
@ManyToOne | Олон → Нэг | Одоогийн хүснэгтэд FK |
@OneToMany | Нэг → Олон | Нөгөө хүснэгтэд FK |
@OneToOne | Нэг → Нэг | Аль нэг хүснэгтэд FK |
@ManyToMany | Олон ↔ Олон | Завсрын хүснэгтэд |
1.10.3 FetchType — LAZY vs EAGER
| Төрөл | Тайлбар | Хэзээ ачаалах |
|---|---|---|
| LAZY | Шаардлагатай үед ачаална | student.getDepartment() дуудахад |
| EAGER | Шууд ачаална | Student ачаалахад Department ч ачаална |
Зөвлөмж: Бараг бүх тохиолдолд LAZY ашиглах. EAGER = N+1 асуудал үүсэх эрсдэлтэй.
1.10.4 N+1 асуудал
// ❌ N+1 Problem
List<Student> students = studentRepository.findAll(); // 1 query
for (Student s : students) {
System.out.println(s.getDepartment().getName()); // N query (оюутан бүрт 1)
}
// Нийт: 1 + N query (100 оюутан = 101 query!)
// ✅ JOIN FETCH-аар шийдэх
@Query("SELECT s FROM Student s JOIN FETCH s.department")
List<Student> findAllWithDepartment(); // 1 query (JOIN)
1.11 Өгөгдлийн төрлүүд (Data Types)
PostgreSQL-ийн үндсэн төрлүүд
| Төрөл | SQL | Java | Тайлбар |
|---|---|---|---|
| Бүхэл тоо | INTEGER, BIGINT | Integer, Long | ID, тоо |
| Бутархай | DECIMAL(p,s), NUMERIC | BigDecimal | Мөнгө, GPA |
| Текст | VARCHAR(n), TEXT | String | Нэр, имэйл |
| Огноо | DATE | LocalDate | Огноо |
| Цаг | TIMESTAMP | LocalDateTime | Огноо + цаг |
| Boolean | BOOLEAN | Boolean | true/false |
| JSON | JSONB | String / Custom | Бүтэцтэй өгөгдөл |
| UUID | UUID | UUID | Давтагдашгүй ID |
⚠️ Мөнгөн дүнд
DECIMALашиглах,FLOAT/DOUBLEбиш! Float/Double = Бутархай тооны нарийвчлал алдагдна.
1.12 NoSQL ойлголт
SQL vs NoSQL
| Шинж | SQL (RDBMS) | NoSQL |
|---|---|---|
| Бүтэц | Хатуу schema (хүснэгт) | Уян хатан schema |
| Хэл | SQL | API / Query Language |
| Харилцаа | JOIN, FK | Embedded document |
| Scale | Vertical (сервер сайжруулах) | Horizontal (сервер нэмэх) |
| ACID | Бүрэн дэмжинэ | Зарим нь л |
| Тохиромжтой | Бүтэцтэй өгөгдөл, гүйлгээ | Уян хатан, том хэмжээ |
NoSQL-ийн төрлүүд
| Төрөл | Жишээ | Хэрэглээ |
|---|---|---|
| Document | MongoDB | JSON бүтэцтэй өгөгдөл, CMS |
| Key-Value | Redis | Кэш, session |
| Wide Column | Cassandra | Олон тооны бичлэг, IoT |
| Graph | Neo4j | Нийгмийн сүлжээ, зөвлөмж |
// SQL (RDBMS) // NoSQL (MongoDB)
┌──────────────┐ {
│ students │ "_id": "abc123",
├──────────────┤ "name": "Батболд",
│ id: 1 │ "email": "bat@example.com",
│ name: Батболд│ ───► "gpa": 3.75,
│ email: bat@ │ "department": {
│ dept_id: 1 │ "name": "CS",
└──────────────┘ "code": "CSE"
┌──────────────┐ },
│ departments │ "courses": [
├──────────────┤ {"name": "Java", "grade": "A"},
│ id: 1 │ {"name": "DB", "grade": "B+"}
│ name: CS │ ]
└──────────────┘ }
2 хүснэгт + JOIN 1 document (embedded)
Хэзээ SQL? Бүтэцтэй, харилцаатай өгөгдөл, ACID чухал (банк, ERP). Хэзээ NoSQL? Уян хатан бүтэц, том хэмжээ, хурдан бичих (лог, IoT, кэш).
1.13 Мэдээллийн сангийн дизайны шилдэг туршлагууд
| # | Зарчим | Тайлбар |
|---|---|---|
| 1 | Нормалчлал (3NF) | Давхардал арилгах, бүрэн бүтэн байдал |
| 2 | Surrogate PK | Auto-increment ID ашиглах (бизнес утгагүй) |
| 3 | Нэрлэлт | snake_case: student_id, created_at, олон тоо: students |
| 4 | FK Constraint | Referential Integrity хангах |
| 5 | Индекс | WHERE, JOIN, ORDER BY баганад |
| 6 | NOT NULL | Шаардлагатай баганууд |
| 7 | DEFAULT утга | status DEFAULT 'ACTIVE', created_at DEFAULT NOW() |
| 8 | CHECK Constraint | gpa CHECK (gpa >= 0 AND gpa <= 4) |
| 9 | Огноо багана | created_at, updated_at — Audit trail |
| 10 | Soft Delete | deleted_at багана — Бүрмөсөн устгахгүй |
| 11 | DECIMAL мөнгөнд | FLOAT/DOUBLE биш — нарийвчлал |
| 12 | LAZY fetch | N+1 асуудлаас зайлсхийх |
ХЭСЭГ 2: ТҮЛХҮҮР ҮГ БА МЭРГЭЖЛИЙН НЭР ТОМЬЁО (Keywords & Glossary)
| # | Англи нэр томьёо | Монгол утга | Дэлгэрэнгүй тайлбар |
|---|---|---|---|
| 1 | Database | Мэдээллийн сан | Зохион байгуулагдсан өгөгдлийн цуглуулга. |
| 2 | DBMS | МС удирдлагын систем | Database Management System — Өгөгдлийг удирдах програм. |
| 3 | RDBMS | Харилцааны МС | Хүснэгт, харилцаанд суурилсан МС (PostgreSQL, MySQL). |
| 4 | Table | Хүснэгт | Мөр, баганаас бүрдсэн өгөгдлийн бүтэц. |
| 5 | Row / Record | Мөр / Бичлэг | Хүснэгтийн нэг бичлэг (нэг оюутан). |
| 6 | Column / Field | Багана / Талбар | Хүснэгтийн нэг шинж чанар (нэр, имэйл). |
| 7 | Primary Key | Анхдагч түлхүүр | Мөр бүрийг давтагдашгүй тодорхойлох. |
| 8 | Foreign Key | Гадаад түлхүүр | Өөр хүснэгтийн PK-г заах — холбоос. |
| 9 | Schema | Схем | Хүснэгтүүдийн бүтцийн тодорхойлолт. |
| 10 | Normalization | Нормалчлал | Давхардал арилгах, бүрэн бүтэн байдал хангах. |
| 11 | 1NF / 2NF / 3NF | Нормал хэлбэрүүд | Нормалчлалын түвшнүүд. |
| 12 | Denormalization | Нормалчлалаас буцах | Performance-ийн тулд давхардуулах. |
| 13 | ER Diagram | ER диаграм | Entity-Relationship — Бүтцийг зурагаар илэрхийлэх. |
| 14 | SQL | SQL хэл | Structured Query Language. |
| 15 | DDL | Бүтэц тодорхойлох | CREATE, ALTER, DROP. |
| 16 | DML | Өгөгдөл өөрчлөх | INSERT, UPDATE, DELETE. |
| 17 | DQL | Өгөгдөл хайх | SELECT. |
| 18 | JOIN | Холбох | Хүснэгтүүдийг холбож мэдээлэл авах. |
| 19 | INNER JOIN | Дотоод холбоос | Хоёуланд тохирох мөрүүд. |
| 20 | LEFT JOIN | Зүүн холбоос | Зүүн хүснэгтийн бүх мөр + тохирох. |
| 21 | Index | Индекс | Хайлтыг хурдасгах тусгай бүтэц. |
| 22 | Transaction | Гүйлгээ | Олон үйлдлийн нэг логик нэгж. |
| 23 | ACID | ACID зарчим | Atomicity, Consistency, Isolation, Durability. |
| 24 | COMMIT | Баталгаажуулах | Transaction амжилттай — өгөгдлийг хадгалах. |
| 25 | ROLLBACK | Буцаах | Transaction цуцалж, бүгдийг буцаах. |
| 26 | Isolation Level | Тусгаарлалтын түвшин | Transaction хоорондын нөлөөллийн зохицуулалт. |
| 27 | Constraint | Хязгаарлалт | NOT NULL, UNIQUE, CHECK, FK зэрэг дүрмүүд. |
| 28 | Aggregate Function | Агрегат функц | COUNT, SUM, AVG, MAX, MIN. |
| 29 | GROUP BY | Бүлэглэх | Мөрүүдийг бүлэглэж агрегат тооцоолох. |
| 30 | HAVING | Бүлэг шүүх | GROUP BY-н дараа шүүлт хийх. |
| 31 | Subquery | Дэд асуулга | SELECT дотор SELECT. |
| 32 | View | Харагдац | Хадгалагдсан SELECT — виртуал хүснэгт. |
| 33 | Stored Procedure | Хадгалагдсан процедур | DB-д хадгалагдсан SQL логик. |
| 34 | Trigger | Триггер | INSERT/UPDATE/DELETE-д автоматаар ажиллах логик. |
| 35 | JPA | Java Persistence API | Java объектыг DB-тэй холбох стандарт. |
| 36 | Hibernate | Hibernate | JPA-ийн хамгийн түгээмэл implementation. |
| 37 | ORM | Объект-Харилцааны зураглал | Object-Relational Mapping. |
| 38 | Lazy Loading | Хойшлуулсан ачаалал | Шаардлагатай үед л өгөгдөл ачаалах. |
| 39 | N+1 Problem | N+1 асуудал | 1 query + N нэмэлт query = Удаан. |
| 40 | NoSQL | NoSQL | Хүснэгтэд суурилдаггүй мэдээллийн сан. |