一、工作内容
功能开发,基于需求设计数据库表,确定输入输出数据,对大部分数据表做CURD。
二、功能实现
数据库表的设计要注意以下几点:
表结构设计
- 明确表的目的和需求
- 确定合理的字段及数据类型
- 设计主键和外键关系
命名规范
- 表名和字段名见名知义、简洁明了
- 遵循统一的命名习惯
索引设计
- 为常查询字段创建索引
- 合理设置索引字段
数据完整性约束
- 设置主键、非空、唯一性等约束
- 确保数据类型和长度合理
性能优化
- 减少冗余字段和重复数据
- 合理设计分区或分表策略
数据安全和备份
- 控制字段访问权限
- 制定备份和恢复策略
对于同一个表的CURD,输入输出大部分不需要全部的数据。拿user表举例,user表中可能包含字段信息如下:
id | 主键,自增 |
name | 账号 |
password | 密码 |
邮箱 | |
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_database
、your_username
和your_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
。
- 在 MySQL 配置文件中设置
-
设置慢查询时间阈值
- 通过参数
long_query_time
设置慢查询的时间阈值,默认为 10 秒。 - 建议设置为 1-3 秒,以便及时发现性能问题。
- 通过参数
-
分析慢查询日志
- 可以使用
mysqldumpslow
等工具分析慢查询日志。 - 分析可以得到常见的慢查询语句、查询时间分布、索引使用情况等信息。
- 可以使用
-
优化慢查询
- 根据分析结果,针对性地优化慢查询语句:
- 添加合适的索引
- 优化 SQL 语句结构
- 调整查询条件
- 优化数据库表结构
- 根据分析结果,针对性地优化慢查询语句:
-
监控慢查询
- 可以设置报警机制,监控慢查询日志。
- 当出现频繁的慢查询时,及时发现并进行优化。
合理使用慢查询日志,可以有效地发现 MySQL 性能瓶颈,提高数据库的整体性能。慢查询日志是 MySQL 调优的重要工具之一。
四、问题记录
由于wagger 在生成文档时,无法直接从 Spring 的校验分组中获取相关信息,当使用@Validated进行分组注解时,默认情况下 Swagger 文档可能无法正确地显示分组信息,所以会在swagger中都变为必填。
解决方案:手动判断一下返回报错吧。