SSM整合
Maven + SpringMVC + Mybatis
Maven
打包 mvn clean package 部署 mvn clean install/deploy
在 properties 标签中指定版本 然后用deoendencyManagement 标签引用版本用来父工程统一版本
MyBatis
快速上手
MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
准备数据模型
CREATE DATABASE `mybatis-example`; |
依赖导入
<dependencies> |
准备实体类 添加get set 方法
创建Mapper接口和MapperXML接口
/** |
|
准备MyBatis配置文件 mybatis-config.xml
|
测试类 结合springioc容器后 我们可以将获取Mapper对象之前的步骤全部省略
/** |
添加日志输出
在 mybatis-config.xml中添加
<settings> |
数据输入
#{key} 和 ${key} 的区别
<!-- |
类型传入时,按类型属性名传入
<insert id="insertEmployee"> |
零散的简单型数据,可以在接口中添加注解来进行数据输入,也可以通过mybatis的默认机制,arg0,arg1… 或者 param1,param2…..
int updateEmployee(; Integer empId, Double empSalary) |
<update id="updateEmployee"> |
Map类型传入
int updateEmployeeByMap(Map<String, Object> paramMap); |
<!-- |
数据输出
单个简单类型
<!--通过resultType指定查询返回值类型--> |
类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。例如:
<typeAliases> |
当这样配置时,Blog
可以用在任何使用 domain.blog.Blog
的地方。
也可以指定一个包名,MyBatis 会在包名下面搜索需要的 Java Bean,比如:
<typeAliases> <package name="domain.blog"/> </typeAliases> |
返回实体对象类型
<!-- 编写具体的SQL语句,使用id属性唯一的标记一条SQL语句 --> |
自动给字段设别名的方式过于繁琐,我们可以增加全局配置来自动识别对应关系,这样就可以用* 代替,或者直接写对象中的属性名
<!-- 在全局范围内对Mybatis进行配置 --> |
返回map类型 适用于SQL查询返回的各个字段综合起来并不和任何一个现有的实体类对应,没法封装到实体类对象中。
<select id="selectEmpNameAndMaxSalary" resultType="map"> |
返回List类型 查询结果返回多个实体类对象,希望把多个实体类对象放在List集合中返回。
Mapper上的抽象方法
List<Employee> selectAll(); |
<select id="selectAll" resultType="com.atguigu.mybatis.entity.Employee"> |
测试类中遍历List
自增主键回显 插入数据后 将自增主键的值设置到对象中
Mapper接口中的抽象方法
int insertEmployee(Employee employee); |
sql
<!-- useGeneratedKeys属性字面意思就是“使用生成的主键” --> |
测试类
|
非自增长类型主键
而对于不支持自增型主键的数据库(例如 Oracle)或者字符串类型主键,则可以使用 selectKey 子元素:selectKey 元素将会首先运行,id 会被设置,然后插入语句会被调用
1.自己维护主键
|
2.在查询之前 生成主键值
<insert id="insertUser" parameterType="User"> |
实体类属性和数据库字段对应关系
- 别名对应,将字段的别名设置成和实体类属性一致。
<select id="selectEmployee" resultType="com.atguigu.mybatis.entity.Employee"> |
- 全局配置自动识别驼峰式命名规则
<!-- 使用settings对Mybatis全局进行设置 --> |
- 使用resultMap(多用于多表查询)
<!-- 专门声明一个resultMap设定column到property之间的对应关系 --> |
多表映射
设计方案
如果是一对一的 就在类中包含单个对方对象类型的属性。如果是一对多的,就在类中包含对方的集合对象属性
案例模拟
数据库
CREATE TABLE `t_customer` (`customer_id` INT NOT NULL AUTO_INCREMENT, `customer_name` CHAR(100), PRIMARY KEY (`customer_id`) ); |
添加用户和订单的实体类
|
对一映射 (根据ID查询订单以及相关的用户信息)
订单对应用户是对一关系
OrderMapper接口
public interface OrderMapper { |
OderMapper.xml配置文件(记得在全局中注册Mapper文件)
<!-- 创建resultMap实现“对一”关联关系映射 --> |
测试类
|
对多映射(查询客户和客户关联的订单信息)
CustomerMapper接口
public interface CustomerMapper { |
CustomerMapper.xml文件 (记得在全局中注册Mapper文件)
<!-- 配置resultMap实现从Customer到OrderList的“对多”关联关系 --> |
测试类
|
多表映射优化
我们可以将autoMappingBehavior设置为full,进行多表resultMap映射的时候,可以省略符合列和属性命名映射规则(列名=属性名,或者开启驼峰映射也可以自定映射)的result标签!
修改mybatis-config.xml
<!--开启resultMap自动映射 --> |
修改CustomerMapper.xml
<resultMap id="selectCustomerWithOrderListResultMap" type="customer"> |
总结
关联关系 | 配置项关键词 | 所在配置文件和具体位置 |
---|---|---|
对一 | association标签/javaType属性/property属性 | Mapper配置文件中的resultMap标签内 |
对多 | collection标签/ofType属性/property属性 | Mapper配置文件中的resultMap标签内 |
动态语句
有些语句的条件是多变的 可能有些条件是不取值的,可以使用动态SQL来解决
if和where标签
<select id="selectEmployeeByCondition" resultType="employee"> |
set标签
<update id="updateEmployeeDynamic"> |
trim标签(trim标签更灵活,可以用在任何有需要的地方)
<!-- List<Employee> selectEmployeeByConditionByTrim(Employee employee) --> |
choose/when/otherwise标签
<select id="selectEmployeeByConditionByChoose" resultType="com.atguigu.mybatis.entity.Employee"> |
foreach标签 (*)
<!-- |
批量更新的时候要注意 在全局配置中添加allowMultiQueries=true
atguigu.dev.url=jdbc:mysql:///mybatis-example?allowMultiQueries=true
如果没有给接口中List类型的参数使用@Param注解指定一个具体的名字,那么在collection属性中默认可以使用collection或list来引用这个list集合
<!-- int updateEmployeeBatch(@Param("empList") List<Employee> empList) --> |
抽取重复的SQL片段
<!-- 使用sql标签抽取重复出现的SQL片段 --> |
拓展
资源创建的要求 Mapper接口要和Mapper配置文件名称一致 可以在sources下创建mapper接口包一致的文件夹结构存放mapperxml文件,最终打包位置一致,符合包扫描的mapper要求
PageHelper插件使用
导入依赖
<dependency> |
在 MyBatis 的配置文件中添加 PageHelper 的插件:其中,com.github.pagehelper.PageInterceptor
是 PageHelper 插件的名称,dialect
属性用于指定数据库类型(支持多种数据库)
<plugins> |
页插件的使用
|
逆向工程和MybatisX插件
逆向工程只能生成单表crud的操作,多表查询依然需要我们自己编写
现在插件市场搜索 MyBatisX进行安装
然后连接数据库,在右侧的Database标签中添加Mysql数据库,填写相关信息
展开要展示的数据库,选中要显示的数据库,然后选中逆向工程的表右键使用MybatisX-Generator
-就会自动创建Mapper接口 Mapper配置文件和实体类了
SpringMVC
SpringMVC处理请求流程
- DispatcherServlet : SpringMVC提供,我们需要使用web.xml配置使其生效,它是整个流程处理的核心,所有请求都经过它的处理和分发![ CEO ]
- HandlerMapping : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它内部缓存handler(controller方法)和handler访问路径数据,被DispatcherServlet调用,用于查找路径对应的handler![秘书]
- HandlerAdapter : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效,它可以处理请求参数和处理响应数据数据,每次DispatcherServlet都是通过handlerAdapter间接调用handler,他是handler和DispatcherServlet之间的适配器![经理]
- Handler : handler又称处理器,他是Controller类内部的方法简称,是由我们自己定义,用来接收参数,向后调用业务,最终返回响应结果![打工人]
- ViewResovler : SpringMVC提供,我们需要进行IoC配置使其加入IoC容器方可生效!视图解析器主要作用简化模版视图页面查找的,但是需要注意,前后端分离项目,后端只返回JSON数据,不返回页面,那就不需要视图解析器!所以,视图解析器,相对其他的组件不是必须的![财务]
准备环境
导入依赖
<dependencies> |
声明Controller
|
声明springmvc设计组件信息的配置类
//TODO: SpringMVC对应组件的配置类 [声明SpringMVC需要的组件信息] |
SpringMVC提供的接口,是替代web.xml的方案,更方便实现完全注解方式ssm处理!
//TODO: Springmvc框架会自动检查当前类的实现类,会自动加载 getRootConfigClasses / getServletConfigClasses 提供的配置类 |
配置tomcat 然后在地址栏中输入路径访问hander
接收数据
违背请求方式,会出现405异常!!!
param:
- 直接接收:handler(类型 形参名) 形参名 = 请求参数名
- 注解指定 hander(@RequestParam(name=”请求参数名” ,required=true(是否必需传入),defaultValue=”默认值”))
- 一名多值 hander(@RequestParam List key) 多值必须添加@RequestParam注解
- 实体接收 hander(实体 对象) 对象属性名 = 请求参数名
|
路径参数:
- 设置动态路径和标识 : /{key}/info/{key}
- 接受路径 handler(@PathVariable(动态路径key) 类型 形参名)
/** |
json
数据接收 hander(@RequestBody 实体类 对象)
需要导入jackson依赖和@EnableWebMvc
导入jackson依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
|
接收Cookie数据
|
接收请求头数据
|
原生api对象操作
/** |
共享域
使用 Model 类型的形参
public String testAttrRequestModel(
// 在形参位置声明Model类型变量,用于存储模型数据
Model model) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
model.addAttribute("requestScopeMessageModel","i am very happy[model]");
return "target";
}使用 ModelMap 类型的形参
public String testAttrRequestModelMap(
// 在形参位置声明ModelMap类型变量,用于存储模型数据
ModelMap modelMap) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
modelMap.addAttribute("requestScopeMessageModelMap","i am very happy[model map]");
return "target";
}使用 Map 类型的形参
public String testAttrRequestMap(
// 在形参位置声明Map类型变量,用于存储模型数据
Map<String, Object> map) {
// 我们将数据存入模型,SpringMVC 会帮我们把模型数据存入请求域
// 存入请求域这个动作也被称为暴露到请求域
map.put("requestScopeMessageMap", "i am very happy[map]");
return "target";
}使用原生 request 对象
public String testAttrOriginalRequest(
// 拿到原生对象,就可以调用原生方法执行各种操作
HttpServletRequest request) {
request.setAttribute("requestScopeMessageOriginal", "i am very happy[original]");
return "target";
}使用 ModelAndView 对象
public ModelAndView testAttrByModelAndView() {
// 1.创建ModelAndView对象
ModelAndView modelAndView = new ModelAndView();
// 2.存入模型数据
modelAndView.addObject("requestScopeMessageMAV", "i am very happy[mav]");
// 3.设置视图名称
modelAndView.setViewName("target");
return modelAndView;
}Session级别属性(共享)域
|
- Application级别属性(共享)域
|
响应数据
混合开发
两种开发模式 前后端分离和jsp动态页面混合开发
混合开发
jsp依赖引入
<dependency> |
jsp创建
<%@ page contentType="text/html;charset=UTF-8" language="java" %> |
配置jsp视图解析器
//json数据处理,必须使用此注解,因为他会加入json处理器 |
handler返回视图
|
转发和重定向
|
返回json数据
导入jackson依赖
<dependency> |
在配置类中添加json数据转换器(@EnableWebMvc)
//json数据处理,必须使用此注解,因为他会加入json处理器 |
要响应数据 序列化为XML或JSON格式的数据 , 并发送给客户端 要加入@ResponseBody注解,可以直接跳过视图解析器 直接返回给前端数据
|
如果类中每个方法上都标记了 @ResponseBody 注解,代表该类下的所有方法都生效,类上的 @ResponseBody 注解可以和 @Controller 注解合并为 @RestController 注解
返回静态资源
我们在项目项目中添加了一个images 然后放入一张图片资源,但是我们在网址中无法直接访问到该图片,对于springmvc中 必须有相应的 @RequestMapping 才能找到处理请求的方法,所以访问不到该图片资源
我们可以在配置类中 开启静态资源处理,是专门用于处理静态资源请求的
//json数据处理,必须使用此注解,因为他会加入json处理器 |
再次请求时,就可以访问静态资源
RESTFul风格
客户端使用GET、POST、PUT、DELETE 4个表示操作方式的动词对服务端资源进行操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源;根据接口的具体动作,选择具体的HTTP协议请求方式,过去做增删改查操作需要设计4个不同的URL,现在一个就够了。
操作 | 传统风格 | REST 风格 |
---|---|---|
保存 | /CRUD/saveEmp | URL 地址:/CRUD/emp 请求方式:POST |
删除 | /CRUD/removeEmp?empId=2 | URL 地址:/CRUD/emp/2 请求方式:DELETE |
更新 | /CRUD/updateEmp | URL 地址:/CRUD/emp 请求方式:PUT |
查询 | /CRUD/editEmp?empId=2 | URL 地址:/CRUD/emp/2 请求方式:GET |
实例:
接口设计
功能 | 接口和请求方式 | 请求参数 | 返回值 |
---|---|---|---|
分页查询 | GET /user | page=1&size=10 | { 响应数据 } |
用户添加 | POST /user | { user 数据 } | {响应数据} |
用户详情 | GET /user/1 | 路径参数 | {响应数据} |
用户更新 | PUT /user | { user 更新数据} | {响应数据} |
用户删除 | DELETE /user/1 | 路径参数 | {响应数据} |
条件模糊 | GET /user/search | page=1&size=10&keywork=关键字 | {响应数据} |
/** |
全局异常处理
声明式异常处理,新建异常处理控制类,统一定义异常处理handler方法
记得在配置类中确保异常处理控制类能被包扫描
package error; |
拦截器
创建拦截器类
package interceptor; |
配置详解
package config; |
多个拦截器执行顺序
- preHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置顺序调用各个 preHandle() 方法。
- postHandle() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 postHandle() 方法。
- afterCompletion() 方法:SpringMVC 会把所有拦截器收集到一起,然后按照配置相反的顺序调用各个 afterCompletion() 方法。
参数校验
JSR 303 进行校验
注解 | 规则 |
---|---|
@Null | 标注值必须为 null |
@NotNull | 标注值不可为 null |
@AssertTrue | 标注值必须为 true |
@AssertFalse | 标注值必须为 false |
@Min(value) | 标注值必须大于或等于 value |
@Max(value) | 标注值必须小于或等于 value |
@DecimalMin(value) | 标注值必须大于或等于 value |
@DecimalMax(value) | 标注值必须小于或等于 value |
@Size(max,min) | 标注值大小必须在 max 和 min 限定的范围内 |
@Digits(integer,fratction) | 标注值值必须是一个数字,且必须在可接受的范围内 |
@Past | 标注值只能用于日期型,且必须是过去的日期 |
@Future | 标注值只能用于日期型,且必须是将来的日期 |
@Pattern(value) | 标注值必须符合指定的正则表达式 |
标注值必须是格式正确的 Email 地址 | |
@Length | 标注值字符串大小必须在指定的范围内 |
@NotEmpty | 标注值字符串不能是空字符串 |
@Range | 标注值必须在指定的范围内 |
首先导入依赖
<!-- 校验注解 --> |
直接在实体类中添加注解即可
handler标记和绑定错误信息
|
@NotNull(包装类型不为null)
若要对字符串校验,使用 @NotBlank 或 @NotEmpty 注解。
@NotEmpty (集合类型长度大于0)
对于 CharSequence、Collection、Map 或者数组对象类型的属性进行校验,对于其他类型此注解无效,需要注意的是只校验空格前后的字符串,如果该字符串中间只有空格,不会被认为是空字符串,校验不会失败。
@NotBlank (字符串,不为null,切不为” “字符串)
@NotBlank 注解只能用于字符串类型的校验。
案例
导入依赖
|
添加实体类
|
logback配置 : resources/logback.xml
|
控制层配置编写(SpringMVC整合)
/** |
业务层配置类(service , aop ,tx)
/** |
持久层配置编写(MyBatis整合)
将SqlSessionFactory实例存储到IoC容器,将Mapper实例存储到IoC容器,mybatis提供了提供封装SqlSessionFactory和Mapper实例化的逻辑的FactoryBean组件,我们只需要声明和指定少量的配置即可!
准备数据库连接信息jdbc.properties
jdbc.user=root |
挖个坑,找不到路径 未解决 有时间来解决
SpringBoot3
快速入门
添加依赖,是一个组合包,已此项目为父工程,直接引用,不需要添加版本
<!--所有springboot项目都必须继承自 spring-boot-starter-parent--> |
添加web启动器
让Spring Boot帮我们完成各种自动配置,我们必须引入Spring Boot提供的自动配置依赖,我们称为启动器。因为我们是web项目,这里我们引入web启动器,在 pom.xml 文件中加入如下依赖:
<dependencies> |
新建启动类 MainApplication.class
/** |
SpringBoot工程下,进行统一的配置管理,你想设置的任何参数(端口号、项目根路径、数据库连接信息等等)都集中到一个固定位置和命名的配置文件(application.properties
或application.yml
)中!配置文件放在src/main/resources中,如果同时存在application.properties | application.yml(.yaml) , properties的优先级更高。
常用yaml后缀的配置文件
例如
spring: |
application.yaml(开发)
spring: |
application-test.yaml(测试)
spring: |
application-prod.yml(生产)
spring: |
环境激活
spring: |
如果设置了spring.profiles.active,并且和application有重叠属性,以active设置优先。
如果设置了spring.profiles.active,和application无重叠属性,application设置依然生效!
读取配置文件
package com.atguigu.properties; |
在controller中注入然后测试
|
加入@@ConfigurationProperties(prefix = “spring.jdbc.datasource”),读取属性文件中前缀为spring.jdbc.datasource的值。前缀和属性名称和配置文件中的key必须要保持一致才可以注入成功
测试批量配置文件注入
|
SpringBoot3整合SpringMVC
引入依赖
<?xml version="1.0" encoding="UTF-8"?> |
创建启动类和实体类 l略
创建application.yml
# web相关的配置 |
server.servlet.context-path 设置上下文路径
spring.mvc.view.prefix
和
spring.mvc.view.suffix: 这两个属性用于配置视图解析器的前缀和后缀spring.resources.static-locations: 配置静态资源的位置。
spring.http.encoding.charset
和
spring.http.encoding.enabled: 这两个属性用于配置HTTP请求和响应的字符编码 ebabled用于启用或禁用字符编码的自动配置
创建Controller
|
静态资源访问
定义静态资源默认查找路径
package org.springframework.boot.autoconfigure.web; |
也可以在application.yaml中配置静态资源地址
spring: |
自定义拦截器
拦截器声明
|
拦截器配置,配置类要在启动类的同包或者子包方可生效
|
SpringBoot3整合Druid数据源
添加依赖
|
创建启动类 创建实体类-
添加druid连接池配置
spring: |
创建EmpController
|
启动测试后 发现Druid虽然适配了SpringBoot3 但是缺少自动装配的配置文件 ,需要手动在resources目录下创建META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceAutoConfigure |
SpringBoot3整合Mybatis
导入依赖
<parent> |
配置文件application.yaml
server: |
创建实体类
创建Mapper接口,在UserMapper.xml中实现sql语句
创建三层
controller
|
service
|
创建启动类和接口扫描
//mapper接口扫描配置 |
声明式事务整合配置
依赖导入
<dependency> |
只需在方法(或者类)加上 @Transactional 注解,就自动纳入 Spring 的事务管理了
AOP整合
依赖
<dependency> |
直接使用aop注解即可
|
Mybatis-Plus
就是mybatis的增强版
快速入门
准备数据
CREATE TABLE user |
导入对应依赖
|
新建连接池配置和自动装配文件 (自动装配在上面有)
# 连接池配置 |
创建com.jason的包(自定义包)编写实体类和启动类
|
|
然后再test中创建同样的包 ,测试查询所有的信息
.springframework.boot.test.context.SpringBootTest |
可以在application.yaml中配置mybatis-plus mapperxml的地址
mybatis-plus: # mybatis-plus的配置 |
insert (插入记录),delete(删除),deleteByMap(),select方法,update
// T 就是要插入的实体对象 |
基于Service接口CRUD
通用 Service CRUD 封装[IService ](https://gitee.com/baomidou/mybatis-plus/blob/3.0/mybatis-plus-extension/src/main/java/com/baomidou/mybatisplus/extension/service/IService.java “IService (opens new window)”接口,进一步封装 CRUD 采用 get 查询单行
remove 删除
list 查询集合
page 分页
前缀命名方式区分 Mapper
层避免混淆,
比mapper接口添加了批量方法,自动添加事务
接口继承IService接口
public interface UserService extends IService<User> { |
实现类继承ServiceImpl实现类,一半的抽象方法在Iservice中还有一半在ServiceImpl中,所以要继承一个接口+一个类
|
具体方法
保存: |
分页
在MainApplication中导入分类插件
|
使用分页查询
|
自定义mapper方法使用分页
mapper中添加方法
IPage<User> selectPageVo(IPage<User> page,; Integer id) |
mapper.xml
<mapper namespace="com.jason.mapper.UserMapper"> |
application.yaml中配置别名和信息
# 连接池配置 |
Test中添加测试
|
条件构造器
自定义限制条件,来选择对应的数据,可以构建灵活、高效的查询条件,而不需要手动编写复杂的 SQL 语句,但是条件很复杂的时候,还是要用sql。
QueryWrapper<User> queryWrapper = new QueryWrapper<>(); |
查询条件
|
排序条件
|
and和or的使用
|
使用condition判断
queryWrapper.eq(!StringUtils.isEmpty(name),"name",name) |
updateWrapper
|
LambdaQueryWrapper
//QueryWrapper |
注解
@TableName注解
//表名注解,表示实体类对应的表 |
@TableId 注解
|
属性 | 类型 | 必须指定 | 默认值 | 描述 |
---|---|---|---|---|
value | String | 否 | “” | 主键字段名 |
type | Enum | 否 | IdType.NONE | 指定主键类型 |
IdType属性可选值: | ||||
值 | 描述 | |||
AUTO | 数据库 ID 自增 (mysql配置主键自增长) | |||
ASSIGN_ID(默认) | 分配 ID(主键类型为 Number(Long )或 String)(since 3.3.0),使用接口IdentifierGenerator 的方法nextId (默认实现类为DefaultIdentifierGenerator 雪花算法) |
|||
全局配置修改主键策略: |
application.yaml配置
mybatis-plus: |
在以下场景下,添加@TableId
注解是必要的:
- 实体类的字段与数据库表的主键字段不同名:如果实体类中的字段与数据库表的主键字段不一致,需要使用
@TableId
注解来指定实体类中表示主键的字段。 - 主键生成策略不是默认策略:如果需要使用除了默认主键生成策略以外的策略,也需要添加
@TableId
注解,并通过value
属性指定生成策略。
@TableFiled 字段注解
|
插件
逻辑删除实现, 平常的delete删除是物理删除,会对数据库中的数据进行直接删除。逻辑删除是吧数据库中的该字段或表变成被删除状态,数据库中仍能看到这个数据
实现:
表中添加删除字段
ALTER TABLE USER ADD deleted INT DEFAULT 0 ; # int 类型 1 逻辑删除 0 未逻辑删除 |
在实体类中指定逻辑删除字段和属性值
单一指定
|
全局指定
mybatis-plus: |
加入逻辑删除以后,删除语句实质为修改语句
//逻辑删除 |
乐观锁实现
悲观锁: 在数据访问的过程中,将共享资源锁定,阻塞其他线程的访问,当完成操作时,才释放锁,但在高并发环境下,效率低
乐观锁:在数据访问时不加锁,记录版本信息,如果该资源的版本和之前读取的版本不一致,说明其他线程修改了该资源,进行冲突处理,如果一致,则进行更新操作。
实现流程:更新时,检查版本号是不是数据库当前的版本号,如果一致,执行更新,version+=1; 如果version不对,更新失败
使用mybatis-plus使用乐观锁
添加版本号更新插件
//乐观锁插件(版本号) 在更新的时,自动对比版本号和版本号+1 |
在数据库中添加version字段
ALTER TABLE USER ADD VERSION INT DEFAULT 1 ; # int 类型 乐观锁字段 |
在实体类中属性中添加@Version注解
|
测试
//演示乐观锁生效场景 |
防全表更新和删除实现
启动类添加防止全表更新和删除拦截器插件
|
测试
|
也可使用mybatisX来实现逆向工程快速生成 与Myabtis 逆向工程同理
微头条案例
数据库数据导入
CREATE DATABASE sm_db; |
前端代码
云盘自取⋘
后端代码
导入依赖
<parent> |
appliation.yaml
# server配置 |
druid兼容boot3文件
META-INF.spring
文件名:org.springframework.boot.autoconfigure.AutoConfiguration.imports |
新建启动类
package com.jason; |
在idea中连接数据库 然后使用mybatisX的逆向工程
准备工具类
结果封装类
package com.jason.utils; |
统一返回结果状态信息类
package com.jason.utils; |
MD5加密
package com.jason.utils; |