阅读 144

Mybatis-plus 上

简介

1.什么是Mybatis-plus

MyBatis-Plus(简称 MP)是一个 MyBatis的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。


愿景

我们的愿景是成为 MyBatis 最好的搭档,就像魂斗罗中的 1P、2P,基友搭配,效率翻倍。

1

2.特性

  • 无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑

  • 损耗小:启动即会自动注入基本 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 操作智能分析阻断,也可自定义拦截规则,预防误操作

快速入门

我们将通过一个简单的 Demo 来阐述 MyBatis-Plus 的强大功能,在此之前,我们假设您已经:

  • 拥有 Java 开发环境以及相应 IDE

  • 熟悉 Spring Boot

  • 熟悉 Maven

1.数据库

创建一个mybatis-plus数据库

现有一张 User 表,其表结构如下:

idnameageemail
1小张18test1@qq.com
2小王20test2@163.com
3小李25test3@qq.com
4小驰21test4@qq.com
5小刘24test5@163.com
  • 对应的数据库 Schema 脚本如下:

DROP TABLE IF EXISTS 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)
);

真实开发中,version(乐观锁)、deleted(逻辑删除)、gmt_create、gmt_modified

  • 其对应的数据库 Data 脚本如下:

DELETE FROM user;INSERT INTO user (id, name, age, email) VALUES(1, '小张', 18, 'test1@qq.com'),
(2, '小王', 20, 'test2@163.com'),
(3, '小李', 25, 'test3@qq.com'),
(4, '小驰', 21, 'test4@qq.com'),
(5, '小刘', 24, 'test5@163.com');

2.初始化工程

创建一个SpringBoot项目:创建时选择 starter-web 依赖。

2.1 导入依赖

<!-- 数据库驱动  --><dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId></dependency><!-- lombok  --><dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId></dependency><!-- mybatis-plus  --><dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.1.0</version></dependency>

使用mybatis-plus可以节省我们大量的代码,尽量不要同时导入 mybatis 和 mybatis-plus

2.2 连接数据库

直接在application.properties配置文件中配置:

# mysql 5   驱动不同# mysql 8   驱动不同、需要增加时区  serverTime=UTCspring.datasource.username=rootspring.datasource.password=148729spring.datasource.url=jdbc:mysql://localhost:3306/mybatis-plus?useSSL=false&useUnicode=true&charEncoding=utf-8&serverTime=UTCspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

3.搭建项目

传统方式:pojo---dao(连接mybatis,配置mapper.xml文件)--- service---- controller

使用了mybatis-plus:

  • pojo

  • mapper接口

  • 启动

3.1 pojo

这里使用了lombok插件,导入lombok依赖,

@Data@AllArgsConstructor@NoArgsConstructorpublic class User {    private Long id;    private String name;    private Integer age;    private String email; 
}

3.2 mapper

  • 创建一个xxxmapper接口

  • 该接口继承BaseMapper<>,泛型为实体类

  • 加注解@Repository

@Repositorypublic interface UserMapper extends BaseMapper<User> {
}

3.3 启动器

加入@MapperScan(""),对mapper包进行扫描

@SpringBootApplication@MapperScan("com.zc.mapper")public class MybatisPlus01QsApplication {    public static void main(String[] args) {
        SpringApplication.run(MybatisPlus01QsApplication.class, args);
    }
}

3.4 测试类

@SpringBootTestclass MybatisPlus01QsApplicationTests {    @Autowired
    private UserMapper userMapper;    
    @Test
    void contextLoads() {        //查询全部用户
        List<User> users = userMapper.selectList(null);
        users.forEach(System.out::print;
    }
}

2

4.配置日志

在配置文件中进行配置:

# 配置日志mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

测试运行:

3

插入操作

1.插入数据

@Testvoid insert() {    //插入新用户
    User user = new User();
    user.setName("咚咚");
    user.setAge(16);
    user.setEmail("111@insert.com");    int insert = userMapper.insert(user);
    System.out.println(insert);
    System.out.println(user);
}

4

我们从上图可以看出:主键自动生成

2.雪花算法

2.1 含义

SnowFlake算法是Twitter公司出品的开源的分布式id生成算法,结果是一个long型的ID
其特点为 使用一个64 bit的long型的数字作为全局唯一 id
雪花算法在分布式系统中的应用十分广泛 且引入了时间戳 基本保持自增

2.2 字符串含义

其核心思想是:

41bit作为毫秒数

10bit作为机器的ID(5个bit是数据中心,5个bit的机器D)

12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生4096个ID)

最后还有个符号位,永远是0。可以保证几乎全球唯一!

5

  • 第1位是符号位 始终为0
    (这是因为生成的id都是正数 而在二进制中第一个bit若为0则不为负数)

  • 后面是41位的时间戳 精确到毫秒级
    41位的长度可以表示2^41-1个毫秒值 也就是说可以使用69年
    时间戳还有一个很重要的作用 可以根据时间进行排序

  • 之后的10位是机器标识 前5bit是机房id 后5bit是机器id
    10位的长度表明该服务最多可以部署在2^10台机器(即1024台机器)上

  • 最后12位是计数序列号
    序列号是一系列的自增id 表示了同一个毫秒内产生的不同id
    可以支持同一节点同一毫秒生成多个id 12位的计数序列号支持每个节点每毫秒产生2^12-1(即4096)个ID序号

2.3 生成过程

  1. 若某个服务需要生成一个唯一id 则发送一个请求给部署了SnowFlake算法的系统(前提是该SnowFlake算法系统知道自己所在的机房和机器的编号)

  2. SnowFlake算法系统接收到该请求后 使用二进制位运算的方式生成一个64bit的long型id 当然 第一个bit是无意义的

  3. 接着41个bit使用当前时间戳(单位为毫秒) 然后的5bit设为该机房的id 剩余5bit设为机器的id

  4. 最后 再判断当前机房的该机器在这一毫秒内是第几个请求 给本次生成id的请求后再累加一个序号 作为id最后的12个bit

至此 就得到了一个64bit的唯一id 这就是雪花算法

3.主键自增

需要配置主键自增:

  1. 开启数据库 主键自增

  2. 实体类主键字段上 @TableId(type=IdType.AUTO)

  3. 再次测试

IdType类中枚举解释

AUTO(0),           // 数据库id自增NONE(1),           // 未设置主键INPUT(2),          // 手动输入ID_WORKER(3),      // 默认的全局唯一idUUID(4),           // 全局唯-id uuidID_WORKER_STR(5);  // ID_WORKER 字符串表示法

更新操作

@Testvoid update() {    //更新用户
    User user = new User();
    user.setId(5L);      // id 在数据库中设置的类型为 long
    user.setName("我不是小刘啦");    // 虽然是ById,实际上应该传入 泛型T
    int i = userMapper.updateById(user);
}

6

mybatis-plus 中都是自动化,自动拼接动态Sql

自动填充

创建时间修改时间,这些操作一般都是自动化完成的,不希望手动更新
阿里巴巴开发手册:所有的数据库表:gmt_creategmt_modified几乎所有的表都要配置上,而且需要自动化

1.数据库级别

如果你使用的Navicat Premium,在mysql5.5以上已经不支持两个字段自动更新

如果觉得很麻烦,可以直接看第二种代码级别自动填充

1、在表中新增字段create_timeupdate_time

8

9

因为不支持两个列为timestamp类型,所以这里设置更新时间为timestamp

下面的默认必须为CURRENT_TIMESTAMP,然后打对号

如果没有CURRENT_TIMESTAMP,可以使用两个方法:

一、默认框下拉,选择空白处,将这段英文复制进去 ,然后保存

二、把表删了,运行下面的sql语句

CREATE TABLE `mybatis-plus`.`Untitled`  (  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',  `name` varchar(30) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '姓名',  `age` int(11) NULL DEFAULT NULL COMMENT '年龄',  `email` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '邮箱',  `create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 1374350451559940100 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;

2.实体类增加字段

private Date createTime;private Date updateTime;

3.更新测试

9

10

数据库中的更新时间也会进行更新

2.代码级别

1.在表中新增字段create_timeupdate_time

11

2.实体类加入注解

@TableField(fill = FieldFill.INSERT)private Date createTime;@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateTime;

3.创建配置类

@Component@Slf4jpublic class MyMetaobjectHandler implements MetaObjectHandler {    @Override
    public void insertFill(MetaObject metaObject) {
        log. info("start insert fill.....");        //setFieldValByName(String fieldName, object fieldVal, Metaobject metaobject
        this.setFieldValByName ("createTime", new Date(), metaObject);        this.setFieldValByName ("updateTime", new Date(), metaObject);
    }    @Override
    public void updateFill(MetaObject metaObject) {
        log. info("start  update fill.....");        this.setFieldValByName ("updateTime", new Date(), metaObject);
    }
}

4.插入测试

@Testvoid insert() {
    User user = new User();
    user.setName("邦邦");
    user.setAge(20);
    user.setEmail("insert@insert.com");    int insert = userMapper.insert(user);
    System.out.println(insert);
    System.out.println(user);
}

12

5.更新测试

@Testvoid update() {
    User user = new User();
    user.setId(5L);      // id 在数据库中设置的类型为 long
    user.setName("我bu是小刘啦");    // 虽然是ById,实际上应该传入 泛型T
    int i = userMapper.updateById(user);
}

13

乐观锁

乐观锁:故名思意十分乐观,总是认为不会出现问题,无论干什么不去上锁,先进行事务,如果出现了问题,再次更新值测试

悲观锁:故名思意十分悲观,总是认为总是出现问题,无论干什么都会上锁,再去操作

乐观锁实现方式:

  • 取出记录时,获取当前versionl

  • 更新时,带上这个version执行

  • 更新时,set version = newVersion where version =oldVersion

  • 如果version不对,就更新失败

举例:

先查询出 version,进行操作时 version + 1
线程A:update user set name = "zc",version = version+1 where id=? and version=1线程B:update user set name = "zc",version = version+1 where id=? and version=1

可以看出,先查询了老的version,在更新时version+1;

如果 线程B先于线程A完成该更新操作,那version==2,这时候线程A不成立,更新失败

添加乐观锁

1.数据库中添加version字段:int类型,全部设为 1 即可

14

2.实体类加入对应字段、注释

@Version   //乐观锁Version注解private Integer version;

3.注册组件

@EnableTransactionManagement@Configuration@MapperScan("com.zc.mapper")public class MyBatisPlusConfig {    //注册乐观锁插件
    @Bean
    public OptimisticLockerInterceptor optimisticLockerInterceptor() {        return new OptimisticLockerInterceptor();
    }
}

4.测试乐观锁

成功:

@Testpublic void optimisticlocker_success(){    //1、查询用户信息
    User user = userMapper.selectById(1L);    //2、修改用户信息
    user.setName("zc");
    user.setEmail("update@qq.com");    //3、执行更新操作
    userMapper.updateById(user);
}

失败:

@Testpublic void optimisticlocker_fail(){    //线程A
    User user = userMapper.selectById(1L);
    user.setName("zc");
    user.setEmail("A@qq.com");    //线程B
    User user1 = userMapper.selectById(1L);
    user.setName("zc1");
    user.setEmail("B@qq.com");

    userMapper.updateById(user1);
    userMapper.updateById(user);
}

我们使,线程B 先于 线程A 进行更新。

这时会发现,虽然可以运行,version字段也会增加,但是并不会进行更新。


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐