第2章:文章介绍

以下为2020年gg的mybatis笔记

第3章:CRUD增删改查

3.1、创建库,实体

-- 创建库
CREATE DATABASE mp;

-- 使用库
USE mp;

-- 创建表
CREATE TABLE tbl_employee(
    id INT(11) PRIMARY KEY AUTO_INCREMENT,
    last_name VARCHAR(50),
    email VARCHAR(50),
    gender CHAR(1),
    age int
);

INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Tom','tom@zgb.com',1,22);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Jerry','jerry@zgb.com',0,25);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('Black','black@zgb.com',1,30);
INSERT INTO tbl_employee(last_name,email,gender,age) VALUES('White','white@zgb.com',0,35);

@TableId 实体类字段加注解

/*
 * @TableId:
 *          value: 指定表中的主键列的列名,如果实体属性名与列名一致,可以省略不指定。
 *          type: 指定主键策略。
 */
@TableId(value="id", type = IdType.AUTO)
private Integer id;    // int
private String lastName;
private String email;

注入全局配置规则

 <!-- 注入全局MP策略配置 -->
<property name="globalConfig" ref="globalConfiguration"></property>
</bean>

<!-- 定义MybatisPlus的全局策略配置 -->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
    <!-- 在2.3版本以后,dbColumnUnderline 默认值就是true -->
    <property name="dbColumnUnderline" value="true"></property>

    <!-- 全局的主键策略 -->
    <property name="idType" value="0"></property>
</bean>

@TableField 忽略不是数据库字段

private String email;
private Integer gender;
private Integer age;
@TableField(exist=false)
private Double salary;

3.2 插入操作

  1. Integer insert(T entity);
  2. @TableName
  3. 全局的 MP 配置:
<property name="tablePrefix" value="tbl_"></property>
 <!-- 全局的表前缀策略配置 -->
<property name="tablePrefix" value="tbl_"></property>
  1. @TableField
  2. 全局的 MP 配置:
<property name="dbColumnUnderline" value="true"></property>

下划线驼峰
6. @TableId
7. 全局的 MP 配置:

<property name="idType" value="0"></property>

自增
8. 支持主键自增的数据库插入数据获取主键值
Mybatis: 需要通过 useGeneratedKeys 以及 keyProperty 来设置
MP: 自动将主键值回写到实体类中
9. Integer insertAllColumn(T entity)

// 插入到数据库
// insert方法在插入时,会根据实体类的每个属性进行非空判断,只有非空的属性对应的字段才会出现到SQL语句中
// Integer result = employeeMapper.insert(employee);

// insertAllColumn方法在插入时,不管属性是否非空,属性所对应的字段都会出现到SQL语句中。
Integer result = employeeMapper.insertAllColumn(employee);

3.3 更新操作

  1. Integer updateById(@Param(“et”) T entity);
  2. Integer updateAllColumnById(@Param(“et”) T entity)

updateAllColumnById 如果不设置就会更新为null

3.4 查询操作

  1. T selectById(Serializable id);
  2. T selectOne(@Param(“ew”) T entity);
  3. List selectBatchIds(List<? extends Serializable> idList);
  4. List selectByMap(@Param(“cm”) Map<String, Object> columnMap);
//4. 通过Map封装条件查询
Map<String, Object> columnMap = new HashMap<>();
columnMap.put("last_name", "Tom");
columnMap.put("gender", 1);

List<Employee> emps = employeeMapper.selectByMap(columnMap);
System.out.println(emps);

注意!!是数据库的列
5. List selectPage(RowBounds rowBounds, @Param(“ew”) Wrapper wrapper);

//5. 分页查询
List<Employee> emps = employeeMapper.selectPage(new Page<>(3, 2), null);
System.out.println(emps);

注意!!查的时候是查的全部数据,查回来根据内存分的,所以别用这个方法!!

3.5 删除操作

  1. Integer deleteById(Serializable id);
  2. Integer deleteByMap(@Param(“cm”) Map<String, Object> columnMap);
  3. Integer deleteBatchIds(List<? extends Serializable> idList);

第4章:高级查询 EntityWrapper

4.1 EntityWrapper 简介

  1. Mybatis-Plus 通过 EntityWrapper(简称 EW,MP 封装的一个查询条件构造器)或者Condition(与 EW 类似)来让用户自由的构建查询条件,简单便捷,没有额外的负担,能够有效提高开发效率
  2. 实体包装器,主要用于处理 sql 拼接,排序,实体参数查询等
  3. 注意: 使用的是数据库字段,不是 Java 属性!
  4. 条件参数说明:
    【图片】

【图片】

4.2 使用 EntityWrapper 的方式打开如上需求:

//我们需要分页查询tbl_employee表中,年龄在18~50之间性别为男且姓名为Tom的所有用户
List<Employee> userList = employeeMapper.selectPage(new Page<Employee>(2, 3),new EntityWrapper<Employee>()
.eq("last_name","MybatisPlus")
.eq("gender", 1)
.between("age", 18, 50));

4.3 带条件的查询

  1. List selectList(@Param(“ew”) Wrapper wrapper);
// 查询tbl_employee表中,性别为女并且名字中带有"老师" 或者 邮箱中带有"a"
List<Employee> emps = employeeMapper.selectList(
    new EntityWrapper<Employee>()
    .eq("gender", 0)
    .like("last_name", "老师")
    .or()       // orNew()
    .like("email", "a")
);
System.out.println(emps);
//----------------------------------------------------------------------------
List<Employee> emps = employeeMapper.selectList(
    new EntityWrapper<Employee>()
    .eq("gender", 0)
    .like("last_name", "老师")
    // .or()       // SQL: (gender = ? AND last_name LIKE ? OR email LIKE ?)
    .orNew()      // SQL: (gender = ? AND last_name LIKE ?) OR (email LIKE ?)
    .like("email", "a")
);
System.out.println(emps);

4.4 带条件的修改

  1. Integer update(@Param(“et”) T entity, @Param(“ew”) Wrapper wrapper);
Employee employee = new Employee();
employee.setLastName("苍老师");
employee.setEmail("cls@sina.com");
employee.setGender(0);

EmployeeMapper.update(employee,
    new EntityWrapper<Employee>()
        .eq("last_name", "Tom")
        .eq("age", 44)
);

4.5 带条件的删除

  1. Integer delete(@Param(“ew”) Wrapper wrapper);
employeeMapper.delete(
    new EntityWrapper<Employee>()
        .eq("last_name", "Tom")
        .eq("age", 22)
);

查询排序,默认是 asc

// 查询性别为女的,根据age进行排序(asc/desc),简单分页
List<Employee> emps = employeeMapper.selectList(
    new EntityWrapper<Employee>()
    .eq("gender", 0)
    // .orderBy("age")
    .orderDesc(Arrays.asList(new String [] {"age"}))
);

在后面拼接sql 有注入风险

List<Employee> emps = employeeMapper.selectList(
    new EntityWrapper<Employee>()
    .eq("gender", 0)
    .orderBy("age")
    // .orderDesc(Arrays.asList(new String [] {"age"}))
    .last("desc limit 1,3")
);
System.out.println(emps);

4.6 使用 Condition 的方式打开如上需求

List<Employee> userListCondition = employeeMapper.selectPage(
new Page<Employee>(2,3),
Condition.create().
eq("gender", 1).
eq("last_name", "MyBatisPlus").
between("age", 18, 50));
List<Employee> emps = employeeMapper.selectPage(
    new Page<Employee>(1, 2),
    Condition.create()
        .between("age", 18, 50)
        .eq("gender", "1")
        .eq("last_name", "Tom")
);

4.7 小结

MP: EntityWrapper Condition 条件构造器
MyBatis MBG : xxxExample→Criteria : QBC( Query By Criteria)
Hibernate 、 通用 Mapper

第 5 章:领域模型模式CRUD

Active Record(活动记录),是一种领域模型模式,特点是一个模型类对应关系型数据库中的一个表,而模型类的一个实例对应表中的一行记录。
ActiveRecord 一直广受动态语言( PHP 、 Ruby 等)的喜爱,而 Java 作为准静态语言,对于 ActiveRecord 往往只能感叹其优雅,所以 MP 也在 AR 道路上进行了一定的探索

5.1 如何使用 AR 模式

  1. 仅仅需要让实体类继承 Model 类且实现主键指定方法,即可开启 AR 之旅.
@TableName("tbl_employee")
public class Employee extends Model<Employee>{
// .. fields
// .. getter and setter
@Override
protected Serializable pkVal() {
  return this.id;
}

5.2 AR 基本 CRUD

1) 插入操作

public boolean insert()
/**
 * AR 插入操作
 */
@Test
public void testARInsert() {
    Employee employee = new Employee();
    employee.setLastName("宋老师");
    employee.setEmail("sls@atguigu.com");
    employee.setGender(1);
    employee.setAge(35);

    boolean result = employee.insert();
    System.out.println("result:" + result);
}

2) 修改操作

public boolean updateById()
Employee employee = new Employee();
    employee.setId(14);
    employee.setLastName("宋老湿");
    employee.setEmail("sls@atguigu.com");
    employee.setGender(1);
    employee.setAge(36);

    boolean result = employee.updateById();
    System.out.println("result:");

3) 查询操作

public T selectById()
public T selectById(Serializable id)
public List<T> selectAll()
public List<T> selectList(Wrapper wrapper)
public int selectCount(Wrapper wrapper)

4) 删除操作

public boolean deleteById()
public boolean deleteById(Serializable id)
public boolean delete(Wrapper wrapper)

注意:删除不存在的数据 逻辑上也是属于成功的。

5) 分页复杂操作

public Page<T> selectPage(Page<T> page, Wrapper<T> wrapper)
 Employee employee = new Employee();

Page<Employee> page = employee.selectPage(new Page<>(1, 1), new EntityWrapper<Employee>().like("last_name", "老"));
List<Employee> emps = page.getRecords();
System.out.println(emps);

5.3 AR 小结

  1. AR 模式提供了一种更加便捷的方式实现 CRUD 操作,其本质还是调用的 Mybatis 对应的方法,类似于语法糖语法糖是指计算机语言中添加的某种语法,这种语法对原本语言的功能并没有影响.可以更方便开发者使用,可以避免出错的机会,让程序可读性更好.
  2. 到此,我们简单领略了 Mybatis-Plus 的魅力与高效率,值得注意的一点是:我们提供了强大的代码生成器,可以快速生成各类代码,真正的做到了即开即用

第 6 章:代码生成器

  1. MP 提供了大量的自定义设置,生成的代码完全能够满足各类型的需求
  2. MP 的代码生成器 和 Mybatis MBG 代码生成器:
    MP 的代码生成器都是基于 java 代码来生成。MBG 基于 xml 文件进行代码生成
    MyBatis 的代码生成器可生成: 实体类、Mapper 接口、Mapper 映射文件
    MP 的代码生成器可生成: 实体类(可以选择是否支持 AR)、Mapper 接口、Mapper 映射文件、 Service 层、Controller 层.
  3. 表及字段命名策略选择
    在 MP 中,我们建议数据库表名 和 表字段名采用驼峰命名方式, 如果采用下划线命名方式 请开启全局下划线开关,如果表名字段名命名方式不一致请注解指定,我们建议最好保持一致。这么做的原因是为了避免在对应实体类时产生的性能损耗,这样字段不用做映射就能直接和实体类对应。当然如果项目里不用考虑这点性能损耗,那么你采用下滑线也是没问题的,只需要在生成代码时配置 dbColumnUnderline 属性就可以

6.1 代码生成器依赖

  1. 模板引擎
    MP 的代码生成器默认使用的是 Apache 的 Velocity 模板,当然也可以更换为别的模板
    技术,例如 freemarker。此处不做过多的介绍。
    需要加入 Apache Velocity 的依赖
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.0</version>
</dependency>
  1. 加入 slf4j ,查看日志输出信息
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.7</version>
</dependency>
<dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.7</version>
</dependency>

6.2 MP 代码生成器示例代码

@Test
public void testGenerator() {
    // 全局配置
    GlobalConfig config = new GlobalConfig();
    config.setActiveRecord(true) // 是否支持AR模式
          .setAuthor("zhuguanbo") // 作者
          .setOutputDir("D:\\workspace_my\\mp03\\src\\main\\java") // 生成路径
          .setFileOverride(true) // 文件覆盖
          .setServiceName("%sService") // 设置生成的service接口名,首字母是否为I
          .setIdType(IdType.AUTO); // 主键策略

    DataSourceConfig dsConfig = new DataSourceConfig();
    dsConfig.setDbType(DbType.MYSQL)
            .setUrl("jdbc:mysql://localhost:3306/javaEE_0228")
            .setDriverName("com.mysql.jdbc.Driver")
            .setUsername("root")
            .setPassword("1234");

    // 策略配置
    StrategyConfig stConfig = new StrategyConfig();
    stConfig.setCapitalMode(true) // 全局大写命名
            .setDbColumnUnderline(true) // 表名、字段名是否使用下划线命名
            .setNaming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略
            .setInclude("tbl_employee") // 生成的表
            .setTablePrefix("tbl_"); // 表前缀

    // 包名策略
    PackageConfig pkConfig = new PackageConfig();
    pkConfig.setParent("com.zhuguanbo.mp")
            .setController("controller")
            .setEntity("beans")
            .setService("service");

    AutoGenerator ag = new AutoGenerator()
            .setGlobalConfig(config)
            .setDataSource(dsConfig)
            .setStrategy(stConfig)
            .setPackageInfo(pkConfig);
            
    ag.execute();
}

6.3 ServiceImpl 说明

EmployeeServiceImpl 继承了 ServiceImpl 类,mybatis-plus 通过这种方
式为我们注入了 EmployeeMapper,这样可以使用 service 层默认为我们提供的很
多方法,也可以调用我们自己在 dao 层编写的操作数据库的方法.

第 7 章:插件扩展

7.1 Mybatis 插件机制简介

  1. 插件机制:
    Mybatis 通过插件(Interceptor) 可以做到拦截四大对象相关方法的执行,根据需求,完成相关数据的动态改变。
    Executor
    StatementHandler
    ParameterHandler
    ResultSetHandler
  2. 插件原理
    四大对象的每个对象在创建时,都会执行 interceptorChain.pluginAll(),会经过每个插件对象的 plugin()方法,目的是为当前的四大对象创建代理。代理对象就可以拦截到四大对象相关方法的执行,因为要执行四大对象的方法需要经过代理.

7.2 分页插件

  1. com.baomidou.mybatisplus.plugins.PaginationInterceptor
@Test
public void testPage() {
    Page<Employee> page = new Page<>(1, 1);
    List<Employee> emps = employeeMapper.selectPage(page, null);
    System.out.println(emps);

    System.out.println("===============获取分页相关的一些信息===============");
    System.out.println("总条数:" + page.getTotal());
    System.out.println("当前页码: " + page.getCurrent());
    System.out.println("总页码:" + page.getPages());
    System.out.println("每页显示的条数:" + page.getSize());
    System.out.println("是否有上一页: " + page.hasPrevious());
    System.out.println("是否有下一页: " + page.hasNext());

    //将查询的结果封装到page对象中
    page.setRecords(emps);
}

7.3 执行分析插件

  1. com.baomidou.mybatisplus.plugins.SqlExplainInterceptor
  2. SQL 执行分析拦截器,只支持 MySQL5.6.3 以上版本
  3. 该插件的作用是分析 DELETE UPDATE 语句,防止小白或者恶意进行 DELETE UPDATE 全表操作
  4. 只建议在开发环境中使用,不建议在生产环境使用
  5. 在插件的底层 通过 SQL 语句分析命令:Explain 分析当前的 SQL 语句,根据结果集中的 Extra 列来断定当前是否全表操作。
    【图片】

7.4 性能分析插件

  1. com.baomidou.mybatisplus.plugins.PerformanceInterceptor
  2. 性能分析拦截器,用于输出每条 SQL 语句及其执行时间
  3. SQL 性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题
    【图片】

7.5 乐观锁插件

  1. com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor
  2. 如果想实现如下需求: 当要更新一条记录的时候,希望这条记录没有被别人更新
  3. 乐观锁的实现原理:
    取出记录时,获取当前 version 2
    更新时,带上这个 version 2
    执行更新时, set version = yourVersion+1 where version = yourVersion
    如果 version 不对,就更新失败
  4. @Version 用于注解实体字段,必须要有。
    【图片】
<!-- 注册乐观锁插件 -->
<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"> </bean>
private Integer age;
@Version
private Integer version;

第 8 章:自定义全局操作

根据 MybatisPlus 的 AutoSqlInjector 可以自定义各种你想要的 sql ,注入到全局中,相当于自定义 Mybatisplus 自动注入的方法。
之前需要在 xml 中进行配置的 SQL 语句,现在通过扩展 AutoSqlInjector 在加载 mybatis 环境时就注入。

8.1 AutoSqlInjector

  1. 在 Mapper 接口中定义相关的 CRUD 方法
    【图片】
/**
*@since"2018-06-21
*/
public interface EmployeeMapper extends BaseMapper<Employee>{
int deleteA 11();
}
  1. 扩展 AutoSqlInjector inject 方法,实现 Mapper 接口中方法要注入的 SQL
    【图片】
/**
自定义全局操作
public class MySqlInjector extends
AutoSqlInjector{
/**
* 扩展inject 方法, 完成自定义全局操作
@Override
public void inject(Configuration configuration, MapperbuilderAssistant builderAssistant, Class<?> n
Class<?> modelClass, TableInfo table) {
//将EmployeeMapper中定义的deleteAl1, 处理成对应的MappedStatement对象, 加入configuration对象中。|
}
}
Class<?> modelClass, TableInfo table) {
//将EmployeeMapper中定义的deleteAl1, 处理成对应的MappedStatement对象, 加入到configuration对象中。
//注入的SQL语句
String sql = "delete from " +table.getTableName();
//注入的方法名 一定要与EmployeeMapper接口中的方法名一致
String method ="deleteAll";
//构造Sq1Source对象
Sq1Source sqlSource =languageDriver. createsqlSource(configuration, sql, modelclass);
//构造一个删除的MappedStatement
this. addDeleteMappedStatemenit (mapperClass, method, sqlSource) ;
}
  1. 在 MP 全局策略中,配置 自定义注入器
    【图片】

测试
【图片】

/**
* 测试自定义全局操作
*/
@Test
I
public void testMySqlInjector(){
Integer result = employeeMapper.deleteAl1();
System.out.println("result:" +result);
}

8.2 自定义注入器的应用之 逻辑删除

假删除、逻辑删除: 并不会真正的从数据库中将数据删除掉,而是将当前被删除的这条数据中的一个逻辑删除字段置为删除状态.tbl_user logic_flag = 1 → -1

  1. com.baomidou.mybatisplus.mapper.LogicSqlInjector
  2. logicDeleteValue 逻辑删除全局值
  3. logicNotDeleteValue 逻辑未删除全局值
  4. 在 POJO 的逻辑删除字段 添加 @TableLogic 注解
  5. 会在 mp 自带查询和更新方法的 sql 后面,追加『逻辑删除字段』=『LogicNotDeleteValue默认值』删除方法: deleteById()和其他 delete 方法, 底层 SQL 调用的是 update tbl_xxx set 『逻辑删除字段』=『logicDeleteValue 默认值』
    【图片】

【图片】

public class User {
    private Integer id;
    private String name;
    @TableLogic // 逻辑删除属性
    private Integer logicFlag;
 }

【图片】

 /**
 * 测试逻辑删除
 */
@Test
public void testLogicDelete() {
    Integer result = userMapper.deleteById(1);
    System.out.println("result:" + result);
}

【图片】

第 9 章:公共字段自动填充

9.1 元数据处理器接口

com.baomidou.mybatisplus.mapper.MetaObjectHandler
insertFill(MetaObject metaObject)
updateFill(MetaObject metaObject)
metaobject: 元对象. 是 Mybatis 提供的一个用于更加方便,更加优雅的访问对象的属性,给对象的属性设置值 的一个对象. 还会用于包装对象. 支持对 Object 、Map、Collection等对象进行包装本质上 metaObject 获取对象的属性值或者是给对象的属性设置值,最终是要通过 Reflector 获取到属性的对应方法的 Invoker, 最终 invoke.

9.2 开发步骤

  1. 注解填充字段 @TableFile(fill = FieldFill.INSERT) 查看 FieldFill
  2. 自定义公共字段填充处理器
  3. MP 全局注入 自定义公共字段填充处理器
 public class User {
    private Integer id;
    @TableField(fill=FieldFill.INSERT_UPDATE)
    private String name;
    @TableLogic // 逻辑删除属性
    private Integer logicFlag;
}
public enum FieldFill {
    DEFAULT(0, "默认不处理"),
    INSERT(1, "插入填充字段"),
    UPDATE(2, "更新填充字段"),
    INSERT_UPDATE(3, "插入和更新填充字段");
}

【图片】

【图片】

import com. baomidou. mybatisplus. mapper. Meta0bjectHandler;
/**
*自定义公共字段填充处理器
*/
public class [MyMeta0bjectHandlerextends Meta0bjectHandler{
/**
插入操作自动填充
*
@Override
public void insertFil1(Meta0bject meta0bject) {
}
/**
修改操作自动填充
@Override
public void updateFill(Meta0bject meta0bject) {
}
}
Writable
Smart Insert
8:16)
public void insertFill(MetaObject metaObject) {
    //获取到需要被填充的字段的值
    Object fieldValue = getFieldValByName("name", metaObject);
    if(fieldValue == null) {
        System.out.println("**********插入操作 满足填充条件**********");
        setFieldValByName("name", "zhugaunbo", metaObject);
    }
}
/**
 * 修改操作 自动填充
 */
@Override
public void updateFill(MetaObject metaObject) {
    Object fieldValue = getFieldValByName("name", metaObject);
    if(fieldValue == null) {
        System.out.println("**********修改操作 满足填充条件**********");
        setFieldValByName("name", "weiyyh", metaObject);
    }
}
//测试  如果不设置值就用我们填充的,有值就用设置的值
@Test
public void testMetaObjectHandler() {
    User user = new User();
    user.setName("Tom");
    user.setLogicFlag(1);

    userMapper.insert(user);
}

如果文章对你有一点点帮助,欢迎【点赞、留言、+ 关注】
您的关注是我持续创作的重要动力!有问题欢迎随时交流!多一个朋友多一条路!

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐