一 PageHelper
1. 介绍
PageHelper 是一个 MyBatis 分页插件,它通过拦截 MyBatis 的 SQL 执行过程,动态注入分页逻辑(如 LIMIT
、OFFSET
),从而自动实现物理分页。你无需手动编写分页 SQL 或额外的 count 查询
3. 核心工作原理
PageHelper 的实现基于 MyBatis 的拦截器机制(Interceptor
),主要流程如下:
- 设置分页参数
调用PageHelper.startPage()
会将分页参数(页码、每页条数)存储到 ThreadLocal 中34。 - 拦截 SQL 执行
在 MyBatis 执行查询前,拦截器从 ThreadLocal 获取分页参数,并重写原 SQL:- 添加数据库特定的分页语句(如 MySQL 的
LIMIT offset, pageSize
); - 自动生成并执行
COUNT(*)
查询获取总记录数46。
- 添加数据库特定的分页语句(如 MySQL 的
- 返回包装结果
查询结果被封装为Page
对象(本质是ArrayList
),同时可通过PageInfo
获取完整分页信息4
4. 添加依赖
xml
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>最新版</version> <!-- 如 1.4.7 -->
</dependency>
5. 示例
package com.itheima.mapper;
import com.itheima.pojo.Emp;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper
public interface EmpMapper {
@Select("select emp.*,dept.name deptName from emp left join dept on emp.dept_id = dept.id" + " order by emp.update_time desc ")
public List<Emp> list();
}
package com.itheima.service.impl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.Emp;
import com.itheima.pojo.PageResult;
import com.itheima.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class EmpServiceImpl implements EmpService {
@Autowired
private EmpMapper empMapper;
/*
* 基于pageHelper分页查询
* */
public PageResult<Emp> page(Integer page, Integer pageSize){
PageHelper.startPage(page,pageSize);
List<Emp> empList = empMapper.list();
Page<Emp> empPage = (Page<Emp>) empList;
return new PageResult<Emp>(empPage.getTotal(), empPage.getResult());
}
}
package com.itheima.controller;
import com.itheima.mapper.EmpMapper;
import com.itheima.pojo.Emp;
import com.itheima.pojo.PageResult;
import com.itheima.pojo.Result;
import com.itheima.service.EmpService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@RequestMapping("/emps")
public class EmpController {
@Autowired
private EmpService empService;
/*
分页查询
*/
@GetMapping
public Result page(@RequestParam(defaultValue = "1") Integer page,
@RequestParam(defaultValue = "10") Integer pageSize){
log.info("分页查询,参数:{},{}",page,pageSize);
PageResult<Emp> pageResult= empService.page(page,pageSize);
return Result.success(pageResult);
}
}
6. 注意事项
sql语句结尾不要加分号
PageHelper只会对紧跟在其后的第一条sql进行分页处理
二 @Transactional
1. 介绍
Spring 框架中用于声明式事务管理的核心注解。它极大地简化了在应用程序中使用事务的复杂度,避免了手动编写事务管理代码(如开始事务、提交事务、回滚事务等),让开发者可以专注于业务逻辑。
2. 核心作用:
-
声明方法或类需要在一个事务的上下文中执行。
-
定义该事务的属性,例如传播行为、隔离级别、超时时间、只读标志、回滚规则等。
3. 基本用法:
- 启用事务管理: 在 Spring 配置类(通常是
@Configuration
类)上添加@EnableTransactionManagement
注解。 - 标注事务边界:
- 在方法上: 最常用。表示该方法执行时需要一个事务。
- 在类上: 表示该类的所有公共方法都默认使用事务(相当于给每个公共方法都加了
@Transactional
)。方法上的注解会覆盖类上的注解定义。 - 在接口上: 也可以,但不推荐(因为 Java 注解在接口上的继承规则可能导致问题)。推荐使用基于类的代理(CGLIB)或直接在实现类上标注。
java
@Service
public class MyService {
@Autowired
private MyRepository repository;
// 在需要事务的方法上添加注解
@Transactional
public void performBusinessOperation() {
// 业务逻辑,包含多个数据库操作
repository.updateDataA();
repository.updateDataB(); // 如果这里失败,updateDataA() 的更改也会回滚
}
// 可以指定特定属性
@Transactional(propagation = Propagation.REQUIRES_NEW,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
readOnly = false,
rollbackFor = {MyBusinessException.class},
noRollbackFor = {ValidationException.class})
public void anotherTransactionalMethod() {
// ...
}
}
4. 属性介绍
(1) rollbackFor
/ rollbackForClassName
(回滚规则): 指定哪些检查型异常(checked exceptions) 或非 RuntimeException
发生时也应该触发事务回滚(默认只对 RuntimeException
和 Error
回滚)。
rollbackFor = {Exception.class}
(2)propagation
(传播行为 - Propagation
): 定义了当前事务方法与已存在事务上下文之间的关系。这是理解事务嵌套的关键。
REQUIRED
(默认值):如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。REQUIRES_NEW
:总是创建一个新事务。如果当前存在事务,则挂起(suspend)当前事务。新事务独立提交或回滚,不受外层事务影响。
三 全局异常处理器
全局异常处理器是实现统一错误处理的核心机制,尤其在使用Spring框架时,通过集中管理异常处理逻辑,能显著提升代码可维护性和用户体验
一 核心实现机制:基于Spring的全局异常处理
- 注解组合使用
@RestControllerAdvice
:是@ControllerAdvice
与@ResponseBody
的组合注解,适用于RESTful API,自动将返回值序列化为JSON/XML110。@ExceptionHandler
:标记处理特定异常的方法,可指定异常类型
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler
public Result handleException(Exception e){
log.error("全局异常信息:{}",e.getMessage());
return Result.error("全局异常信息");
}
}
四 SpringAOP
1.通知类型
1. 前置通知 @Before
-
执行时机:在目标方法执行之前触发。
-
特点:
- 无法阻止目标方法执行(除非抛出异常)。
- 无法获取目标方法的返回值。
-
典型场景:参数校验、权限检查、日志记录。
-
示例:
java
@Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void beforeAdvice(JoinPoint joinPoint) { String methodName = joinPoint.getSignature().getName(); System.out.println("【前置通知】准备执行方法: " + methodName); } }
2. 后置通知 @AfterReturning
-
执行时机:在目标方法成功执行后触发(未抛出异常)。
-
特点:
- 可以获取目标方法的返回值(通过
returning
属性)。
- 可以获取目标方法的返回值(通过
-
典型场景:记录方法返回值、执行结果统计。
-
示例:
java
@Aspect @Component public class ResultAspect { @AfterReturning( pointcut = "execution(* com.example.service.*.*(..))", returning = "result" // 绑定返回值到 result 参数 ) public void afterReturningAdvice(JoinPoint joinPoint, Object result) { System.out.println("【后置通知】方法返回结果: " + result); } }
3. 异常通知 @AfterThrowing
-
执行时机:在目标方法抛出异常后触发。
-
特点:
- 可以捕获异常对象(通过
throwing
属性)。
- 可以捕获异常对象(通过
-
典型场景:异常日志记录、错误报警。
-
示例:
java
@Aspect @Component public class ExceptionAspect { @AfterThrowing( pointcut = "execution(* com.example.service.*.*(..))", throwing = "ex" // 绑定异常对象到 ex 参数 ) public void afterThrowingAdvice(JoinPoint joinPoint, Exception ex) { System.out.println("【异常通知】方法抛出异常: " + ex.getMessage()); } }
4. 最终通知 @After
-
执行时机:在目标方法执行结束后触发(无论是否抛出异常)。
-
特点:
- 类似 Java 中的
finally
代码块。 - 无法获取返回值或异常对象。
- 类似 Java 中的
-
典型场景:资源清理(如关闭文件、数据库连接)。
-
示例:
java
@Aspect @Component public class CleanupAspect { @After("execution(* com.example.service.*.*(..))") public void afterAdvice(JoinPoint joinPoint) { System.out.println("【最终通知】方法执行完毕"); } }
5. 环绕通知 @Around
(最强大)
-
执行时机:完全控制目标方法的执行(方法执行前后均可插入逻辑)。
-
特点:
- 需通过
ProceedingJoinPoint.proceed()
显式调用目标方法。 - 可以修改参数、返回值,甚至阻止方法执行。
- 需通过
-
典型场景:性能监控、事务管理、缓存控制。
-
示例:
java
@Aspect @Component public class PerformanceAspect { @Around("execution(* com.example.service.*.*(..))") public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable { long startTime = System.currentTimeMillis(); // 执行目标方法(可修改参数或跳过执行) Object result = joinPoint.proceed(); long endTime = System.currentTimeMillis(); System.out.println("【环绕通知】方法执行耗时: " + (endTime - startTime) + "ms"); return result; // 可修改返回值 } }
核心对比表
通知类型 | 注解 | 执行时机 | 能否修改返回值 | 能否阻止方法执行 |
---|---|---|---|---|
前置通知 | @Before | 目标方法执行前 | ❌ | ❌(抛异常除外) |
后置通知 | @AfterReturning | 目标方法成功返回后 | ❌ | ❌ |
异常通知 | @AfterThrowing | 目标方法抛出异常后 | ❌ | ❌ |
最终通知 | @After | 目标方法结束后(无论成败) | ❌ | ❌ |
环绕通知 | @Around | 完全控制方法执行全过程 | ✅ | ✅ |
2. @Pointcut
主要作用是声明切点(Pointcut)表达式,让通知(Advice)可以引用这些表达式,实现切点定义的模块化和复用
1. 定义可重用切点
java
@Aspect
@Component
public class LoggingAspect {
// 定义可重用的切点表达式
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {} // 空方法体
@Pointcut("@annotation(com.example.Loggable)")
public void loggableMethod() {}
}
2. 在通知中引用切点
java
// 使用定义好的切点
@Before("serviceLayer()")
public void logBeforeService(JoinPoint joinPoint) {
System.out.println("调用服务方法: " + joinPoint.getSignature());
}
// 组合多个切点
@After("serviceLayer() && loggableMethod()")
public void logAfterLoggableService() {
System.out.println("记录日志完成");
}
3. 通知顺序
(1)不同切面类中,默认按照切面类的类字母排序
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
(2)用@order(数字)加在切面类上控制顺序
目标方法前的通知方法:数字小的先执行
@Aspect
@Order(1) // 数字越小优先级越高
@Component
public class SecurityAspect {
// 安全相关通知
}
@Aspect
@Order(2)
@Component
public class LoggingAspect {
// 日志相关通知
}
目标方法前的通知方法:数字小的后执行
五 linux
常用命令
一、核心文件和目录操作
这些命令是你与文件系统交互的基础。
命令 | 全称/含义 | 常用参数/示例 | 说明 |
---|---|---|---|
ls | List | -l (详情), -a (显示隐藏文件), -h (人性化文件大小) | 列出目录内容 |
ls -lah | 以详情模式列出所有文件(包括隐藏文件) | ||
cd | Change Directory | cd /home cd .. cd ~ cd - | 切换目录 (.. 上级, ~ 家目录, - 返回上次目录) |
pwd | Print Working Directory | pwd | 显示当前所在目录的绝对路径 |
mkdir | Make Directory | -p (递归创建) mkdir new_dir mkdir -p a/b/c | 创建新目录 |
cp | Copy | -r (递归复制目录) -i (交互确认) | 复制文件或目录 |
cp file1.txt file2.txt cp -r dir1/ dir2/ | |||
mv | Move | mv file1.txt /tmp/ mv old.txt new.txt | 移动文件/目录 或 重命名 |
rm | Remove | -r (递归删除目录), -f (强制删除), -i (交互确认) | 删除文件或目录 (慎用!) |
rm file.txt rm -rf somedir/ (极其危险!) | |||
touch | touch new_file.txt | 创建空文件 或 更新文件时间戳 | |
cat | Concatenate | cat file.txt cat > new_file.txt (创建) | 查看文件内容、创建文件、合并文件 |
less / more | less long_file.log | 分页查看文件内容(less 更强大,支持上下翻) | |
head | -n 10 (指定行数) head -20 file.log | 查看文件头部内容(默认10行) | |
tail | -n 20 -f (实时追踪文件更新) | 查看文件尾部内容,-f 常用于看日志 | |
tail -f /var/log/syslog |
二 压缩
命令 | 文件格式 | 常用示例 |
---|---|---|
tar | .tar , .tar.gz , .tar.bz2 | 打包压缩: tar -czvf archive.tar.gz /path/to/dir/ 解压: tar -xzvf archive.tar.gz |
tar
参数解释:
-c
:创建归档-x
:提取归档-z
:使用 gzip 压缩/解压-j
:使用 bzip2 压缩/解压-v
:显示详细过程-f
:指定文件名
三 文本编辑
启动:
vim filename.txt # 编辑或创建文件
关闭:
-
:w
:保存 (Write) -
:wq
或:x
:保存并退出 -
:q!
:强制退出,不保存修改! -
进入插入模式:
i
:在光标前插入a
:在光标后插入 (Append)o
:在当前行下方新建一行并插入I
:在行首插入A
:在行尾插入
-
移动光标(替代方向键):
h
(左),j
(下),k
(上),l
(右)gg
:跳到文件第一行G
:跳到文件最后一行:n
:跳到第 n 行(在命令行模式下,例如:50
跳转到第50行)
-
复制、粘贴、删除:
yy
:复制当前行 (Yank)dd
:删除(剪切)当前行p
:在光标后粘贴u
:撤销 (Undo)Ctrl + r
:重做 (Redo)
四 查找命令
find
基本语法: find [路径] [选项] [操作]
-
按名称查找 (
-name
,-iname
):find /home -name "report.txt" # 在 /home 下精确查找名为 report.txt 的文件(区分大小写) find . -name "*.log" # 在当前目录及子目录中查找所有 .log 结尾的文件 find /var -iname "*.JPG" # -iname 不区分大小写,会找到 .jpg, .JPG, .Jpg 等
-
按类型查找 (
-type
):find /tmp -type f # 查找所有普通文件 (f=file) find . -type d # 查找所有目录 (d=directory) find /dev -type l # 查找所有符号链接 (l=link)
grep
-
基本搜索:
grep "error" /var/log/syslog # 在 syslog 文件中搜索包含 "error" 的行 grep "TODO" *.py # 在所有 .py 文件中搜索 "TODO"
-
常用选项:
grep -i "warning" file.log # -i 忽略大小写 grep -r "function" /my/code/ # -r 递归搜索目录下的所有文件 grep -n "pattern" file.txt # -n 显示匹配行所在的行号
六 GIT
一 初始化和配置
命令 | 说明 |
---|---|
git init | 在当前目录初始化一个新的 Git 仓库 |
git clone <url> | 克隆一个远程仓库到本地(如 git clone https://github.com/user/repo.git ) |
git config --global user.name "Your Name" | 设置全局用户名 |
git config --global user.email "email@example.com" | 设置全局邮箱地址 |
git config --list | 查看当前的所有配置 |
说明:--global
选项表示该配置对当前用户的所有仓库生效。如果只想对单个仓库生效,去掉 --global
即可。
二 基本工作流程(最常用)
这些命令构成了日常开发中最基本的代码管理流程。
命令 | 说明 |
---|---|
git status | 查看仓库当前的状态(哪些文件被修改、已暂存等),这是最常用的命令之一 |
git add <file> | 将工作区的指定文件添加到暂存区(Stage) |
git add . | 将当前目录下所有变更加入暂存区(新增、修改,不包括删除) |
三 分支管理
命令 | 说明 |
---|---|
git branch | 查看所有本地分支(当前分支前有 * 号) |
git branch -a | 查看所有分支(包括远程分支) |
git branch <branch-name> | 创建一个新分支 |
git checkout <branch-name> | 切换到指定分支 |
git switch <branch-name> | (Git 2.23+) 切换到指定分支(更推荐的命令) |
git checkout -b <new-branch> | 创建并切换到新分支(旧式) |
git switch -c <new-branch> | (Git 2.23+) 创建并切换到新分支(新式) |
git merge <branch-name> | 合并指定分支到当前分支 |
四 远程仓库操作
命令 | 说明 |
---|---|
git remote -v | 查看关联的远程仓库地址(verbose) |
git remote add origin <url> | 关联一个远程仓库,并起别名为 origin |
git push -u origin main | 首次推送本地 main 分支到远程 origin ,并建立追踪关系(-u ) |
git push | 将当前分支的提交推送到远程关联分支 |
git pull | 拉取远程关联分支的更新并合并到当前分支(= git fetch + git merge ) |