Files
ruoyi-vue-pro/sql/mysql/education/002-education-practice-session.sql

102 lines
6.6 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =============================================
-- Education 模块 — 练习会话与题目快照 DDL
-- Ticket #6: 练习会话创建、题目快照、恢复与状态机
-- Migration: 002
-- Prerequisites: 000-education-schema.sql (database creation)
-- 001-education-tenant-seed.sql (tenant seed data)
-- =============================================
-- =============================================
-- Preconditions
-- =============================================
-- This migration MUST fail if either table already exists (no IF NOT EXISTS).
-- Operator is expected to verify:
-- SELECT COUNT(*) FROM information_schema.tables
-- WHERE table_schema = DATABASE()
-- AND table_name IN ('education_practice_session', 'education_practice_question');
-- Result MUST be 0 before executing this migration.
-- =============================================
-- 练习会话表
-- =============================================
-- Indexes:
-- uk_tenant_client_session — per-tenant uniqueness for clientSessionId idempotency.
-- Used by: selectByTenantAndClientSessionId (idempotent create check),
-- DuplicateKeyException catch for concurrent-create race resolution.
-- idx_tenant_user_status — covers getCurrentSession (latest ACTIVE by tenant+user)
-- and ownership queries. Column order: (tenant_id, user_id, status) so the
-- index supports both filtering by tenant+user and tenant+user+status.
-- Lock impact: INSERT acquires next-key lock on uk_tenant_client_session unique key;
-- concurrent inserts with same (tenant_id, client_session_id) serialize naturally.
-- No additional table-level locks required.
CREATE TABLE `education_practice_session` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '会话主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`user_id` BIGINT NOT NULL COMMENT 'Member 用户编号',
`client_session_id` VARCHAR(36) NOT NULL COMMENT '客户端生成的会话标识UUID用于幂等创建',
`status` VARCHAR(20) NOT NULL DEFAULT 'ACTIVE'
COMMENT '会话状态ACTIVE-进行中, SUBMITTED-已提交, EXPIRED-已过期, CANCELLED-已取消',
`question_count` INT NOT NULL DEFAULT 0 COMMENT '题目总数',
`collection_id` VARCHAR(64) DEFAULT NULL COMMENT '源题集 ID',
`node_id` VARCHAR(64) DEFAULT NULL COMMENT '源目录节点 ID',
`type` VARCHAR(32) DEFAULT NULL COMMENT '筛选题型',
`difficulty` VARCHAR(32) DEFAULT NULL COMMENT '筛选难度',
`version` INT NOT NULL DEFAULT 0 COMMENT '乐观锁版本号',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_client_session` (`tenant_id`, `client_session_id`),
KEY `idx_tenant_user_status` (`tenant_id`, `user_id`, `status`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-练习会话';
-- =============================================
-- 练习会话题目快照表
-- =============================================
-- Indexes:
-- uk_session_sequence — per-session uniqueness for question sequence numbers.
-- Used by: insertBatch to ensure no duplicate sequences within a session.
-- idx_session_id — covers selectBySessionIdOrderBySequence (load all questions
-- for a session, ordered by sequence). Also used by cascade delete lookups.
-- Lock impact: INSERT acquires gap locks within session_id range on uk_session_sequence;
-- concurrent inserts into different sessions are independent.
-- Options column: JSON data type stores only label, content, order — never isCorrect.
-- Application layer (optionsToSafeJson) strips correctness before storage.
CREATE TABLE `education_practice_question` (
`id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
`tenant_id` BIGINT NOT NULL COMMENT '租户编号',
`session_id` BIGINT NOT NULL COMMENT '会话 ID',
`sequence` INT NOT NULL COMMENT '题目序号1-based服务端固定',
`question_id` VARCHAR(64) NOT NULL COMMENT '原始题目 ID',
`content_version` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '快照时的题目内容版本',
`stem` TEXT NOT NULL COMMENT '题干快照',
`type` VARCHAR(32) NOT NULL COMMENT '题型快照',
`difficulty` VARCHAR(32) DEFAULT NULL COMMENT '难度快照',
`options` JSON NOT NULL COMMENT '选项快照 JSON不含 isCorrect',
`selected_answer` TEXT DEFAULT NULL COMMENT '学生已选答案',
`is_answered` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否已作答',
`creator` VARCHAR(64) DEFAULT '' COMMENT '创建者',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` VARCHAR(64) DEFAULT '' COMMENT '更新者',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` BIT(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_session_sequence` (`session_id`, `sequence`),
KEY `idx_session_id` (`session_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教育-练习会话题目快照';
-- =============================================
-- Post-migration verification queries
-- =============================================
-- Verify tables exist with correct structure:
-- SHOW CREATE TABLE education_practice_session;
-- SHOW CREATE TABLE education_practice_question;
-- Verify unique keys are enforced:
-- SHOW INDEX FROM education_practice_session WHERE Key_name = 'uk_tenant_client_session';
-- SHOW INDEX FROM education_practice_question WHERE Key_name = 'uk_session_sequence';
-- Verify no orphan data (should be 0 after fresh migration):
-- SELECT COUNT(*) FROM education_practice_session;
-- SELECT COUNT(*) FROM education_practice_question;