MybatisPlus快速入门
MybatisPlus快速入门
一、MybatisPlus简介
MybatisPlus是一个MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生
二、快速开始
1、创建数据库 mybatis_plus
2、创建User表
CREATE TABLE user ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名', age INT(11) NULL DEFAULT NULL COMMENT '年龄', email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱', PRIMARY KEY (id) );
3、添加数据
INSERT INTO user (id, name, age, email) VALUES (1, 'Jone', 18, 'test1@baomidou.com'), (2, 'Jack', 20, 'test2@baomidou.com'), (3, 'Tom', 28, 'test3@baomidou.com'), (4, 'Sandy', 21, 'test4@baomidou.com'), (5, 'Billie', 24, 'test5@baomidou.com');
4、打开IDEA在pom.xml添加相关依赖
<!--mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.3.1</version> </dependency> <!--mysql运行时依赖--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!--lombok用来简化实体类--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
5、编写连接数据库的properties
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.url=jdbc:mysql://localhost:3306/mybatis_plus?serverTimezone=GMT%2B8 spring.datasource.username=root spring.datasource.password=123456 # MybatisPlus日志 mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
6、创建包entity编写User实体类
@Data public class User { private Long id; private String name; private Integer age; private String email; }
7、创建mapper编写UserMapper文件(MybatisPlus核心持久层接口)
@Repository public interface UserMapper extends BaseMapper<User> { }
8、在主启动类上添加扫面mapper文件夹(稍后我们会统一放入MybatisPlusConfig文件内)
@SpringBootApplication @MapperScan("xxx.xxxx.mapper") public class MybatisPlusApplication { ...... }
9、在测试类中完成测试
@SpringBootTest class MybatisPlusApplicationTests { @Autowired private UserMapper userMapper; @Test void testMybatis_QuickStart() { List<User> users = userMapper.selectList(null); users.forEach(System.out::println); } }
10、在控制台查看输出效果
-
三、插入数据和主键策略
插入数据
@Autowired private UserMapper userMapper; @Test public void testInsert(){ User user = new User(); user.setName("张三"); user.setAge(18); user.setEmail("1746344046@qq.com"); int result = userMapper.insert(user); System.out.println("成功添加的行数:" + result); System.out.println("添加用户的id为:" + user.getId()); //id:1272668550292856834 MybatisPlus默认主键策略为雪花算法 }
主键策略
1、ASSIGN_ID
MyBatis-Plus默认的主键策略是:ASSIGN_ID(使用了雪花算法)
@TableId(type = IdType.ASSIGN_ID) private Long id;
2、AUTO自增策略
需要在数据库的id字段设置主键自增
@TableId(type = IdType.AUTO) private Long id;
3、要想影响所有实体的配置,可以设置全局主键配置(properties或yml文件)
# 全局设置主键生成策略 mybatis-plus.global-config.db-config.id-type=auto
四、更新数据、自动填充和乐观锁
更新数据
@Test public void testUpdate(){ User user = new User(); user.setId(1L); user.setName("李四"); int result = userMapper.updateById(user); System.out.println("成功更新的行数:" + result); }
自动填充
1、需求:项目中经常会遇到一些数据,每次都使用相同的方式填充,例如记录的创建时间,更新时间等。
2、数据库修改
在User表中添加datetime类型的新的字段 create_time、update_time
3、实体类修改
@Data public class User { ...... @TableField(fill = FieldFill.INSERT) private Date createTime; //@TableField(fill = FieldFill.UPDATE) @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime; }
4、实现元对象处理器接口
创建handler包编写MyMetaObjectHandler文件
@Slf4j @Component public class MyMetaObjectHandler implements MetaObjectHandler { @Override public void insertFill(MetaObject metaObject) { log.info("开始填充insertFill......."); this.setFieldValByName("createTime", new Date(), metaObject); this.setFieldValByName("updateTime", new Date(), metaObject); } @Override public void updateFill(MetaObject metaObject) { log.info("开始填充updateFill......."); this.setFieldValByName("updateTime", new Date(), metaObject); } }
5、测试
@Test public void testAutoInsertFill(){ User user = new User(); user.setName("王五"); user.setAge(20); user.setEmail("1746344046@qq.com"); int result = userMapper.insert(user); System.out.println("成功添加的行数:" + result); //2020-06-16 07:32:57.821(Timestamp), 2020-06-16 07:32:57.821(Timestamp) }
乐观锁
1、场景:
一件商品,成本价是80元,售价是100元。老板先是通知小李,说你去把商品价格增加50元。小李正在玩游戏,耽搁了一个小时。正好一个小时后,老板觉得商品价格增加到150元,价格太高,可能会影响销量。又通知小王,你把商品价格降低30元
此时,小李和小王同时操作商品后台系统。小李操作的时候,系统先取出商品价格100元;小王也在操作,取出的商品价格也是100元。小李将价格加了50元,并将100+50=150元存入了数据库;小王将商品减了30元,并将100-30=70元存入了数据库。是的,如果没有锁,小李的操作就完全被小王的覆盖了
现在商品价格是70元,比成本价低10元。几分钟后,这个商品很快出售了1千多件商品,老板亏1万多
2、乐观锁与悲观锁
- 上面的故事,如果是乐观锁,小王保存价格前,会检查下价格是否被人修改过了。如果被修改过了,则重新取出的被修改后的价格,150元,这样他会将120元存入数据库
- 如果是悲观锁,小李取出数据后,小王只能等小李操作完之后,才能对价格进行操作,也会保证最终的价格是120元
3、模拟上述场景
-
数据库中增加商品表
CREATE TABLE product ( id BIGINT(20) NOT NULL COMMENT '主键ID', name VARCHAR(30) NULL DEFAULT NULL COMMENT '商品名称', price INT(11) DEFAULT 0 COMMENT '价格', version INT(11) DEFAULT 0 COMMENT '乐观锁版本号', PRIMARY KEY (id) );
-
添加数据
INSERT INTO product (id, NAME, price) VALUES (1, 'RTX3080', 100);
-
编写实体类
@Data public class Product { private Long id; private String name; private Integer price; private Integer version; }
-
编写ProductMapper
@Repository public interface ProductMapper extends BaseMapper<Product> { }
-
测试
@Autowired private ProductMapper productMapper; @Test public void testNoLockCurrentUpdate(){ //1、小李 Product p1 = productMapper.selectById(1L); System.out.println("小李取出的价格:" + p1.getPrice()); //2、小王 Product p2 = productMapper.selectById(1L); System.out.println("小王取出的价格:" + p2.getPrice()); //3、小李将价格加了50元,存入了数据库 p1.setPrice(p1.getPrice() + 50); productMapper.updateById(p1); //4、小王将商品减了30元,存入了数据库 p2.setPrice(p2.getPrice() - 30); int result = productMapper.updateById(p2); if(result == 0){//更新失败,重试 //重新获取数据 p2 = productMapper.selectById(1L); //更新 p2.setPrice(p2.getPrice() - 30); productMapper.updateById(p2); } //5、最后的结果 Product p3 = productMapper.selectById(1L); System.out.println("最后的结果:" + p3.getPrice()); //最后的结果:70 }
4、使用MybatisPlus的乐观苏解决问题
- 数据库中添加version字段
-
修改实体类
@Version private Integer version;
-
创建配置文件
- 创建config包,创建文件MybatisPlusConfig.java
- 此时可以删除主启动类中的
@MapperScan
扫描注解
@EnableTransactionManagement @Configuration @MapperScan("xxxx.xxxx.mapper") public class MybatisPlusConfig { }
-
编写乐观锁插件
/** * 乐观锁插件 */ @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); }
-
测试
@Autowired private ProductMapper productMapper; @Test public void testNoLockCurrentUpdate(){ //1、小李 Product p1 = productMapper.selectById(1L); System.out.println("小李取出的价格:" + p1.getPrice()); //2、小王 Product p2 = productMapper.selectById(1L); System.out.println("小王取出的价格:" + p2.getPrice()); //3、小李将价格加了50元,存入了数据库 p1.setPrice(p1.getPrice() + 50); productMapper.updateById(p1); //4、小王将商品减了30元,存入了数据库 p2.setPrice(p2.getPrice() - 30); int result = productMapper.updateById(p2); if(result == 0){//更新失败,重试 //重新获取数据 p2 = productMapper.selectById(1L); //更新 p2.setPrice(p2.getPrice() - 30); productMapper.updateById(p2); } //5、最后的结果 Product p3 = productMapper.selectById(1L); System.out.println("最后的结果:" + p3.getPrice()); //最后的结果:120 }
- 总结:当我们使用了乐观锁后,如果出现了多个人同时修改同一数据的情况,那么所有人在拿到数据的同时也获取了乐观锁的版本号,当第一个人修改完毕后,乐观锁就会版本号+1,那么当其他人提交数据时由于版本号不对应的关系,所以数据就会提交失败
五、查询数据和分页插件
查询数据
1、通过多个id批量查询
@Test public void testSelectByBatchIds(){ List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3)); users.forEach(System.out::println); }
2、通过map封装完成简单条件查询
@Test public void testSelectByMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("name", "张三"); map.put("age", 18); List<User> users = userMapper.selectByMap(map); users.forEach(System.out::println); }
分页插件
1、在MybatisPlusConfig添加组件
/** * 分页插件 */ @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
2、测试
@Test public void testSelectPage() { Page<User> page = new Page<>(1,5); Page<User> pageParam = userMapper.selectPage(page, null); pageParam.getRecords().forEach(System.out::println); System.out.println(pageParam.getCurrent()); // 获取当前是第几页 System.out.println(pageParam.getPages()); // 获取一共的页数 System.out.println(pageParam.getSize()); // 获取每一页的个数 System.out.println(pageParam.getTotal()); // 获取总记录条数 System.out.println(pageParam.hasNext()); // 判断是否还有下一页 System.out.println(pageParam.hasPrevious()); // 判断是否还有前一页 }
3、通过QueryWrapper完成条件查询
@Test public void testSelectMapsPage() { Page<Map<String, Object>> page = new Page<>(1, 5); QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.select("name", "age"); // 表示查询结果只显示name和age列 Page<Map<String, Object>> pageParam = userMapper.selectMapsPage(page, queryWrapper); List<Map<String, Object>> records = pageParam.getRecords(); records.forEach(System.out::println); }
六、删除数据与逻辑删除
删除数据
1、根据id删除数据
@Test public void testDeleteById(){ int result = userMapper.deleteById(5L); System.out.println(result); }
2、批量删除数据
@Test public void testDeleteBatchIds() { int result = userMapper.deleteBatchIds(Arrays.asList(8, 9, 10)); System.out.println(result); }
3、根据map封装完成删除
@Test public void testDeleteByMap() { HashMap<String, Object> map = new HashMap<>(); map.put("name", "张三"); map.put("age", 18); int result = userMapper.deleteByMap(map); System.out.println(result); }
逻辑删除
1、修改数据库字段
ALTER TABLE `user` ADD COLUMN `deleted` tinyint DEFAULT false
2、修改实体类
@TableLogic private Integer deleted;
3、测试
@Test public void testLogicDelete(){ int result = userMapper.deleteById(1L); //此时的删除只是把deleted字段变成1 System.out.println(result); }
七、条件构造器和常用接口
案例一:
@Test public void testDelete() { //删除名字为空年龄大于12且邮箱不为空的用户(这里SQL为UPODATE因为逻辑删除原因) QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.isNull("name").ge("age", 12).isNotNull("email"); int result = userMapper.delete(queryWrapper); // UPDATE user SET deleted=1 WHERE deleted=0 AND (name IS NULL AND age >= ? AND email IS NOT NULL) System.out.println("delete return count = " + result); }
案例二:
@Test public void testSelectObjs() { // 查询id in (select id from user where id <= 3) QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.inSql("id", "select id from user where id <= 3"); List<Object> objects = userMapper.selectObjs(queryWrapper); //返回值是Object列表 objects.forEach(System.out::println); }
案例三:
@Test public void testSelectCount() { // 查询age在20-30之间的数量(包含20与30) QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.between("age", 20, 30); Integer count = userMapper.selectCount(queryWrapper); //返回数据数量 System.out.println(count); }
案例四:
@Test public void testSelectListOrderBy() { // 先按照age降序排列,如果age相同按照id降序排列 QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.orderByDesc("age", "id"); List<User> users = userMapper.selectList(queryWrapper); users.forEach(System.out::println); }
Wrapper的常见查询关键字:
-

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
支付宝应用和小程序开发:使用阿里云KMS保护应用私钥
一、支付宝开放平台的公私钥机制 支付宝开放平台的应用管理体系,使用了公私钥的机制,来保障商户应用和支付宝交互的安全性。这一机制包括两个部分: 商户应用使用自己的私钥对消息加签之后,将消息和签名传递给支付宝,支付宝则使用应用的公钥验证消息的真实性(来自于合法应用的真实消息)。 对于支付宝返回消息给商户应用的情形,应用则使用支付宝的“平台公钥”来验证返回消息的真实性。 下图简单描述了上述第一部分的交互机制: 这一机制的关键前提假定是: 商户应用必须保障应用私钥的安全性,从而保障应用和和支付宝交互的安全性。 反之,一旦私钥发生泄露,商户则会面临较大的安全风险。若应用和支付宝的交互涉及到资金类接口则风险更甚。 二、阿里云KMS带来的价值 相比于在应用中使用应用私钥的明文来对消息进行加签,阿里云KMS为用户带来了如下几个方面的优势: 保障私钥安全性:用户可以将签名私钥安全托管在KMS的托管密码机内。用户通过KMS的开放API使用私钥加签时,私钥会在密码机的硬件安全边界之内,完成运算后返回签名值,从而防止私钥的泄露。 控制谁可以使用私钥:用户可以通过阿里云访问控制服务(RAM服务),中心化的管理和...
- 下一篇
十个问题弄清JVM&GC(一)
十个问题弄清JVM&GC(一) 每个java开发同学不管是日常工作中还是面试里,都会遇到JDK、JVM和GC的问题。本文会从以下10个问题为切入点,带着大家一起全面了解一下JVM的方方面面。 JVM、JRE和JDK的区别和联系 JVM是什么?以及它的主要作用 JVM的核心功能有哪些 类加载机制和过程 运行时数据区的逻辑结构 JVM的内存模型 如何确定对象是垃圾 垃圾收集的算法有哪些 各种问世的垃圾收集器 JVM调优的参数配置 1、JVM、JRE和JDK的区别和联系 这个基本是步入java世界的入门级知识认知,首先我们来看一下来自java官网的一张图: 从这张图里我们基本就可以看出“JRE”是运行Java语言编写的程序所不可缺少的运行环境。有了JRE我们写的java程序才可以运行起来被用户所使用。 而“JDK”俗称java开发工具包,它包括了Java运行环境JRE(Java Runtime Envirnment)以及一堆Java工具(javac/java/jdb等)和Java基础的类库(即Java API 包括rt.jar)。 但不管是JRE还是JDK都是以JVM为基石的。可以说...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- Docker安装Oracle12C,快速搭建Oracle学习环境
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6