java学习笔记--springboot、mysql、mybatisplus
Maven
生命周期
clean:移除上一次构建生成的文件
compile:编译项目源代码
test:使用合适的单元测试框架运行测试(junit)
package:将编译后的文件打包,如:jar、war等
install:安装项目到本地仓库
Springboot
Springboot原理
起步依赖:依赖传递
自动配置
分层解耦
三层架构
controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
service:业务逻辑层,处理具体的业务逻辑。
dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。
分层解耦
控制反转:Inversion Of Control,简称IOC.对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为bean。
Spring Framework的StringUtils
StringUtils常用方法
空值检查
// 检查字符串是否有内容(不为null且长度>0)
StringUtils.hasLength(str)
// 检查字符串是否有实际文本(不为null且包含非空白字符)
StringUtils.hasText(str)
// 检查字符串是否为空(null或空字符串)
StringUtils.isEmpty(str)
字符串处理
// 去除前后空白
StringUtils.trimWhitespace(str)
// 去除所有空白(包括中间的)
StringUtils.trimAllWhitespace(str)
// 将字符串数组用分隔符连接
StringUtils.collectionToDelimitedString(list, ",")
// 将逗号分隔的字符串转为数组
StringUtils.commaDelimitedListToStringArray(str)
// 首字母大写
StringUtils.capitalize(str)
// 首字母小写
StringUtils.uncapitalize(str)
Apache Commons Lang的StringUtils
空值检查
// 检查是否为空(null或空字符串)
StringUtils.isEmpty(str)
// 检查是否为空白(null、空字符串或纯空白字符)
StringUtils.isBlank(str)
// 对应的非空检查
StringUtils.isNotEmpty(str)
StringUtils.isNotBlank(str)
字符串比较
// 安全的字符串比较(处理null值)
StringUtils.equals(str1, str2)
// 忽略大小写比较
StringUtils.equalsIgnoreCase(str1, str2)
字符串处理
// 截取子字符串(安全处理null和越界)
StringUtils.substring(str, start, end)
// 左侧填充
StringUtils.leftPad(str, size, padChar)
// 右侧填充
StringUtils.rightPad(str, size, padChar)
// 去除空白
StringUtils.trim(str)
StringUtils.strip(str) // 更强大的去除空白
// 重复字符串
StringUtils.repeat(str, count)
字符串转换
// 大小写转换
StringUtils.upperCase(str)
StringUtils.lowerCase(str)
// 缩写处理
StringUtils.abbreviate(str, maxWidth)
// 反转字符串
StringUtils.reverse(str)
集合操作
// 用分隔符连接字符串数组/集合
StringUtils.join(array, separator)
// 拆分字符串
StringUtils.split(str, separator)
Bean管理
获取bean
默认情况下,Spring项目启动时,会把bean都创建好放在I0C容器中,通过@Autowired自动注入来获取bean对象。如果想要主动获取这些bean,可以通过如下方式:
bean的作用域
@Lazy: 延迟bean的初始化。
@Scope:设置bean的作用域。如:@Scope(“prototype”)
第三方bean
@Bean注解:将方法返回值交给I0C容器管理,成为I0C容器的beap对象。
如果要管理的bean对象来自于第三方(不是自定义的),是无法用 @Component及衍生注解声明bean的,就需要用到 @Bean注解,一般在配置类中定义。如:
@SpringBootApplication
@MapperScan("com.myproject.*.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
/**
* 密码加密工具类
* @return
*/
@Bean
public PasswordEncoder passwordEncoder(){
System.out.println("是否自动运行Bean:true");
return new BCryptPasswordEncoder();
}
}
MySQL
DDL:数据定义语言,用来定义数据库对象(数据库,表,字段)
DML:数据操作语言,用来对数据库表中的数据进行增删改
DQL:数据查询语言,用来查询数据库中表的记录
DCL:数据控制语言,用来创建数据库用户、控制数据库的访问权限
函数
now():获取当前系统时间。
if(条件表达式,true取值,false取值)
case 表达式 when 值l then 结果1 when 值2 then 结果2 …else … end
数学函数
| 函数 | 说明 | 示例 |
|---|---|---|
ABS(x) |
绝对值 | ABS(-5)=5 |
ROUND(x,d) |
四舍五入 | ROUND(3.1415,2)=3.14 |
TRUNCATE(x,d) |
截断 | TRUNCATE(3.1415,2)=3.14 |
CEIL(x) / CEILING(x) |
向上取整 | CEIL(3.1)=4 |
FLOOR(x) |
向下取整 | FLOOR(3.9)=3 |
MOD(x,y) |
取余 | MOD(10,3)=1 |
POWER(x,y) |
幂运算 | POWER(2,3)=8 |
SQRT(x) |
平方根 | SQRT(9)=3 |
RAND() |
随机数(0-1) | RAND() |
字符串函数
| 函数 | 说明 | 示例 |
|---|---|---|
LENGTH(s) |
字节长度 | 中文 3 字节 |
CHAR_LENGTH(s) 或 LENGTH(s) |
字符长度 | 中文 1 字符 |
CONCAT(a,b,...) |
拼接 | CONCAT('a','b')='ab' |
CONCAT_WS(sep,a,b) |
带分隔符拼接 | CONCAT_WS('-',1,2)=1-2 |
SUBSTRING(s,start,len) |
截取 | SUBSTRING('abc',2,2)='bc' |
LEFT(s,n) |
左截取 | LEFT('abc',2)='ab' |
RIGHT(s,n) |
右截取 | RIGHT('abc',2)='bc' |
UPPER(s) |
大写 | |
LOWER(s) |
小写 | |
REPLACE(s,a,b) |
替换 | REPLACE('a-b','-','_') |
TRIM(s) |
去空格 | |
LTRIM(s) |
去左空格 | |
RTRIM(s) |
去右空格 | |
LOCATE(substr,str) |
查找位置 | LOCATE('b','abc')=2 |
INSTR(str,substr) |
同上 |
日期时间函数
| 函数 | 说明 | 示例 |
|---|---|---|
NOW() |
当前日期时间 | 2025-11-20 09:33:00 |
CURDATE() |
当前日期 | |
CURTIME() |
当前时间 | |
DATE_ADD(date,INTERVAL x UNIT) |
日期加减 | DATE_ADD(NOW(),INTERVAL 1 DAY) |
DATE_SUB(date,INTERVAL x UNIT) |
日期减 | |
DATEDIFF(a,b) |
天数差 | |
TIMESTAMPDIFF(unit,a,b) |
精确差 | TIMESTAMPDIFF(MINUTE,a,b) |
YEAR(date) |
提取年份 | |
MONTH(date) |
月 | |
DAY(date) |
日 | |
HOUR(date) |
时 | |
MINUTE(date) |
分 | |
SECOND(date) |
秒 | |
DATE_FORMAT(date,format) |
格式化 | DATE_FORMAT(NOW(),'%Y-%m-%d') |
STR_TO_DATE(str,format) |
字符串转日期 |
聚合函数
| 函数 | 说明 |
|---|---|
COUNT(*) |
统计行数 |
COUNT(column) |
统计非 NULL 数量 |
SUM(column) |
求和 |
AVG(column) |
平均值 |
MAX(column) |
最大值 |
MIN(column) |
最小值 |
条件函数
| 函数 | 说明 |
|---|---|
IF(condition, a, b) |
类似三元表达式 |
IFNULL(a, b) |
NULL 返回默认值 |
NULLIF(a, b) |
相等返回 NULL |
类型转换函数
| 函数 | 说明 |
|---|---|
CAST(x AS type) |
转换类型 |
CONVERT(x, type) |
同上 |
BINARY |
强制按字节比较 |
SELECT CAST('123' AS UNSIGNED); -- 123
SELECT CAST(3.14 AS DECIMAL(5,2));
JSON 相关函数(常用)
| 函数 | 说明 |
|---|---|
JSON_EXTRACT(json, path) |
获取字段 |
JSON_SET(json, path, val) |
设置字段 |
JSON_REMOVE(json, path) |
删除字段 |
JSON_ARRAY() |
创建数组 |
JSON_OBJECT(k,v,...) |
创建对象 |
SELECT JSON_EXTRACT('{"a":1}','$.a');
DDL(表操作)
语法结构

create table 表名(
字段1 字段类型[约束][comment 字段1注释],
...
字段n 字段类型[约束][comment 字段n注释]
)[comment 表注释];

实例
// 创建表
create TABLE test(
id INT COMMENT 'ID',
user_name VARCHAR(20) comment '用户名',
name VARCHAR(20) comment '姓名',
age INT COMMENT '年龄',
gender VARCHAR(2) COMMENT '性别'
) COMMENT '用户表'
//查看表的当前结构
DESCRIBE test;
// 添加主键约束
ALTER TABLE test
MODIFY COLUMN id INT AUTO_INCREMENT,
ADD CONSTRAINT primary_key PRIMARY KEY (id)
// 添加唯一约束和非空约束
ALTER TABLE test
MODIFY user_name VARCHAR(20) NOT NULL,
ADD CONSTRAINT uq_users_username UNIQUE (user_name)
// 添加默认约束
ALTER TABLE test ALTER gender SET DEFAULT('男')
DML(数据操作)
语法结构



实例
// 新增--单条
INSERT into test(user_name) VALUES('caiw2');
// 新增--批量
INSERT INTO test(user_name) VALUES ('caiw3'),('caiw4');
// 修改
UPDATE test SET name='蔡旺',age=18 WHERE id=1;
//修改--批量
UPDATE test SET name='蔡旺',age=18
// 删除
DELETE FROM test WHERE id = 2;
DQL(查询操作)
语法结构





where与having区别
- 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤
- 判断条件不同:where不能对聚合函数进行判断,而having可以。


实例
// 基本查询
select * from test;
// 去除重复记录
SELECT DISTINCT user_name, name, age FROM test
// 条件查询
SELECT * FROM test WHERE (user_name in('caiw2','caiw3') and age = 18 and id> 2 ) || id=5
// 聚合函数
SELECT count(id) from test
SELECT count(1) from test
SELECT count(*) from test
SELECT min(age) FROM test
SELECT max(age) from test
SELECT avg(age) from test
SELECT sum(age) from test
// 分组查询--只能返回分组字段和聚合函数
select age,count(*) as '数量' from test
GROUP BY age
HAVING count(*) > 1
// 排序查询
SELECT * FROM test ORDER BY age;
SELECT * FROM test ORDER BY age desc,id DESC;
// 分页查询
SELECT * FROM test LIMIT 0 ,5
// 条件表达式--if
select IF(gender='男','男生','女生') as 性别,count(*) as 数量 FROM test GROUP BY gender;
// 条件表达式-case
select
(CASE gender
WHEN '男' THEN '男生'
WHEN '女' THEN '女生'
ELSE '太监'
END)
as 性别,
count(*) as 数量 FROM test GROUP BY gender
数据类型
数值类型

字符串类型

CHAR 和 VARCHAR的区别
CHAR 是 定长 的。你定义一个 CHAR(10),无论你存入什么字符串,它都会固定占用 10个字符 的存储空间。速度快。浪费空间
VARCHAR 是 变长 的。你定义一个 VARCHAR(10),它占用的空间是 实际字符串长度 + 1个或2个额外字节。速度慢,节省空间。
日期类型

多表设计
物理外键–不推荐使用,一般使用逻辑外键(代码实现)
1对多:在多的表里增加字段;
多对多:增加中间表来关联
多表查询 ★
连接查询
内连接:相当于查询A、B交集部分数据。
// 隐式内连接
SELECT a.*,b.category_name from test_dish as a,test_category as b WHERE b.id = a.category_id AND a.id=1
// 显示内连接
SELECT a.*,b.category_name FROM test_dish as a JOIN test_category as b ON b.id = a.category_id AND a.id=1
外连接:
左外连接:查询左表所有数据(包括两张表交集部分数据);
右外连接:查询右表所有数据(包括两张表交集部分数据);

// 左外连接
SELECT a.*,b.category_name from test_dish as a LEFT JOIN test_category as b ON b.id = a.category_id AND b.category_name='菜品品类'
SELECT a.*,b.category_name from test_dish as a LEFT JOIN test_category as b ON b.id = a.category_id WHERE b.category_name='菜品品类'
// 右外连接
SELECT a.*,b.category_name from test_dish as a RIGHT JOIN test_category as b ON b.id = a.category_id
子查询

// 标量子查询--查询所有品类为'菜品品类'的所有菜品,先获取菜品品类的id,根据id来获取菜品
SELECT * FROM test_dish as a WHERE a.category_id = (SELECT b.id FROM test_category b WHERE b.category_name='菜品品类')
// 列子查询--查询所有品类为'菜品品类、水果品类'的所有菜品,先获取菜品品类的id,根据id来获取菜品
SELECT * FROM test_dish as a WHERE a.category_id in(SELECT b.id FROM test_category b WHERE b.category_name in('菜品品类','水果品类'))
// 行子查询--查询品类为'菜品品类'并且状态一致的所有菜品
SELECT * FROM test_dish as a WHERE a.category_id = (SELECT b.id FROM test_category b WHERE b.category_name='菜品品类') and a.STATUS = (SELECT b.STATUS FROM test_category b WHERE b.category_name='菜品品类')
SELECT * FROM test_dish as a WHERE (a.category_id,a.STATUS) = (SELECT b.id,b.STATUS FROM test_category b WHERE b.category_name='菜品品类')
事务
事务:是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,即这些操作 要么同时成功,要么同时失败。
// 事务
BEGIN;
INSERT INTO test_category(category_name,create_time,update_time)VALUES('ax41',now(),now());
INSERT INTO test_dish(dish_name,price,category_id,create_time,update_time) VALUES('aaa1',200,5,now(),now());
COMMIT;
ROLLBACK;
四大特性
原子性:事务是不可分割的最小单元,要么全部成功,要么全部失败。
一致性:事务完成时,必须使所有的数据都保持一致状态。
隔离性:数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行。
持久性:事务一旦提交或回滚,它对数据库中的数据的改变就是永久的。
索引
索引(index):是帮助数据库 高效获取数据 的 数据结构。B+Tree(多路平衡搜索树)
优点:
- 提高数据查询的效率,降低数据库的I0成本。
- 通过索引列对数据进行排序,降低数据排序的成本降低CPU消耗。
缺点
3. 索引会占用存储空间。
4. 索引大大提高了查询效率,同时却也降低了insert、update、delete的效率。

MybatisPlus
BaseMapper 与 IService 方法对比

条件构造器LambdaQueryWrapper


实例
// SELECT * FROM user
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
// WHERE username = 'zhangsan'
wrapper.eq(User::getUsername, user.getUsername());
// 执行查询并获取结果
User loginUser = this.baseMapper.selectOne(wrapper);
在Mybatis中的参数#{参数}和${参数}的区别
- #是预编译sql,效率更高,防止sql注入。
LambdaQueryWrapper 与lambdaQuery()区别
| 对比项 | LambdaQueryWrapper |
lambdaQuery()(返回 LambdaQueryChainWrapper) |
|---|---|---|
| 本质 | 条件构造器 | 链式查询器(包含 wrapper + mapper) |
| 是否需要自己 new | ✔ 需要 new | ✘ 不需要 |
| 是否需要自己调用 mapper | ✔ 需要 mapper.selectList | ✘ 不需要,直接 list() 执行 |
| 能否自动识别实体类型 | ❌ 不能,需要 <User> 泛型 |
✔ 能,基于 ServiceImpl 泛型 |
| 使用场景 | Mapper 或 Service 都可 | Service 层(IService/ServiceImpl 内) |
| 代码复杂度 | 较多 | 最简洁 |
| 内部存在关系 | 是 λ 链式查询器内部使用的对象 | 包含了 LambdaQueryWrapper |
JSON 处理器
数据库字段为json类型
| 项目 | 说明 |
|---|---|
| JSON 处理器 | TypeHandler 机制自动转换 JSON |
| 常用处理器 | JacksonTypeHandler(推荐)、FastjsonTypeHandler |
| 注解使用 | @TableField(typeHandler = JacksonTypeHandler.class) |
| XML 场景 | @TableName(autoResultMap = true) 必须开启 |
| 数据库类型 | 推荐 JSON 类型 |
| 用途 | 自动序列化/反序列化 List/Map/对象 |
@Data
public class User {
private Long id;
@TableField(typeHandler = JacksonTypeHandler.class)
private List<String> hobbies;
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> configs;
@TableField(typeHandler = JacksonTypeHandler.class)
private Address address;
}
XML映射文件
- XML映射文件的名称与Mapper接口名称一致,并且将XML映射文件和Mapper接口放置在相同包下(同包同名)。
- XML映射文件的namespace属性为Mapper接口全限定名一致。
- XML映射文件中sql语句的id与Mapper 接口中的方法名一致,并保持返回类型一致。

<!-- 定义 resultMap -->
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<result property="email" column="user_email"/>
<result property="createTime" column="create_time"/>
</resultMap>
<!-- 使用 resultMap -->
<select id="getUser" resultMap="userResultMap">
SELECT user_id, user_name, user_email, create_time
FROM users
WHERE user_id = #{id}
</select>
动态SQL
if、where、set
<select id="getAll" resultType="com.myproject.demo.entity.TestCategory" parameterType="com.myproject.demo.entity.vo.VCategory">
select * from test_category
<where>
<if test="categoryName != null">
and category_name like CONCAT('%',#{categoryName},'%')
</if>
</where>
</select>
foreach批量操作
<!--
collection:遍历的集台
item:遍历出来的元素
separator:分隔符
open:遍历开始前拼接的SQL片段
close:遍历结束后拼接的sql片段
-->
<delete id="deleteByIds">
delete from test_category where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
sql、include
<sql id="list" >
select id,category_name,category_type,status,create_time,update_time from test_category
</sql>
<select id="getAll" resultType="com.myproject.demo.entity.TestCategory"
parameterType="com.myproject.demo.entity.vo.VCategory">
<include refid="list"></include>
<where>
<if test="categoryName != null">
and category_name like CONCAT('%',#{categoryName},'%')
</if>
</where>
</select>
文件上传
接收文件 – MultipartFile
@PostMapping(value="/upload")
public Result upload(@RequestPart("file") MultipartFile file) {
log.info("文件上传--------》",file);
return Result.success();
}
本地存储
使用transferTo方法转存到指定目录中
public Result upload(@RequestPart("file") MultipartFile file) throws IOException {
log.info("文件上传--------》",file);
// 转存到本地指定目录
file.transferTo(new File("D:\\logs\\"+file.getOriginalFilename()));
return Result.success();
}
存储到OSS
存储到minio
过滤器Filter
Filter(过滤器) 是 Java Web 开发中的一个重要概念,它类似于一个"安检站",在请求到达目标资源(如 Servlet、Controller)之前和响应返回给客户端之前进行拦截和处理。
public interface Filter {
// 初始化方法
void init(FilterConfig filterConfig);
// 核心过滤方法
void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain);
// 销毁方法
void destroy();
}
- 更底层的请求/响应处理
- 与具体业务逻辑无关的通用设置
- 需要在Spring MVC框架之前执行
拦截器Interceptor
作用:Spring框架提供。类似过滤器。拦截请求,在指定的方法调用前后,根据业务需要执行预先设定的代码。
常用于业务逻辑层面的拦截。
过滤器和拦截器同时存在时,过滤器先执行,放行后,再执行拦截器。
过滤器Filter会拦截所有的资源,而Interceptor只会拦截Spring环境中的资源
全局异常处理器
/**
* 全局异常处理器
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result ex(Exception ex){
ex.printStackTrace();
return Result.fail("操作失败!");
}
}
事务回滚
@Transactional(rollbackFor = Exception.class)
默认只有运行异常RuntimeException才会回滚异常。rollbackFor属性控制回滚任何异常。
@Transactional(propagation = Propagation.REQUIRED)
根据propagation 来控制事务的传播行为。
REQUIRED:【默认值】需要事务,有则加入,无则创建新事务。
REQUIRES_NEW:需要新事务,无论有无,总是创建新事务。
AOP面向切面编程
AOP: Aspect Oriented Programming(面向切面编程、面向方面编程),其实就是面向特定方法编程。
实现: 动态代理是面向切面编程最主流的实现。
通知类型
@Aroupd:环绕通知,此注解标注的通知方法在目标方法前、后都被执行。如:@Around(“execution(* com.myproject.demo.service..(…))”)
@Before:前置通知,此注解标注的通知方法在目标方法前被执行。
@After :后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行。
@AfterReturning :返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行。
@AfterThrowing :异常后通知,此注解标注的通知方法发生异常后执行
切入点
-
execution(.):根据方法的签名来匹配。

-
@annotation(.):根据注解匹配。
// 定义切入点
// @Pointcut("execution(* com.myproject.demo.service.*.*(..))")
// 拦截带有@OperLogAnnotation注解的方法
@Pointcut("@annotation(com.myproject.myAnnotation.OperLogAnnotation)")
public void operLogPointCut() {}
// 引入切入点
@Around("operLogPointCut()")
public Object addLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
Object proceed = proceedingJoinPoint.proceed();
OperateLog operateLog = new OperateLog();
operateLog.setClassName(proceedingJoinPoint.getTarget().getClass().getName());
operateLog.setCreateId("admin");
iOperateLogService.save(operateLog);
return proceed;
}
配置优先级
高到低:命令行参数->java系统属性->application.properties->application.yml。
java系统属性和命令行参数
// jar包运行
java -jar demo-0.0.1-SNAPSHOT.jar
// 配置端口号
java -Dserver.port=10000 -jar demo-0.0.1-SNAPSHOT.jar // java系统属性
java -jar demo-0.0.1-SNAPSHOT.jar --server.port=10000 // 命令行属性,优先级高于系统属性
更多推荐


所有评论(0)