MybatisPlus增删改查
写这个笔记之前,仅仅学习了Mybatis,简单讲解一下我的编程感受,我的数据库本身学的不是很好,sql语句说会也会,也可以说不会;一旦涉及到多表查询就开始头疼了,而使用Mybatis进行写增删改查的sql就比较麻烦。用了MybatisPlus后就有方便许多了,它减少了很多很多的sql语句,更加方便开发人员的编码。
一句俗话:用过的人都说好!
回归正题,下面就是我最近学习MybatisPlus的一点感悟,感谢各位博客大佬提供的理论文字知识。
特性:
无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操作
接下来就是进入idea中在springboot框架里面进行MybatisPlus的相关实际操作啦。在这里数据库默认已经建立完成。
1.MybatisPlus依赖
<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version></dependency> <!-- 阿里数据源--> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-generator</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
2.数据库连接
spring: datasource: type: com.alibaba.druid.pool.DruidDataSource # driver-class-name: com.mysql.cj.jdbc.Driver # url: jdbc:mysql://localhost:3306/jtdb?serverTimezone=UTC driver-class-name: com.p6spy.engine.spy.P6SpyDriver url: jdbc:p6spy:mysql://localhost:3306/jtdb?serverTimezone=UTC password: 123456 username: root main: banner-mode: off # 关闭SpringBoot启动图标(banner) mybatis-plus: # configuration: # log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #打印到控制台 global-config: banner: off #关闭mebatisplus启动图标 # mapper-locations: classpath:/mapper/*Mapper.xml mapper-locations: com.cqie:/mapper/xml/*Mapper.xml
3.代码生成器
使用代码生成器需要在pom.xml文件中引入依赖:velocity-engine-core
<!-- 模板引擎 --> <dependency> <groupId>org.apache.velocity</groupId> <artifactId>velocity-engine-core</artifactId> <version>2.0</version> </dependency>
代码生成器代码:CodeGenerator
import com.baomidou.mybatisplus.core.mapper.BaseMapper;` `import com.baomidou.mybatisplus.generator.FastAutoGenerator;` `import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;` `import java.util.ArrayList;` `import java.util.List;` `public class CodeGenerator {` `public static void main(String[] args){` `String url = "jdbc:mysql://localhost:3306/jtdb?serverTimezone=UTC";` `String username = "root";` `String password = "123456";` `String mudel = "";//项目模块名称` `String outPath = System.getProperty("user.dir") + "/" + mudel + "/src/main/java";//路径` String parent = "com.cqie";//父包的名称 String mudelName = "";//模块名 String entity = "entity"; String mapper = "mapper"; String service = "service"; String serviceImpl = "service.Impl"; String controller = "controller"; String mapperXml = "mapper.xml"; List<String> tables = new ArrayList<>(); tables.add("user");//生成表 FastAutoGenerator.create(url, username, password) `// 全局配置` `.globalConfig(builder -> {` `builder.author("baomidou") // 设置作者` `// .enableSwagger() // 开启 swagger 模式` `.fileOverride() // 覆盖已生成文件` `.outputDir(outPath)// 指定输出目录` `.disableOpenDir();//生成后不打开` `})` `// 包配置` `.packageConfig(builder -> {` `builder.parent(parent) // 设置父包名` `.moduleName(mudelName) // 设置父包模块名` `.entity(entity)` `.mapper(mapper)` `.service(service)` `.serviceImpl(serviceImpl)` `.controller(controller)` `.xml(mapperXml);` `})` `// 模板配置` `// ...` `// 策略配置` `.strategyConfig(builder -> {` `builder.addInclude(tables) // 设置需要生成的表名` `// .addTablePrefix("t_", "c_"); // 设置过滤表前缀` `.entityBuilder()//开启生成实体类` `.enableLombok()//开启生成lombok` `.mapperBuilder()//开启生成mapper` `.superClass(BaseMapper.class)` `// .enableBaseResultMap()//开启mapper注解` `.formatMapperFileName("%sMapper")//格式化mapper名称` `.formatXmlFileName("%sMapper")//格式化xml名称` `.serviceBuilder()//开启生成service` `.formatServiceFileName("%sService")//格式化service名称` `.formatServiceImplFileName("%sServiceImpl")//格式化接口文件serviceImpl名称` `.controllerBuilder()//开启生成controller` `.formatFileName("%sController")//格式化controller名称` `.enableRestStyle();` `})` `.templateEngine(new VelocityTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板` `.execute();` `}` `}
生成之后的项目结构如下,它会将连接的数据库中的表全部进行生成代码,包括controller、entity、mapper、service。
4、增删改查代码
4.1数据新增
//插入数据 //mapper层中可以进行插入操作,在其中封装了insert方法 User user = new User(); user.setAge(20); user.setName("rong"); user.setSex("女"); userMapper.insert(user); int id = user.getId(); System.out.println("id:" + id); //伪批量插入 List<User> userList = new ArrayList<>(); for(int i = 1;i<6;i++){ User user = new User(); user.setName("hahah"+i); user.setAge(21); if(i%2==0){ user.setSex("女"); }else{ user.setSex("男"); } userList.add(user); } boolean isSuccess = userService.saveBatch(userList); System.out.println(isSuccess);
这里使用到了saveBatch(),即如果数据库中存在,则进行更新并保存;如果不存在则进行新增。
// 批量更新 List<User> userList = new ArrayList<>(); for(int i = 3;i<10;i++){ User user = new User(); user.setName("hahah"+i); user.setAge(21); if(i%2==0){ user.setSex("女"); }else{ user.setSex("男"); } userList.add(user); } // service中封装的插入方法save boolean isSuccess = userService.saveBatch(userList); System.out.println(isSuccess);
4.2数据删除
// Mapper层删除功能 // 根据主键id删除数据(直接传id) int count = userMapper.deleteById(9); System.out.println("删除了:"+ count); // 根据主键id删除(传实体类) User user = new User(); user.setId(8); int count = userMapper.deleteById(user); System.out.println("删除了:"+ count); // 根据主键id批量删除数据 List<int> ids = new ArrayList<>(); ids.add(1); ids.add(2); // delete from user where id in (1,2); userMapper.deleteBatchIds(ids); // 通过构造Wrapper构造器删除 QueryWrapper wrapper = new QueryWrapper<>(); wrapper.eq("name","xiaoming"); wrapper.eq("age",11); // delete from user where (name="xiaoming" and age = 11); userMapper.delete(wrapper); // lambda表达式 userMapper.delete(new QueryWrapper<User>() .lambda() .eq(User::getName, "xiaoming") .eq(User::getAge,11) ); // 使用map设置条件删除 Map<String, Object> col = new HashMap<>(); col.put("name","xiaoming2"); col.put("age",12); int count = userMapper.deleteByMap(col); System.out.println("删除了:" + count);
4.3数据更新
// 更新数据 // mapper层 User user = User.builder() .name("xiaoxiaoming") .id(5L) .gender(0) .build(); int count = userMapper.updateById(user); System.out.println("更新了:" + count); // // 通过wrapper进行更新 User user = User.builder().name("hahah").gender(0).build(); UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.eq("age",13); int count = userMapper.update(user,userUpdateWrapper); // service层 UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>(); userUpdateWrapper.set("name","xixix"); userUpdateWrapper.eq("id",5L).eq("age",13); userService.update(userUpdateWrapper);
4.4数据查询
(1)mapper查询
// 查询数据 // mapper层 // 根据 id查询数据 User user = userMapper.selectById(5L); System.out.println(user.toString()); // 通过构造wrapper条件查询一条数据 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // 设置查询字段;仅查询name id字段 queryWrapper.select("id","name"); // 添加查询条件 queryWrapper.eq("id",6L); User user1 = userMapper.selectOne(queryWrapper); System.out.println(user1.toString()); //根据id批量查询 List<User> userList = userMapper.selectBatchIds(Arrays.asList(5L,6L,7L)); // 通过Wrapper组装查询条件,查询全部数据 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // 设置查询字段;仅查询name id字段 queryWrapper.select("id","name"); // 添加查询条件 queryWrapper.eq("age",30); List<User> users = userMapper.selectList(queryWrapper); // 查询全部数据 // 根据columnMap设置查询条件 Map<String,Object> colMap = new HashMap<>(); colMap.put("name","xixix"); colMap.put("age",13); // select * from user where name="xixix" and age=13; List<User> userList1 = userMapper.selectByMap(colMap); // 使用map构造查询 // 根据wrapper条件,查询记录总数 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name","xixi").eq("age",13); long count = userMapper.selectCount(queryWrapper); // 获取总量
(2)service查询
// service User user = userService.getById(5L); // 根据id获取数据 // 通过Wrapper条件查询一条数据,当结果出现多条数据是会抛出异常 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name","xixi").eq("id",5L); // select * from user where id= 5 and name = "xixi" User user1 = userService.getOne(queryWrapper);
(3)条件查询:
(3.1)list方式
// 通过list开头的方法来查询多条数据 // 条件查询 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("name","xixi").eq("id",5L); // select * from user where id= 5 and name = "xixi" List<User> users = userService.list(queryWrapper); // select * from user where id in(5,6) List<User> userList = userService.listByIds(Arrays.asList(5L,6L));
(3.2)map方式
// 通过map构造查询条件 Map<String,Object> cloMap = new HashMap<>(); cloMap.put("name","xixi"); cloMap.put("age",13); // select * from user where age= 5 and name = "xixi" List<User> userList1 = userService.listByMap(cloMap);
(4)循环插入
// 获取查询总数 QueryWrapper<User> queryWrapper1 = new QueryWrapper<>(); queryWrapper1.eq("name","xixi").eq("id",5L); userService.count(queryWrapper1); // 获取查询总数 // 循环插入 100 条测试数据 // INSERT INTO t_user ( name, age, gender ) VALUES ( 'xiaoxia0', 30, 1 ),( 'xiaoxia0', 30, 1 ),( 'xiaoxia0', 30, 1 ) for (int i = 0; i < 100; i++) { User user = new User(); user.setName("xiaoxia" + i); user.setAge(30); user.setGender(1); userMapper.insert(user); }
(5)多表查询:
// 多表关联查询 // 需求:假设前端需要展示数据:订单号、商品名称、商品价格、下单用户名、下单用户年龄、性别 // select o.order_id,o.user_id,o.goods_name,o.goods_price,u.name,u.age,u.gender from t_order as o left join t_user as u on o.user_id=u.id List<OrderVo> orderVos = userMapper.selectOrders(); orderVos.forEach(System.out::println);
在多表查询中需要用到mapper中的UserMapper.xml写sql语句:使用resultMap的形式进行多表的查询
<resultMap id="orderMap" type="com.gcxy.entity.OrderVo"> <result property="userName" column="name"/> <result property="userAge" column="age"/> <result property="userGender" column="gender"/> <result property="orderId" column="order_id"/> <result property="userId" column="user_id"/> <result property="goodsName" column="goods_name"/> <result property="goodsPrice" column="goods_price"/> </resultMap> <select id="selectOrders" resultMap="orderMap"> select o.order_id, o.user_id, o.goods_name, o.goods_price, u.name, u.age, u.gender from t_order as o left join t_user as u on o.user_id = u.id </select>
(6)分页查询:
(6.1)mapper层、service层
// mapper 层分页查询 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",30); Page<User> page = new Page<>(2,10); // 查询第2页,每页10条数据 page = userMapper.selectPage(page,queryWrapper); System.out.println("总共记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 获取当前也数据 List<User> users = page.getRecords(); users.forEach(System.out::println); // service层分页查询 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",30); Page<User> page = new Page<>(2,10); // 查询第2页,每页10条数据 page = userService.page(page,queryWrapper); System.out.println("总共记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 获取当前也数据 List<User> users = page.getRecords(); users.forEach(System.out::println);
(6.2)sql组装分页查询
// 组装查询条件 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age", 30); // 查询第 2 页数据,每页 10 条 Page<User> page = new Page<>(2, 10); page = userMapper.selectPage(page, queryWrapper); System.out.println("总记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 当前页数据 List<User> users = page.getRecords(); users.forEach(System.out::println); // 组装查询条件 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); // where age = 30 queryWrapper.eq("age", 30); // 查询第 2 页数据,每页 10 条 Page<User> page = new Page<>(2, 10); page = userService.page(page, queryWrapper); System.out.println("总记录数:" + page.getTotal()); System.out.println("总共多少页:" + page.getPages()); System.out.println("当前页码:" + page.getCurrent()); // 当前页数据 List<User> users = page.getRecords(); List<OrderVo> orderVOS = userMapper.selectOrders(); orderVOS.forEach(System.out::println);
(7)关联分页查询
// 关联分页查询 //查询第一页,每页数据显示10条 Page<OrderVo> page = new Page<>(1,10); // 手动关闭sql优化,不然查询总数的时候只会查询主表 page.setOptimizeCountSql(false); //组装插叙你条件 age = 30 QueryWrapper<OrderVo> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("age",30); IPage<OrderVo> page1 = userMapper.selectOrderPage(page,queryWrapper); System.out.println("总记录数:" + page1.getTotal()); System.out.println("总共页数:" + page1.getPages()); System.out.println("当前页码:" + page1.getCurrent()); System.out.println("当前查询数据:" + page1.getRecords());
UserMapper.xml中的sql语句代码:
<select id="selectOrderPage" resultMap="orderMap"> select o.order_id, o.user_id, o.goods_name, o.goods_price, u.name, u.age, u.gender from t_order as o left join t_user as u on o.user_id = u.id ${ew.customSqlSegment} </select>
仍需要继续深入学习MybatisPlus,初学一下,大为震撼,前辈们创建出来的需要我们不断的去学习。