mybatis-plus应用

mybatis-plus应用

官网地址[链接](https://mp.baomidou.com/)

版本: 3.0.5

导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ccj.appliction</groupId>
    <artifactId>appliction</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>appliction</name>
    <description>firstAppliction</description>


    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <druid.version>1.0.26</druid.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <!-- druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.6</version>
        </dependency>
        <dependency>
            <groupId>commons-pool</groupId>
            <artifactId>commons-pool</artifactId>
            <version>1.6</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.4.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.8</version>
        </dependency>

        <!-- Mybatis-plus -->
        <!-- mybatisPlus 核心库 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.8.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>RELEASE</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

连接数据库

spring:
#redis简单配置
   redis:
    host: 127.0.0.1
    port: 6379
    database: 0

  #数据源
  datasource:
    username: root
    password: root
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/appliction?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai
    type: com.alibaba.druid.pool.DruidDataSource
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    filters: stat,wall
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

mybatis-plus:
  mapper-locations: classpath:/mappers/*Mapper.xml
  typeAliasesPackage: com.ccj.application
  global-config:
    id-type: 0
    field-strategy: 1
    #db-column-underline: true
    refresh-mapper: true
    #capital-mode: true
    #key-generator: com.baomidou.mybatisplus.incrementer.OracleKeyGenerator
    #logic-delete-value: 1
    #logic-not-delete-value: 0
    #sql-injector: com.baomidou.mybatisplus.mapper.LogicSqlInjector
    #meta-object-handler: com.baomidou.springboot.MyMetaObjectHandler
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    #\u914D\u7F6EJdbcTypeForNull
    jdbc-type-for-null: 'null'
    #日志输出
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

pojo-dao(连接mybatis,配置mapper.xml文件)-serice-controller

使用mybatis-plus之后

  • pojo

    package com.ccj.application.model;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    
    /**
     * <p>
     * 用户表
     * </p>
     *
     * @author Cai.ChangJun
     * @since 2020-07-12
     */
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        private Long id;
        private String name;
        private Integer age;
        private String email;
    
    
    }
    
    
  • mapper接口

    package com.ccj.application.dao;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.ccj.application.model.User;
    import org.springframework.stereotype.Repository;
    
    /**
     * <p>
     * 用户表 Mapper 接口
     * </p>
     *
     * @author Cai.ChangJun
     * @since 2020-07-12
     */
    @Repository
    public interface UserMapper extends BaseMapper<User> {
    
    }
    
    

    baseMapper源码直观感受

    package com.baomidou.mybatisplus.core.mapper;
    
    import com.baomidou.mybatisplus.core.conditions.Wrapper;
    import com.baomidou.mybatisplus.core.metadata.IPage;
    import java.io.Serializable;
    import java.util.Collection;
    import java.util.List;
    import java.util.Map;
    import org.apache.ibatis.annotations.Param;
    
    public interface BaseMapper<T> {
        int insert(T var1);
    
        int deleteById(Serializable var1);
    
        int deleteByMap(@Param("cm") Map<String, Object> var1);
    
        int delete(@Param("ew") Wrapper<T> var1);
    
        int deleteBatchIds(@Param("coll") Collection<? extends Serializable> var1);
    
        int updateById(@Param("et") T var1);
    
        int update(@Param("et") T var1, @Param("ew") Wrapper<T> var2);
    
        T selectById(Serializable var1);
    
        List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> var1);
    
        List<T> selectByMap(@Param("cm") Map<String, Object> var1);
    
        T selectOne(@Param("ew") Wrapper<T> var1);
    
        Integer selectCount(@Param("ew") Wrapper<T> var1);
    
        List<T> selectList(@Param("ew") Wrapper<T> var1);
    
        List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> var1);
    
        List<Object> selectObjs(@Param("ew") Wrapper<T> var1);
    
        IPage<T> selectPage(IPage<T> var1, @Param("ew") Wrapper<T> var2);
    
        IPage<Map<String, Object>> selectMapsPage(IPage<T> var1, @Param("ew") Wrapper<T> var2);
    }
    
    
  • 注意点:在appliction.java主启动类加上@MapperScan(mapper位置)

  • 使用

    package com.ccj.application;
    import com.ccj.application.model.User;
    import com.ccj.application.service.UserService;
    import org.junit.jupiter.api.Test;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    
    
    import java.util.List;
    
    @SpringBootTest
    public class SpringbootMybatisPlusApplicationTests {
    
        @Autowired
        private UserService userService;
    
        @Test
        public void contextLoads() {
    
            // 所有用户
            List<User> users = userService.selectList(null);
            System.out.println(users);
            
            //查询id=1的用户
            User user = userService.selectById(1);
            System.out.println("users1=="+user);
        }
    
    }
    

分布式系统唯一id生成:https://blog.csdn.net/rainyear/article/details/86293122

Twitter的snowflake算法

雪花算法:

nowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。具体实现的代码可以参看https://github.com/twitter/snowflake。

算法实现:

 public class IdWorker
    {
        private long workerId;
        private long datacenterId;
        private long sequence = 0L;

        private static long twepoch = 1288834974657L;

        private static long workerIdBits = 5L;
        private static long datacenterIdBits = 5L;
        private static long maxWorkerId = -1L ^ (-1L << (int)workerIdBits);
        private static long maxDatacenterId = -1L ^ (-1L << (int)datacenterIdBits);
        private static long sequenceBits = 12L;

        private long workerIdShift = sequenceBits;
        private long datacenterIdShift = sequenceBits + workerIdBits;
        private long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
        private long sequenceMask = -1L ^ (-1L << (int)sequenceBits);

        private long lastTimestamp = -1L;
        private static object syncRoot = new object();

        public IdWorker(long workerId, long datacenterId)
        {

            // sanity check for workerId
            if (workerId > maxWorkerId || workerId < 0)
            {
                throw new ArgumentException(string.Format("worker Id can't be greater than %d or less than 0", maxWorkerId));
            }
            if (datacenterId > maxDatacenterId || datacenterId < 0)
            {
                throw new ArgumentException(string.Format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
            }
            this.workerId = workerId;
            this.datacenterId = datacenterId;
        }

        public long nextId()
        {
            lock (syncRoot)
            {
                long timestamp = timeGen();

                if (timestamp < lastTimestamp)
                {
                    throw new ApplicationException(string.Format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
                }

                if (lastTimestamp == timestamp)
                {
                    sequence = (sequence + 1) & sequenceMask;
                    if (sequence == 0)
                    {
                        timestamp = tilNextMillis(lastTimestamp);
                    }
                }
                else
                {
                    sequence = 0L;
                }

                lastTimestamp = timestamp;

                return ((timestamp - twepoch) << (int)timestampLeftShift) | (datacenterId << (int)datacenterIdShift) | (workerId << (int)workerIdShift) | sequence;
            }
        }

        protected long tilNextMillis(long lastTimestamp)
        {
            long timestamp = timeGen();
            while (timestamp <= lastTimestamp)
            {
                timestamp = timeGen();
            }
            return timestamp;
        }

        protected long timeGen()
        {
            return (long)(DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds;
        }
    }

mybatis-plus中的id自增策略

@TableId(type = "")

type种类:

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

插入操作

自增策略

需要配置主键自增

  1. 实体类上@TableId(type = IdType.AUTO)

  2. 数据库字段要是自增

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nRdJN1XQ-1612421886576)(C:\Users\ccj\AppData\Roaming\Typora\typora-user-images\image-20200718232935065.png)]

        @Test
        public void testinsert(){
            User user = new User();
            user.setName("张三");
            user.setAge(23);
            user.setEmail("123456@qq.com");
            Integer insert = userMapper.insert(user);
            System.out.println(insert);
            System.out.println(user);
        }
    

更新操作

@Test
    public void testUpdate(){
        User user = new User();
        user.setId(6L);
        user.setName("李四");
        user.setAge(23);
        //null和""都不更新该字段
        user.setEmail("123456@qq.com");
        userMapper.updateById(user);
    }

自动填充

创建时间、修改时间。。。这些操作都是数据库自动完成的,我们不希望手动更新

阿里巴巴开发手册: 参考阿里规范 建表约规 第9条

1. 【强制】表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint
(1 表示是,0 表示否)。
说明:任何字段如果为非负数,必须是 unsigned。
注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀,所以,需要在<resultMap>设置从 is_xxx 到
Xxx 的映射关系。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的命名方式是为了明确其取值含
义与取值范围。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。
2. 【强制】表名、字段名必须使用小写字母或数字,禁止出现数字开头,禁止两个下划线中间只
出现数字。数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
说明:MySQL 在 Windows 下不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、表名、
字段名,都不允许出现任何大写字母,避免节外生枝。
正例:aliyun_admin,rdc_config,level3_name
反例:AliyunAdmin,rdcConfig,level_3_name
3. 【强制】表名不使用复数名词。
说明:表名应该仅仅表示表里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数形式,符合
表达习惯。
4. 【强制】禁用保留字,如 desc、range、match、delayed 等,请参考 MySQL 官方保留字。
5. 【强制】主键索引名为 pk_字段名;唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
说明:pk_ 即 primary key;uk_ 即 unique key;idx_ 即 index 的简称。
6. 【强制】小数类型为 decimal,禁止使用 float 和 double。
说明:在存储的时候,float 和 double 都存在精度损失的问题,很可能在比较值的时候,得到不正确的
结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数并分开存储。
7. 【强制】如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
8. 【强制】varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度
大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索引效
率。
9. 【强制】表必备三字段:id, gmt_create, gmt_modified。
说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。gmt_create, gmt_modified
的类型均为 datetime 类型,前者现在时表示主动式创建,后者过去分词表示被动式更新。
Java 开发手册
 37/57
10.【推荐】表的命名最好是遵循“业务名称_表的作用”。
正例:alipay_task / force_project / trade_config
11.【推荐】库名与应用名称尽量一致。
12.【推荐】如果修改字段含义或对字段表示的状态追加时,需要及时更新字段注释。
13.【推荐】字段允许适当冗余,以提高查询性能,但必须考虑数据一致。冗余字段应遵循:
1) 不是频繁修改的字段。
2) 不是唯一索引的字段。
 3) 不是 varchar 超长字段,更不能是 text 字段。
 正例:各业务线经常冗余存储商品名称,避免查询时需要调用 IC 服务获取。
14.【推荐】单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。
说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
15.【参考】合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索
速度。
正例:无符号值可以避免误存负数,且扩大了表示范围。
对象 年龄区间 类型 字节 表示范围
人 150 岁之内 tinyint unsigned 1 无符号值:0 到 255
龟 数百岁 smallint unsigned 2 无符号值:0 到 65535
恐龙化石 数千万年 int unsigned 4 无符号值:0 到约 43 亿
太阳 约 50 亿年 bigint unsigned 8 无符号值:0 到约 10 的 19 次方
方式一:数据库级别
  1. 在表中新增字段create_time,update_time设置默认值

    DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间'
    DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP  COMMENT '更新时间'
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-APHZZFTg-1612421886578)(C:\Users\ccj\AppData\Roaming\Typora\typora-user-images\image-20200719001211235.png)]

插入数据时会自动插入时间

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sGuGvOYc-1612421886579)(C:\Users\ccj\AppData\Roaming\Typora\typora-user-images\image-20200719002458007.png)]

方式二:代码级别
  1. 数据库中没有自动生成日期的默认值

  2. 实体类上需要怎加注解

        @TableField(fill = FieldFill.INSERT)
        private Date createTime;
        @TableField(fill = FieldFill.INSERT_UPDATE)
        private Date updateTime;
    
  3. 编写处理器处理注解

    package com.ccj.application.handler;
    
    
    
    import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
    import lombok.extern.slf4j.Slf4j;
    import org.apache.ibatis.reflection.MetaObject;
    import org.springframework.stereotype.Component;
    
    import java.time.LocalDateTime;
    import java.util.Date;
    
    /**
     * @Description: 原数据处理
     * @Date: 2020/7/19
     * @author:Cai.ChangJun
     */
    @Slf4j
    @Component
    public class MyMetaObjectHandler implements MetaObjectHandler {
        /**
         * 插入时的填充策略
         * @Author Cai.ChangJun
          * @param metaObject :
         * @return void
         * @throws
         * @Date 2020/7/19 0:51
         */
        @Override
        public void insertFill(MetaObject metaObject) {
            log.info("start insert fill ....");
            this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
            this.setInsertFieldValByName("updateTime", new Date(), metaObject);
        }
    
        /**
         * 更新时的填充策略
         * @Author Cai.ChangJun
          * @param metaObject :
         * @return void
         * @throws
         * @Date 2020/7/19 0:52
         */
        @Override
        public void updateFill(MetaObject metaObject) {
           log.info("start update fill ....");
           this.setInsertFieldValByName("updateTime",new Date(), metaObject);
        }
    }
    
    

乐观锁

乐观锁,悲观锁

原子引用

乐观锁: 总是认为不会出现问题,无论做什么都不去上锁,如果出现问题,再次更新值测试

悲观锁:总是认为会出现问题,无论做什么都会上锁,再去操作

version、new version

乐观锁:1、先查询、获取版本号 version = 1
---线程A
update user set name = "caichangjun", version = version + 1 
 where id = 2 and version = 1
 
 ---线程B 抢先完成
 update user set name = "caichangjun", version = version + 1 
 where id = 2 and version = 1

mybatis-plus实现乐观锁

  1. 数据库表中添加字段version 默认值为1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6gud4Fpt-1612421886581)(C:\Users\ccj\AppData\Roaming\Typora\typora-user-images\image-20200719012001888.png)]

  1. 添加字段

@Version
private Integer version;
  1. 注册组件

    在mybatisConfig配置类中添加乐观锁插件

    package com.ccj.application.config;
    import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
    import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.transaction.annotation.EnableTransactionManagement;
    
    /**
     * @author zh
     * @ClassName cn.saytime.config.MybatisConfiguration
     * @Description
     */
    //开启事务
    @EnableTransactionManagement
    @Configuration
    @MapperScan("com.ccj.application.dao")
    public class MybatisConfiguration {
    
        /*
        * 分页插件,自动识别数据库类型
        * 多租户,请参考官网【插件扩展】
        */
        @Bean
        public PaginationInterceptor paginationInterceptor() {
            return new PaginationInterceptor();
        }
    
        /**
         * mybatis-plus实现乐观锁 注册乐观锁插件
         * @Author Cai.ChangJun
         * @return com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor
         * @throws
         * @Date 2020/7/19 1:22
         */
        @Bean
        public OptimisticLockerInterceptor optimisticLockerInterceptor() {
            return new OptimisticLockerInterceptor();
        }
    
       /*
        * oracle数据库配置JdbcTypeForNull
        * 参考:https://gitee.com/baomidou/mybatisplus-boot-starter/issues/IHS8X
        不需要这样配置了,参考 yml:
        mybatis-plus:
          confuguration
            dbc-type-for-null: 'null'
       @Bean
       public ConfigurationCustomizer configurationCustomizer(){
           return new MybatisPlusCustomizers();
       }
    
       class MybatisPlusCustomizers implements ConfigurationCustomizer {
    
           @Override
           public void customize(org.apache.ibatis.session.Configuration configuration) {
               configuration.setJdbcTypeForNull(JdbcType.NULL);
           }
       }
       */
    
    }
    
    1. 测试

    //测试乐观锁成功
    @Test
    public void testOptimisticLockerInterceptor(){
        //查询用户信息
        User user = userMapper.selectById(1);
        //修改用户信息
        user.setName("caichangjun");
        user.setEmail("123456@qq.com");
        //执行更新操作
        userMapper.updateById(user);
    }
    //测试乐观锁失败
    @Test
    public void testOptimisticLockerInterceptorError(){
        //线程1
        //查询用户信息
        User user = userMapper.selectById(1);
        //修改用户信息
        user.setName("caichangjun");
        user.setEmail("123456@qq.com");
        //模拟另一个线程执行插队操作
        User user2 = userMapper.selectById(1);
        user2.setName("caichangjun2222");
        user2.setEmail("222@qq.com");
        userMapper.updateById(user2);
        //自旋锁来多次尝试提交
        userMapper.updateById(user);  //如果没有乐观锁就会覆盖插队线程的值
    }
    

查询操作

//测试批量查询
@Test
public void  testSelect(){
    List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
    System.out.println(users);
}

@Test
//条件查询使用map
public void testSelectByMap(){
    Map<String, Object> map = new HashMap<>();
    map.put("name","张三");
    userMapper.selectByMap(map);
    
}

分页查询

  1. 原始limit分页

  2. pageHelper 第三方插件

  3. mybatis-plus内置插件

    使用mybatis-plus插件实现分页

    1.配置拦截器组件

    //Spring boot方式
    @EnableTransactionManagement
    @Configuration
    @MapperScan("com.baomidou.cloud.service.*.mapper*")
    public class MybatisPlusConfig {
    
        @Bean
        public PaginationInterceptor paginationInterceptor() {        
            PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
            // 设置请求的页面大于最大页后操作, true调回到首页,false 继续请求  默认false
            // paginationInterceptor.setOverflow(false);
            // 设置最大单页限制数量,默认 500 条,-1 不受限制
            // paginationInterceptor.setLimit(500);
            // 开启 count 的 join 优化,只针对部分 left join
            // paginationInterceptor.setCountSqlParser(new JsqlParserCountOptimize(true));
            return paginationInterceptor;
        }
    }
    
    1. 测试

      @Test
          //测试分页查询
          public void testPage(){
              //参数一:当前页
              //参数二:页面大小
              Page<User> userPage = new Page<>(1,5);
              IPage<User> userIPage = userMapper.selectPage(userPage, null);
              userIPage.getRecords().forEach(System.out::println);
          }
      

基本的删除操作

  1. 根据id删除数据

    @Test
    //测试删除
    public void testDelete(){
        int i = userMapper.deleteById(1284534058264678402L);
        System.out.println(i);
    }
    
    @Test
    //通过id批量删除
    public void testDeleteBatchId(){
        userMapper.deleteBatchIds(Arrays.asList(2, 3, 4));
    }
    
    @Test
        //根据条件删除
        public void testDeleteByMap(){
            HashMap<String, Object> map = new HashMap<>();
            map.put("name","李四");
            userMapper.deleteByMap(map);
    
        }
    

逻辑删除

物理删除: 在数据库中直接移除

逻辑删除: 在数据库中没有被移除,而是通过一个变量来让他失效  deleted = 0 => deleted = 1

测试:

  1. 在数据库表中添加一个delete字段

  2. 实体类中增加属性

    @TableLogic //逻辑删除
        private Integer deleted;
    
  3. 配置逻辑删除

/**
 * 逻辑删除组件
 * @Author Cai.ChangJun
 * @return com.baomidou.mybatisplus.core.injector.ISqlInjector
 * @throws
 * @Date 2020/7/19 17:10
 */
@Bean
public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)

性能分析

查询数据库中执行的慢sql

mybatis-plus提供的性能分析插件,如果超过这个时间就停止运行,作用:性能分析拦截器,用于输出每条sql语句及其执行时间

  1. 导入插件

    设置springboot环境为测试环境

    spring:
      #设置开发环境
      profiles:
        active: dev
    
    /**
     * SQL执行效率插件
     */
    @Bean
    @Profile({"dev","test"})// 设置 dev test 环境开启
    public PerformanceInterceptor performanceInterceptor() {
        PerformanceInterceptor performanceInterceptor = new PerformanceInterceptor();
        //ms 设置sql执行最大时间超过了不执行
        performanceInterceptor.setMaxTime(100);
        //开启格式化支持
        performanceInterceptor.setFormat(true);
        return performanceInterceptor;
    }
    
  2. 测试使用

 Time:8 ms - ID:com.ccj.application.dao.UserMapper.selectPage
Execute SQL:
    SELECT
        id,
        name,
        age,
        email,
        create_time,
        update_time,
        version,
        is_delete 
    FROM
        user 
    WHERE
        is_delete=0 LIMIT 0,5

条件构造器

复杂sql可以使用它替代

条件参数说明

查询方式说明
setSqlSelect设置 SELECT 查询字段
whereWHERE 语句,拼接 + WHERE 条件
andAND 语句,拼接 + AND 字段=值
andNewAND 语句,拼接 + AND (字段=值)
orOR 语句,拼接 + OR 字段=值
orNewOR 语句,拼接 + OR (字段=值)
eq等于=
allEq基于 map 内容等于=
ne不等于<>
gt大于>
ge大于等于>=
lt小于<
le小于等于<=
like模糊查询 LIKE
notLike模糊查询 NOT LIKE
inIN 查询
notInNOT IN 查询
isNullNULL 值查询
isNotNullIS NOT NULL
groupBy分组 GROUP BY
havingHAVING 关键词
orderBy排序 ORDER BY
orderAscASC 排序 ORDER BY
orderDescDESC 排序 ORDER BY
existsEXISTS 条件语句
notExistsNOT EXISTS 条件语句
betweenBETWEEN 条件语句
notBetweenNOT BETWEEN 条件语句
addFilter自由拼接 SQL
last拼接在最后,例如:last(“LIMIT 1”)

package com.ccj.application;



import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ccj.application.dao.UserMapper;
import com.ccj.application.model.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.util.List;
import java.util.Map;

/**
 * @Description: 条件构造器测试
 * @Date: 2020/7/19
 * @author:Cai.ChangJun
 */
@SpringBootTest
public class WrapperTest {
    @Autowired
    private UserMapper userMapper;
    @Test
    public void contextLoads() {
        //查询name不为空的并且邮箱不为空的,年龄大于等于12
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.isNotNull("name")
               .isNotNull("email")
               .ge("age",12);
        userMapper.selectList(wrapper).forEach(System.out::println);
    }

    @Test
    void test2(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("name","小蔡");
        User user = userMapper.selectOne(wrapper);
        System.out.println(user);
    }

    @Test
    void test3(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.between("age",20,25);
        Integer integer = userMapper.selectCount(wrapper);
        System.out.println(integer);
    }

    //模糊查询
    @Test
    void test4(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.like("name","三")
                .likeRight("email", "9");
        List<Map<String, Object>> maps = userMapper.selectMaps(wrapper);
        maps.forEach(System.out::println);
    }


    //模糊查询
    @Test
    void test5(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //id在子查询中查询出来
        wrapper.inSql("id","select id from user where id < 3");
        /*SELECT
                id,
                name,
                age,
                email,
                create_time,
                update_time,
                version,
                is_delete
        FROM
                user
        WHERE
                is_delete=0
        AND id IN (
                select
                id
                from
                user
                where
                id < 3
        )*/
        List<Object> objects = userMapper.selectObjs(wrapper);
        objects.forEach(System.out::println);
    }
    
    //查询排序
    @Test
    void test6(){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        //通过id进行降序排序
        wrapper.orderByDesc("id");
        userMapper.selectList(wrapper).forEach(System.out::println);

    }
}

代码自动生成器

AutoGenerator 是 MyBatis-Plus 的代码生成器,通过 AutoGenerator 可以快速生成 Entity、Mapper、Mapper XML、Service、Controller 等各个模块的代码,极大的提升了开发效率。

测试

加入依赖

 		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.30</version>
        </dependency>
        <dependency>
            <groupId>com.ibeetl</groupId>
            <artifactId>beetl</artifactId>
            <version>3.1.8.RELEASE</version>
        </dependency>

代码实现

package com.ccj.application;



import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.po.TableFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;

import java.util.ArrayList;

/**
 * @Description: 代码生成器
 * @Date: 2020/7/19
 * @author:Cai.ChangJun
 */
public class AutoCode {
    public static void main(String[] args) {

        //需要构建一个代码生成器对象
        AutoGenerator autoGenerator = new AutoGenerator();
        //配置策略
        //1.全局配置
        GlobalConfig gc = new GlobalConfig();
        String projectPath = System.getProperty("user.dir");
        gc.setOutputDir(projectPath+"/src/main/java");
        //生成作者
        gc.setAuthor("Cai.ChangJun");
        //是否打开资源管理器
        gc.setOpen(false);
        //是否覆盖原来生成的文件
        gc.setFileOverride(true);
        //去service的I前缀
        gc.setServiceName("%sService");
        //设置生成id策略  雪花算法
        gc.setIdType(IdType.ID_WORKER);
        //设置日期类型
        gc.setDateType(DateType.ONLY_DATE);
        //自动生成swagger文档
//        gc.setSwagger2(true);
        //将配置文件放入代码生成器对象中
        autoGenerator.setGlobalConfig(gc);
        //设置数据源
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl("jdbc:mysql://192.168.71.10:3306/appliction?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull&transformedBitIsBoolean=true&useSSL=false&allowMultiQueries=true&serverTimezone=Asia/Shanghai");
        dsc.setDriverName("com.mysql.cj.jdbc.Driver");
        dsc.setUsername("root");
        dsc.setPassword("root");
        dsc.setDbType(DbType.MYSQL);
        autoGenerator.setDataSource(dsc);

        //3.包的配置
        PackageConfig pc = new PackageConfig();
        pc.setParent("com.ccj.application");
        pc.setEntity("model");
        pc.setMapper("dao");
        pc.setService("service");
        pc.setServiceImpl("service.impl");
        pc.setController("api");
        autoGenerator.setPackageInfo(pc);

        //4.策略配置
        StrategyConfig strategy = new StrategyConfig();
        //设置要映射的表名
        strategy.setInclude("test");
        strategy.setNaming(NamingStrategy.underline_to_camel);
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
//        strategy.setSuperEntityClass("你自己的父类实体,没有就不用设置!");
        strategy.setEntityLombokModel(true);
        strategy.setRestControllerStyle(true);
        //逻辑删除
        strategy.setLogicDeleteFieldName("is_delete");
        //乐观锁
        strategy.setVersionFieldName("version");
        //自动填充
        TableFill createTime = new TableFill("create_time", FieldFill.INSERT);
        TableFill updateTime = new TableFill("update_time", FieldFill.INSERT_UPDATE);
        ArrayList<TableFill> tableFills = new ArrayList<>();
        tableFills.add(createTime);
        tableFills.add(updateTime);
        strategy.setTableFillList(tableFills);
        //设置restful风格的controller
        strategy.setRestControllerStyle(true);
        //127.0.0.1:8080/hello_id_2
        strategy.setControllerMappingHyphenStyle(true);
       /* // 公共父类
        strategy.setSuperControllerClass("你自己的父类控制器,没有就不用设置!");
        // 写于父类中的公共字段
        strategy.setSuperEntityColumns("id");
        strategy.setInclude(scanner("表名,多个英文逗号分割").split(","));
        strategy.setControllerMappingHyphenStyle(true);
        strategy.setTablePrefix(pc.getModuleName() + "_");*/
        autoGenerator.setStrategy(strategy);
       /* // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();

        // 配置自定义输出模板
        //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
        // templateConfig.setEntity("templates/entity2.java");
        // templateConfig.setService();
        // templateConfig.setController();

        templateConfig.setXml(null);
        autoGenerator.setTemplate(templateConfig);*/
        autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
        //执行
        autoGenerator.execute();
    }
}

原学习视频地址

https://www.bilibili.com/video/BV17E411N7KN?p=1

原视频作者:

te_time", FieldFill.INSERT);
TableFill updateTime = new TableFill(“update_time”, FieldFill.INSERT_UPDATE);
ArrayList tableFills = new ArrayList<>();
tableFills.add(createTime);
tableFills.add(updateTime);
strategy.setTableFillList(tableFills);
//设置restful风格的controller
strategy.setRestControllerStyle(true);
//127.0.0.1:8080/hello_id_2
strategy.setControllerMappingHyphenStyle(true);
/* // 公共父类
strategy.setSuperControllerClass(“你自己的父类控制器,没有就不用设置!”);
// 写于父类中的公共字段
strategy.setSuperEntityColumns(“id”);
strategy.setInclude(scanner(“表名,多个英文逗号分割”).split(","));
strategy.setControllerMappingHyphenStyle(true);
strategy.setTablePrefix(pc.getModuleName() + “_”);/
autoGenerator.setStrategy(strategy);
/
// 配置模板
TemplateConfig templateConfig = new TemplateConfig();

    // 配置自定义输出模板
    //指定自定义模板路径,注意不要带上.ftl/.vm, 会根据使用的模板引擎自动识别
    // templateConfig.setEntity("templates/entity2.java");
    // templateConfig.setService();
    // templateConfig.setController();

    templateConfig.setXml(null);
    autoGenerator.setTemplate(templateConfig);*/
    autoGenerator.setTemplateEngine(new FreemarkerTemplateEngine());
    //执行
    autoGenerator.execute();
}

}




原学习视频地址

https://www.bilibili.com/video/BV17E411N7KN?p=1

原视频作者:

狂神说
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值