自学内容网 自学内容网

Mybatis-plus

基本框架

环境

springboot3
mysql8+
JDK17

依赖导入

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
    </parent>
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
<!--测试-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>3.1.5</version>
        </dependency>

<!--        springboot3需要使用Mybatisplus3-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-spring-boot3-starter</artifactId>
            <version>3.5.5</version>
        </dependency>
<!--        简化操作-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.34</version>
        </dependency>
        
<!--        mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.33</version>
        </dependency>
<!--        连接池-->
        <dependency>
            <groupId>cn.benma666</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.22</version>
        </dependency>
        

配置文件

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=false
    #mysql8需要添加serverTimeZone=GMT%2B8
    username: root
    password: xxxxxxx

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

实体类

@Data
@TableName("t_user")
public class User {
    @TableId(type = IdType.NONE)
    private Long id;
    private String name;
    private Integer age;
    private String mail;
}

  • 表明不同有两种方式

    1. 使用 @TableName(“数据库对应表名”)
    2. 如果只是数据库多了前缀——设置全局前缀(慎用)
        global-config:
       db-config:
       table-prefix: 
      
  • 主键相关

    1. BP默认使用id变量作为主键
    2. 如果变量名和数据库字段名不同意,可以使用@TableId@TableField指定
    3. BP的键默认使用雪花算法,(不指定Id默认自动生成),如果需要使用自增id,在@TableId(type = IdType.AUTO) 或者在配置文件中指定mybatis-plus.global-config.db-config.id-type
    4. 插入对象默认会有主键回显

业务类结构

定义mapper.XXMapper接口

@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
  • 说明
    1. BaseMapper提供了默认的单表实现,不需要自己完成
    2. 如果需要自定义实现可以添加并实现
    3. 可以在mapper类上使用@Mapper 或者在启动类上添加@MapperScan("mapper包路径"),进行mapper接口扫描

基本功能——提供的mapper接口及实现

插入

删除——返回受影响行数

在这里插入图片描述

  • 更具id删除——雪花算法使用Long类型
  • 根据实体类指定id删除
  • 根据map删除——指明条件map
    HashMap<String, Object> condition = new HashMap<>();
        condition.put("name","lisi");
        condition.put("age",14);
        int i = userMapper.deleteByMap(condition);
        System.out.println("return result:"+i);
    //        ==>  Preparing: DELETE FROM t_user WHERE (name = ? AND age = ?)
    //        ==> Parameters: lisi(String), 14(Integer)
    //        <==    Updates: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@36525ab]
    //        return result:1
    
  • id列表批量删除
    List<Long> ids = Arrays.asList(1L, 3L, 4L);
        int i = userMapper.deleteBatchIds(ids);
        System.out.println("return result:"+i);
        //    ==>  Preparing: DELETE FROM t_user WHERE id IN ( ? , ? , ? )
        //    ==> Parameters: 1(Long), 3(Long), 4(Long)
        //    <==    Updates: 3
        //    Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3b362f1]
        //    return result:3
    
  • 根据Wrapper条件删除

修改数据

baseMapper删除方法

  • 更具实体类更新updateById(id必须有:id确定记录,Entity指定需要修改的字段)
    User user = new User();
        user.setId(1846522555456847874L);
        user.setMail("hahahha.@163.com");
        int i = userMapper.updateById(user);
        System.out.println("return result:"+i);
    //        ==>  Preparing: UPDATE t_user SET mail=? WHERE id=?
    //        ==> Parameters: hahahha.@163.com(String), 1846522555456847874(Long)
    //        <==    Updates: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6451a288]
    //        return result:1
    
  • 根据条件构造器选择数据使用实体类对象更新

查询方法

  • 根据id查询
  • 根据id列表批量查
    List<Long> ids = Arrays.asList(1846522555456847874L, 1846525211126554626L);
        List<User> users = userMapper.selectBatchIds(ids);
        users.forEach(System.out::println);
    //        ==>  Preparing: SELECT id,name,age,mail FROM t_user WHERE id IN ( ? , ? )
    //        ==> Parameters: 1846522555456847874(Long), 1846525211126554626(Long)
    //        <==    Columns: id, name, age, mail
    //        <==        Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com
    //        <==        Row: 1846525211126554626, dearfriend1, 13, null
    //        <==      Total: 2
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1850f2da]
    //        User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com)
    //        User(id=1846525211126554626, name=dearfriend1, age=13, mail=null)
    
  • 更具map指定条件查询(只能用=)
            HashMap<String, Object> condition= new HashMap<>();
        condition.put("age",12);
        List<User> users1 = userMapper.selectByMap(condition);
        users1.forEach(System.out::println);
    //        ==>  Preparing: SELECT id,name,age,mail FROM t_user WHERE (age = ?)
    //        ==> Parameters: 12(Integer)
    //        <==    Columns: id, name, age, mail
    //        <==        Row: 8, haha, 12, null
    //        <==        Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com
    //        <==      Total: 2
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3dbb3fb7]
    //        User(id=8, name=haha, age=12, mail=null)
    //        User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com)
    
  • 条件构造器(可为null)

自定义mapper(和mybatis一样)

  1. 添加xml映射文件路径
    mybatis-plus.mapper-locations: 默认为classpath*:/mapper/**/*.xml
  2. 添加自定义mapper接口:mapper.UserMapper.java
    @Repository
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
     Map<String,Object> selectMapById(Long id);
    }
    
    
  3. 实现mapper接口,编写映射文件:resources.mapper.UserMapper.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <!--namespace为接口的全限定符-->
    <mapper namespace="org.dearfriend.mapper.UserMapper">
    
    <!--        声明sql语句-->
    <!--        每个标签为一个接口的实现-->
    <select id="selectMapById" resultType="map">
        select id, name, t_user.age, t_user.mail
        from t_user
        where id = #{id}
    </select>
    </mapper>
    
  4. 调用
    Map<String, Object> user = userMapper.selectMapById(1846525252671111169L);
        System.out.println(user);
    //        ==>  Preparing: select id, name, t_user.age, t_user.mail from t_user where id = ?
    //        ==> Parameters: 1846525252671111169(Long)
    //        <==    Columns: id, name, age, mail
    //        <==        Row: 1846525252671111169, dearfriend3, 14, null
    //        <==      Total: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@a69f9d]
    //        {name=dearfriend3, id=1846525252671111169, age=14}
    

相关功能——提供的Service方法

ibatis封装了IService接口和实现,使用如下前缀区分mapper接口

  • get——查询
  • save——插入
  • update——修改
  • remove——删除
  • list——查询
  • page——分页

注:如果存在自定义方法,推荐创建自己的Service,继承BP提供的基类

  • IService提供了单表操作的服务层接口
  • Service Impl提供了IService的实现

Service层搭建

  1. 创建自定义Service接口,继承IService
  2. 实现自定义Serivce接口Service Impl实现了基本的接口,直接继承过来,包含两个范型Service<M,T>Mapper接口和实体类对象

如此以来,既能使用BP提供的基本服务,也能够自定义服务

相关方法

添加记录
  • 批量添加saveBatch(T t)——多次调用insert方法进行
    ArrayList<User> users = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            User user = new User();
            user.setName("user"+(i+1));
            user.setAge(20+i);
            user.setName("user"+(i+1)+"@163.com");
            users.add(user);
        }
        boolean b = userService.saveBatch(users);
        System.out.println("添加状态:"+(b? "success":"fail"));
    //        ==>  Preparing: INSERT INTO t_user ( id, name, age ) VALUES ( ?, ?, ? )
    //        ==> Parameters: 1846548533952438273(Long), user1@163.com(String), 20(Integer)
    //        ==> Parameters: 1846548534006964225(Long), user2@163.com(String), 21(Integer)
    //        ==> Parameters: 1846548534006964226(Long), user3@163.com(String), 22(Integer) 
    //        ==> Parameters: 1846548534006964227(Long), user4@163.com(String), 23(Integer)
    //        ==> Parameters: 1846548534006964228(Long), user5@163.com(String), 24(Integer)
    //        ==> Parameters: 1846548534011158530(Long), user6@163.com(String), 25(Integer)
    //        ==> Parameters: 1846548534011158531(Long), user7@163.com(String), 26(Integer)
    //        ==> Parameters: 1846548534011158532(Long), user8@163.com(String), 27(Integer)
    //        ==> Parameters: 1846548534011158533(Long), user9@163.com(String), 28(Integer)
    //        ==> Parameters: 1846548534015352834(Long), user10@163.com(String), 29(Integer)
    //        添加状态:success
    
插入或更新(看是否有id)

常用注解

注解作用
@TableName指定绑定实体类对应的mysql表名
@TableId指定绑定实体类中主键字段,type可以指定主键策略
@TableField绑定实体类中字段和mysql中字段
@TableLogic逻辑删除-可以进行数据恢复,加载逻辑删除字段上
@Version乐观锁版本字段-使用版本好的方式实现乐观锁
  • 绑定@TableLogic后,删除默认为逻辑删除,(修改逻辑删除字段),查询的查询的时候也会自动排除已逻辑删除的记录
    boolean b = userService.removeBatchByIds(Arrays.asList(8L));
        System.out.println("删除状态:"+(b?"success":"fail!"));
    
    //        ==>  Preparing: UPDATE t_user SET is_deleted=1 WHERE id=? AND is_deleted=0
    //        ==> Parameters: 8(Long)
    //        删除状态:success
    
           List<User> list = userService.list();
    //        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0
    //        ==> Parameters: 
    //        <==    Columns: id, name, age, mail, is_deleted
    //        <==        Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0
    //        <==        Row: 1846525211126554626, dearfriend1, 13, null, 0
    

条件构造器

类的基本结构

在这里插入图片描述

  • Wrapper:条件构造抽象类,最顶端必类

    • AbstractWrapper:用于查询条件封装,生成sql的where条件
      • QueryWrapper:查询条件封装
      • UpdateWrapper:Update条件封装
      • AbstractLambdaWrapper:使用Lambda语法
        • LambdaQueryWrapper:用于Lambda语法使用的查询Wrapper
        • LambdaUpdateWrapper: Lambda #iT=J%Wrapper
  • 通过条件锁定记录的操作(select、delete、update)——字段都是条件QueryWrapper

  • 条件中有包含更改目标值(update)——UpdateWrapper中可以通过set()设置值

逻辑条件

  • 默认为and
  • 调用.or(),上下条件为||
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("age",28)
                .or()
                .eq("name","dearfriend");
    
        User user = new User();
        user.setMail("123456@123.com");
        boolean update = userService.update(user, userQueryWrapper);
        System.out.println("更新结果:"+(update?"success!":"fail!"));
    //        ==>  Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (age = ? OR name = ?)
    //        ==> Parameters: 123456@123.com(String), 28(Integer), dearfriend(String)
    //        ==    Updates: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@73b0ed03]
    //        更新结果:success!
    
  • 有优先级的逻辑判断——显式调用.and()/.or(),传入的参数为Consumer<Param> consumer,其实还是一个Wrapper
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like("name", "a")
                .and(i -> i.gt("age", 20)
                        .or()
                        .isNull("mail"));
        List<User> list = userService.list(userQueryWrapper);
        list.forEach(System.out::println);
    //
    //        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND (age > ? OR mail IS NULL))
    //        ==> Parameters: %a%(String), 20(Integer)
    //        <==      Total: 0
    

条件查询——QueryWrapper

注:cloumn字段需要使用数据库表的字段名称,而不是实体类的名称

  • 查询指定字段.select(String... cloumns)serivce.listMaps(QueryWrapper wrapper)
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.select("name","age");
        List<Map<String, Object>> maps = userService.listMaps(userQueryWrapper);
        maps.forEach(System.out::println);
        
    //        ==>  Preparing: SELECT name,age FROM t_user WHERE is_deleted=0
    //        ==> Parameters: 
    //        <==    Columns: name, age
    //        <==        Row: dearfriend, 12
    //        <==      Total: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@344f9467]
    //        {name=dearfriend, age=12}
    
  • Like、Between、notNull
//用户名包含a,邮箱不为null,年龄(10,30)
        QueryWrapper<User> condition = new QueryWrapper<>();
        //链式编程,构造条件
        condition.like("name","a")
                .isNotNull("mail")
                .between("age",10,30);
        List<User> list = userService.list(condition);
        list.forEach(System.out::println);
        
//        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name LIKE ? AND mail IS NOT NULL AND age BETWEEN ? AND ?)
//        ==> Parameters: %a%(String), 10(Integer), 30(Integer)
//        <==    Columns: id, name, age, mail, is_deleted
//        <==        Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0
//        <==      Total: 1
//        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6ec3d8e4]
//        User(id=1846522555456847874, name=dearfriend, age=12, mail=hahahha.@163.com, isDeleted=0)
  • 排序查询——调用升降序方法,指定排序字段
//根据age升序,id降序
        QueryWrapper<User> condition = new QueryWrapper<>();
        condition.orderByAsc("age")
                .orderByDesc("id");
        List<User> list = userService.list(condition);
        list.forEach(System.out::println);
        
//        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 ORDER BY age ASC,id DESC
//        ==> Parameters: 
//                <==    Columns: id, name, age, mail, is_deleted
//                <==        Row: 1846522555456847874, dearfriend, 12, hahahha.@163.com, 0
//                <==        Row: 1846525211126554626, dearfriend1, 13, null, 0
//                <==        Row: 1846525252671111169, dearfriend3, 14, null, 0
//                <==        Row: 1846548381057470465, user1@163.com, 20, null, 0
//                <==        Row: 1846548381120385025, user2@163.com, 21, null, 0
//                <==        Row: 1846548381120385026, user3@163.com, 22, null, 0
//                <==        Row: 1846548381120385027, user4@163.com, 23, null, 0
//                <==        Row: 1846548381120385028, user5@163.com, 24, null, 0
//                <==        Row: 1846548381124579330, user6@163.com, 25, null, 0
//                <==        Row: 1846548381124579331, user7@163.com, 26, null, 0
//                <==        Row: 1846548381124579332, user8@163.com, 27, null, 0
//                <==        Row: 1846548381124579333, user9@163.com, 28, null, 0
//                <==        Row: 1846548381124579334, user10@163.com, 29, null, 0
//                <==      Total: 13
  • 组装子查询.insql(cloumn,inval)——cloumn字段名,inval可以使用sql语句写(里面的内容会直接放入sql语句中,包括明确的值集合,是一个拼接)

删除条件——QueryWrapper

QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.isNull("mail");
        boolean remove = userService.remove(userQueryWrapper);
        System.out.println("删除状态:"+(remove? "success!":"fail!"));
        
//        ==>  Preparing: UPDATE t_user SET is_deleted=1 WHERE is_deleted=0 AND (mail IS NULL)
//        ==> Parameters: 
//        <==    Updates: 12
//        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1ed9d173]
//        删除状态:success!

更新操作

  • queryWrapper+Entity
    QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("age",28)
                .or()
                .eq("name","dearfriend");
    
        User user = new User();
        user.setMail("123456@123.com");
        boolean update = userService.update(user, userQueryWrapper);
        System.out.println("更新结果:"+(update?"success!":"fail!"));
    //        ==>  Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (age = ? OR name = ?)
    //        ==> Parameters: 123456@123.com(String), 28(Integer), dearfriend(String)
    //        ==    Updates: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@73b0ed03]
    //        更新结果:success!
    
  • updateWrapper(条件+修改值)/updateWrapper+Entity
    UpdateWrapper<User> userUpdateWrapper = new UpdateWrapper<>();
    //      锁定记录
        userUpdateWrapper.isNull("mail");
        userUpdateWrapper.set("mail","default@123.com");
        boolean update = userService.update(userUpdateWrapper);
        System.out.println("更新结果:"+(update?"success!":"fail"));
        
    //        ==>  Preparing: UPDATE t_user SET mail=? WHERE is_deleted=0 AND (mail IS NULL) 
    //        ==> Parameters: default@123.com(String)
    //        <==    Updates: 0
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1aeff8ca]
    //        更新结果:fail
    

模拟条件组装

  • 方式一:Wrapper使用链式编程,可以通过判断+链式条件添加
  • 方式二:Wrapper中可以通过方法中的condition指定添加的条件(如果满足指定条件bool类型,才会添加字段限制)boolean condition, R column, Object val
    String name="";
        Integer age = 14;
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
    
        userQueryWrapper.eq(!StringUtils.isBlank(name),"name",name)
                .eq(!ObjectUtils.isEmpty(age),"age",age);
    
        List<User> list = userService.list(userQueryWrapper);
        list.forEach(System.out::println);
    
    //        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (age = ?)
    //        ==> Parameters: 14(Integer)
    //                <==    Columns: id, name, age, mail, is_deleted
    //                <==        Row: 1846525252671111169, dearfriend3, 14, null, 0
    //                <==      Total: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@143413cd]
    //        User(id=1846525252671111169, name=dearfriend3, age=14, mail=null, isDeleted=0)
    

其他功能

Lamda表达式——防止mysql名称写错,直接使用实体类字段

  • LamdaQuerryWrapper
    LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getName,"dearfriend");
        List<User> list = userService.list(userLambdaQueryWrapper);
        list.forEach(System.out::println);
    //        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 AND (name = ?)
    //        ==> Parameters: dearfriend(String)
    //                <==    Columns: id, name, age, mail, is_deleted
    //                <==        Row: 1846522555456847874, dearfriend, 12, 123456@123.com, 0
    //                <==      Total: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@1ed9d173]
    //        User(id=1846522555456847874, name=dearfriend, age=12, mail=123456@123.com, isDeleted=0)
    
  • LamdaUpdateWrapper
    LambdaUpdateWrapper<User> userLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        userLambdaUpdateWrapper.set(User::getName,"Lambda")
                .eq(User::getName,"dearfriend");
        boolean update = userService.update(userLambdaUpdateWrapper);
        System.out.println("更新状态:"+(update?"success!":"fail"));
        
    //        ==>  Preparing: UPDATE t_user SET name=? WHERE is_deleted=0 AND (name = ?)
    //        ==> Parameters: Lambda(String), dearfriend(String)
    //        <==    Updates: 1
    //        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@14590fe2]
    //        更新状态:success!
    
  • 注:主要是在原来的cloumn中使用Lamda表达式使用实体类的方法获取字段,而不是mysql中的列名

分页插件

  1. 配置分页插件
@Configuration
public class BPconfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor();
        //设置数据库类型——穿件分页拦截器
        mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor1;
    }
}
  1. 分页业务代码
  • 方式一:传入Page参数,仅作为查询条件page无法存储记录
Page<User> userPage = new Page<>(2,3);
        List<User> list = userService.list(userPage, null);
        System.out.println(list);
        
//        ==>  Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0 
//        ==> Parameters: 
//        <==    Columns: total
//        <==        Row: 6
//        <==      Total: 1
//        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
//        ==> Parameters: 3(Long), 3(Long)
//        <==    Columns: id, name, age, mail, is_deleted
//        <==        Row: 1846525252671111169, dearfriend3, 14, null, 0
//        <==        Row: 1846548381057470465, user1@163.com, 20, null, 0
//        <==        Row: 1846548381120385025, user2@163.com, 21, null, 0
//        <==      Total: 3
  • 方式二:调用page()方法,所有记录存在于page对象中、mapper层也提供了selectPage()方法
Page<User> userPage = new Page<>(2,2);
        userService.page(userPage, null);
//        System.out.println(list);
        System.out.println("总页数:"+userPage.getPages());
        System.out.println("当前页:"+userPage.getCurrent());
        System.out.println("-------------------------------");
        System.out.println("本页记录为:");
        userPage.getRecords().forEach(System.out::println);
        System.out.println("总记录数:"+userPage.getTotal());
        System.out.println("-------------------------------");
        System.out.println("是否有下一页"+userPage.hasNext());
        System.out.println("是否有上一页"+userPage.hasPrevious());
//        ==>  Preparing: SELECT COUNT(*) AS total FROM t_user WHERE is_deleted = 0
//        ==> Parameters:
//        <==    Columns: total
//        <==        Row: 6
//        <==      Total: 1
//        ==>  Preparing: SELECT id,name,age,mail,is_deleted FROM t_user WHERE is_deleted=0 LIMIT ?,?
//        ==> Parameters: 2(Long), 2(Long)
//        <==    Columns: id, name, age, mail, is_deleted
//        <==        Row: 1846525211126554626, dearfriend1, 13, null, 0
//        <==        Row: 1846525252671111169, dearfriend3, 14, null, 0
//        <==      Total: 2
//        Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@70485aa]
//        总页数:3
//        当前页:2
//        -------------------------------
//        本页记录为:
//        User(id=1846525211126554626, name=dearfriend1, age=13, mail=null, isDeleted=0)
//        User(id=1846525252671111169, name=dearfriend3, age=14, mail=null, isDeleted=0)
//        总记录数:6
//        -------------------------------
//        是否有下一页true
//        是否有上一页true
  • 自定义mapper结构的分页实现
    接口定义——传入Page类型参数
@Repository
@Mapper
public interface UserMapper extends BaseMapper<User> {
    /*自定sql语句分页查询*/
    Page<User> selectPageV(@Param("page") Page<User> page, @Param("age") Integer age);
}

接口实现使用别名指定User,需要添加别名配置mybatis-plus.type-aliases-package: 包名

<select id="selectPageV" resultType="User">
        select t_user.id,t_user.age,t_user.name,t_user.mail
        from t_user
        where age > #{age}
    </select>

方法调用

@Test
    public void  testSelfPage(){
        Page<User> userPage = new Page<>(1,3);
        userMapper.selectPageV(userPage,10);
        userPage.getRecords().forEach(System.out::println);
    }

乐观锁和悲观锁

  • 悲观锁:一方操作资源,其他人全部阻塞

  • 乐观锁:此处通过版本号实现,每次修改查询版本号,修改后版本号改变,操作失败;操作成功,更改值,更改版本号+1

  • mybatis-plus实现乐观锁

    • 添加version字段使用@Version注解(还是需要自己实现循环的业务代码判断重试
    • 插件配置类配置乐观锁插件
      @Bean
      public MybatisPlusInterceptor mybatisPlusInterceptor(){
      MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor();
      //设置数据库类型——穿件分页拦截器
      mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      //添加乐观锁插件
      mybatisPlusInterceptor1.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
      return mybatisPlusInterceptor1;
      }
      

通用枚举

  1. 数据库中添加存储枚举数据的字段(就使用普通的类型,枚举类有多个属性选择一个存储)
  2. 创建枚举类,实体类添加枚举类属性
    @Data
    @TableName("t_user")
    public class User {
    @TableId(type = IdType.NONE)
    private Long id;
    private String name;
    private Integer age;
    private String mail;
    //  指定的逻辑删除存储字段
    @TableLogic
    private Integer isDeleted;
    @Version
    private Integer version;
    
    private Sex sex;
    
    @Getter
    public enum Sex{
        MALE(1,"男"),
        FEMALE(2,"女");
        @EnumValue
        private final Integer code;
        private final String sexName;
    
        Sex(int code, String sexName) {
            this.code = code;
            this.sexName = sexName;
        }
    }
    }
    
    注:需要在枚举类中使用@EnumValue在需要保存的到数据库中的枚举类属性上方进行注解(低版本的BP还要在配置文件中指定枚举类位置mybatis-plus.type-aliases-package——当前版本以弃用)

代码生成器

3.5.1以上代码生成器——此处使用的版本3.5.5
3.5.1以下版本代码生成器

  1. 依赖的导入
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-generator</artifactId>
    <version>3.5.5</version>
    </dependency>
    
  2. 根据自己的需要,选择对应的生成模版(),还可以选择生成方式(快速生成、交互式生成)
    文件时时模版
    import com.baomidou.mybatisplus.generator.FastAutoGenerator;
    import com.baomidou.mybatisplus.generator.config.OutputFile;
    import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
    import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
    
    
    import java.sql.Types;
    import java.util.Collections;
    
    //相关依赖
    //        <!--BP代码生成依赖-->
    //        <dependency>
    //            <groupId>com.baomidou</groupId>
    //            <artifactId>mybatis-plus-generator</artifactId>
    //            <version>3.5.5</version>
    //        </dependency>
    //        <!--生成模版依赖-->
    //        <dependency>
    //            <groupId>org.freemarker</groupId>
    //            <artifactId>freemarker</artifactId>
    //            <version>2.3.33</version>
    //        </dependency>
        
    //---------------------------------------
    public class ${ClassName} {
    public static void main(String[] args) {
    
    //        1.配置数据库连接
        FastAutoGenerator.create("${mysqlurl}", "${username}", "${passworld}")
                .globalConfig(builder -> {
                    builder.author("${author}") // 设置作者
                            .enableSwagger() // 开启 swagger 模式
                            //2.指定输出目录
                            .outputDir("$file_out_dir"); // 指定输出目录
                })
                .dataSourceConfig(builder ->
                        builder.typeConvertHandler((globalConfig, typeRegistry, metaInfo) -> {
                            int typeCode = metaInfo.getJdbcType().TYPE_CODE;
                            if (typeCode == Types.SMALLINT) {
                               // 自定义类型转换
                                return DbColumnType.INTEGER;
                            }
                            return typeRegistry.getColumnType(metaInfo);
                            })
                )
                .packageConfig(builder ->
    //                        3.指定父包目录
                        builder.parent("${groupId}") // 设置父包名
    //                                4.指定模块目录
                                .moduleName("${artifactId}") // 设置父包模块名
    //                                5.指定xml映射文件目录
                                .pathInfo(Collections.singletonMap(OutputFile.xml, "${file_out_dir}")) // 设置mapperXml生成路径
                )
    //                策略配置
               .strategyConfig(builder ->
    //                        6.指定需要生成的表
                        builder.addInclude("${table_name}") // 设置需要生成的表名
                                .addTablePrefix("t_", "c_") // 设置过滤表前缀
                )
                .templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板,默认的是Velocity引擎模板
                .execute();
    }
    }
    
    在这里插入图片描述

MybatisX插件

  1. 能够自动跳转mapper接口和映射文件

  2. 能够自动生成代码
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  3. 自动生成CRUD操作(包括xml的sql映射)
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

多数据源官网

  1. 依赖导入

    <!--spring-boot 1.5.x 2.x.x-->
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
    <version>${version}</version>
    </dependency>
    <!--spring-boot3及以上-->
    <dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
    <version>${version}</version>
    </dependency>
    
  2. 配置数据源

    spring:
    datasource:
    dynamic:
      enabled: true #启用动态数据源,默认true
      primary: master #设置默认的数据源或者数据源组,默认值即为master
      strict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源
      grace-destroy: false #是否优雅关闭数据源,默认为false,设置为true时,关闭数据源时如果数据源中还存在活跃连接,至多等待10s后强制关闭
      datasource:
        master:
          url: jdbc:mysql://xx.xx.xx.xx:3306/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置
        slave_1:
          url: jdbc:mysql://xx.xx.xx.xx:3307/dynamic
          username: root
          password: 123456
          driver-class-name: com.mysql.jdbc.Driver
        slave_2:
          url: ENC(xxxxx) # 内置加密,使用请查看详细文档
          username: ENC(xxxxx)
          password: ENC(xxxxx)
          driver-class-name: com.mysql.jdbc.Driver
        #......省略
        #以上会配置一个默认库master,一个组slave下有两个子库slave_1,slave_2
    
  3. 使用@DS指定操作的数据库
    @DS 可以注解在方法上或类上,同时存在就近原则 方法上注解 优先于 类上注解。

    注解结果
    没有@DS默认数据源
    有@DS(“dsName”)dsName可以为组名也可以为具体某个库的名称
适用场景

存粹多库、读写分离、一主多从、混合模式

相关概念

雪花算法

分布式主键生成算法,能够保证不同表的主键不重复,相同表的有序性(有利于索引)

核心思想
  • 长度为64bit——Long类型
  • 结构
    • 第一位:符号位
    • 2-42(41bit): 时间戳(当前时间-开始时间)
    • 43-52(10bit): 机器id(5bit数据中心,5bit机器id)(可以部署在1024个节点)
    • 53-64(12 bit): 毫秒内的流水号(每毫秒可以产生4096个id)
优点

整体上按照时间自增排序,并且整个分布式系统内不会发生id碰撞,且效率高


原文地址:https://blog.csdn.net/Dearfrienda/article/details/142983587

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!