写项目之数据库使用有感

数据库感觉真的真的太重要了!!!

文章目录


前言

我在做JavaWeb课程设计的学生成绩输入系统时,包括我自己在网上找的家居项目,感觉数据库特别的重要,不管是我们对于Service层的往DAO层的调用 还是数据库把数据封装到实体当中,还是前端页面的显示,我们或多或少都会用到数据库,我感觉到了数据库的强大,下面给大家说说我在基于这些项目中对数据库的看法。


提示:以下是本篇文章正文内容,下面案例可供参考

一、为什么我们需要数据库呢?

就是我想问大家一个问题,就是我们为什么会需要数据库来存储数据呢,我们如果想存储数据可以用其他方法呀,比如用一个文本就可以存储呀,又何必谈何用到数据库呢?

数据库的相关特点:

持久化存储:数据长期保存,不会因为程序结束而丢失

结构化组织:数据按照特定的数据模型组织

共享性:可以被多个用户和应用共享使用

减少冗余:通过数据共享减少数据重复存储

数据独立性:数据与应用程序相互独立

完整性保障:保证数据的正确性和一致性

安全性控制:提供数据保护机制

我们先了解这些特点,然后我们再结合具体:

我们就以这个学生成绩管理系统来举例:

假设我们用文本文件来存储:

students.txt

复制代码
2021001,张三,计算机2101班
2021002,李四,计算机2101班
2021003,王五,计算机2102班

scores.txt

复制代码
2021001,CS101,85,78,82,2023-2024-1
2021001,CS102,88,85,90,2023-2024-1
2021002,CS101,90,88,92,2023-2024-1

文件存储面临的问题:

数据冗余的问题:
复制代码
# 如果每个学生有多门课程,学生信息重复存储
2021001,张三,计算机2101班,CS101,85,78,82
2021001,张三,计算机2101班,CS102,88,85,90
2021001,张三,计算机2101班,CS103,76,80,85
# 同样的学生信息重复了3次!
数据不一致的问题:
复制代码
# 如果学生转班,需要修改所有相关记录
# 容易漏改,导致数据不一致
2021001,张三,计算机2101班,CS101,85,78,82  # 已更新
2021001,张三,计算机2101班,CS102,88,85,90  # 漏改了!
2021001,张三,计算机2102班,CS103,76,80,85  # 已更新
复杂查询困难:
java 复制代码
// 如果要查询"计算机2101班Java程序设计课程平均分"
// 文件操作代码会非常复杂
public double calculateClassAverage(String className, String courseName) {
    try {
        // 1. 先读取所有学生文件,找到指定班级的学生
        List<String> studentsInClass = new ArrayList<>();
        BufferedReader studentReader = new BufferedReader(new FileReader("students.txt"));
        String line;
        while ((line = studentReader.readLine()) != null) {
            String[] parts = line.split(",");
            if (parts[2].equals(className)) {
                studentsInClass.add(parts[0]); // 学号
            }
        }
        
        // 2. 再读取成绩文件,统计平均分
        double total = 0;
        int count = 0;
        BufferedReader scoreReader = new BufferedReader(new FileReader("scores.txt"));
        while ((line = scoreReader.readLine()) != null) {
            String[] parts = line.split(",");
            String studentId = parts[0];
            String course = parts[1];
            
            if (studentsInClass.contains(studentId) && course.equals(courseName)) {
                total += Double.parseDouble(parts[5]); // 总评成绩
                count++;
            }
        }
        
        return count > 0 ? total / count : 0;
        
    } catch (IOException e) {
        e.printStackTrace();
        return 0;
    }
}

数据库的优势体现:

相同的查询,数据库体现;
sql 复制代码
-- 一句SQL完成复杂查询
SELECT AVG(s.total_score) as 平均分
FROM scores s
JOIN students st ON s.student_id = st.id
JOIN courses c ON s.course_id = c.id
JOIN classes cl ON st.class_id = cl.id
WHERE cl.class_name = '计算机2101班' 
AND c.name = 'Java程序设计';

二、数据库解决的核心问题:

1.数据一致性:

c 复制代码
-- 学生转班,只需更新一次
UPDATE students SET class_id = 2 WHERE id = 1;
-- 所有相关查询自动获取最新数据,不会出现不一致

2.并发控制:

c 复制代码
// 多个老师同时录入成绩,文件系统会冲突
// 数据库自动处理并发
public class ScoreService {
    public synchronized boolean saveScore(Score score) {
        // 数据库事务保证数据完整性
        Connection conn = null;
        try {
            conn = DBUtil.getConnection();
            conn.setAutoCommit(false);
            
            // 检查是否已存在记录
            String checkSql = "SELECT id FROM scores WHERE student_id = ? AND course_id = ?";
            PreparedStatement checkStmt = conn.prepareStatement(checkSql);
            checkStmt.setInt(1, score.getStudentId());
            checkStmt.setInt(2, score.getCourseId());
            ResultSet rs = checkStmt.executeQuery();
            
            if (rs.next()) {
                // 更新 existing record
                updateScore(conn, score);
            } else {
                // 插入 new record
                insertScore(conn, score);
            }
            
            conn.commit();
            return true;
        } catch (SQLException e) {
            if (conn != null) {
                try { conn.rollback(); } catch (SQLException ex) {}
            }
            return false;
        }
    }
}

3.复杂查询和统计:

sql 复制代码
-- 成绩分布统计
SELECT 
    CASE 
        WHEN total_score >= 90 THEN '优秀'
        WHEN total_score >= 80 THEN '良好'
        WHEN total_score >= 70 THEN '中等'
        WHEN total_score >= 60 THEN '及格'
        ELSE '不及格'
    END as 等级,
    COUNT(*) as 人数,
    ROUND(COUNT(*) * 100.0 / (SELECT COUNT(*) FROM scores WHERE course_id = 1), 2) as 百分比
FROM scores 
WHERE course_id = 1
GROUP BY 
    CASE 
        WHEN total_score >= 90 THEN '优秀'
        WHEN total_score >= 80 THEN '良好'
        WHEN total_score >= 70 THEN '中等'
        WHEN total_score >= 60 THEN '及格'
        ELSE '不及格'
    END
ORDER BY MIN(total_score) DESC;

4.数据完整性约束:

sql 复制代码
-- 数据库自动强制执行业务规则
ALTER TABLE scores 
ADD CONSTRAINT chk_score_range 
CHECK (regular_score >= 0 AND regular_score <= 100);

ALTER TABLE scores
ADD CONSTRAINT chk_final_score  
CHECK (final_score >= 0 AND final_score <= 100);

-- 防止重复成绩记录
ALTER TABLE scores
ADD UNIQUE unique_student_course (student_id, course_id, semester);

5.具体场景对比:

文件查询:
java 复制代码
public void getCourseScores(String teacherId, String courseId) {
    // 1. 读取课程文件,找到课程
    // 2. 读取教师授课关系文件
    // 3. 读取学生选课文件
    // 4. 读取成绩文件
    // 需要4个文件操作,多次循环匹配
    // 代码复杂,性能低下
}

数据库方案:

sql 复制代码
SELECT s.name as 学生姓名, sc.regular_score as 平时成绩, 
       sc.final_score as 期末成绩, sc.total_score as 总评成绩
FROM scores sc
JOIN students s ON sc.student_id = s.id
WHERE sc.course_id = ? AND sc.teacher_id = ?
ORDER BY s.student_number;

为什么需要数据库:

对于你的项目来说,数据库是必需的,因为:

  1. 数据结构复杂

    • 多个表之间存在复杂关系(学生-课程-成绩-教师)

    • 需要维护数据的一致性和完整性

  2. 查询需求复杂

    • 需要多表关联查询

    • 需要聚合统计(平均分、最高分、排名等)

    • 需要条件组合查询

  3. 并发访问需求

    • 多个老师可能同时录入成绩

    • 学生同时查询成绩

    • 需要事务保证数据安全

  4. 数据量会增长

    • 每个学期都会新增大量成绩记录

    • 需要高效的查询性能

  5. 业务规则复杂

    • 成绩计算公式

    • 数据验证规则

    • 权限控制需求

什么情况下可以用文件?

  • 配置信息:系统配置参数

  • 日志文件:操作日志记录

  • 静态数据:很少变化的参考数据

  • 小型个人应用:数据量小,结构简单

结论

对于学生成绩管理系统 这种具有复杂关系、需要高效查询、多人并发访问的企业级应用,数据库是唯一正确的选择。文件存储只适用于极其简单的数据存储需求。

你的项目选择MySQL数据库是完全正确的,这为系统的稳定性、性能和可扩展性奠定了坚实基础!

三、自己的见解:

  • 数据写死(硬编码): ​ 关系是静态的、固化的。任何业务逻辑的变更(比如新增一个分类、修改用户归属)都必须修改代码并重新部署。数据与关系缺乏"生命力"和"可管理性"

  • 使用数据库: ​ 将数据本身数据之间的关系 都存储下来,变成可以动态增、删、改、查 的对象。这正是"数据库"这个名字的含义------数据的仓库。外键是关系型数据库中定义和强制这种"关系"的核心机制之一

外键:不仅仅是"表示关系"

您说"用外键表示好实体之间的关系",这很对。但外键的作用不止于"表示",更重要的是强制保持数据的一致性与完整性

举个例子:用户表(users)订单表(orders)。订单属于某个用户。

  • 有外键时:

    • orders表中有一个 user_id字段,并设置为指向 users.id的外键。

    • 数据库会自动保证: ​ 你无法插入一条 user_idusers表中不存在的订单。这避免了"幽灵订单"。

    • 当删除一个用户时,你可以通过外键约束定义级联操作(CASCADE, SET NULL, RESTRICT)。

      • RESTRICT: 如果该用户还有订单,则禁止删除此用户。

      • CASCADE: 删除用户时,自动删除他所有的订单。

    • 作用:数据的完整性由数据库底层保证,应用层可以更专注于业务逻辑,出错的可能性更低。

  • 无外键时(即使在数据库中):

    • 你只能通过应用程序逻辑来保证:在创建订单前检查用户是否存在,在删除用户前检查他是否有未处理订单。

    • 风险:phenyl ​ 如果应用逻辑有漏洞,或者有多个入口(如后台、API、直接操作数据库)可以操作数据,就很容易产生脏数据(无效的 user_id)。

现代开发中的权衡与演进

在实际的中大型Web项目中,关于外键的使用有一些更深入的讨论和实践:

  • 优势(必须用):

    1. **数据强一致性:**​ 如上所述,是数据库级别的保证,最可靠。

    2. **文档化:**​ 表结构定义本身就直接说明了关系,一目了然。

    3. **简化开发:**​ 很多ORM框架能利用外键自动建立模型关联,方便查询。

  • 争议与替代方案(可能不用):

    1. **性能考量:**​ 在高并发写入场景下,外键约束检查会带来额外的开销。在分库分表(水平拆分)时,外键难以实现。

    2. 耦合与灵活性: ​ 外键将数据关系紧密绑定在数据库层。在微服务架构下,订单服务和用户服务可能拥有独立的数据库。这时无法使用数据库外键,而是通过业务代码服务间的API调用 来维护逻辑上的关联,这被称为"应用层外键"。

    3. **迁移与扩展:**​ 修改外键关系(特别是生产环境)可能比较麻烦,需要复杂的DDL操作。

因此,现代开发中常见的思路是:

  • 单体型应用,强一致性要求高:强烈推荐使用外键。它能以最小成本避免大量数据错误。

  • 微服务架构,大规模分布式系统:通常在数据库层不用外键,因为数据分散在不同服务的数据库中。一致性通过分布式事务(如Saga模式)、最终一致性和应用逻辑来保证。

  • 折中方案: ​ 在数据库中定义外键关系 (用于文档化和开发便利),但不添加外键约束FOREIGN KEYconstraint),将一致性检查的责任交给应用层。但这需要极其严谨的团队纪律。

在绝大多数Web项目起步阶段,使用带有外键的关系型数据库(如MySQL, PostgreSQL)是最优、最专业的选择。

一个生动的比喻:

  • 写死的数据​ 像刻在石碑上的家谱,无法更改。

  • 有外键的数据库​ 像一套严谨的家族档案管理系统,每个人都有一个唯一ID,记录父母子女时必须引用有效的ID,系统会自动防止你给一个不存的人当儿子。

  • 无外键的数据库​ 像一个自由记录的家族笔记本,虽然灵活,但需要记录者自己非常小心,否则很容易把关系写乱。


总结

数据库是现代信息系统的核心基础设施 ,它通过结构化存储高效查询事务保证安全管理 ,为应用程序提供了可靠的数据支撑。掌握数据库技术不仅是完成当前项目的需要,更是成为一名合格软件工程师的必备技能。随着数据量的爆炸式增长,数据库技术的重要性将愈发凸显。

相关推荐
倒流时光三十年2 小时前
PostgreSQL 高级特性. FILTER RETURNING 特性
数据库·postgresql·filter·sql调优
填满你的记忆2 小时前
【从零开始——Redis 进化日志|Day1】初见 Redis,开启内存加速之旅
数据库·redis·缓存
么么...2 小时前
掌握 MySQL:约束、范式与视图详解
数据库·经验分享·sql·mysql
盒马coding2 小时前
高性能MySQL到PostgreSQL异构数据库转换工具MySQL2PG
数据库·mysql·postgresql
摇滚侠2 小时前
RocketMQ 教程丨深度掌握 MQ 消息中间件,RocketMQ 集群,笔记 28-38
数据库·笔记·rocketmq
Gobysec2 小时前
Goby 漏洞安全通告|MongoDB Zlib 信息泄露漏洞(CVE-2025-14847)
数据库·安全·mongodb·漏洞检测工具
醉风塘2 小时前
深入解析与彻底解决:MongoDB“about to fork child process”启动故障
数据库·mongodb
大猫会长2 小时前
新手的postgreSQL笔记
数据库·笔记·postgresql
大鱼>2 小时前
按时间删除MongoDB中按时间命名的Collection
数据库·mongodb