1、在 application.properties 中添加一个配置(如果删除为1,不删除为0,这一步就可以不用配置)
#该配置表示删除时为1,不删除时为0
#也可以不配置这两行,因为默认就是删除为1,不删除为0
#如果设置删除为111,不删除为000等配置时,就要加上这两行配置
mybatis-plus.global-config.db-config.logic-delete-value=0
mybatis-plus.global-config.db-config.logic-not-delete-value=1
mybatis-plus全部配置如下
mybatis-plus.mapper-locations=classpath:/mapper/*/*.xml
mybatis-plus.typeAliasesPackage=com.km.sglototo.sys.entity
#mybatis-plus.typeEnumsPackage=com.zscat.sglototo.sys.entity.enums
mybatis-plus.global-config.db-config.id-type=id_worker
mybatis-plus.global-config.db-config.field-strategy=not_empty
mybatis-plus.global-config.db-config.column-underline=true
mybatis-plus.global-config.db-config.logic-delete-value=0 #逻辑删除
mybatis-plus.global-config.db-config.logic-not-delete-value=1 #逻辑删除
mybatis-plus.global-config.db-config.db-type=mysql
mybatis-plus.global-config.refresh=true
mybatis-plus.configuration.map-underscore-to-camel-case=true
mybatis-plus.configuration.cache-enabled=false
2、在mybatisPlusConifg.java文件配置逻辑删除插件如下(MP高版本不用配置插件,可直接跳过,进入第三步骤)
//逻辑删除插件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
全部配置信息内容如下
package com.km.sglototo.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
import com.km.sglototo.enums.ConstansValue;
import com.km.sglototo.ApiContext;
import com.km.sglototo.enums.ConstansValue;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import java.util.List;
//Spring boot方式
@EnableTransactionManagement
@Configuration
@MapperScan("com.km.sglototo.*.mapper*")
public class MybatisPlusConfig {
private static final List<String> IGNORE_TENANT_TABLES = ConstansValue.IGNORE_TENANT_TABLES;
@Autowired
private ApiContext apiContext;
/**
* 分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor() {
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
paginationInterceptor.setDialectType("mysql");
return paginationInterceptor;
}
/**
* 性能分析拦截器,不建议生产使用
* 用来观察 SQL 执行情况及执行时长
*/
@Bean
public PerformanceInterceptor performanceInterceptor() {
return new PerformanceInterceptor();
}
//逻辑删除插件
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
3、向对应的实体类中属性上添加 @TableLogic 注解
/**
* 是否显示 1-显示 0不显示
*/
@TableLogic(value = "1",delval = "0")
private Long isdel;
4、调用mybatisPlus删除接口进行测试
sysNoticeService.removeById(3) ;
乐观锁
概念
在学乐观锁之前,我们还是先由一个案例来引入
- 业务并发现象带来的问题:秒杀
- 假如有100个商品在售,为了保证每个商品只能被一个人购买,如何保证不会超买或者重复卖
- 对于这一类的问题,其实有很多的解决方案可以使用
- 第一个最先想到的就是锁,锁在一台服务器中是可以解决的,但是如果在多台服务器下就没办法控制,比如12306有两台服务器,在进行卖票,在两台服务器上都添加锁的话,那也有可能会在同一时刻有两个线程在卖票,还是会出现并发问题
- 我们接下来介绍的这种方式就是针对于小型企业的解决方案,因为数据库本身的性能就是个瓶颈,如果对其并发超过2000以上的就需要考虑其他解决方案了
简单来说,乐观锁主要解决的问题是,当要更新一条记录的时候,希望这条记录没有被别人更新
sql模拟解决方案
DROP TABLE IF EXISTS `repertory`;
CREATE TABLE `repertory` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`product_name` varchar(11) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '商品名称',
`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin NULL DEFAULT NULL COMMENT '地址',
`repertory` int(11) NULL DEFAULT NULL COMMENT '库存',
`version` int(11) NULL DEFAULT 1 COMMENT '版本',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of repertory
-- ----------------------------
INSERT INTO `repertory` VALUES (1, '手机', NULL, 2, 1);
INSERT INTO `repertory` VALUES (2, '电脑', NULL, 2, 1);
- 数据库表中添加
version
字段,比如默认值给个1 - 第一个线程要修改数据之前,取出记录时,获取当前的version=1
- 第二个线程要修改数据之前,取出记录时,获取当前的version=1
-- 第一个并发
UPDATE repertory SET repertory = repertory-1, version = 1 WHERE id = 1;-- 第二个并发
UPDATE repertory SET repertory = repertory-1, version = 1 WHERE id = 1;
-- sql加版本号控制超卖
-- 第一个并发
UPDATE repertory SET repertory = repertory-1, version = version + 1 WHERE id = 1 and version = 1;
-- 第二个并发
UPDATE repertory SET repertory = repertory-1, version = version + 1 WHERE id = 1 and version = 1;
mp解决方案
步骤一:
数据库表添加列
加一列version,长度给个11,默认值设为1步骤二:
在模型类中添加对应的属性
package com.example.demo27.bean;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class Repertory implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.AUTO)
private Integer id;
/**
* 商品名称
*/
private String productName;
/**
* 地址
*/
private String address;
/**
* 库存
*/
private Integer repertory;
/**
* 版本
*/
@Version
private Integer version;
}
步骤三:
添加乐观锁拦截器
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MpConfig {
@Bean
public MybatisPlusInterceptor mpInterceptor() {
//1.定义Mp拦截器
MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
//3.添加乐观锁拦截器
mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mpInterceptor;
}
}
@Test
void contextLoads2() {
Repertory repertory1 = repertoryService.getById(1);
repertory1.setAddress("广州");
repertoryService.updateById(repertory1);
}
查看日志的SQL语句
==> Preparing: UPDATE repertory SET product_name=?, address=?, repertory=?, version=? WHERE id=? AND version=?
==> Parameters: 手机(String), 广州(String), 7(Integer), 4(Integer), 1(Integer), 3(Integer)
我们传递的是1(oldVersion),MP会将1进行加1,变成2,然后更新回到数据库中(newVersion)
大概分析完乐观锁的实现步骤以后,我们来模拟一种加锁的情况,看看能不能实现多个人修改同一个数据的时候,只能有一个人修改成功
@Test
void contextLoads() {
Repertory repertory1 = repertoryService.getById(1);
repertory1.setRepertory(repertory1.getRepertory()-1);
repertory1.setVersion(1);
repertoryService.updateById(repertory1);
Repertory repertory2 = repertoryService.getById(1);
repertory2.setRepertory(repertory2.getRepertory()-1);
repertory2.setVersion(1);
repertoryService.updateById(repertory2);
}