ЛЕКЦ 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 | Хүснэгтэд суурилдаггүй мэдээллийн сан. |
ХЭСЭГ 3: ЛАБОРАТОРИ БА ПРАКТИК ЗААВАР (Labs & Step-by-Step Guide)
3.1 Лабораторийн зорилго
Энэ лабораторид та:
- PostgreSQL (эсвэл H2)-д хүснэгтүүд үүсгэх
- SQL командуудаар өгөгдөл удирдах
- JOIN, агрегат функц, индекс ашиглах
- Spring Boot JPA Entity Mapping хийх
Хэл: SQL (PostgreSQL) + Java 17+ | IDE: Eclipse IDE + DBeaver (эсвэл H2 Console)
3.2 Лаб 1: Мэдээллийн сангийн хүснэгтүүд үүсгэх (DDL)
Алхам 1: Хүснэгтүүд үүсгэх
-- 1. Тэнхимүүд
CREATE TABLE departments (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL UNIQUE,
code VARCHAR(10) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 2. Оюутнууд
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,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
-- 3. Хичээлүүд
CREATE TABLE courses (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
name VARCHAR(100) NOT NULL,
code VARCHAR(10) NOT NULL UNIQUE,
credits INTEGER NOT NULL CHECK (credits > 0 AND credits <= 6),
department_id BIGINT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);
-- 4. Бүртгэл (M:N завсрын хүснэгт)
CREATE TABLE enrollments (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
student_id BIGINT NOT NULL,
course_id BIGINT NOT NULL,
grade VARCHAR(2),
enrolled_at DATE DEFAULT CURRENT_DATE,
UNIQUE (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE,
FOREIGN KEY (course_id) REFERENCES courses(id) ON DELETE CASCADE
);
-- 5. Оюутны профайл (1:1)
CREATE TABLE student_profiles (
id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
student_id BIGINT NOT NULL UNIQUE,
bio TEXT,
avatar_url VARCHAR(500),
phone VARCHAR(20),
FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE
);
Алхам 2: Индексүүд үүсгэх
CREATE INDEX idx_students_email ON students(email);
CREATE INDEX idx_students_dept ON students(department_id);
CREATE INDEX idx_students_status ON students(status);
CREATE INDEX idx_enrollments_student ON enrollments(student_id);
CREATE INDEX idx_enrollments_course ON enrollments(course_id);
3.3 Лаб 2: Өгөгдөл нэмэх ба хайх (DML + DQL)
Алхам 1: Өгөгдөл нэмэх
-- Тэнхимүүд
INSERT INTO departments (name, code) VALUES
('Компьютерийн шинжлэх ухаан', 'CSE'),
('Математик', 'MATH'),
('Физик', 'PHYS');
-- Оюутнууд
INSERT INTO students (name, email, gpa, department_id) VALUES
('Батболд', 'batbold@example.com', 3.75, 1),
('Сарангэрэл', 'sarangerel@example.com', 3.90, 1),
('Дорж', 'dorj@example.com', 3.20, 2),
('Оюуна', 'oyuuna@example.com', 3.60, 1),
('Ганбаатар', 'ganbaatar@example.com', 2.80, 3),
('Нарангэрэл', 'narangerel@example.com', 3.45, 2),
('Болдбаатар', 'boldbaatar@example.com', 3.10, 3),
('Цэцэгмаа', 'tsetsegmaa@example.com', 3.85, 1),
('Энхбат', 'enkhbat@example.com', 2.50, 2),
('Алтанцэцэг', 'altantsetseg@example.com', 3.95, 1);
-- Хичээлүүд
INSERT INTO courses (name, code, credits, department_id) VALUES
('Java програмчлал', 'CS101', 3, 1),
('Мэдээллийн сан', 'CS201', 3, 1),
('Веб хөгжүүлэлт', 'CS301', 4, 1),
('Математик анализ', 'MATH101', 4, 2),
('Статистик', 'MATH201', 3, 2),
('Квантум физик', 'PHYS301', 3, 3);
-- Бүртгэл
INSERT INTO enrollments (student_id, course_id, grade) VALUES
(1, 1, 'A'), (1, 2, 'A-'), (1, 3, 'B+'),
(2, 1, 'A+'), (2, 2, 'A'),
(3, 4, 'B'), (3, 5, 'B+'),
(4, 1, 'A-'), (4, 3, 'A'),
(5, 6, 'C+'),
(6, 4, 'A'), (6, 5, 'A-'),
(8, 1, 'A'), (8, 2, 'A+'), (8, 3, 'A'),
(10, 1, 'A+'), (10, 2, 'A+');
-- Профайл
INSERT INTO student_profiles (student_id, bio, phone) VALUES
(1, 'Java хөгжүүлэгч болох зорилготой', '99001122'),
(2, 'Full-stack developer', '99003344');
Алхам 2: SELECT хайлтууд
-- 1. GPA >= 3.5 оюутнууд
SELECT name, email, gpa FROM students WHERE gpa >= 3.5 ORDER BY gpa DESC;
-- 2. Тэнхим бүрийн оюутны тоо, дундаж GPA
SELECT d.name as department, COUNT(s.id) as student_count,
ROUND(AVG(s.gpa), 2) as avg_gpa
FROM departments d
LEFT JOIN students s ON d.id = s.department_id
GROUP BY d.name
ORDER BY avg_gpa DESC;
-- 3. Хамгийн олон оюутантай тэнхим
SELECT d.name, COUNT(s.id) as count
FROM departments d
JOIN students s ON d.id = s.department_id
GROUP BY d.name
ORDER BY count DESC
LIMIT 1;
-- 4. Java хичээл авсан оюутнууд
SELECT s.name, e.grade
FROM students s
JOIN enrollments e ON s.id = e.student_id
JOIN courses c ON e.course_id = c.id
WHERE c.code = 'CS101'
ORDER BY s.name;
-- 5. Оюутан бүрийн авсан хичээлийн тоо
SELECT s.name, COUNT(e.course_id) as course_count
FROM students s
LEFT JOIN enrollments e ON s.id = e.student_id
GROUP BY s.name
ORDER BY course_count DESC;
-- 6. A+ дүнтэй оюутнууд
SELECT DISTINCT s.name, s.email
FROM students s
JOIN enrollments e ON s.id = e.student_id
WHERE e.grade = 'A+';
-- 7. Хичээл аваагүй оюутнууд
SELECT s.name, s.email
FROM students s
LEFT JOIN enrollments e ON s.id = e.student_id
WHERE e.id IS NULL;
-- 8. Дундаж GPA-аас дээш оюутнууд (Subquery)
SELECT name, gpa
FROM students
WHERE gpa > (SELECT AVG(gpa) FROM students);
-- 9. Хичээл бүрийн оюутны тоо
SELECT c.name as course, c.code, COUNT(e.student_id) as students
FROM courses c
LEFT JOIN enrollments e ON c.id = e.course_id
GROUP BY c.name, c.code
ORDER BY students DESC;
-- 10. UPDATE: GPA шинэчлэх
UPDATE students SET gpa = 3.80, updated_at = CURRENT_TIMESTAMP
WHERE id = 1;
3.4 Лаб 3: JPA Entity Mapping (Spring Boot)
Алхам 1: Department Entity
// src/main/java/com/example/studentapi/entity/Department.java
package com.example.studentapi.entity;
import jakarta.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "departments")
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, unique = true, length = 100)
private String name;
@Column(nullable = false, unique = true, length = 10)
private String code;
@OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
private List<Student> students = new ArrayList<>();
public Department() {}
// Getter, Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCode() { return code; }
public void setCode(String code) { this.code = code; }
public List<Student> getStudents() { return students; }
public void setStudents(List<Student> students) { this.students = students; }
}
Алхам 2: Student Entity (харилцаатай)
// src/main/java/com/example/studentapi/entity/Student.java
package com.example.studentapi.entity;
import jakarta.persistence.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Set;
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 100)
private String name;
@Column(nullable = false, unique = true, length = 150)
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,
fetch = FetchType.LAZY)
private StudentProfile profile;
@ManyToMany(fetch = FetchType.LAZY)
@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();
@Column(name = "updated_at")
private LocalDateTime updatedAt = LocalDateTime.now();
public Student() {}
// Getter, Setter
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
public BigDecimal getGpa() { return gpa; }
public void setGpa(BigDecimal gpa) { this.gpa = gpa; }
public StudentStatus getStatus() { return status; }
public void setStatus(StudentStatus status) { this.status = status; }
public Department getDepartment() { return department; }
public void setDepartment(Department department) { this.department = department; }
public StudentProfile getProfile() { return profile; }
public void setProfile(StudentProfile profile) { this.profile = profile; }
public Set<Course> getCourses() { return courses; }
public void setCourses(Set<Course> courses) { this.courses = courses; }
}
Алхам 3: N+1 шийдэл — JOIN FETCH
// StudentRepository.java
public interface StudentRepository extends JpaRepository<Student, Long> {
// N+1 асуудалгүй — 1 query-ээр бүгдийг авна
@Query("SELECT s FROM Student s JOIN FETCH s.department")
List<Student> findAllWithDepartment();
// Тэнхимээр шүүх
@Query("SELECT s FROM Student s JOIN FETCH s.department d WHERE d.code = :code")
List<Student> findByDepartmentCode(@Param("code") String code);
// GPA-аар шүүх + тэнхимтэй
@Query("SELECT s FROM Student s JOIN FETCH s.department WHERE s.gpa >= :minGpa")
List<Student> findByMinGpaWithDepartment(@Param("minGpa") BigDecimal minGpa);
}
3.5 Лаб 4: Transaction ба Бизнес логик
// StudentService.java — Transaction жишээ
@Service
public class StudentService {
private final StudentRepository studentRepository;
private final EnrollmentRepository enrollmentRepository;
public StudentService(StudentRepository studentRepository,
EnrollmentRepository enrollmentRepository) {
this.studentRepository = studentRepository;
this.enrollmentRepository = enrollmentRepository;
}
@Transactional
public void enrollStudentInCourse(Long studentId, Long courseId) {
// 1. Оюутан олох
Student student = studentRepository.findById(studentId)
.orElseThrow(() -> new StudentNotFoundException(
"ID=" + studentId + " оюутан олдсонгүй"
));
// 2. Бүртгэлтэй эсэхийг шалгах
if (enrollmentRepository.existsByStudentIdAndCourseId(studentId, courseId)) {
throw new DuplicateEnrollmentException(
"Оюутан энэ хичээлд бүртгэлтэй байна"
);
}
// 3. Бүртгэл үүсгэх
Enrollment enrollment = new Enrollment();
enrollment.setStudentId(studentId);
enrollment.setCourseId(courseId);
enrollmentRepository.save(enrollment);
// 4. Оюутны хичээлийн тоо шинэчлэх
// Алдаа гарвал бүгд ROLLBACK — Atomicity!
}
}
---
---
# ХЭСЭГ 4: ШАЛГАЛТЫН АСУУЛТ (Knowledge Check — 100 тест)
## Тест 1
**Мэдээллийн сан (Database) гэж юу вэ?**
- A) Зөвхөн Excel файл
- B) Зохион байгуулагдсан, удирдагддаг өгөгдлийн цуглуулга
- C) Зөвхөн вэб хуудас
- D) Програмын код
**Зөв хариулт: B**
> **Тайлбар:** Database = Өгөгдлийг бүтэцтэй хадгалж, хайлт, шинэчлэлт, устгалт хийх боломжтой цуглуулга. DBMS (PostgreSQL, MySQL) ашиглан удирдана.
## Тест 2
**RDBMS гэж юу вэ?**
- A) NoSQL мэдээллийн сан
- B) Харилцааны мэдээллийн сангийн удирдлагын систем — хүснэгт, харилцаанд суурилсан
- C) Файл систем
- D) Кэш систем
**Зөв хариулт: B**
> **Тайлбар:** RDBMS = Relational DBMS. Өгөгдлийг хүснэгтэд хадгалж, хүснэгтүүд FK-аар холбогдоно. PostgreSQL, MySQL, Oracle = RDBMS.
## Тест 3
**Primary Key (PK) юу хийдэг вэ?**
- A) Хүснэгтийг устгах
- B) Хүснэгтийн мөр бүрийг ДАВТАГДАШГҮЙ тодорхойлох
- C) Зөвхөн текст хадгалах
- D) Индекс устгах
**Зөв хариулт: B**
> **Тайлбар:** PK = Мөр бүрийн давтагдашгүй ID. NOT NULL + UNIQUE. Хүснэгтэд ганц PK. Ихэвчлэн auto-increment (1, 2, 3...).
## Тест 4
**Foreign Key (FK) юу хийдэг вэ?**
- A) Хүснэгт үүсгэх
- B) Өөр хүснэгтийн PK-г заах — хүснэгт хоорондын ХОЛБООС
- C) Индекс үүсгэх
- D) Мөр устгах
**Зөв хариулт: B**
> **Тайлбар:** FK = students.department_id → departments.id. Referential Integrity = FK-ийн заасан PK заавал байх ёстой.
## Тест 5
**Нэг-Олон (One-to-Many) харилцааны жишээ аль нь вэ?**
- A) Оюутан ↔ Оюутан
- B) Нэг тэнхим → Олон оюутан
- C) Нэг оюутан → Нэг профайл
- D) Олон оюутан ↔ Олон хичээл
**Зөв хариулт: B**
> **Тайлбар:** 1:N = Нэг тэнхимд олон оюутан. FK нь "олон" талд байна: students.department_id → departments.id.
## Тест 6
**Many-to-Many харилцааг хэрхэн хэрэгжүүлэх вэ?**
- A) FK нэмэх
- B) ЗАВСРЫН хүснэгт (Junction Table) ашиглах — enrollments(student_id, course_id)
- C) PK устгах
- D) Нэг хүснэгтэд олон багана нэмэх
**Зөв хариулт: B**
> **Тайлбар:** M:N = Олон оюутан ↔ Олон хичээл. Завсрын хүснэгт enrollments(student_id FK, course_id FK) ашиглана. Хоёр FK = Хоёр хүснэгтийг холбоно.
## Тест 7
**Нормалчлалын (Normalization) гол зорилго юу вэ?**
- A) Хурд нэмэх
- B) Өгөгдлийн ДАВХАРДЛЫГ арилгаж, бүрэн бүтэн байдлыг хангах
- C) Хүснэгт устгах
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** Нормалчлал = Давхардал арилгах → Өгөгдөл нэг л газар → Нэг газар засахад л хангалттай. Inconsistency-ээс хамгаалах.
## Тест 8
**1NF (Эхний нормал хэлбэр)-ийн дүрэм юу вэ?**
- A) FK арилгах
- B) Багана бүрт ГАНЦ утга (atomic) — олон утга нэг баганад байхгүй
- C) PK арилгах
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** 1NF = Atomic. "Java, Python, DB" нэг баганад = 1NF ЗӨРЧИЛ. Тус тусдаа мөрөнд = 1NF.
## Тест 9
**3NF-ийн дүрэм юу вэ?**
- A) Бүх давхардлыг арилгах
- B) 2NF + Transitive Dependency арилгах — PK-аас ШУУД БУС хамааралтай баганыг тусдаа хүснэгтэд
- C) Зөвхөн PK байх
- D) Индекс заавал байх
**Зөв хариулт: B**
> **Тайлбар:** students(id, name, dept_id, dept_name) → dept_name нь id-аас шууд бус (dept_id-аар дамжуулж). → departments(id, name) тусдаа = 3NF.
## Тест 10
**SQL-ийн DDL (Data Definition Language) аль командуудыг агуулдаг вэ?**
- A) SELECT, INSERT
- B) CREATE, ALTER, DROP, TRUNCATE
- C) COMMIT, ROLLBACK
- D) GRANT, REVOKE
**Зөв хариулт: B**
> **Тайлбар:** DDL = Мэдээллийн сангийн БҮТЦИЙГ тодорхойлох. CREATE = Үүсгэх, ALTER = Өөрчлөх, DROP = Устгах, TRUNCATE = Бүх мөрийг арилгах.
## Тест 11
**`SELECT * FROM students WHERE gpa >= 3.5` юу хийдэг вэ?**
- A) Бүх оюутнуудыг устгах
- B) GPA 3.5 ба түүнээс дээш бүх оюутнуудыг СОНГОХ
- C) GPA-г шинэчлэх
- D) Хүснэгт үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** SELECT = Өгөгдөл уншиx (DQL). WHERE = Нөхцөл. gpa >= 3.5 = GPA 3.5+ оюутнууд. * = Бүх багана.
## Тест 12
**INNER JOIN юу хийдэг вэ?**
- A) Бүх мөрийг авах
- B) ХОЁР хүснэгтэд ХОЁУЛАНД нь тохирох мөрүүдийг буцаах
- C) Зүүн хүснэгтийн бүх мөр
- D) Баруун хүснэгтийн бүх мөр
**Зөв хариулт: B**
> **Тайлбар:** INNER JOIN = A ∩ B. Хоёр хүснэгтэд хоёуланд тохирох мөрүүд. Тохирохгүй мөрүүд орохгүй.
## Тест 13
**LEFT JOIN юу хийдэг вэ?**
- A) Зөвхөн тохирох мөрүүд
- B) ЗҮҮН хүснэгтийн БҮХ мөр + баруунаас тохирох (тохирохгүй бол NULL)
- C) Баруун хүснэгтийн бүх мөр
- D) Хоёулангийн бүх мөр
**Зөв хариулт: B**
> **Тайлбар:** LEFT JOIN = Зүүн бүгд + тохирох. Тэнхимгүй оюутан ч гарна (department = NULL). Хичээл аваагүй оюутан олоход тохиромжтой.
## Тест 14
**GROUP BY юу хийдэг вэ?**
- A) Мөр устгах
- B) Мөрүүдийг бүлэглэж, агрегат функц (COUNT, AVG, SUM) тооцоолох
- C) Мөр нэмэх
- D) Индекс үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** `GROUP BY department_id` = Тэнхимээр бүлэглэж, `COUNT(*)` = тэнхим бүрийн оюутны тоо, `AVG(gpa)` = дундаж GPA.
## Тест 15
**HAVING ба WHERE-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) WHERE = GROUP BY-н ӨМНӨ мөр шүүх, HAVING = GROUP BY-н ДАРАА бүлэг шүүх
- C) WHERE нь агрегатад ашиглагдана
- D) HAVING нь мөр бүрт
**Зөв хариулт: B**
> **Тайлбар:** WHERE = Мөр бүрт нөхцөл (GROUP BY-н өмнө). HAVING = Бүлэг бүрт нөхцөл (GROUP BY-н дараа). `HAVING AVG(gpa) > 3.5` = Дундаж GPA > 3.5 бүлгүүд.
## Тест 16
**Индекс (Index) юу хийдэг вэ?**
- A) Өгөгдөл устгах
- B) Хайлтыг ХУРДАСГАХ тусгай бүтэц — Full Table Scan-аас зайлсхийх
- C) Хүснэгт үүсгэх
- D) FK нэмэх
**Зөв хариулт: B**
> **Тайлбар:** Индекс = Номын каталог шиг. B-Tree бүтцээр хурдан олно. Индексгүй = 1,000,000 мөрийг нэг нэгээр шалгана (Full Scan).
## Тест 17
**Индексийн сул тал юу вэ?**
- A) Сул талгүй
- B) INSERT/UPDATE/DELETE-ийг УДААШРУУЛНА — Индексийг ч шинэчлэх шаардлагатай
- C) SELECT удаашруулна
- D) Хүснэгт устна
**Зөв хариулт: B**
> **Тайлбар:** Индекс = READ хурдасгана, WRITE удаашруулна. Мөр нэмэх/устгахад индексийг ч шинэчлэх → Хэтэрхий олон индекс = WRITE удаан.
## Тест 18
**Transaction (Гүйлгээ) гэж юу вэ?**
- A) Нэг SQL команд
- B) Олон үйлдлийн НЭГ логик нэгж — бүгд амжилттай эсвэл бүгд буцаагдах
- C) Зөвхөн SELECT
- D) Индекс
**Зөв хариулт: B**
> **Тайлбар:** Transaction = Мөнгө шилжүүлэх (хасах + нэмэх) = 1 transaction. Нэг алдаа → Бүгд ROLLBACK. Хоёулаа амжилттай → COMMIT.
## Тест 19
**ACID зарчмын "A" (Atomicity) юу вэ?**
- A) Хурд
- B) Бүгд эсвэл юу ч ҮГҮЙ — Transaction дотор бүх үйлдэл амжилттай эсвэл бүгд буцна
- C) Нэвтрэлт
- D) Индекс
**Зөв хариулт: B**
> **Тайлбар:** Atomicity = "All or Nothing". Мөнгө хасагдсан, гэхдээ нөгөө рүү нэмэгдээгүй = БАЙЖ БОЛОХГҮЙ. Бүгд эсвэл юу ч үгүй.
## Тест 20
**ACID зарчмын "I" (Isolation) юу вэ?**
- A) Хурд
- B) Зэрэг ажиллаж буй transaction-ууд бие биедээ НӨЛӨӨЛӨХГҮЙ
- C) Өгөгдөл хадгалагдах
- D) Бүгд эсвэл юу ч үгүй
**Зөв хариулт: B**
> **Тайлбар:** Isolation = Transaction A ажиллаж байхад Transaction B-ийн хийж буй өөрчлөлтийг харахгүй. Isolation Level-ээр зохицуулна.
## Тест 21
**COMMIT ба ROLLBACK-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) COMMIT = Өөрчлөлтийг БАТАЛГААЖУУЛЖ хадгалах, ROLLBACK = Бүгдийг БУЦААХ
- C) Хоёулаа устгах
- D) Хоёулаа нэмэх
**Зөв хариулт: B**
> **Тайлбар:** COMMIT = "Зөв! Хадгал." ROLLBACK = "Буруу! Буцаа." Transaction дотор алдаа гарвал ROLLBACK → Өгөгдөл хэвээрээ.
## Тест 22
**`DELETE FROM students WHERE id = 1` юу хийдэг вэ?**
- A) Бүх оюутнуудыг устгах
- B) ID=1 оюутны мөрийг УСТГАХ
- C) Хүснэгтийг устгах
- D) GPA шинэчлэх
**Зөв хариулт: B**
> **Тайлбар:** DELETE + WHERE = Нөхцөлд тохирох мөрийг устгана. ⚠️ WHERE-гүй бол БҮГДИЙГ устгана! Болгоомжтой!
## Тест 23
**`DROP TABLE students` ба `TRUNCATE TABLE students`-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) DROP = Хүснэгтийг БҮТЦИЙН ХАМТ устгах, TRUNCATE = Бүх мөрийг устгах (бүтэц хадгалах)
- C) Хоёулаа бүтэц хадгалах
- D) Хоёулаа бүтэц устгах
**Зөв хариулт: B**
> **Тайлбар:** DROP = Хүснэгт алга болно. TRUNCATE = Хүснэгт хоосорно (бүтэц хэвээрээ). DELETE = WHERE-тэй мөр устгах.
## Тест 24
**Subquery (Дэд асуулга) гэж юу вэ?**
- A) Хоёр хүснэгт холбох
- B) SELECT дотор SELECT — Нэг query-ийн ÜР ДҮНГ нөгөөд ашиглах
- C) Индекс
- D) Transaction
**Зөв хариулт: B**
> **Тайлбар:** `WHERE gpa > (SELECT AVG(gpa) FROM students)` = Дундаж GPA-аас дээш. Дотоод SELECT эхлээд ажиллаж, үр дүнг гадна SELECT-д дамжуулна.
## Тест 25
**`NOT NULL` constraint юу хийдэг вэ?**
- A) NULL утга оноох
- B) Багана NULL утга авахыг ХОРИГЛОХ — Заавал утга оруулна
- C) Индекс нэмэх
- D) FK нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `name VARCHAR(100) NOT NULL` = Нэр ЗААВАЛ оруулна. NULL утга = "Мэдэхгүй" → NOT NULL = Өгөгдлийн бүрэн бүтэн байдал.
## Тест 26
**`UNIQUE` constraint юу хийдэг вэ?**
- A) PK болгох
- B) Баганын утга ДАВТАГДАХГҮЙ — Ижил утга 2 мөрөнд байхгүй
- C) NOT NULL нэмэх
- D) FK нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `email VARCHAR(150) UNIQUE` = 2 оюутан ижил имэйлтэй байж болохгүй. PK-аас ялгаа: UNIQUE багана NULL байж болно.
## Тест 27
**`CHECK` constraint юу хийдэг вэ?**
- A) Хүснэгт үүсгэх
- B) Баганын утгад НӨХЦӨЛ тавих — `CHECK (gpa >= 0 AND gpa <= 4)`
- C) FK нэмэх
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** CHECK = Бизнес дүрэм DB түвшинд. GPA 0-4, credits 1-6 зэрэг. Буруу утга оруулахаас хамгаална.
## Тест 28
**`ON DELETE CASCADE` юу хийдэг вэ?**
- A) Юу ч хийхгүй
- B) Эцэг хүснэгтийн мөр устахад хүүхэд хүснэгтийн холбоотой мөрүүдийг АВТОМАТААР устгах
- C) FK арилгах
- D) PK арилгах
**Зөв хариулт: B**
> **Тайлбар:** `FOREIGN KEY (student_id) REFERENCES students(id) ON DELETE CASCADE` = Оюутан устгахад түүний бүртгэл (enrollments) автоматаар устна.
## Тест 29
**`ORDER BY gpa DESC` юу хийдэг вэ?**
- A) GPA нэмэгдэх дарааллаар
- B) GPA БУУРАХ дарааллаар эрэмбэлэх
- C) GPA устгах
- D) GPA шинэчлэх
**Зөв хариулт: B**
> **Тайлбар:** DESC = Descending (буурах). ASC = Ascending (өсөх, default). `ORDER BY gpa DESC` = 4.0 → 3.5 → 3.0...
## Тест 30
**`LIMIT 10 OFFSET 20` юу хийдэг вэ?**
- A) 10 мөр устгах
- B) Эхний 20 мөрийг АЛГАСАЖ, дараагийн 10 мөрийг авах (3-р хуудас)
- C) 20 мөр нэмэх
- D) Бүх мөр авах
**Зөв хариулт: B**
> **Тайлбар:** LIMIT 10 = 10 мөр авах. OFFSET 20 = Эхний 20-ийг алгасах. Хуудаслалт: page 3, size 10 = OFFSET 20 LIMIT 10.
## Тест 31
**`COUNT(*)` функц юу хийдэг вэ?**
- A) Мөр устгах
- B) Мөрийн ТООГ тоолох
- C) Дундаж тооцоолох
- D) Мөр нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `SELECT COUNT(*) FROM students` = Нийт оюутны тоо. `COUNT(column)` = NULL биш утгуудыг тоолно.
## Тест 32
**`AVG(gpa)` функц юу хийдэг вэ?**
- A) Хамгийн их GPA
- B) GPA-ийн ДУНДАЖИЙГ тооцоолох
- C) GPA-ийн нийлбэр
- D) Хамгийн бага GPA
**Зөв хариулт: B**
> **Тайлбар:** AVG = Average (дундаж). `SELECT AVG(gpa) FROM students` = Бүх оюутны GPA-ийн дундаж. NULL утгуудыг тооцохгүй.
## Тест 33
**JPA `@ManyToOne` annotation юу хийдэг вэ?**
- A) Хүснэгт үүсгэх
- B) Олон → Нэг харилцаа тодорхойлох — FK одоогийн Entity-д
- C) PK тодорхойлох
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `@ManyToOne` = Олон оюутан → Нэг тэнхим. Student Entity-д `department_id` FK. `@JoinColumn(name = "department_id")`.
## Тест 34
**FetchType.LAZY ба FetchType.EAGER-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) LAZY = Шаардлагатай үед ачаална, EAGER = Шууд бүгдийг ачаална
- C) LAZY = Хурдан, EAGER = Удаан
- D) LAZY = Бүгдийг, EAGER = Зарим
**Зөв хариулт: B**
> **Тайлбар:** LAZY = `student.getDepartment()` дуудахад л DB query. EAGER = Student ачаалахад Department ч шууд. LAZY = N+1 асуудалтай, EAGER = Хэт олон ачаалах.
## Тест 35
**N+1 асуудал гэж юу вэ?**
- A) Нэрлэлтийн асуудал
- B) 1 query-ээр жагсаалт авч, бичлэг БҮРД нэмэлт query ажиллуулах → N+1 query
- C) Зөвхөн индексийн асуудал
- D) Зөвхөн тестийн асуудал
**Зөв хариулт: B**
> **Тайлбар:** 100 оюутан (1 query) + тэнхим нь бүрт (100 query) = 101 query! `JOIN FETCH`, `@EntityGraph`-аар 1 query-ээр шийднэ.
## Тест 36
**Surrogate Key ба Natural Key-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) Surrogate = Бизнес утгагүй (auto-increment ID), Natural = Бизнес утгатай (email, ИД дугаар)
- C) Хоёулаа auto-increment
- D) Хоёулаа бизнес утгатай
**Зөв хариулт: B**
> **Тайлбар:** Surrogate Key = 1, 2, 3 (бизнес утгагүй, уян хатан). Natural Key = email (бизнес дүрэм өөрчлөгдвөл эвдрэх эрсдэлтэй). Surrogate илүү тохиромжтой.
## Тест 37
**Composite Key гэж юу вэ?**
- A) Нэг баганат PK
- B) 2 ба түүнээс олон баганаас бүрдсэн PK — `PRIMARY KEY (student_id, course_id)`
- C) FK
- D) Индекс
**Зөв хариулт: B**
> **Тайлбар:** Composite Key = Завсрын хүснэгтэд (enrollments) ашигладаг. `(student_id, course_id)` хос = Давтагдашгүй. Нэг оюутан нэг хичээлд нэг удаа.
## Тест 38
**`ALTER TABLE students ADD COLUMN phone VARCHAR(20)` юу хийдэг вэ?**
- A) Хүснэгт устгах
- B) students хүснэгтэд phone БАГАНА НЭМЭХ
- C) Мөр нэмэх
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** ALTER TABLE = Хүснэгтийн БҮТЦИЙГ өөрчлөх (DDL). ADD COLUMN = Шинэ багана нэмэх. DROP COLUMN = Багана устгах.
## Тест 39
**`INSERT INTO students (name, email) VALUES ('Бат', 'bat@test.com')` юу хийдэг вэ?**
- A) Мөр устгах
- B) students хүснэгтэд шинэ мөр НЭМЭХ
- C) Мөр шинэчлэх
- D) Хүснэгт үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** INSERT = Шинэ мөр нэмэх (DML). VALUES дахь утгууд баганын дарааллаар оруулагдана.
## Тест 40
**`UPDATE students SET gpa = 3.80 WHERE id = 1` юу хийдэг вэ?**
- A) Бүх GPA-г шинэчлэх
- B) ID=1 оюутны GPA-г 3.80 болгож ШИНЭЧЛЭХ
- C) Мөр устгах
- D) Хүснэгт үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** UPDATE + WHERE = Нөхцөлд тохирох мөрийг шинэчлэх. ⚠️ WHERE-гүй бол БҮГДИЙГ шинэчилнэ!
## Тест 41
**`LIKE 'Бат%'` юу хийдэг вэ?**
- A) Яг "Бат" тэнцүү
- B) "Бат"-аар ЭХЭЛСЭН бүх утгуудыг хайх (Батболд, Батсайхан...)
- C) "Бат"-аар төгссөн
- D) "Бат" агуулсан
**Зөв хариулт: B**
> **Тайлбар:** `%` = 0 ба түүнээс олон тэмдэгт. `'Бат%'` = Бат-аар эхэлсэн. `'%бат'` = бат-аар төгссөн. `'%бат%'` = бат агуулсан.
## Тест 42
**`BETWEEN 3.0 AND 3.5` юу хийдэг вэ?**
- A) 3.0-аас бага
- B) 3.0 ба 3.5-ийн ХООРОНД (хоёулангийг оролцуулсан)
- C) 3.5-аас их
- D) Зөвхөн 3.0
**Зөв хариулт: B**
> **Тайлбар:** `BETWEEN 3.0 AND 3.5` = `gpa >= 3.0 AND gpa <= 3.5`. Хоёр хязгаарыг ОРОЛЦУУЛНА (inclusive).
## Тест 43
**`IN (1, 2, 3)` юу хийдэг вэ?**
- A) 1, 2, 3 нийлбэр
- B) Утга нь 1, 2, 3-ийн АЛЬ НЭГТЭЙ тэнцүү эсэхийг шалгах
- C) 1-ээс 3 хүртэл
- D) 3 мөр нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `WHERE department_id IN (1, 2, 3)` = `department_id = 1 OR department_id = 2 OR department_id = 3`. Олон OR-ийн товчлол.
## Тест 44
**`IS NULL` ба `= NULL`-ийн ялгаа юу вэ?**
- A) Ялгаагүй
- B) `IS NULL` = NULL утга шалгах ЗӨВ арга, `= NULL` = Үргэлж FALSE (буруу)
- C) Хоёулаа зөв
- D) Хоёулаа буруу
**Зөв хариулт: B**
> **Тайлбар:** SQL-д NULL = NULL → UNKNOWN (TRUE биш!). NULL утгыг шалгахад `IS NULL`, `IS NOT NULL` ашиглана. `= NULL` хэзээ ч TRUE буцаахгүй.
## Тест 45
**`DISTINCT` юу хийдэг вэ?**
- A) Мөр устгах
- B) Давтагдсан утгуудыг АРИЛГАЖ, зөвхөн давтагдашгүй утгуудыг буцаах
- C) Мөр нэмэх
- D) Эрэмбэлэх
**Зөв хариулт: B**
> **Тайлбар:** `SELECT DISTINCT status FROM students` = ACTIVE, INACTIVE, GRADUATED (давтагдашгүй). 100 оюутнаас зөвхөн 3 статус.
## Тест 46
**View (Харагдац) гэж юу вэ?**
- A) Шинэ хүснэгт
- B) Хадгалагдсан SELECT query — Виртуал хүснэгт шиг ашиглагдах
- C) Индекс
- D) Transaction
**Зөв хариулт: B**
> **Тайлбар:** `CREATE VIEW active_students AS SELECT * FROM students WHERE status = 'ACTIVE'` → `SELECT * FROM active_students` = Идэвхтэй оюутнуудыг хялбар авах.
## Тест 47
**Stored Procedure юу вэ?**
- A) Java код
- B) DB-д ХАДГАЛАГДСАН SQL логик — Олон SQL командыг нэг нэрээр дуудах
- C) Индекс
- D) Тест
**Зөв хариулт: B**
> **Тайлбар:** Stored Procedure = DB серверт ажиллана. Сүлжээний зардал бага (олон SQL → нэг дуудалт). Гэхдээ debug, version control хэцүү.
## Тест 48
**Trigger юу хийдэг вэ?**
- A) Гараар ажиллуулах
- B) INSERT/UPDATE/DELETE-д АВТОМАТААР ажиллах DB логик
- C) Индекс нэмэх
- D) Хүснэгт устгах
**Зөв хариулт: B**
> **Тайлбар:** `AFTER INSERT ON students` = Оюутан нэмэгдэхэд автоматаар audit_log хүснэгтэд бичлэг нэмэх. ⚠️ Хэтэрхий олон trigger = Debug хэцүү.
## Тест 49
**ORM (Object-Relational Mapping) юу хийдэг вэ?**
- A) HTML үүсгэх
- B) Java объект ↔ DB хүснэгт автоматаар ЗУРАГЛАХ — SQL-гүйгээр CRUD хийх
- C) Тест ажиллуулах
- D) API үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** ORM = Student объект → students хүснэгт. `repository.save(student)` → INSERT SQL автомат. Hibernate = JPA-ийн хамгийн түгээмэл ORM.
## Тест 50
**`@GeneratedValue(strategy = GenerationType.IDENTITY)` юу хийдэг вэ?**
- A) Гараар ID оноох
- B) DB автоматаар ID үүсгэх (AUTO INCREMENT)
- C) UUID үүсгэх
- D) Timestamp үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** IDENTITY = DB-ийн auto-increment. 1, 2, 3... автоматаар. SEQUENCE = DB sequence ашиглах. UUID = Давтагдашгүй 128-bit ID.
## Тест 51
**`@Enumerated(EnumType.STRING)` юу хийдэг вэ?**
- A) Тоогоор хадгалах
- B) Enum утгыг DB-д STRING болгон хадгалах — "ACTIVE", "INACTIVE"
- C) JSON-д хөрвүүлэх
- D) Validation хийх
**Зөв хариулт: B**
> **Тайлбар:** STRING = "ACTIVE" хадгалагдана. ORDINAL = 0, 1, 2 (Enum дарааллыг өөрчлөвөл эвдэрнэ!). STRING = Аюулгүй, ойлгомжтой.
## Тест 52
**`@JoinColumn(name = "department_id")` юу хийдэг вэ?**
- A) PK тодорхойлох
- B) FK БАГАНЫН нэрийг тодорхойлох — DB-д department_id багана
- C) Индекс нэмэх
- D) Хүснэгт үүсгэх
**Зөв хариулт: B**
> **Тайлбар:** `@JoinColumn` = Харилцааны FK багана. `@ManyToOne` + `@JoinColumn(name = "department_id")` = students.department_id → departments.id.
## Тест 53
**`CascadeType.ALL` юу хийдэг вэ?**
- A) Юу ч хийхгүй
- B) Эцэг Entity-д хийсэн үйлдлийг хүүхэд Entity-д ч АВТОМАТААР хийх (persist, merge, remove...)
- C) Зөвхөн устгах
- D) Зөвхөн нэмэх
**Зөв хариулт: B**
> **Тайлбар:** `CascadeType.ALL` = Student хадгалахад Profile ч хадгалагдана. Student устгахад Profile ч устагдана. Бүх үйлдэл "cascade" хийгдэнэ.
## Тест 54
**`@JoinTable` annotation хэзээ ашигладаг вэ?**
- A) 1:1 харилцаанд
- B) Many-to-Many харилцааны ЗАВСРЫН ХҮСНЭГТИЙГ тодорхойлоход
- C) 1:N харилцаанд
- D) Индекс нэмэхэд
**Зөв хариулт: B**
> **Тайлбар:** `@JoinTable(name = "enrollments", joinColumns = ..., inverseJoinColumns = ...)` = M:N харилцааны enrollments завсрын хүснэгт.
## Тест 55
**Denormalization гэж юу вэ?**
- A) Нормалчлал хийх
- B) Performance-ийн тулд зориудаар ДАВХАРДУУЛАХ — JOIN-ийн тоог бууруулах
- C) Хүснэгт устгах
- D) Индекс нэмэх
**Зөв хариулт: B**
> **Тайлбар:** Нормалчлал = Давхардал арилгах (бүрэн бүтэн байдал). Denormalization = Давхардуулах (хурд). Read-heavy системд зарим талбарыг давхардуулж JOIN-ийг багасгана.
## Тест 56
**Дараах SQL-д юу буруу вэ?**
```sql
SELECT department_id, name, COUNT(*)
FROM students
GROUP BY department_id;
- A) Бүх зүйл зөв
- B)
nameнь GROUP BY-д ОРООГҮЙ ч SELECT-д байна — Алдаа - C) COUNT(*) буруу
- D) FROM буруу
Зөв хариулт: B
Тайлбар: GROUP BY-д ороогүй багана SELECT-д агрегатгүйгээр байж БОЛОХГҮЙ. Аль оюутны нэрийг харуулах вэ? → Тодорхойгүй.
nameGROUP BY-д нэмэх эсвэл хасах.
Тест 57
COALESCE(phone, 'N/A') юу хийдэг вэ?
- A) Хоёр утгыг нийлүүлэх
- B) phone NULL бол 'N/A' буцаах — NULL утгыг ОРЛУУЛАХ
- C) phone устгах
- D) phone шинэчлэх
Зөв хариулт: B
Тайлбар: COALESCE = Эхний NULL биш утгыг буцаана.
COALESCE(phone, mobile, 'N/A')= phone → mobile → 'N/A' (бүгд NULL бол).
Тест 58
"Dirty Read" гэж юу вэ?
- A) Зөв уншилт
- B) COMMIT хийгдээгүй өөрчлөлтийг унших — Transaction B ROLLBACK хийвэл буруу мэдээлэл
- C) Удаан уншилт
- D) Индексгүй уншилт
Зөв хариулт: B
Тайлбар: Dirty Read = Transaction A GPA-г 3.5 → 4.0 болгосон (COMMIT-гүй). Transaction B 4.0-г уншина. A ROLLBACK хийвэл B буруу мэдээлэл ашиглаж байна.
Тест 59
READ COMMITTED isolation level юу хийдэг вэ?
- A) Бүх асуудлыг шийднэ
- B) Зөвхөн COMMIT хийгдсэн өгөгдлийг уншина — Dirty Read-аас хамгаална
- C) Бүх уншилтыг хориглоно
- D) Transaction ашиглахгүй
Зөв хариулт: B
Тайлбар: READ COMMITTED = PostgreSQL-ийн default. COMMIT хийгдсэн л бол унших → Dirty Read БОЛОХГҮЙ. Гэхдээ Non-Repeatable Read болж болно.
Тест 60
EXPLAIN ANALYZE юу хийдэг вэ?
- A) Мөр устгах
- B) SQL query-ийн ГҮЙЦЭТГЭЛИЙН ТӨЛӨВЛӨГӨӨГ харуулах — хурд, индекс ашиглалтыг шинжлэх
- C) Хүснэгт үүсгэх
- D) Мөр нэмэх
Зөв хариулт: B
Тайлбар:
EXPLAIN ANALYZE SELECT * FROM students WHERE email = 'bat@test.com'→ Seq Scan (Full Scan) эсвэл Index Scan, query хугацаа, зардал (cost) харуулна.
Тест 61
B-Tree индекс юу вэ?
- A) Binary Tree
- B) Тэнцвэрт мод бүтэц —
=,<,>,BETWEEN,ORDER BYхайлтад тохиромжтой DEFAULT индекс - C) Hash функц
- D) Array бүтэц
Зөв хариулт: B
Тайлбар: B-Tree = PostgreSQL, MySQL-ийн default индекс. Бүх төрлийн хайлтад ашиглагдана. Тэнцвэрт → O(log n) хурдтай.
Тест 62
Partial Index юу вэ?
- A) Бүх мөрөнд индекс
- B) Зөвхөн НӨХЦӨЛД тохирох мөрүүдэд индекс —
WHERE status = 'ACTIVE' - C) Нэг баганат индекс
- D) Олон баганат индекс
Зөв хариулт: B
Тайлбар:
CREATE INDEX idx_active ON students(email) WHERE status = 'ACTIVE'= Зөвхөн идэвхтэй оюутнуудын email-д индекс. Жижиг, хурдан.
Тест 63
Мөнгөн дүнд ямар төрөл ашиглах вэ?
- A) FLOAT
- B) DECIMAL / NUMERIC — Нарийвчлал алдагдахгүй
- C) DOUBLE
- D) INTEGER
Зөв хариулт: B
Тайлбар: FLOAT/DOUBLE = Бутархай тооны нарийвчлал алдагдна (0.1 + 0.2 ≠ 0.3). DECIMAL = Яг тодорхой нарийвчлал. Мөнгө, GPA = DECIMAL.
Тест 64
"Soft Delete" гэж юу вэ?
- A) Бүрмөсөн устгах
- B) Мөрийг УСТГАХГҮЙГЭЭР
deleted_atбаганад цаг тэмдэглэх — Сэргээх боломжтой - C) Хүснэгт устгах
- D) Индекс устгах
Зөв хариулт: B
Тайлбар: Hard Delete =
DELETE FROM students WHERE id = 1(бүрмөсөн). Soft Delete =UPDATE students SET deleted_at = NOW() WHERE id = 1.WHERE deleted_at IS NULLшүүнэ.
Тест 65
@Transactional annotation (Spring) юу хийдэг вэ?
- A) Тест зарлах
- B) Методын бүх DB үйлдлийг НЭГ transaction-д багтааж, алдаа гарвал ROLLBACK
- C) Лог бичих
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
@Transactional= enrollStudentInCourse() дотор 3 DB үйлдэл. Алдаа гарвал бүгд ROLLBACK. Spring AOP proxy-ээр удирдана.
Тест 66
NoSQL мэдээллийн сангийн давуу тал юу вэ?
- A) JOIN хийж чадна
- B) Уян хатан schema, хэвтээ scale, том хэмжээний өгөгдөлд тохиромжтой
- C) ACID бүрэн дэмждэг
- D) SQL хэл ашиглана
Зөв хариулт: B
Тайлбар: NoSQL = Schema-free (багана нэмэхэд ALTER TABLE шаардлагагүй). Horizontal scaling (сервер нэмэх). Том өгөгдөл, хурдан бичих. Гэхдээ JOIN хэцүү.
Тест 67
MongoDB юу вэ?
- A) RDBMS
- B) Document-based NoSQL — JSON (BSON) формат document хадгалах
- C) Key-Value store
- D) Graph DB
Зөв хариулт: B
Тайлбар: MongoDB = JSON-тэй адил document. Nested object, array хадгалж болно. Schema уян хатан. Вэб апп, CMS, бүртгэлд тохиромжтой.
Тест 68
Redis юу вэ?
- A) RDBMS
- B) In-memory Key-Value NoSQL — КЭШ, session хадгалалтад маш хурдан
- C) Document DB
- D) Graph DB
Зөв хариулт: B
Тайлбар: Redis = RAM-д хадгалдаг → Микросекундын хурдтай. Кэш (DB query үр дүнг хадгалах), session, rate limiting, queue-д ашиглана.
Тест 69
@Query annotation (Spring Data JPA) юу хийдэг вэ?
- A) Хүснэгт үүсгэх
- B) Гарын авлагын JPQL эсвэл native SQL query тодорхойлох
- C) Индекс нэмэх
- D) Transaction удирдах
Зөв хариулт: B
Тайлбар:
@Query("SELECT s FROM Student s JOIN FETCH s.department")= JPQL query.nativeQuery = trueбол шууд SQL. Spring Data-ийн автомат method naming-ээс нарийн query хэрэгтэй үед.
Тест 70
mappedBy parameter юу хийдэг вэ?
- A) FK үүсгэх
- B) Харилцааны НӨГӨӨ талыг зааж, FK ЭНЭ хүснэгтэд БАЙХГҮЙГ илэрхийлэх
- C) PK тодорхойлох
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
@OneToMany(mappedBy = "department")= FK нь Student талд (department_id). Department хүснэгтэд FK БАЙХГҮЙ. mappedBy = "Би FK эзэмшигч биш".
Тест 71
Database Migration гэж юу вэ?
- A) DB устгах
- B) DB-ийн schema-ийн өөрчлөлтийг ХУВИЛБАРТАЙГААР удирдах — Flyway, Liquibase
- C) Мөр нэмэх
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар: Migration = Git for DB schema. V1__create_students.sql → V2__add_phone.sql. Бүх хөгжүүлэгч ижил schema-тай. Flyway, Liquibase = Java-д түгээмэл.
Тест 72
ddl-auto=validate юу хийдэг вэ?
- A) Хүснэгт үүсгэх
- B) Entity ба DB schema ТОХИРЧ БАЙГААГ шалгах — Тохирохгүй бол алдаа
- C) Хүснэгт устгах
- D) Мөр нэмэх
Зөв хариулт: B
Тайлбар:
validate= Production-д тохиромжтой. Entity ба DB schema-г харьцуулж, зөрүүтэй бол програм эхлэхгүй.create-drop= Зөвхөн хөгжүүлэлтэд!
Тест 73
Дараах аль нь зөв DB нэрлэлт вэ?
- A)
StudentProfiles(PascalCase) - B)
student_profiles(snake_case, олон тоо) - C)
studentProfile(camelCase) - D)
STUDENT_PROFILE(UPPER_CASE)
Зөв хариулт: B
Тайлбар: DB нэрлэлт стандарт: snake_case + олон тоо.
students,student_profiles,created_at. Java-д camelCase, DB-д snake_case.
Тест 74
created_at ба updated_at баганууд яагаад хэрэгтэй вэ?
- A) Шаардлагагүй
- B) AUDIT TRAIL — Мөр хэзээ үүссэн, хэзээ шинэчлэгдсэнийг мэдэх
- C) Зөвхөн formат
- D) Зөвхөн тест
Зөв хариулт: B
Тайлбар: Audit trail = "Хэзээ хэн юу хийсэн?"
created_at= Үүссэн.updated_at= Шинэчлэгдсэн. Debug, report, compliance-д чухал.
Тест 75
Дараах SQL-ийн үр дүн юу вэ?
SELECT COUNT(*) FROM students WHERE gpa IS NULL;
- A) Бүх оюутны тоо
- B) GPA утга NULL (оруулаагүй) оюутнуудын ТОО
- C) Бүх GPA-ийн нийлбэр
- D) Алдаа
Зөв хариулт: B
Тайлбар:
WHERE gpa IS NULL= GPA утга оруулаагүй мөрүүд.COUNT(*)= Тэдний тоо. NULL = "Утга байхгүй" (0 биш!).
Тест 76
UNION ба UNION ALL-ийн ялгаа юу вэ?
- A) Ялгаагүй
- B) UNION = Давтагдсан мөрийг АРИЛГАХ, UNION ALL = Бүгдийг ХАДГАЛАХ
- C) UNION ALL удаан
- D) UNION хурдан
Зөв хариулт: B
Тайлбар: UNION = DISTINCT (давтагдал арилгах → нэмэлт зардал). UNION ALL = Бүгдийг (хурдан). Давтагдал байхгүй гэдэг итгэлтэй бол UNION ALL ашиглах.
Тест 77
EXISTS юу хийдэг вэ?
- A) Мөр нэмэх
- B) Дэд query-ийн ÜР ДҮН БАЙГАА ЭСЭХИЙГ шалгах (TRUE/FALSE)
- C) Мөр устгах
- D) Хүснэгт үүсгэх
Зөв хариулт: B
Тайлбар:
WHERE EXISTS (SELECT 1 FROM enrollments WHERE student_id = s.id)= Хичээлд бүртгэлтэй оюутнууд.NOT EXISTS= Бүртгэлгүй оюутнууд.
Тест 78
CASE WHEN expression юу хийдэг вэ?
- A) Transaction удирдах
- B) SQL дотор НӨХЦӨЛТ логик (if-else) хэрэгжүүлэх
- C) Индекс нэмэх
- D) FK нэмэх
Зөв хариулт: B
Тайлбар:
CASE WHEN gpa >= 3.5 THEN 'Excellent' WHEN gpa >= 3.0 THEN 'Good' ELSE 'Average' END= GPA-аас хамааран ангилал оноох.
Тест 79
Database Connection Pool гэж юу вэ?
- A) Нэг холболт
- B) Урьдчилан нээлттэй DB холболтуудын САНГАС — Шинэ холболт нээх зардлыг бууруулах
- C) Индекс
- D) Transaction
Зөв хариулт: B
Тайлбар: Connection Pool = HikariCP (Spring Boot default). Холболтуудыг нээж бэлэн байлгана → Хүсэлт бүрт шинэ холболт нээхгүй (3-5ms хэмнэнэ).
Тест 80
spring.datasource.url юу хийдэг вэ?
- A) API URL тохируулах
- B) DB-ийн ХОЛБОЛТЫН URL тодорхойлох —
jdbc:postgresql://localhost:5432/mydb - C) Frontend URL
- D) Тестийн URL
Зөв хариулт: B
Тайлбар:
jdbc:postgresql://localhost:5432/mydb= PostgreSQL, localhost, port 5432, mydb database. H2:jdbc:h2:mem:testdb.
Тест 81
Referential Integrity гэж юу вэ?
- A) Индексийн бүтэн байдал
- B) FK-ийн заасан PK ЗААВАЛ байх — Байхгүй PK руу FK заах боломжгүй
- C) Нэрлэлтийн дүрэм
- D) Transaction дүрэм
Зөв хариулт: B
Тайлбар:
student_id = 999→ students хүснэгтэд id=999 БАЙХ ЁСТОЙ. Байхгүй бол DB алдаа буцаана. FK = Мэдээллийн бүрэн бүтэн байдлын хамгаалагч.
Тест 82
SERIAL ба GENERATED ALWAYS AS IDENTITY-ийн ялгаа юу вэ?
- A) Ялгаагүй
- B) SERIAL = Хуучин PostgreSQL, IDENTITY = SQL стандарт, илүү АЮУЛГҮЙ (гараар утга оноохыг хориглоно)
- C) SERIAL = Шинэ
- D) IDENTITY = Хуучин
Зөв хариулт: B
Тайлбар:
GENERATED ALWAYS AS IDENTITY= SQL:2003 стандарт. Гараар INSERT хийхэд ID оруулж БОЛОХГҮЙ → Бүрэн автомат. SERIAL = Legacy, гараар override хийж болно.
Тест 83
@EntityGraph annotation юу хийдэг вэ?
- A) Entity үүсгэх
- B) JPA query-д аль харилцааг НИЙЛҮҮЛЖ ачаалахыг тодорхойлох — N+1 шийдэл
- C) Индекс нэмэх
- D) Transaction удирдах
Зөв хариулт: B
Тайлбар:
@EntityGraph(attributePaths = {"department"})= findAll() дуудахад department-ийг нэг query-ээр (JOIN) ачаална. N+1 асуудлын нэг шийдэл.
Тест 84
Optimistic Locking гэж юу вэ?
- A) Хүснэгт түгжих
- B)
@Versionашиглаж, update хийхдээ ХУВИЛБАР шалгах — Зэрэг update хийвэл алдаа - C) Мөр устгах
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
@Version private Long version;→ A version=1-ийг update хийж version=2 болгоно. B ч version=1-ийг update хийхийг оролдвол → OptimisticLockException. Зөрчилдлийг шийднэ.
Тест 85
JSONB төрөл (PostgreSQL) юу вэ?
- A) Текст
- B) JSON өгөгдлийг BINARY хэлбэрээр хадгалах — Хайлт, индекс хурдан
- C) Тоо
- D) Огноо
Зөв хариулт: B
Тайлбар: JSONB = JSON Binary. PostgreSQL-д JSON өгөгдлийг хадгалж, дотор нь хайх, индекс нэмэх боломжтой.
metadata->>'key'= JSON утга авах.
Тест 86
Data Integrity-ийн 3 түвшин юу вэ?
- A) Зөвхөн нэг түвшин
- B) Entity Integrity (PK), Referential Integrity (FK), Domain Integrity (CHECK, NOT NULL)
- C) Зөвхөн PK
- D) Зөвхөн FK
Зөв хариулт: B
Тайлбар: Entity = PK давтагдашгүй. Referential = FK заасан бичлэг байх. Domain = Утгын хязгаар (GPA 0-4, email формат). 3 түвшин = Өгөгдлийн чанар.
Тест 87
Window Function юу хийдэг вэ?
- A) UI үүсгэх
- B) Мөр бүрт бүлгийн тооцоолол хийх — GROUP BY шиг, гэхдээ мөр ХАДГАЛАГДАНА
- C) Хүснэгт үүсгэх
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
SELECT name, gpa, RANK() OVER (ORDER BY gpa DESC) FROM students= Мөр бүрт дараалал (rank) нэмнэ. GROUP BY = Мөр нэгтгэнэ. Window = Мөр хадгална.
Тест 88
ROW_NUMBER() функц юу хийдэг вэ?
- A) Мөр устгах
- B) Мөр бүрт дарааллын ДУГААР оноох (1, 2, 3...)
- C) Мөр нэмэх
- D) Тоолох
Зөв хариулт: B
Тайлбар:
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY gpa DESC)= Тэнхим бүрт GPA-аар дараалсан дугаар. Тэнхим бүрийн шилдэг 3-ыг олоход ашиглана.
Тест 89
Database Sharding гэж юу вэ?
- A) Backup хийх
- B) Өгөгдлийг олон серверт ХУВААРИЛАХ — Хэвтээ scaling
- C) Индекс нэмэх
- D) Нормалчлах
Зөв хариулт: B
Тайлбар: Sharding = Оюутан A-M → Сервер 1, N-Z → Сервер 2. Маш том өгөгдлийг нэг серверт багтаахгүй үед. Нарийн төвөгтэй, гэхдээ Scale хийнэ.
Тест 90
Database Replication гэж юу вэ?
- A) Мөр устгах
- B) Нэг DB-ийн хуулбарыг олон серверт ХАДГАЛАХ — Read scaling, backup
- C) Индекс нэмэх
- D) Schema өөрчлөх
Зөв хариулт: B
Тайлбар: Primary → Replica(s). Write = Primary. Read = Replica(s). Read олон, Write бага бол маш тохиромжтой. Failover: Primary унтарвал Replica = Primary болно.
Тест 91
spring.jpa.show-sql=true юу хийдэг вэ?
- A) SQL устгах
- B) Hibernate-ийн үүсгэсэн SQL query-г КОНСОЛД харуулах — Debug-д тустай
- C) SQL хурдасгах
- D) SQL кэшлэх
Зөв хариулт: B
Тайлбар:
show-sql=true→SELECT s FROM Student s WHERE s.id = ?консолд гарна. N+1 асуудлыг олж, query тоог шалгахад маш чухал.
Тест 92
VACUUM (PostgreSQL) юу хийдэг вэ?
- A) Мөр нэмэх
- B) Устгагдсан мөрүүдийн зайг ЧӨЛӨӨЛӨХ — DB-ийн хэмжээг бууруулах
- C) Индекс нэмэх
- D) Schema өөрчлөх
Зөв хариулт: B
Тайлбар: PostgreSQL-д DELETE хийхэд мөр "мэдэгдэнэ" (dead tuple), гэхдээ зай чөлөөлөгдөхгүй. VACUUM = Dead tuple-ийг цэвэрлэж зай чөлөөлнө. AUTOVACUUM = Автомат.
Тест 93
Materialized View юу вэ?
- A) Энгийн View
- B) Query-ийн ÜР ДҮНГ ХАДГАЛСАН View — Хурдан, гэхдээ REFRESH хийх шаардлагатай
- C) Хүснэгт
- D) Индекс
Зөв хариулт: B
Тайлбар: View = Дуудах бүрт query ажиллана (удаан). Materialized View = Үр дүнг хадгалж, хурдан авна.
REFRESH MATERIALIZED VIEW= Шинэчлэх.
Тест 94
WITH (CTE - Common Table Expression) юу хийдэг вэ?
- A) Хүснэгт үүсгэх
- B) Нарийн query-г нэртэй, уншигдахуйц хэсгүүдэд ХУВААХ
- C) Индекс нэмэх
- D) Transaction удирдах
Зөв хариулт: B
Тайлбар:
WITH top_students AS (SELECT ... WHERE gpa >= 3.5) SELECT * FROM top_students JOIN ...= Нарийн query-г хуваах. Уншихад хялбар, дахин ашиглах боломжтой.
Тест 95
pg_dump юу хийдэг вэ?
- A) DB устгах
- B) PostgreSQL мэдээллийн сангийн BACKUP (нөөц) файл үүсгэх
- C) DB шинэчлэх
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
pg_dump mydb > backup.sql= mydb-ийн бүх schema + өгөгдлийг SQL файл руу хадгалах.pg_restore= Сэргээх. Production-д backup ЗААВАЛ.
Тест 96
Connection Pool-ийн maximumPoolSize юу хийдэг вэ?
- A) Query хязгаарлах
- B) Нэгэн зэрэг нээлттэй байх DB холболтын ДЭЭД ХЯЗГААР тодорхойлох
- C) Мөр хязгаарлах
- D) Хүснэгт хязгаарлах
Зөв хариулт: B
Тайлбар: HikariCP
maximumPoolSize=10= Хамгийн ихдээ 10 зэрэг холболт. Хэтэрвэл хүлээнэ. Хэт бага = Удаан, хэт их = DB ачаалал.
Тест 97
@Embeddable ба @Embedded юу хийдэг вэ?
- A) Шинэ хүснэгт үүсгэх
- B) Нэг Entity дотор нэмэлт объект ШИНГЭЭХ — Тусдаа хүснэгтгүй
- C) FK нэмэх
- D) Индекс нэмэх
Зөв хариулт: B
Тайлбар:
@Embeddable class Address { city, street }+@Embedded private Address address;= Student хүснэгтэд city, street баганууд нэмэгдэнэ. Тусдаа address хүснэгт БАЙХГҮЙ.
Тест 98
SQL Injection гэж юу вэ?
- A) SQL сурах
- B) Хэрэглэгчийн оролтоор хортой SQL код ШИГТГЭЖ, DB-д зөвшөөрөгдөөгүй үйлдэл хийх
- C) Индекс нэмэх
- D) Backup хийх
Зөв хариулт: B
Тайлбар:
WHERE name = ''; DROP TABLE students; --'= Хэрэглэгч оролт → SQL-д шууд оруулна → Хүснэгт устгана! Prepared Statement / Parameterized Query ашиглаж сэргийлнэ.
Тест 99
Prepared Statement яагаад SQL Injection-аас хамгаалдаг вэ?
- A) Хурдан учраас
- B) Параметрийг SQL КОД биш, УТГА гэж боловсруулна —
?placeholder - C) Индекс ашигладаг
- D) Transaction ашигладаг
Зөв хариулт: B
Тайлбар:
WHERE name = ?+setString(1, userInput)→ userInput ="'; DROP TABLE--"байсан ч, SQL код биш ТЕКСТ утга гэж боловсруулна. JPA/Hibernate автоматаар Prepared Statement ашиглана.
Тест 100
Мэдээллийн сангийн дизайн яагаад програм хангамжийн бүтээлтэд хамгийн чухал вэ?
- A) Зөвхөн хадгалалт
- B) Сайн DB дизайн = Хурд, бүрэн бүтэн байдал, scale, аюулгүй байдал — Системийн СУУРЬ
- C) Зөвхөн query
- D) Зөвхөн backup
Зөв хариулт: B
Тайлбар: DB = Системийн суурь. Муу дизайн = Удаан query, давхардсан өгөгдөл, inconsistency, scale хийж чадахгүй. Сайн дизайн = Хурдан, найдвартай, өсгөж чадах систем. "Сайн суурь = Сайн байшин."
📚 Ашигласан эх сурвалжууд:
- C.J. Date — An Introduction to Database Systems (8th Edition)
- Abraham Silberschatz — Database System Concepts (7th Edition)
- PostgreSQL Official Documentation — postgresql.org/docs
- Spring Data JPA Reference — docs.spring.io/spring-data/jpa
- Vlad Mihalcea — High-Performance Java Persistence
- Use The Index, Luke — use-the-index-luke.com
- Hibernate ORM Documentation — hibernate.org/orm/documentation
- Martin Kleppmann — Designing Data-Intensive Applications (O'Reilly)