配置

注解配置

1、@TableName(value=””)

mybatisplus会默认使用实体类的类名到数据中找对应的表,将bean中的映射表与value指的sql表对应

  1. @TableName(value = "tbl_employee")
  2. public class Employee {}

2、@TableId(value = “”,type = )

主键策略,value指定表中的主键列的列名,如果实体属性名与列名一致,可以省略不指定;type指定主键策略;

//IdType.AUTO:自动生成
@TableId(value = "id",type = IdType.AUTO)
private Integer id ;

3、@TableField(value = “”)

将驼峰命名与数据库中下划线命名对应

@TableField(value = "last_name")
private String  lastName;

4、@TableField(exist = )

字段是数据表中没有的,如果强行加入会报错,使用注解可以忽略它

@TableField(exist = false)
private Double salary;

全局配置

注解配置只能针对单个表或属性,若要所有表都遵循规定则要使用applicationContext.xml配置文件

<!--定义mybatis plus全局配置策略-->
<bean id="globalConfiguration" class="com.baomidou.mybatisplus.entity.GlobalConfiguration">
   <!--在2.3以后,dbColumnUnderline默认为true,自动开启,类似注解3-->
    <property name="dbColumnUnderline" value="true"></property>
    <!--全局的主键策略,注解只能用于一个,作用类似注解2-->
    <property name="idType" value="0"></property>
    <!--全局的表前缀策略配置,类似注解1-->
    <property name="tablePrefix" value="tbl_"></property>
</bean>

通用操作

插入

  1. insert
@Test
public void testCommonInsert(){
    //初始化Employee对象
    Employee employee = new Employee();
    employee.setLastName("mp");
    employee.setEmail("111@guigu.com");
    employee.setAge(23);
    employee.setGender(2);
    //插入到数据库,会根据实体类的每个属性进行非空判断,只有非空的属性对应的字段才会出现在sql语句中
    Integer result = employeeMapper.insert(employee);
    System.out.println("result:"+result);
    //自动获取当前插入数据的ID
    Integer id = employee.getId();
    System.out.println(id);
}
  1. insertAllColumn
@Test
public void testCommonInsert(){
    //初始化Employee对象
    Employee employee = new Employee();
    employee.setLastName("mp");
    employee.setEmail("111@guigu.com");
    employee.setAge(23);
    employee.setGender(2);
    //插入全部属性,不管属性是否非空,属性所对应的字段都会出现sql语句中
    Integer result1 = employeeMapper.insertAllColumn(employee);
    System.out.println("result1"+result1);
    //自动获取当前插入数据的ID
    Integer id = employee.getId();
    System.out.println(id);
}

删除

  1. deleteById(根据ID删除)
    @Test
    public void testCommonDelect(){
        //根据id删除
        Integer integer = employeeMapper.deleteById(3);
        System.out.println(integer);
    }
  1. deleteByMap(根据条件删除)
    @Test
    public void testCommonDelect(){
        //2.根据条件进行删除
        //注意:put中的key写的是sql列名而不是属性名
        Map<String,Object> columnmMap = new HashMap<>();
        columnmMap.put("last_name","mp");
        columnmMap.put("email","111@guigu.com");
        Integer result = employeeMapper.deleteByMap(columnmMap);
        System.out.println(result);
    }
  1. deleteBatchIds(批量删除)
    @Test
    public void testCommonDelect(){
        //3.批量删除
        List<Integer> idlist = new ArrayList<>();
        idlist.add(2);
        idlist.add(3);
        idlist.add(4);
        Integer ids = employeeMapper.deleteBatchIds(idlist);
        System.out.println(ids);
    }

更新

  1. updateById
@Test
public void testCommonUpdate(){
    //初始化修改对象
    Employee employee = new Employee();
    employee.setId(11);
    employee.setLastName("草");
    employee.setEmail("sdfsf@qq.com");
    employee.setGender(0);
    //和insert方法一样,会判断非空,如果是空就不会加入到sql语句中
    Integer result = employeeMapper.updateById(employee);
    System.out.println("result:"+result);

}
  1. updateAllColumnById
@Test
public void testCommonUpdate(){
    //初始化修改对象
    Employee employee = new Employee();
    employee.setId(11);
    employee.setLastName("草");
    employee.setEmail("sdfsf@qq.com");
    employee.setGender(0);
    //和insertAllColumn一样不会判断非空,因此元素为空时就会被改为空
    Integer result2 = employeeMapper.updateAllColumnById(employee);
    System.out.println("result2:"+result2);

}

查询

  1. selectById(ID查询)
    @Test
    public void testCommonSelect(){
        //通过ID查询
        Employee employee = employeeMapper.selectById(7);
        System.out.println(employee);
    }
  1. selectOne(多列查询)
    @Test
    public void testCommonSelect(){
        //2.通过多个列进行查询 例:id + lastName
        //注意:selectOne只能得到一个结果,如果根据条件查询的有多个结果就会报错
        Employee employee = new Employee();
        employee.setId(7);
        employee.setLastName("mp");
        Employee employee1 = employeeMapper.selectOne(employee);
        System.out.println(employee1);
    }
  1. selectBatchIds(多ID查询)
    @Test
    public void testCommonSelect(){
        //3.通过多个ID进行查询
        List<Integer> idlist = new ArrayList<>();
        idlist.add(10);
        idlist.add(11);
        List<Employee> employees = employeeMapper.selectBatchIds(idlist);
        System.out.println(employees);
    }
  1. selectByMap(map条件查询)
    @Test
    public void testCommonSelect(){
        //4.通过map封装条件查询
        //注意:put中的key写的是sql列名而不是属性名
        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);
    }
  1. selectPage(分页查询)
    @Test
    public void testCommonSelect(){
        //5.分页查询,并不是物理分页
        List<Employee> emps = employeeMapper.selectPage(new Page<>(2, 2), null);
        System.out.println(emps);
    }

条件构造器EntityWrapper

让用户自由的构建查询条件,实体包装器,主要用于处理sql拼接吗,排序,实体参数查询等。

注意:使用的数据库字段,不是java属性

  1. 带条件查询
/**
 * 条件构造器 查询操作
 */
@Test
public void testEntityWrapperSelect(){
    //分页查询表中年龄在18-50之间性别为i男性且姓名xx的所有用户
    List<Employee> list = employeeMapper.selectPage(new Page<Employee>(1, 2), new EntityWrapper<Employee>()
            .between("age", 18, 50)
            .eq("gender", 1)
            .eq("last_name", "Tom"));
    System.out.println(list);
}
    @Test
    public void testEntityWrapperSelect(){
        //查询表中性别为女,且名字带有“老师”或邮箱带有“a”
        //or方法
        List<Employee> emps = employeeMapper.selectList(new EntityWrapper<Employee>().eq("gender",1)
                .like("last_name","老师")
                .or()// SELECT id,last_name AS lastName,email,gender,age FROM tbl_employee WHERE (gender = ? AND last_name LIKE ? OR email LIKE ?)
                .like("email","a")
        );
        System.out.println(emps);
    }
@Test
public void testEntityWrapperSelect(){
    //查询表中性别为女,且名字带有“老师”或邮箱带有“a”
    //ornew方法
    List<Employee> emps = employeeMapper.selectList(new EntityWrapper<Employee>().eq("gender",1)
            .like("last_name","老师")
            .orNew()//SELECT id,last_name AS lastName,email,gender,age FROM tbl_employee WHERE (gender = ? AND last_name LIKE ?) OR (email LIKE ?)
            .like("email","a")
    );
    System.out.println(emps);
}
    @Test
    public void testEntityWrapperSelect(){
        //查询性别为女,根据age进行排序(asc/desc),简单分页
        List<Employee> emps = employeeMapper.selectList(new EntityWrapper<Employee>()
                .eq("gender",0)
                .orderBy("age")//以字段age排正序
                //.orderDesc(Arrays.asList(new String[]{"age"}))//倒序,传入的为集合
                //.orderAsc(Arrays.asList(new String[]{"age"}))//正序,传入的为集合
                .last("desc limit 1,3")//之接将指接到sql语句后;倒序,显示第一条到第三条数据
        );
        System.out.println(emps);
    }
  1. 带条件的修改操作
/**
 * 条件构造器 修改操作
 */
@Test
public void testEntityWrapperUpdate(){
    //将名字为Tom年龄为22的修改名字、邮箱和性别
    Employee employee = new Employee();
    employee.setLastName("产老师");
    employee.setEmail("cls@qq.com");
    employee.setGender(0);
    Integer update = employeeMapper.update(employee,new EntityWrapper<Employee>()
            .eq("last_name","Tom")
            .eq("age",22));
    System.out.println(update);
}
  1. 带条件删除
/**
 * 条件构造器 删除操作
 */
@Test
public void testEntityWrapperDelete(){
    //将名字为Tom,年龄为22的删除
    Integer delete = employeeMapper.delete(new EntityWrapper<Employee>()
    .eq("last_name","Tom")
    .eq("age",22));
    System.out.println(delete);
}

条件构造器Condition

内部还是wrapper

    @Test
    public void testEntityWrapperSelect(){
        //分页查询表中年龄在18-50之间性别为i男性且姓名xx的所有用户
        //condition使用了单例模式,所以直接调用。create方法,之后的使用和wrapper相同
        List emps = employeeMapper.selectPage(new Page<Employee>(1, 2),
                Condition.create()
                        .between("age", 18, 50)
                        .eq("gender", "1")
                        .eq("last_name", "Tom"));
    }

ActiveRecord(活动记录)

一种领域模型模式,特点是一个模型类对应关系数据库中的一个表,而模型类的一个实例对应表中的一行记录。

动态语言使用广泛

使用AR模式

让实体类继承Model类并且实现主键指定方法

public class Employee extends Model<Employee> {
    /**
     * 返回主键
     * @return
     */
    @Override
    protected Serializable pkVal() {
        return id;
    }
  1. 通用插入
/**
 * AR 插入操作
 */
@Test
public void testARInsert(){
    Employee employee = new Employee();
    employee.setLastName("宋老师");
    employee.setGender(0);
    employee.setAge(23);
    employee.setEmail("song@qq.com");
    boolean insert = employee.insert();
    System.out.println(insert);
}
  1. 通用更新
/**
 * AR 更新操作
 */
@Test
public void testARUpdate(){
    Employee employee = new Employee();
    employee.setEmail("qwe@qq.com");
    employee.setId(16);
    boolean result = employee.updateById();
    System.out.println(result);
}
  1. 通用查询

根据ID查询

/**
 * AR 查询操作
 */
@Test
public void testARSelect(){
    Employee employee = new Employee();
    //方式1
    Employee employee1 = employee.selectById(16);
    //方式2
    employee.setId(1);
    Employee employee2 = employee.selectById();
    System.out.println("employee1:"+employee1+"employee2:"+employee2);
}

查询全部

    @Test
    public void testARSelect(){
        Employee employee = new Employee();
        List<Employee> employees = employee.selectAll();
        System.out.println(employees);
    }

条件查询

    @Test
    public void testARSelect(){
        Employee employee = new Employee();
        List<Employee> employees = employee.selectList(new EntityWrapper<Employee>().like("last_name", "老师"));
        System.out.println(employees);
    }

统计查询(统计符合要求的数据有多少)

    @Test
    public void testARSelect(){
        Employee employee = new Employee();
        int gender = employee.selectCount(new EntityWrapper<Employee>().eq("gender", 0));
        System.out.println(gender);
    }
  1. 通用删除
/**
 * AR 删除操作,删除不存在的逻辑上属于成功,因此返回true
 */
@Test
public void testARDelete(){
    Employee employee = new Employee();
    //方法一
    boolean b = employee.deleteById(1);
    //方法二
    employee.setId(2);
    boolean b1 = employee.deleteById();
    System.out.println("b"+b+"b1"+b1);
}

条件删除

/**
 * AR 删除操作,删除不存在的逻辑上属于成功,因此返回true
 */
@Test
public void testARDelete(){
    Employee employee = new Employee();
    boolean delete = employee.delete(new EntityWrapper().like("last_name", "xiao"));
    System.out.println(delete);
}
  1. 分页操作
/**
 * AR 分页复杂操作
 */
@Test
public void testARPage(){
    Employee employee = new Employee();
    Page<Employee> employeePage = employee.selectPage(new Page<Employee>(1, 1), new EntityWrapper<Employee>().like("last_name", "老"));
    List<Employee> emps = employeePage.getRecords();//获取数据
    System.out.println(emps);
}

代码生成器

可以自动生成service层,controller层,mapper,beans等

配置代码

在test中写入生成配置代码

package com.atguigu.mp.test;

import com.baomidou.mybatisplus.enums.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.rules.DbType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import org.junit.Test;

/**
 * @description:
 * @author: yuqiong
 * @createDate: 2020/1/19
 * @version: 1.0
 */
public class Testmp {
/**
 * 代码生成
 */
 @Test
    public void genCode(){
        // 1、创建代码生成器
        AutoGenerator mpg = new AutoGenerator();

        // 2、全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");

        gc.setAuthor("testjava");
        gc.setOpen(false); //生成后是否打开资源管理器
        gc.setFileOverride(false); //重新生成时文件是否覆盖
        gc.setServiceName("%sService");    //去掉Service接口的首字母I
        gc.setIdType(IdType.ID_WORKER_STR); //主键策略
        gc.setDateType(DateType.ONLY_DATE);//定义生成的实体类中日期类型
        gc.setSwagger2(true);//开启Swagger2模式

        mpg.setGlobalConfig(gc);

        // 3、数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://39.96.44.244/readbook?serverTimezone=GMT%2B8");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        mpg.setDataSource(dsc);

        // 4、包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName("useservice"); //模块名
        pc.setParent("com.wenhua.readbook");

        pc.setController("controller");
        pc.setEntity("entity");
        pc.setService("service");
        pc.setMapper("mapper");
        mpg.setPackageInfo(pc);

        // 5、策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setInclude("readbook_bookrack");

        strategy.setNaming(NamingStrategy.underline_to_camel);//数据库表映射到实体的命名策略
        strategy.setTablePrefix(pc.getModuleName() + "_"); //生成实体时去掉表前缀
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);//数据库表字段映射到实体的命名策略
        strategy.setEntityLombokModel(true); // lombok 模型 @Accessors(chain = true) setter链式操作
        strategy.setRestControllerStyle(true); //restful api风格控制器
        strategy.setControllerMappingHyphenStyle(true); //url中驼峰转连字符

        mpg.setStrategy(strategy);

        // 6、执行
        mpg.execute();
    }
}

插件扩展

分页插件

配置

方法一:在mybatis配置文件中配置

<plugins>
        <plugin interceptor="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></plugin>
</plugins>

方法二:在application.xml中配置

<!--sqlSessionFactoryBean中配置-->
 <bean id="sqlSessionFactoryBean" class="com.baomidou.mybatisplus.spring.MybatisSqlSessionFactoryBean">
        <!--插件注册-->
        <property name="plugins">
            <list>
                <!--注册分页插件-->
                <bean class="com.baomidou.mybatisplus.plugins.PaginationInterceptor"></bean>
            </list>
        </property>
</bean>

测试

public class Testmp {
    ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    EmployeeMapper employeeMapper = ctx.getBean("employeeMapper",EmployeeMapper.class);
    /**
     * 测试分页插件,可以获取各种信息
     */
    @Test
    public void testPage(){
        Page<Employee> employeePage = new Page<>(1,1);
        List<Employee> employees = employeeMapper.selectPage(employeePage, null);
        System.out.println(employees);
        System.out.println("获取分页相关一些信息");
        System.out.println("总条数"+employeePage.getTotal());
        System.out.println("当前页面"+employeePage.getCurrent());
        System.out.println("总页码"+employeePage.getPages());
        System.out.println("每个页面的条件"+employeePage.getSize());
        System.out.println("是否有上一页"+employeePage.hasPrevious());
        System.out.println("是否有下一页"+employeePage.hasNext());

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

执行分析插件

分析DELETE UPDATE语句,防止小白,或者恶意进行delete update全表操作

只建议在开发环境中使用,不建议在生产环境使用,mysql5.6.3以上

在插件底层通过sql语句分析命令:Explain分析当前sql语句,根据结果集中的Extra列来断定当前是否是全表操作

配置

<!--注册执行分析插件-->
<bean class="com.baomidou.mybatisplus.plugins.SqlExplainInterceptor">
    <!--发现问题是否停止操作-->
    <property name="stopProceed" value="true"></property>
</bean>

当出现全表操作时会报错,阻止全表操作

/**
 * 测试sql执行分析操作
 */
@Test
public void testSQLExplain(){
employeeMapper.delete(null);
}

性能分析插件

用于输出每条sql语句及其执行时间,sql性能执行分析,开发环境使用,超过指定时间,停止运行。有助于发现问题。

<!--注册性能分析插件-->
<bean class="com.baomidou.mybatisplus.plugins.PerformanceInterceptor">
    <!--显示格式化后的sql语句-->
    <property name="format" value="true"></property>
    <!--执行事件,超过则暂停-->
    <property name="maxTime" value="5"></property>
</bean>

乐观锁插件

如果想实现如下需求:当要更新一条记录的时候,希望这条记录没有被别人更新

实现原理:取出记录时,获取当前version;更新记录时,带上这个version;执行更新时,set version = yourVersion + 1 where version = yoursVersion;如果version不对,就更新失败

@Version用于注解实体字段,必须要有

<!--注册乐观锁插件-->
<bean class="com.baomidou.mybatisplus.plugins.OptimisticLockerInterceptor"></bean>

自定义全局操作

根据mybatisplus的autosqlinjector可以自定义各种sql,注入到全局中,相当于自定义mybatisplus自动注入的方法。

mybatis需要在xml中进行配置的sql语句,现在通过扩展autosqlinjector在加载mybatis环境时就注入

AutoSqlInjector

  1. 在mapper接口中定义相关的crud方法
  2. 扩展AutoSqlInjector inject方法,实现mapper接口中方法要注入的SQL
  3. 在MP全局策略中,配置自定义注入器