工作日志:第二周

一、工作内容

功能开发,基于需求设计数据库表,确定输入输出数据,对大部分数据表做CURD。

二、功能实现

数据库表的设计要注意以下几点:

  • 表结构设计

    • 明确表的目的和需求
    • 确定合理的字段及数据类型
    • 设计主键和外键关系
  • 命名规范

    • 表名和字段名见名知义、简洁明了
    • 遵循统一的命名习惯
  • 索引设计

    • 为常查询字段创建索引
    • 合理设置索引字段
  • 数据完整性约束

    • 设置主键、非空、唯一性等约束
    • 确保数据类型和长度合理
  • 性能优化

    • 减少冗余字段和重复数据
    • 合理设计分区或分表策略
  • 数据安全和备份

    • 控制字段访问权限
    • 制定备份和恢复策略

对于同一个表的CURD,输入输出大部分不需要全部的数据。拿user表举例,user表中可能包含字段信息如下:

id主键,自增
name账号
password密码
email邮箱
phone手机号
is_admin是否为管理
create_time创建时间
update_time更新时间
id_deleted

删除标志

有一些字段是不可被编辑的(如create_time、update_tis_deleted),有一些字段是不可见的(如id_deleted),所以可以建立UserInput与UserOutput类来控制,在service层进行类型之间的转换。

当进行不同操作时有些必填字段是不同的,对于必填字段可以在UserInput类中参数上添加注解@NotBlank或@NotNull等来进行限制并返回错误信息,如下:

public class UserInput {
    @NotNull(message = "用户名不能为空")
    private String name;

    @NotBlank(message = "密码不能为空")
    private String password;

    // Getters and setters
}

但这样直接添加注解会在所有以UserInput类为输入生效,为了实现更精细的参数校验可以使用Spring Validation 的分组功能,如下:

public class UserInput {
    public interface RegisterGroup {}
    public interface LoginGroup {}

    @NotNull(message = "用户名不能为空", groups = {RegisterGroup.class, LoginGroup.class})
    private String name;

    @NotBlank(message = "密码不能为空", groups = {LoginGroup.class})
    private String password;

    // Getters and setters
}

这样在使用时就可以更精确地控制参数校验

@PostMapping("/register")
public ResponseEntity<Void> register(@Validated(UserInput.register.class) UserInput userInput) {
    // 处理注册逻辑
    return ResponseEntity.status(HttpStatus.CREATED).build();
}

@PutMapping("/login")
public ResponseEntity<Void> login(@Validated(UserInput.login.class) UserInput userInput) {
    // 处理登录逻辑
    return ResponseEntity.ok().build();
}

三、工具使用

log打印(使用SLF4J)

SLF4J (Simple Logging Facade for Java)是一个日志框架的抽象层,它为各种流行的日志框架提供了一个统一的API,让开发者可以在编码时使用SLF4J,而不需要具体选择某一个日志框架的实现。这样既可以让应用程序保持灵活性,又能提高代码的可移植性。

在SLF4J中,常用的日志记录方法包括:

  • 日志级别方法

    • log.trace() \\最低的日志级别,用于记录一些非常细节的、调试用途的信息
    • log.debug() \\用于记录一些调试信息,帮助开发者分析和解决问题
    • log.info()  \\用于记录一些重要但不紧急的信息,比如应用程序的正常运行状态
    • log.warn()  \\用于记录一些潜在的问题,但暂时不会影响系统的正常运行
    • log.error()  \\用于记录一些严重的错误,可能会影响系统的正常运行

这些方法对应了不同的日志级别,开发者可以根据需要选择合适的级别记录日志信息。

  • 参数化日志

    SLF4J支持使用占位符的方式记录带有参数的日志信息,例如:

    logger.info("User {} logged in from IP address {}", username, ipAddress);
    

    这样可以提高日志信息的可读性和可维护性。

  • 异常记录

    SLF4J提供了记录异常信息的方法,例如:

    try {
        // some code
    } catch (Exception e) {
        logger.error("An error occurred", e);
    }
    

    将异常对象作为参数传递给log.error()方法,可以自动记录异常的堆栈信息。

数据库

MyBatis+MySQL整合

MyBatis是一个Java持久层框架,它简化了JDBC编程中的很多复杂操作。MyBatis也支持与MySQL数据库的集成。

下面是使用MyBatis和MySQL的基本步骤:

  • 添加依赖

    在项目的pom.xml文件中添加MyBatis和MySQL驱动的依赖:

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.25</version>
    </dependency>
    
  • 创建MyBatis配置文件

    src/main/resources目录下创建mybatis-config.xml文件,用于配置MyBatis的基本设置:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <environments default="development">
            <environment id="development">
                <transactionManager type="JDBC"/>
                <dataSource type="POOLED">
                    <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/your_database"/>
                    <property name="username" value="your_username"/>
                    <property name="password" value="your_password"/>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <mapper resource="dao/UserMapper.xml"/>
        </mappers>
    </configuration>
    

    这里需要替换your_databaseyour_usernameyour_password

创建实体类

根据数据库表结构,创建对应的Java实体类,例如User.java

  • 创建Mapper接口

    src/main/java目录下创建dao包,并在其中创建UserMapper.java接口,用于定义与数据库表操作相关的方法。

  • 创建Mapper XML文件

    src/main/resources/dao目录下创建UserMapper.xml文件,用于编写SQL语句和配置与Mapper接口的映射关系。

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="dao.UserMapper">
        <select id="getById" parameterType="int" resultType="entity.User">
            SELECT * FROM users WHERE id = #{id}
        </select>
    </mapper>
    
  • 使用MyBatis

    在需要使用MyBatis的地方,创建SqlSessionFactory并执行SQL操作:

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
            .build(Resources.getResourceAsReader("mybatis-config.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getById(1);
    

通过这些步骤,就可以在Java应用程序中使用MyBatis连接和操作MySQL数据库了。MyBatis提供了许多高级特性,如动态SQL、缓存、结果映射等,可以大大简化数据访问层的开发工作。

索引

  • 索引使用场景
    • 频繁出现在 WHERE、ORDER BY、JOIN 条件中的列
    • 区分度高的列(包含较少重复值)
    • 数据量大的表
  • 索引数据结构
    • B-Tree: 多叉树数据结构,查找效率高
    • Hash: 基于哈希表的数据结构,等值查询效率高
    • R-Tree: 用于空间数据索引,适用于范围查询
    • Bitmap: 位图索引,适用于基数较小的列
  • 索引创建原则
    • 针对经常出现在查询条件、排序条件、连接条件中的列创建索引
    • 选择独立性好、离散度高的列作为索引
    • 尽量缩短索引长度,仅包含查询中需要的列
    • 避免对频繁更新的列创建索引,更新会降低性能
  • 最左匹配原则
    • 联合索引中,查询条件要匹配索引最左边的列
    • 索引 (a, b, c) 可以支持 WHERE a=1, WHERE a=1 and b=2, WHERE a=1 and b=2 and c=3
    • 不支持 WHERE b=2, WHERE c=3

总的来说,MySQL 索引是提高查询性能的关键。合理利用索引需要根据具体的业务场景和查询需求来设计。索引的创建应遵循一定的原则,尤其要注意最左匹配原则。合理设计索引可以大幅提升 MySQL 的查询效率

事务

  • 事务的定义
    • 事务是数据库操作的基本单元
    • 事务由一组 SQL 语句组成,要么全部执行成功,要么全部执行失败
  • 事务的四大特性(ACID)
    • 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成
    • 一致性(Consistency):事务执行前后数据库状态从一个合法状态转变到另一个合法状态
    • 隔离性(Isolation):并发执行的事务之间不会互相影响
    • 持久性(Durability):事务完成后,结果必须永久保存
  • 事务的隔离级别
    • 读未提交(Read Uncommitted):最低级别,事务可以读取未提交的数据,会出现脏读、不可重复读、幻读等问题
    • 读提交(Read Committed):事务只能读取已提交的数据,可避免脏读,但可能出现不可重复读、幻读
    • 可重复读(Repeatable Read,MySQL默认级别):事务在整个过程中看到的数据是一致的,可避免脏读和不可重复读,但可能出现幻读
    • 串行化(Serializable):最高级别,事务串行执行,无法并发,可避免所有问题,但并发性能最差
  • 脏读、不可重复读、幻读
    • 脏读(Dirty Read)

      • 定义:一个事务读取到了另一个事务未提交的数据
      • 问题:如果已读取的数据最终被回滚,那么之前的读取结果就是无效的
    • 不可重复读(Non-Repeatable Read)

      • 定义:一个事务两次读取同一数据,但读取到的结果不一致
      • 问题:第二次读取时,数据已被其他事务修改并提交
    • 幻读(Phantom Read)

      • 定义:一个事务执行相同的查询两次,但返回的记录数不同
      • 问题:第二次查询时,数据已被其他事务插入或删除

总的来说,事务是数据库操作的基础,具有 ACID 特性。根据业务需求,合理选择数据库的隔离级别,可以在数据一致性和并发性能之间找到平衡。

日志

日志种类

MySQL 中主要有以下几种日志机制:

  • 二进制日志(Binary Log)

    • 记录所有改变数据库数据的操作,用于数据恢复和复制。
    • 可以指定记录格式(ROW、STATEMENT、MIXED)和记录范围。
  • 错误日志(Error Log)

    • 记录 MySQL 服务启动、停止以及运行过程中的错误信息。
    • 可以指定错误日志的输出位置和输出级别。
  • 查询日志(General Query Log)

    • 记录所有对数据库的访问操作,包括查询、更新等。
    • 主要用于调试和分析访问情况,但会影响性能。
  • 慢查询日志(Slow Query Log)

    • 记录执行时间超过指定阈值的查询语句。
    • 用于发现性能瓶颈,调优查询语句。
  • 中继日志(Relay Log)

    • 用于主从复制中,从库记录主库传过来的二进制日志。
    • 从库读取中继日志来恢复数据。
  • InnoDB 重做日志(Redo Log)

    • InnoDB 存储引擎专有的日志,记录数据页的物理修改。
    • 保证数据库在发生异常情况下可以恢复到最新的状态。

这些日志机制在 MySQL 的事务处理、故障恢复、主从复制等诸多场景中发挥着重要作用。合理配置和管理这些日志,有助于提高 MySQL 的可靠性和性能。

慢查询

慢查询是指在 MySQL 数据库中执行时间超过指定阈值的查询语句。也就是说,当一个 SQL 语句的执行时间超过了数据库管理员设定的时间阈值,这个 SQL 语句就被认为是"慢查询"。

慢查询的一些特点包括:
  • 执行时间长:执行时间超过了数据库管理员设定的阈值,通常为 1-3 秒。

  • 资源消耗大:这些查询语句在执行过程中会消耗大量的 CPU、IO 和内存资源。

  • 可能引发性能问题:如果慢查询语句过多,会严重影响数据库的整体性能。

慢查询的常见原因包括:
  • 查询语句设计不合理:如未合理使用索引、查询条件不当等。

  • 数据量大:当查询的数据量很大时,即使查询语句设计合理,也可能会执行很慢。

  • 服务器硬件配置不足:CPU、内存、磁盘等硬件资源不足会导致查询执行缓慢。

慢查询日志使用流程:
  • 开启慢查询日志

    • 在 MySQL 配置文件中设置 slow_query_log=1 开启慢查询日志。
    • 可以指定日志文件路径 slow_query_log_file=/path/to/slow.log
  • 设置慢查询时间阈值

    • 通过参数 long_query_time 设置慢查询的时间阈值,默认为 10 秒。
    • 建议设置为 1-3 秒,以便及时发现性能问题。
  • 分析慢查询日志

    • 可以使用 mysqldumpslow 等工具分析慢查询日志。
    • 分析可以得到常见的慢查询语句、查询时间分布、索引使用情况等信息。
  • 优化慢查询

    • 根据分析结果,针对性地优化慢查询语句:
      • 添加合适的索引
      • 优化 SQL 语句结构
      • 调整查询条件
      • 优化数据库表结构
  • 监控慢查询

    • 可以设置报警机制,监控慢查询日志。
    • 当出现频繁的慢查询时,及时发现并进行优化。

合理使用慢查询日志,可以有效地发现 MySQL 性能瓶颈,提高数据库的整体性能。慢查询日志是 MySQL 调优的重要工具之一。

四、问题记录

由于wagger 在生成文档时,无法直接从 Spring 的校验分组中获取相关信息,当使用@Validated进行分组注解时,默认情况下 Swagger 文档可能无法正确地显示分组信息,所以会在swagger中都变为必填。

解决方案:手动判断一下返回报错吧。

  • 16
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值