{"content":{"title":"MyBatis-Plus快速入门指南：零基础学习也能轻松上手","body":"> 在Java开发的世界里，持久层框架的选择对于项目的成功至关重要。今天，我们要聊的主角是MyBatis-Plus——一个增强版的MyBatis，它以其强大的功能、简洁的代码和高效的性能，正在成为越来越多开发者的新宠。\r\n\r\n那么，MyBatis-Plus到底是什么？又该如何快速入门呢？让我们一起探索这个强大的工具。\r\n\r\n## 一、MyBatis-Plus简介\r\n\r\n### 1、简介\r\n\r\nMyBatis-Plus (opens new window)（简称 MP）是一个 MyBatis (opens new window)的增强工具，在 MyBatis 的基础上只做增强不做改变，为简化开发、提高效率而生。\r\n\r\n![Description](https://ydcqoss.ydcode.cn/ydyx/bbs/1708935118-nyK8LN.png)\r\n\r\n### 2、特性\r\n\r\n**无侵入：** 只做增强不做改变，引入它不会对现有工程产生影响，如丝般顺滑。\r\n\r\n**损耗小：** 启动即会自动注入基本 CURD，性能基本无损耗，直接面向对象操作，BaseMapper。\r\n\r\n**强大的 CRUD 操作：** 内置通用 Mapper、通用 Service，仅仅通过少量配置即可实现单表大部分 CRUD 操作，更有强大的条件构造器，满足各类使用需求，简单的CRUD操作不用自己编写。\r\n\r\n**支持 Lambda 形式调用：** 通过 Lambda 表达式，方便的编写各类查询条件，无需再担心字段写错。\r\n\r\n**支持主键自动生成：** 支持多达 4 种主键策略（内含分布式唯一 ID 生成器 - Sequence），可自由配置，完美解决主键问题。\r\n\r\n**支持 ActiveRecord 模式：** 支持 ActiveRecord 形式调用，实体类只需继承 Model 类即可进行强大的 CRUD 操作。\r\n\r\n**支持自定义全局通用操作：** 支持全局通用方法注入（ Write once, use anywhere ）。\r\n\r\n**内置代码生成器：** 采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码，支持模板引擎，更有超多自定义配置等您来使用（自动生成代码）。\r\n\r\n**内置分页插件：** 基于 MyBatis 物理分页，开发者无需关心具体操作，配置好插件之后，写分页等同于普通 List 查询。\r\n\r\n**分页插件支持多种数据库：** 支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库。\r\n\r\n**内置性能分析插件：** 可输出 SQL 语句以及其执行时间，建议开发测试时启用该功能，能快速揪出慢查询。\r\n\r\n**内置全局拦截插件：** 提供全表 delete 、 update 操作智能分析阻断，也可自定义拦截规则，预防误操作。\r\n\r\n### 3、框架结构\r\n\r\n![Description](https://ydcqoss.ydcode.cn/ydyx/bbs/1708935263-mGlWs0.png)\r\n\r\n## 二、快速入门\r\n\r\n**1.开发环境**\r\n\r\n**2.创建数据库和表**\r\n\r\n1）创建表单\r\n\r\n```\r\nCREATE DATABASE `mp_study` /*!40100 DEFAULT CHARACTER SET utf8mb4 */;\r\nuse `mp_study`;\r\nCREATE TABLE `user` (\r\n`id` bigint(20) NOT NULL COMMENT '主键ID',\r\n`name` varchar(30) DEFAULT NULL COMMENT '姓名',\r\n`age` int(11) DEFAULT NULL COMMENT '年龄',\r\n`email` varchar(50) DEFAULT NULL COMMENT '邮箱',\r\nPRIMARY KEY (`id`)\r\n) ENGINE=InnoDB DEFAULT CHARSET=utf8;\r\n```\r\n\r\n\r\n2）添加数据\r\n\r\n```\r\nINSERT INTO user (id, name, age, email) VALUES\r\n(1, 'Jone', 18, 'test1@baomidou.com'),\r\n(2, 'Jack', 20, 'test2@baomidou.com'),\r\n(3, 'Tom', 28, 'test3@baomidou.com'),\r\n(4, 'Sandy', 21, 'test4@baomidou.com'),\r\n(5, 'Billie', 24, 'test5@baomidou.com');\r\n```\r\n\r\n\r\n**3. 创建SpringBoot工程**\r\n\r\n1）初始化工程\r\n\r\n2）导入依赖\r\n\r\n```\r\n<dependencies>\r\n    <dependency>\r\n        <groupId>org.springframework.boot</groupId>\r\n        <artifactId>spring-boot-starter</artifactId>\r\n    </dependency>\r\n    <dependency>\r\n        <groupId>org.springframework.boot</groupId>\r\n        <artifactId>spring-boot-starter-test</artifactId>\r\n        <scope>test</scope>\r\n    </dependency>\r\n    <dependency>\r\n        <groupId>com.baomidou</groupId>\r\n        <artifactId>mybatis-plus-boot-starter</artifactId>\r\n        <version>3.5.1</version>\r\n    </dependency>\r\n    <dependency>\r\n        <groupId>org.projectlombok</groupId>\r\n        <artifactId>lombok</artifactId>\r\n        <optional>true</optional>\r\n    </dependency>\r\n    <dependency>\r\n        <groupId>mysql</groupId>\r\n        <artifactId>mysql-connector-java</artifactId>\r\n        <scope>runtime</scope>\r\n    </dependency>\r\n</dependencies>\r\n```\r\n\r\n\r\n**4. 编写代码**\r\n\r\n1）配置application.yml\r\n\r\n```\r\n# DataSource Config\r\nspring:\r\n  datasource:\r\n    driver-class-name: com.mysql.cj.jdbc.Driver\r\n    url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8\r\n    username: root\r\n    password: 1234\r\n```\r\n\r\n\r\n2）启动类\r\n\r\n在Spring Boot启动类中添加@MapperScan注解，扫描mapper包\r\n\r\n```\r\n@MapperScan(\"cn.frozenpenguin.mapper\")\r\n@SpringBootApplication\r\npublic class MybatisPlusStudyApplication {\r\n\r\n    public static void main(String[] args) {\r\n        SpringApplication.run(MybatisPlusStudyApplication.class, args);\r\n    }\r\n}\r\n```\r\n\r\n\r\n3）添加实体类\r\n\r\n```\r\n@Data//lombok注解\r\npublic class User {\r\n    private Long id;\r\n    private String name;\r\n    private Integer age;\r\n    private String email;\r\n}\r\n```\r\n\r\n\r\n4）添加mapper\\\r\nBaseMapper是MyBatis-Plus提供的模板mapper，其中包含了基本的CRUD方法，泛型为操作的实体类型。\r\n\r\n```\r\npublic interface UserMapper extends BaseMapper<User> {\r\n}\r\n```\r\n\r\n\r\n5）测试\r\n\r\n```\r\n@Autowired\r\n    private UserMapper userMapper;\r\n\r\n    @Test\r\n    void test01(){\r\n        List<User> users = userMapper.selectList(null);\r\n        for (User user : users) {\r\n            System.out.println(user);\r\n        }\r\n    }\r\n```\r\n\r\n\r\n结果\\\r\n![Description](https://ydcqoss.ydcode.cn/ydyx/bbs/1708936024-2i23l1.png)\\\r\n注意：\r\n\r\nIDEA在 userMapper 处报错，因为找不到注入的对象，因为类是动态创建的，但是程序可以正确执行。为了避免报错，可以在mapper接口上添加 @Repository注解。\r\n\r\n6）添加日志\r\n\r\n我们所有的sql现在是不可见的，我们希望知道它是怎么执行的，所以我们必须要看日志！\r\n\r\n在application.yml中配置日志输出\r\n\r\n```\r\n# 配置日志\r\nmybatis-plus:\r\n  configuration:\r\n    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl\r\n  mapper-locations:\r\n```\r\n\r\n\r\n## 三、基本CRUD\r\n\r\n**1.插入**\r\n\r\n```\r\n @Test\r\n  void insert()\r\n      User user = new User(null, \"lisi\", 2, \"aaa@qq.com\");\r\n      int insert = userMapper.insert(user);\r\n      System.out.println(\"受影响行数\"+insert);\r\n      //1511332162436071425\r\n      System.out.println(user.getId());\r\n   }\r\n```\r\n\r\n\r\nid设置为null，却插入了1511332162436071425，这是因为MyBatis-Plus在实现插入数据时，会默认基于雪花算法的策略生成id。\r\n\r\n**2.删除**\r\n\r\n1）通过id删除记录\r\n\r\n```\r\n@Test\r\nvoid testDeleteById(){\r\n//DELETE FROM user WHERE id=?\r\n    int result = userMapper.deleteById(1);\r\n    System.out.println(\"受影响行数：\"+result);\r\n}\r\n```\r\n\r\n\r\n2) 通过id批量删除记录\r\n\r\n```\r\n@Test\r\nvoid testDeleteBatchIds(){\r\n    //DELETE FROM user WHERE id IN ( ? , ? , ? )\r\n    int result = userMapper.deleteBatchIds(ids);\r\n    System.out.println(\"受影响行数：\"+result);\r\n}\r\n```\r\n\r\n\r\n3) 通过map条件删除记录\r\n\r\n```\r\n@Test\r\nvoid testDeleteByMap(){\r\n    //DELETE FROM user WHERE name = ? AND age = ?\r\n    Map<String,Object> map=new HashMap<>();\r\n    map.put(\"age\",12);\r\n    map.put(\"name\",\"lisi\");\r\n    int result = userMapper.deleteByMap(map);\r\n    System.out.println(\"受影响行数：\"+result);\r\n}\r\n```\r\n\r\n\r\n**3. 修改**\r\n\r\n```\r\n@Test\r\nvoid testUpdateById(){\r\n    //SELECT id,name,age,email FROM user WHERE id=?\r\n    User user = new User(10L, \"hello\", 12, null);\r\n    int result = userMapper.updateById(user);\r\n    //注意：updateById参数是一个对象\r\n    System.out.println(\"受影响行数：\"+result);\r\n}\r\n```\r\n\r\n\r\n**4.自动填充**\r\n\r\n* 创建时间、修改时间！这些个操作都是自动化完成的，我们不希望手动更新！\r\n* 阿里巴巴开发手册：所有的数据库表：gmt_create、gmr_modified、几乎所有的表都要配置上！而且需要自动化！\r\n\r\n**方式一：数据库级别（工作中不允许修改数据库）**\r\n\r\n1）在表中新增字段 create_time, update_time；\r\n\r\n![Description](https://ydcqoss.ydcode.cn/ydyx/bbs/1708936219-7PD3rK.png)\r\n\r\n2）再次测试插入方法，我们需要先把实体类同步！\r\n\r\n3）再次更新查看结果即可。\r\n\r\n![Description](https://ydcqoss.ydcode.cn/ydyx/bbs/1708936235-REQjVk.png)\r\n\r\n**方式二：代码级别**\r\n\r\n* 删除数据库的默认值，更新操作\r\n* 实体类的字段属性上需要加注解\r\n\r\n```\r\n@TableField(fill = FieldFill.INSERT)\r\nprivate Date createTime;\r\n\r\n@TableField(fill = FieldFill.INSERT_UPDATE)\r\nprivate Date updateTime;\r\n```\r\n\r\n\r\n* 编写处理器处理注解\r\n\r\n```\r\n@Component\r\npublic class MyMetaObjectHandler implements MetaObjectHandler {\r\n @Override\r\n public void insertFill(MetaObject metaObject) {\r\n     // 起始版本 3.3.0(推荐使用)\r\n     this.strictInsertFill(metaObject, \"createTime\", LocalDateTime.class, LocalDateTime.now());\r\n }\r\n\r\n\r\n @Override\r\n public void updateFill(MetaObject metaObject) {\r\n     // 起始版本 3.3.0(推荐)\r\n     this.strictUpdateFill(metaObject, \"updateTime\", LocalDateTime.class, LocalDateTime.now());\r\n }\r\n}\r\n```\r\n\r\n* 测试插入\r\n* 测试更新、观察时间即可\r\n\r\n>你还在苦恼找不到真正免费的编程学习平台吗?可以试试【云端源想】！课程视频、知识库、微实战、云实验室、一对一咨询……你想要的全部学习资源这里都有，重点是现在还是免费的！[点这里即可查看！](https://www.ydcode.cn/?sourceId=746)\r\n\r\n**5.查询**\r\n\r\n* 与查询基本一致；\r\n* 根据id查询用户信息；\r\n* 根据多个id查询多个用户信息；\r\n* 通过map条件查询用户信息；\r\n* 查询所有数据；\r\n\r\n```\r\n@Test\r\nvoid test01(){\r\n    List<User> users = userMapper.selectList(null);\r\n    for (User user : users) {\r\n        System.out.println(user);\r\n    }\r\n}\r\n```\r\n\r\n\r\n通过观察BaseMapper中的方法，大多方法中都有Wrapper类型的形参，此为条件构造器，可针 对于SQL语句设置不同的条件，若没有条件，则可以为该形参赋值null，即查询（删除/修改）所有数据。\r\n\r\n**6.通用Service**\r\n\r\n说明：\r\n\r\n* 通用 Service CRUD 封装IService接口，进一步封装 CRUD；\r\n* 采用 get 查询单行；\r\n* remove 删除；\r\n* list 查询集合；\r\n* page 分页；\r\n* 前缀命名方式区分 Mapper 层避免混淆；\r\n* 泛型 T 为任意实体对象；\r\n* 建议如果存在自定义通用 Service 方法的可能，请创建自己的 IBaseService 继承 Mybatis-Plus 提供的基类；\r\n* 官网地址：https\\://baomidou.com/pages/49cc81/#service-crud-%E6%8E%A5%E5%8F%A3。\r\n\r\n**1）IService**\r\n\r\nMyBatis-Plus中有一个接口 IService和其实现类 ServiceImpl，封装了常见的业务层逻辑 详情查看源码IService和ServiceImpl。\r\n\r\n**2）创建Service接口和实现**\r\n\r\n```\r\n/**\r\n *  UserService继承IService模板提供的基础功能\r\n */\r\npublic interface UserService extends IService<User> {\r\n}\r\n```\r\n\r\n\r\n```\r\n/**\r\n * ServiceImpl实现了IService，提供了IService中基础功能的实现\r\n * 若ServiceImpl无法满足业务需求，则可以使用自定的UserService定义方法，并在实现类中实现\r\n */\r\n@Service\r\npublic class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {\r\n}\r\n```\r\n\r\n\r\n\r\n**3）测试查询记录数**\r\n\r\n```\r\n@Test\r\nvoid testGetCount(){\r\n    long count = userService.count();\r\n    System.out.println(\"总记录数：\" + count);\r\n}\r\n```\r\n\r\n\r\n\r\n**4）测试批量插入**\r\n\r\n```\r\n@Test\r\nvoid testSaveBatch(){\r\n    // SQL长度有限制，海量数据插入单条SQL无法实行，\r\n    // 因此MP将批量插入放在了通用Service中实现，而不是通用Mapper\r\n    ArrayList<User> users = new ArrayList<>();\r\n    for (int i = 0; i < 5; i++) {\r\n        User user = new User();\r\n        user.setName(\"lyl\"+i);\r\n        user.setAge(20+i);\r\n        users.add(user);\r\n    }\r\n    //SQL:INSERT INTO t_user ( username, age ) VALUES ( ?, ? )\r\n    userService.saveBatch(users);\r\n}\r\n```\r\n\r\n\r\n> 原理：先把user对象存到list（存在内存中），然后直接save集合list中的所有user。\r\n\r\nMyBatis-Plus作为MyBatis的增强版，不仅继承了MyBatis的所有优点，还在此基础上做了大量的改进和扩展。它的出现，无疑为Java开发者提供了一个更为强大、便捷的数据操作工具。\r\n\r\n技术的世界总是在不断进步，而我们作为开发者，也需要不断学习新的工具和技术。MyBatis-Plus正是这样一把钥匙，它能打开高效数据操作的大门。希望本文能帮助您快速入门MyBatis-Plus！"},"author":{"user":"https://learnblockchain.cn/people/17279","address":null},"history":null,"timestamp":1709023403,"version":1}