MyBatisPlus使用

一、MyBatisPlus

  • MyBatisPlus 能大量的节省我们些CRUD的时间,所有的CRUD都能通过MyBatisPlus来自动完成
  • MyBatis Plus 简称 MP 是一个MyBatis的增强工具包,制作增强不做改变,为简化开发,提高生产率而生
  • MyBatis 官网: https://baomidou.com/
    MyBatis文档: https://baomidou.com/guide/

二、快速入门

1.官网: https://baomidou.com/guide/quick-start.html#%E5%88%9D%E5%A7%8B%E5%8C%96%E5%B7%A5%E7%A8%8B
2.创建一个springboot项目,选上lombok,spring web
3.导入mybatis plus 依赖

<dependency>
  <groupId>com.baomidou</groupId>
  <artifactId>mybatis-plus-boot-starter</artifactId>
  <version>3.0.5</version>
</dependency>

4.创建一个表,随便创建一个用户表
5.编写 application.properties 配置文件

# MySQL 5 配置
spring.datasource.username=root
spring.datasource.password=0000
spring.datasource.url=jdbc:mysql://localhost:3306/mp
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

在这里插入图片描述

6.使用MyBatis之后
创建实体类 User
创建UserMapper接口 继承 BaseMapper 【这个Mapper就是Dao】
在UserMapper接口上添加@Repository 注解
在Application主方法类 上添加
//扫描Mapper文件
@MapperScan(“com.xxx.xxx.dao”)
使用
在这里插入图片描述

1. 细节

MyBatis和MyBatis-spring 依赖就不要加入到项目中了。MyBatisPlus自动维护
在真实开发中,表的字段一般都会有 version(乐观锁) deleted(逻辑删除) gmt_create(创建时间),gmt_modified(修改时间)

2. 坑:

springboot的MySQL start 的mysql依赖版本是 8.0 版本,和电脑上的不匹配的话会报错,所以最好别选mysqlStart,自己添加mysql5.0的依赖
需要在主启动类上去扫描我们的mapper包下所有的接口
@MapperScan(“com.xxx.xxx.dao”)
如果是MySQL8.0的话,那么驱动需修改

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3. 配置日志

因为现在所有的SQL是不可见的,我们希望通过日志的方式将SQL输出出来

配置日志

mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

三、insert update

1. insert 插入

@Test
void insertPlus(){
    User user = new User();
    user.setId(7);
    user.setAge(18);
    user.setName("仝子瑜");
    user.setEmail("2298320493@qq.com");
    // 如果不设置id的话,会帮我们自动生成id值 这个id值很大很大
    int insert = userMapper.insert(user);
    // 输出受影响的行数
    System.out.println(insert);
}

数据库插入的id的默认值为:全局的唯一id
主键生成策略: 雪花算法,uuid,redis 等等等
雪花算法: https://www.cnblogs.com/haoxinyue/p/5208136.html

2. 我们需要配置主键自增

1.在实体类主键字段上添加 @TableId(type = IdType.AUTO)
2.数据库字段一定要是自增的 auto_increment
3.上面设置了后,插入的User对象中,就算id属性赋值了,也会按照它的自增
4.其余的IdType源码解释
在这里插入图片描述
一旦手动输入[ IdType.INPUT ]之后 就需要自己写ID,如果不写就是NULL【其实这个也可以用来自增,因为实体类是null,到数据库里面会根据数据库的值进行自增】

3.update更新

@Test
void updatePlus(){
    User user = new User();
    user.setId(1);
    user.setEmail("2298320493@qq.com");
    user.setName("zhangsan");
    user.setAge(15);
    // 注意!这里传入的值是一个User对象,通过这个user对象的id进行更新
    userMapper.updateById(user);  
}

update的SQL语句都是MyBatisPlus自己的动态SQL ,通过对属性的ifnull 进行判断。

4. 自动填充

    • 创建时间,修改时间!这些操作一般都是自动化完成的,我们不希望手动更新!
    • 阿里巴巴开发手册:所有的数据库表:gmt_create【create_time】 ,gmt_modified 【update_time】几乎所有的表都要配置上,而且需要自动化!
方式一:数据库级别 (工作中不建议使用)

1.在创建表时添加两个字段 create_time update_time
2.字段类型 datetime
3.给字段加上默认约束,获得当前时间,和更新时更新

方式二:代码级别

1.删除数据库字段的默认值
2.实体类的字段属性上需要增加注解

 /**
    * 字段插入时,自动填充
    */
    @TableField(fill = FieldFill.INSERT)
    private Date createTime;
    /**
    * 字段更新时,自动填充
    */
    @TableField(fill = FieldFill.UPDATE)
    private Date updateTime;

3.编写处理器 处理注解
一定要记得在处理器上面添加@Component注解,将组件添加到容器中

/**
* @date: 2021/1/5   0:02
* @author: 易学习
* @Component: 一定不要忘记把组件添加到容器中
*/
@Component
public class MyDateObjectHandler implements MetaObjectHandler {

    /**
     * 插入时的填充策略
     * @param metaObject
     */
    @Override
    public void insertFill(MetaObject metaObject) {
        /**
         * setFieldValByName:填充你要指定的值
         *  第一个参数:要填充的字段名
         *  第二个参数:要填充的值
         *  第三个参数:metaObject
         *  这里要写两个 把更新的字段也写上
         */
        this.setFieldValByName("createTime",new Date(),metaObject);
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
    /**
     * 更新时的填充策略
     * @param metaObject
     */
    @Override
    public void updateFill(MetaObject metaObject) {
        // 和上面一样,只是不需要设置 createTime了
        this.setFieldValByName("updateTime",new Date(),metaObject);
    }
}

四、乐观锁 & 悲观锁

乐观锁:顾名思义十分乐观,他总是认为不会出现问题,无论干什么都不会去上锁!如果出现了问题就再次更新值测试。
悲观锁:顾名思义十分悲观,他总是认为总是出现问题,无论干什么都会去上锁!再去上锁。

乐观锁实现方式:

  • 取出记录时,获取当前version
  • 更新时,带上这个version
  • 执行更新时, SQL: set version = newVersion where version = oldVersion
  • 如果version不对,就更新失败

乐观锁:现查询,获得版本号 version = 1

-- A 线程
update user set name = '仝子瑜',version = version + 1 where id = 22 and version = 1
--- B 线程,抢先修改,这个时候 version = 2 导致A 修改失败
update user set name = '张三',version = version + 1 where id = 22 and version = 1

测试MP中的乐观锁

1.给数据库中增加version 字段 int 类型 默认值为1
2.实体类添加对应的字段,并且加上@version注解,表明这是乐观锁
3.注册组件(最新版也需要注册,3.0.5需要注册组件)

/**
* @Configuration: 表明这个是一个配置类,这样的话,之前注册的处理器的扫描 @MapperScan()也可以放到这里
* @MapperScan: 扫描处理器,这里扫描的是之前那个 createTime 和 updateTime
* @EnableTransactionManagement: 事务控制
*/

@MapperScan("com.yixuexi.mybatisplus.mapper")
@EnableTransactionManagement
@Configuration
public class MyBatisPlusConfig {

    /**
     * 注册乐观锁插件
     */
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor(){
        return new OptimisticLockerInterceptor();
    }
}

4.测试

/**
	* 测试乐观锁,成功案例
	*/
	@Test
	void happyTest(){
	    // 1.查询用户信息
	    User user1 = userMapper.selectById(1);
	    // 2.修改用户信息
	    user1.setName("马保国");
	    user1.setAge(69);
	    user1.setEmail("mabaoguo@163.com");
	    // 3.执行更新操作
	    userMapper.updateById(user1);
	}
/**
* 测试乐观锁,失败案例
*/
@Test
void happyTest2(){
    // 线程1
    User user1 = userMapper.selectById(1);
    user1.setName("马保国");
    user1.setAge(69);
    user1.setEmail("mabaoguo@163.com");
    // 线程2 模拟另外一个线程执行了插队操作
    User user2 = userMapper.selectById(1);
    user2.setName("旭旭宝宝");
    user2.setAge(35);
    // 线程2 抢先更新
    userMapper.updateById(user2);
    // 线程1执行更新操作
    // 如果没有乐观锁,就会覆盖上面的旭旭宝宝,成为马保国
    // 因为设置了乐观锁 没有覆盖 马保国没有被进行更新,因为where的version=? 不成立
    userMapper.updateById(user1); 
}

五、查询

1. 查询

/**
*      * selectById(id)测试根据id查询一个
*/
@Test
void testSelectById(){
    User user = userMapper.selectById(1);
    System.out.println(user);
}
/**
* selectBatchIds(集合) 测试查询批量
*/
@Test
void testSelectBatchIds(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    System.out.println(users);
}
/**
* 条件查询:
*/
@Test
void testSelectByMap(){
    HashMap<String,Object> userHashMap = new HashMap<>();
    //自定义要查询的条件
    userHashMap.put("name","张五");
    List<User> users = userMapper.selectByMap(userHashMap);
    System.out.println(users);
}

2. 分页查询

mp中也集成了分页插件
官网: https://baomidou.com/guide/interceptor.html#%E4%BD%BF%E7%94%A8%E6%96%B9%E5%BC%8F-%E4%BB%A5%E5%88%86%E9%A1%B5%E6%8F%92%E4%BB%B6%E4%B8%BE%E4%BE%8B

1. 加入组件

导入分页插件,在自己创建的MyBatisPlus配置类里面 (3.0.5版本) 分页插件组件

@Configuration
@MapperScan("com.xxx.xxx.mapper")
public class MyBatisPlus{
    /**
     * 分页插件
     */
    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

2.测试分页查询
/**
 * 测试分页插件
 */
@Test
void testPage(){
    //创建一个Page对象
    // 有参构造参数:第一个:当前页。第二个:一次查几个
    Page<User> page = new Page(1,3);
    //通过page的对象getxxx()方法可以获得其余属性
    System.out.println(page.getTotal());
    // 调用selectPage()方法 第一个是page 对象,第二个是wrapper,没有就写null
    IPage<User> userIPage = userMapper.selectPage(page,null);
    System.out.println(userIPage);
}

六、删除

在这里插入图片描述

@Test
void testDeleteByMap(){
    Map<String,Object> map = new HashMap();
    // 根据条件删除,条件是姓名为张三的记录
    map.put("name","张三");
    userMapper.deleteByMap(map);
}

1 逻辑删除
物理删除: 直接从数据库中移除
逻辑删除: 没有从数据库中删除,而是通过一个字段来让他失效 deleted= 1

管理员可以查看被删除的记录,类似于回收站,其实底层数据库就是把字段deleted改成了1

2.测试逻辑删除 :
1.在数据表中增加deleted字段【默认值等于 0】
2.实体类中增加deleted属性 添加@TableLogic注解
在这里插入图片描述

测试删除
此时查询也查不到 deleted为1 的用户了
SELECT id,name,age,email,deleted,version,create_time,update_time FROM user WHERE id=? AND deleted=0 查询会自动在后面拼接一个 and deleted = 0.
在这里插入图片描述

七、条件构造器

用来写复杂的SQL
Wapper 是一个接口,底下有很多的实现类,查询用QueryWrapper类

/**
 * @date: 2021/1/5   23:56
 * @author: 易学习
 */
@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserMapper userMapper;
 
    /**
     * 1. 查询name不为空,并且邮箱不为空的用户,并且年龄>=12
     * isNotNull("字段")   该字段不为空
     * ge("字段",值) 大于等于
     */
    @Test
    void test1(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
                .isNotNull("email")
                .ge("age",12);
        List<User> users = userMapper.selectList(wrapper);
        System.out.println(users);
    }
 
    /**
     * 2. 查询名字为 张五的记录
     */
    @Test
    void test2(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","张五");
        List user = userMapper.selectList(wrapper);
        System.out.println(user);
    }
 
    /**
     * 3. 查询年龄在18-20之间的用户数量
     */
    @Test
    void test3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",18,20);
        Integer integer = userMapper.selectCount(wrapper);
        System.out.println(integer);
    }
    
    /**
     * 4. 模糊查询,名字里面没有五的
     */
    @Test
    void test4(){
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.notLike("name","五");
        List list = userMapper.selectMaps(wrapper);
        System.out.println(list);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

跳舞 D 猴子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值