(自用)Mybatis-plus简易了解-2021-10-15

一. 测试基本准备:

1. Springboot项目: 快速创建Spring Initializer
2. 导入依赖: starter 
3. yml配置: 
    (1). dataSource四大属性
    (2). mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout. StaOutImpl  #开启SQL语句打印
    
4. 实体类: @Data  //lombok注解 -> 类的setter/getter/equals/hashCode/toString方法
5. 数据库表user
6. mapper接口: public interface UserMapper extends BaseMapper<User>{}
7. 启动类mapper接口扫描: @MapperScan("com.changgou.user.dao")
8. 测试类: @SpringBootTest

1. 结论: 针对单表CRUD操作 -> MP自动做数据库下划线命名, 驼峰命名之间的转化;

二. 核心:

1. 8个注解:

@TableName(name="user")  //类映射数据库
public class User {  
    @TableId(value="id")  //字段 -> 主键id
    private Integer id;
    
    @TableField(exist=false) //额外字段, 插入时忽略字段
    private transient String unnecessary;    
    @TableField(insertStragtegy / updateStrategy / whereStrategy) //控制对象字段如何组装SQL   
    @TableField(fill) //自动填充

    @Version //乐观锁
    
    @EnumValue  //枚举字段
    
    @TableLogic  //逻辑删除

    @keySequence //oracle主键不自增, 配置序列主键策略

    @InterceptorIgnore  //拦截器过滤规则      
}

2. CRUD接口:  Mapper CRUD/Service CRUD接口 (封装CRUD方法+条件构造器Wrapper)

Mapper CRUD接口: 
Public interface UserMapper extends BaseMapper<User>{
(1) Mybatis启动 -> MP解析实体类和表关系映射 -> 注入CRUD mapper
    insert(T entity) 插入一条记录
    deleteById(Serializable id) 根据主键id删除一条记录
    delete(Wrapper<T> wrapper) 根据条件构造器wrapper进行删除
    selectById(Serializable id) 根据主键id进行查找
    selectBatchIds(Collection idList) 根据主键id进行批量查找
    selectByMap(Map<String,Object> map) 根据map中指定的列名和列值进行等值匹配查找
    selectMaps(Wrapper<T> wrapper) 根据 wrapper 条件,查询记录,将查询结果封装为一个Map,Map的key为结果的列,value为值
    selectList(Wrapper<T> wrapper) 根据条件构造器wrapper进行查询
    update(T entity, Wrapper<T> wrapper) 根据条件构造器wrapper进行更新
    updateById(T entity)
    
(2) selectMap:  查询指定列, 返回Map<key是列名String, value是列数据Object>
(3) selectObjs: 只返回第一列/字段值
(4) selectCount: 查询满足条件总数, 方法自动添加select count(1)

}
Service CRUD接口: //属于service层, 支持更多批量化操作

(1) public interface UserService extends IService<User> {    }

(2) @Service
    //这里的笔记看不懂, 继承的什么类?
    public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements     UserService{}
(3) IService支持链式调用
    public void TestChain(){
        List<User> list =  userService.lambdaQuery()
                .gt(User::getAge, 39)
                .likeRight(User::getName, "王")
                .list();
                list.forEach(System.out::println);
1. 条件构造器:
   QueryWrapper: SELECT语句 -> select()方法
   UpdateWrapper: UPDATE语句 -> set()方法
   父接口: AbstractMapper
2. WHERE条件:
    eq / allEq / ne / gt / ge / lt / le / between / notBetween
    like("name", "黄"), -> name like '%黄%'
    likeRight("name", "黄") -> name like '黄%'
    likeLeft("name", "黄") -> name like '%黄'
    notlike("name", "黄") -> name not like '%黄%'
    isNull
    isNotNull
    in
    and
    apply: 拼接SQL, 数据库函数, 动态传参
3. 练习了解:
    new QueryWrapper<>().like("name","黄").lt("age", 25).isNotNull("email");
wrapper.likeRight("name","黄").or().ge("age",40).orderByDesc("age").orderByAsc("id");
4.  指定boolean类型的参数condition -> true则加入条件
    //hasText为true时, 拼接like -> where
    new QueryWrapper<>().like(StringUtils.hasText(name), "name", name);
5. 新建对象 -> 属性为空 -> 赋值部分属性 -> 通过 非空属性 = 等值匹配 -> 查询
    User user = new User();
    user.setName("黄冰冰");
    user.setAge(18);
    List<User> users = userMapper.selectList(new QueryWrapper<>(user));  //精准查询
   通过@TableField(condition=SqlCondition.LIKE), 使用like拼接字段
    user.setName("黄");
    
6. lambda条件构造器:
    new LamdaQueryWrapper<>().like(User::getName, "黄").lt(User::getAge, 30);

7. update(T entity, Wrapper<T> wrapper):  更加实体类和构造器更新
    new LambdaUpdateWrapper<>().between(User::getAge, 26,    31).likeRight(User::getName,"吴");

8. 删除: deleteById / deleteBatchIds / deleteByMap / delete(Wrapper<T> wrapper)

9. 原生mybatis: 自定义SQL
    (1) 注解: @Select("select * from user ${ew.customSqlSegment}")
    (2) XML: <select id="findAll" resultType="com.example.mp.po.User">
                SELECT * FROM user ${ew.customSqlSegment}
             </select>
10. 分页:
    (1) selectPage -> java pojo
    (2) selectMapsPage -> 封装Map<String, Object>
    (3) 分页拦截器: MybatisPlusInterceptor
        new MybatisPlusInterceptor().addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    
1. MP主键策略: @TableId(type="")
    (1) 默认策略: 基于雪花算法的自增id
    (2) 策略类型: 枚举类IdType = AUTO / NONE / INPUT / ASSIGN_ID
        1) auto: 依赖数据库ID自增
        2) none: 不设置主键类型
        3) input: 手动设置主键 -> 无则值为NULL(插入操作SQL) -> Oracle
        4) assign_id: 主键为空时, 自动填充
    (3) yml中配置: mybatis-plus: global-config: db-config: id-type: auto

2. 配置:
    (1) configLocation: 全局配置文件
    (2) mapperLocation: xml文件位置
    (3) typeAliasesPackage: 别名包扫描
    (4) mapUnderscoreCamelCase: 约定自动驼峰式
    (5) dbType: 数据库类型
    (6) 字段验证策略:
        1) INGNORED: 不校验
        2) NOT_NULL: 非null校验
        3) NOT_EMPTY: 非空校验
        4) NEVER: 不加SQL

三. MP代码生成器:

public class Generator {
	@Test
	public void generate() {
		AutoGenerator generator = new AutoGenerator();

		// 全局配置
		GlobalConfig config = new GlobalConfig();
		String projectPath = System.getProperty("user.dir");
		// 设置输出到的目录
		config.setOutputDir(projectPath + "/src/main/java");
		config.setAuthor("yogurt");
		// 生成结束后是否打开文件夹
		config.setOpen(false);

		// 全局配置添加到 generator 上
		generator.setGlobalConfig(config);

		// 数据源配置
		DataSourceConfig dataSourceConfig = new DataSourceConfig();
		dataSourceConfig.setUrl("jdbc:mysql://localhost:3306/yogurt?serverTimezone=Asia/Shanghai");
		dataSourceConfig.setDriverName("com.mysql.cj.jdbc.Driver");
		dataSourceConfig.setUsername("root");
		dataSourceConfig.setPassword("root");

		// 数据源配置添加到 generator
		generator.setDataSource(dataSourceConfig);

		// 包配置, 生成的代码放在哪个包下
		PackageConfig packageConfig = new PackageConfig();
		packageConfig.setParent("com.example.mp.generator");

		// 包配置添加到 generator
		generator.setPackageInfo(packageConfig);

		// 策略配置
		StrategyConfig strategyConfig = new StrategyConfig();
		// 下划线驼峰命名转换
		strategyConfig.setNaming(NamingStrategy.underline_to_camel);
		strategyConfig.setColumnNaming(NamingStrategy.underline_to_camel);
		// 开启lombok
		strategyConfig.setEntityLombokModel(true);
		// 开启RestController
		strategyConfig.setRestControllerStyle(true);
		generator.setStrategy(strategyConfig);
		generator.setTemplateEngine(new FreemarkerTemplateEngine());

        // 开始生成
		generator.execute();
	}
}
    

四. 高级功能:

1. 逻辑删除: 数据恢复, 保护数据

mybatis-plus:
  global-config:
    db-config:
      logic-delete-field: deleted  # 全局逻辑删除的实体字段名
      logic-delete-value: 1 # 逻辑已删除值(默认为1)
      logic-not-delete-value: 0 # 逻辑未删除值(默认为0)
      # 若逻辑已删除和未删除的值和默认值一样,则可以不配置这2项
//全局配置: 多个表会统一逻辑删除字段名,统一逻辑已删除和未删除的值
@TableLogic(value = "0", delval = "1")
private Integer deleted;

 2. MP逻辑删除, 会对SQL产生如下的影响

  • INSERT语句:没有影响
  • SELECT语句:追加WHERE条件,过滤掉已删除的数据
  • UPDATE语句:追加WHERE条件,防止更新到已删除的数据
  • DELETE语句:转变为UPDATE语句
  • 只针对mp自动注入的SQL生效。**如果是自己手动添加的自定义SQL,则不会生效

3.  自动填充: 自动填充某些字段的增改

public class User2 {
	private Long id;
	private String name;
	private Integer age;
	private String email;
	private Long managerId;
	@TableField(fill = FieldFill.INSERT) // 插入时自动填充
	private LocalDateTime createTime;
	@TableField(fill = FieldFill.UPDATE) // 更新时自动填充
	private LocalDateTime updateTime;
	private Integer version;
	private Integer deleted;
}

4. 乐观锁插件: -> 并发操作 -> 数据冲突 -> 控制并发

   (1) 悲观锁的方法是,在对数据库的一条记录进行修改时,先直接加锁(数据库的锁机制),锁定这条数据,然后再进行操作;

   (2)  乐观锁,正如其名,它先假设不存在冲突情况,而在实际进行数据操作时,再检查是否冲突  

   (3) 乐观锁的一种通常实现是版本号,在MySQL中也有名为MVCC的基于版本号的并发事务控制

 在读多写少的场景下,乐观锁比较适用,能够减少加锁操作导致的性能开销,提高系统吞吐量。

在写多读少的场景下,悲观锁比较使用,否则会因为乐观锁不断失败重试,反而导致性能下降。

   (4) 乐观锁实现:

(1) 取出记录, 获取version
(2) 更新带上version
(3) 执行更新, set version=newVersion where version = oldVersion
(4) 如果oldVersion != 数据库的version, 更新失败
package com.example.mp.config;

import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MybatisPlusConfig {
    /** 3.4.0以后的mp版本,推荐用如下的配置方式 **/
	@Bean
	public MybatisPlusInterceptor mybatisPlusInterceptor() {
		MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
		interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
		return interceptor;
	}
    /** 旧版mp可以采用如下方式。注意新旧版本中,新版的类,名称带有Inner, 旧版的不带, 不要配错了 **/
    /*
    @Bean
	public OptimisticLockerInterceptor opLocker() {
		return new OptimisticLockerInterceptor();
	}
	*/
}
实体类中表示版本的事务添加注解 @Version
@Data
public class User2 {
	private Long id;
	private String name;
	private Integer age;
	private String email;
	private Long managerId;
	private LocalDateTime createTime;
	private LocalDateTime updateTime;
	@Version
	private Integer version;
	private Integer deleted;
}

五. 性能分析插件

该插件会输出SQL语句的执行时间,以便做SQL语句的性能分析和调优。

注:3.2.0版本之后,mp自带的性能分析插件被官方移除了,而推荐食用第三方性能分析插件

(1)导入依赖: p6spy
(2) yml配置: spring: dataSource:
                dirver-class-name: com.p6spy.engine.spy.p6spyDriver #换成p6spy的驱动
                url: jdbc:p6spy:mysql://localhost:3306/db?serverTimezone=Asia/Shanghai
(3) 在src/main/resources资源目录下添加 spy.properties:
#spy.properties
#3.2.1以上使用
modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
# 真实JDBC driver , 多个以逗号分割,默认为空。由于上面设置了modulelist, 这里可以不用设置driverlist
#driverlist=com.mysql.cj.jdbc.Driver
# 自定义日志打印
logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
#日志输出到控制台
appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
#若要日志输出到文件, 把上面的appnder注释掉, 或者采用下面的appender, 再添加logfile配置
#不配置appender时, 默认是往文件进行输出的
#appender=com.p6spy.engine.spy.appender.FileLogger
#logfile=log.log
# 设置 p6spy driver 代理
deregisterdrivers=true
# 取消JDBC URL前缀
useprefix=true
# 配置记录 Log 例外,可去掉的结果集有error,info,batch,debug,statement,commit,rollback,result,resultset.
excludecategories=info,debug,result,commit,resultset
# 日期格式
dateformat=yyyy-MM-dd HH:mm:ss
# 是否开启慢SQL记录
outagedetection=true
# 慢SQL记录标准 2 秒
outagedetectioninterval=2
# 执行时间设置, 只有超过这个执行时间的才进行记录, 默认值0, 单位毫秒
executionThreshold=10

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值