前言

本篇是承接上一篇写的续篇,不再着重介绍mp的基础使用和查询,而主要是在一些应用功能,配置上面做一些介绍。

一:activeRecord 数据访问设计模式

应用Active Record 时,每一个类的实例对象唯一对应一个数据库表的一行(一对一关系)。你只需继承一个abstract Active Record 类就可以使用该设计模式访问数据库

实体类继承Model<T> 仍然要写mapper 但是在应用中不需要导入
public class User extends Model<User> {

}

Model的方法
image.png

基础的增删改查

新增or更新

    @Test
    public void testInsert() {
        //INSERT INTO tb_user (user_name, age) VALUES (?, ?)
        User user = new User("xiahoudun", 24);
        
        boolean insert = user.insert();
 
        //当原有记录存在时(id存在)则是更新操作
        // boolean update = user.insertOrUpdate();

        System.err.println(insert);
    }

删除

    @Test
    public void testDelete() {

        //DELETE FROM tb_user WHERE id = ?
        User user = new User();
        user.setId(13L);
        //A根据传入的实体的id删除
        //boolean delete = user.deleteById();

        //B直接根据id删除
        //boolean delete2 = new User().deleteById(13L);

        //C根据传入的条件删除
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("user_name", "xiahoudun");
        //DELETE FROM tb_user WHERE (user_name = ?)
        boolean delete3 = new User().delete(wrapper);

        System.err.println(delete3);
    }

修改

    @Test
    public void testUpdate() {
        //构建实体类修改
        User user = new User();
        //修改的记录
        user.setId(15L);
        //修改内容
        user.setName("夏侯惇");
        user.setAge(34);
        //UPDATE tb_user SET name = ?, age = ? WHERE id = ?
        //boolean update = user.updateById();

        //根据条件修改
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        User user1 = new User();
        //修改的内容
        user1.setUserName("xiahoudun");
        user1.setPassword("123");

        //修改条件
        wrapper.eq("id", 15L);
        //UPDATE tb_user SET name = ?, age = ? WHERE (id = ?)
        boolean update1 = user.update(wrapper);

        System.err.println(update1);
    }

根据id查询

    @Test
    public void testSelect() {
        //SELECT id, email AS mail, name, user_name, age FROM tb_user WHERE id = ?
        User user = new User();
        user.setId(15L);
        //根据实体类的id查询
        User user1 = user.selectById();

        //直接输入id查询
        User user2 = new User().selectById(15L);
        System.out.println(user2);
    }

其他查询
selectCount:查询记录数
selectAll:查询所有
selectOne:查询一个
selectPage:分页查询

    @Test
    public void testOther() {

        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.gt("age", 24);
        //查询记录数
        //SELECT COUNT(1) FROM tb_user WHERE (age > ?)
        // Integer integer = new User().selectCount(wrapper);
        //  System.err.println(integer);


        //查询所有
        //SELECT id, email AS mail, name, user_name, age FROM tb_user
        // List<User> users = new User().selectAll();
        //  users.forEach(System.err::println);


        //根据条件查询一个  查询到多个取第一个
        //SELECT id, email AS mail, name, user_name, age FROM tb_user WHERE (age = ?)
        QueryWrapper<User> wrapper2 = new QueryWrapper<>();
        wrapper2.eq("age", 24);
        // User user2 = new User().selectOne(wrapper2);
        // System.err.println(user2);


        //分页查询
        //SELECT id, email AS mail, name, user_name, age FROM tb_user WHERE (age > ?) LIMIT ?,?
        IPage<User> userIPage = new User().selectPage(new Page<>(2L, 4), wrapper);
        System.err.println(userIPage.getRecords().toString());
    }

二:乐观锁插件

当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败
2.1 在配置类或启动类中配置bean
@Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {
        return new OptimisticLockerInterceptor();
    }
2.2 在数据库中要有version字段 在实体类中配置version

version支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
整数类型下 newVersion = oldVersion + 1,newVersion 会回写到 entity 中
在 update(entity, wrapper) 方法下, wrapper 不能复用!!!
仅支持 updateById(id) 与 update(entity, wrapper) 方法

//实体类添加版本信息__乐观锁
    @Version
    private Integer version;
    @Test
    public void testVersion() {
        User user = new User(20L);

        User oldUser = user.selectById();

        //直接设置版本信息
        user.setVersion(oldUser.getVersion());

        //修改内容
        user.setAge(30);

        // UPDATE tb_user SET age = 29, version = 2 WHERE id = 20 AND version = 1
        boolean update = user.updateById();

        System.err.println(update);
    }

三:sql 注入器

3.1 定义自己的方法类
public class FindAll extends AbstractMethod {

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sqlMethod = "findAll";
        String sql = "select * from " + tableInfo.getTableName();

        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);

        return this.addSelectMappedStatement(mapperClass, sqlMethod, sqlSource, modelClass, tableInfo);
    }
}
3.2 把自己定义的方法加到baseMapper中让能被扫到
public class MyInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList() {
        //获得父类所有基础的baseMapper方法
        List<AbstractMethod> methodList = super.getMethodList();
        //添加自定义方法
        methodList.add(new FindAll());

        return methodList;
    }
}
3.3 在配置类或启动类 配置SQL注入器
@Bean
    public MyInjector mySqlInjector() {
        return new MyInjector();
    }
3.4 在自定义mapper类中扩充自己写的findAll()方法
public interface MyBaseMapper<T> extends BaseMapper<T> {

    List<T> findAll();
}
3.5 userMapper不在继承baseMapper而是继承了自定义的mapper类
@Repository
public interface UserMapper2 extends MyBaseMapper<User> {


}
3.6 使用自定义的findAll()方法
@RunWith(SpringRunner.class)
@SpringBootTest~~~~
public class MyApplicationTest6 {

    @Autowired
    UserMapper2 userMapper2;

    /**
     * 自定义方法
     *
     * slelect 不再是每个字段名称 而是自己定义的 select *
     * SELECT * FROM tb_user
     */
    @Test
    public void testFindAll() {
        List<User> users = userMapper2.findAll();
        users.forEach(System.err::println);
    }

    /**
     * baseMapper的方法
     * SELECT id, user_name, name, age, email AS mail, version, deleted, sex FROM tb_user
     */
    @Test
    public void testSelectOne() {

        List<User> users = userMapper2.selectList(null);
        users.forEach(System.err::println);
    }

}

四:自动填充功能

有些时候我们可能会有这样的需求,插入或者更新数据时,希望有些字段可以自动填充数据,比如密码、version等。在MP中提供了这样的功能,可以实现自动填充。

4.1 自定义MetaObjectHandler 新建时默认密码
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    /**
     * 对字段插入时进行操作
     *
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        Object password = getFieldValByName("password", metaObject);
        if (null == password) {
            //密码为,自动填充888888
            setFieldValByName("password", "888888", metaObject);
        }
    }

    /**
     * 对字段更新时进行操作
     *
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {

    }
}
4.2 对password字段进行注解
    //查询时不返回该字段的值
    //fill =FieldFill.INSERT  对插入密码的时候可以进行填充
    @TableField(select = false, fill = FieldFill.INSERT)
    private String password;
4.3 测试
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyApplicationTest7 {

    @Autowired
    private UserMapper userMapper;


    /**
     * 插入测试 默认插入密码
     * INSERT INTO tb_user (user_name, password, name, age) VALUES ('lidian', '888888', '李典', 26)
     */

    @Test
    public void testInsert() {
        User user = new User();
        user.setUserName("lidian");
        user.setName("李典");
        user.setAge(26);

        //返回改变的行数
        int insert = userMapper.insert(user);
        System.err.println("change:" + insert); //1

    }
}

五:逻辑删除

开发系统时,有时候在实现功能时,删除操作需要实现逻辑删除,所谓逻辑删除就是将数据标记为删除,而并非真正的物理删除(非DELETE操作),查询时需要携带状态条件,确保被标记的数据不被查询到。这样做的目的就是避免数据被真正的删除。

5.1 在yml文件中配置 如果是默认值可以不改
#逻辑删除配置
mybatis-plus:
  global-config:
    db-config:
      # 逻辑已删除值(默认为 1)
      logic-delete-value: 1
      # 逻辑未删除值(默认为 0)
      logic-not-delete-value: 0
5.2 在实体类上加上注解 数据库需要有该字段
    //逻辑删除
    @TableLogic
    private Integer deleted;
5.3 在真正执行操作时不是delete操作而是update操作
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyApplicationTest8 {

    @Autowired
    private UserMapper userMapper;

    /**
     * 逻辑删除
     * UPDATE tb_user SET deleted = 1 WHERE id = 5 AND deleted = 0
     */
    @Test
    public void testDel() {
        int del = userMapper.deleteById(5L);
        System.out.println(del);
    }

    /**
     * 测试查询
     * SELECT id, user_name, name, age, email AS mail, version, deleted FROM tb_user WHERE id = ? AND deleted = 0
     */
    @Test
    public void testSelect() {
        User user = userMapper.selectById(5L);
        System.out.println(user);//null
    }
}

六:通用枚举

解决了繁琐的配置,让 mybatis 优雅的使用枚举属性!

6.1 将性别使用枚举值配置
public enum SexEnum implements IEnum<Integer> {

    MAN(1, "男"),
    WOMAN(2, "女");

    private int value;
    private String desc;

    SexEnum(int value, String desc) {
        this.value = value;
        this.desc = desc;
    }

    @Override
    public Integer getValue() {
        return this.value;
    }

    @Override
    public String toString() {
        return this.desc;
    }
}
6.2 配置实体类
    //配置枚举值
    private SexEnum sex;
6.3 操作过程中value和dest会相互转换
@RunWith(SpringRunner.class)
@SpringBootTest
public class MyApplicationTest9 {

    @Autowired
    private UserMapper userMapper;


    /**
     * 枚举  新增
     * INSERT INTO tb_user(user_name, password, name, age, sex) VALUES  ('diaochan','888888','貂蝉',18,2)
     */
    @Test
    public void testInsert() {
        User user = new User();
        user.setName("貂蝉");
        user.setUserName("diaochan");
        user.setAge(18);
        user.setSex(SexEnum.WOMAN);
        int insert = userMapper.insert(user);
        System.out.println(insert);
    }

    /**
     * 枚举值也可以在wrapper条件中使用  value和dest会相互转换
     * SELECT id, user_name, name, age, email    AS mail, version, deleted, sex FROM tb_user WHERE deleted = 0 AND sex = 2
     */
    @Test
    public void testSelect() {
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("sex", SexEnum.WOMAN);

        List<User> users = userMapper.selectList(wrapper);
        //User(id=19, userName=diaochan, password=null, name=貂蝉, age=18, mail=null, address=null, version=1, deleted=0, sex=女)
        System.out.println(users.toString());
    }
}

七:代码自动生成

public class MysqlGenerator {
    /**
     * 读取控制台内容
     *
     * @param tip
     * @return
     */
    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        System.out.println(("请输入" + tip + ":"));
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    /**
     * 运行
     *
     * @param args
     */
    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath + "/src/main/java");
        gc.setAuthor("Rem");
        gc.setOpen(false);
        mpg.setGlobalConfig(gc);
        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://127.0.0.1:3306/mp?serverTimezone=UTC&useSSL=false&useUnicode=true&characterEncoding=utf8");
        // dsc.setSchemaName("public");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        mpg.setDataSource(dsc);
        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(scanner("模块名"));
        pc.setParent("com.hhz.mp.generator");
        mpg.setPackageInfo(pc);
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输入文件名称
                return projectPath + "/mp/src/main/resources/mapper/ " + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);


        mpg.setCfg(cfg);
        mpg.setTemplate(new TemplateConfig().setXml(null));
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        strategy.setSuperEntityClass("com.baomidou.mybatisplus.samples.generator.common.BaseEntity");
        strategy.setEntityLombokModel(true);
        strategy.setSuperControllerClass("com.baomidou.mybatisplus.samples.generator.common.BaseController");
        strategy.setInclude(scanner("表名"));
        strategy.setSuperEntityColumns("id");
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        // 选择 freemarker 引擎需要指定如下加,注意 pom 依赖必须有!
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();

    }

}

Remember
24 声望3 粉丝

蓝色空间号里的blueBoy