Mybatis-plus

Springboot3+Mybatis3.5

基本框架

环境

springboot3

mysql8+

JDK17

依赖导入

xml 复制代码
<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.0</version>
    </parent>
xml 复制代码
		<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>
        

配置文件

yaml 复制代码
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

实体类

java 复制代码
@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. 如果只是数据库多了前缀------设置全局前缀(慎用)

      yaml 复制代码
        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接口

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

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

插入

删除------返回受影响行数

  • 更具id删除------雪花算法使用Long类型

  • 根据实体类指定id删除

  • 根据map删除------指明条件map

    java 复制代码
    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列表批量删除

    java 复制代码
    	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条件删除

修改数据

  • 更具实体类更新updateById(id必须有:id确定记录,Entity指定需要修改的字段)

    java 复制代码
    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列表批量查

    java 复制代码
    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指定条件查询(只能用=)

    java 复制代码
            	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

    java 复制代码
    @Repository
    @Mapper
    public interface UserMapper extends BaseMapper<User> {
     	Map<String,Object> selectMapById(Long id);
    }
  3. 实现mapper接口,编写映射文件:resources.mapper.UserMapper.xml

    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. 调用

    java 复制代码
    	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方法进行

    java 复制代码
    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后,删除默认为逻辑删除,(修改逻辑删除字段),查询的查询的时候也会自动排除已逻辑删除的记录

    java 复制代码
    		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(),上下条件为||

    java 复制代码
    	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

    java 复制代码
    	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)

    java 复制代码
    	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

java 复制代码
//用户名包含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)
  • 排序查询------调用升降序方法,指定排序字段
java 复制代码
//根据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

java 复制代码
		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

    java 复制代码
    	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

    java 复制代码
    	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

    java 复制代码
    	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

    java 复制代码
    	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

    java 复制代码
    	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. 配置分页插件
java 复制代码
@Configuration
public class BPconfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor();
        //设置数据库类型------穿件分页拦截器
        mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        return mybatisPlusInterceptor1;
    }
}
  1. 分页业务代码
  • 方式一:传入Page参数,仅作为查询条件page无法存储记录
java 复制代码
		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()方法
java 复制代码
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类型参数
java 复制代码
@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: 包名

java 复制代码
<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>

方法调用

java 复制代码
	@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注解(还是需要自己实现循环的业务代码判断重试)

    • 插件配置类配置乐观锁插件

      java 复制代码
      @Bean
      public MybatisPlusInterceptor mybatisPlusInterceptor(){
      MybatisPlusInterceptor mybatisPlusInterceptor1 = new MybatisPlusInterceptor();
      //设置数据库类型------穿件分页拦截器
      mybatisPlusInterceptor1.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
      //添加乐观锁插件
      mybatisPlusInterceptor1.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
      return mybatisPlusInterceptor1;
      }

通用枚举

  1. 数据库中添加存储枚举数据的字段(就使用普通的类型,枚举类有多个属性选择一个存储)

  2. 创建枚举类,实体类添加枚举类属性

    java 复制代码
    	@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. 依赖的导入

    xml 复制代码
    <dependency>
    	<groupId>com.baomidou</groupId>
    	<artifactId>mybatis-plus-generator</artifactId>
    	<version>3.5.5</version>
    </dependency>
  2. 根据自己的需要,选择对应的生成模版(),还可以选择生成方式(快速生成、交互式生成)
    文件时时模版

    java 复制代码
    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. 依赖导入

    xml 复制代码
    <!--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. 配置数据源

    yaml 复制代码
    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碰撞,且效率高

相关推荐
秋恬意2 小时前
MyBatis动态 SQL 的执行原理
mybatis
青年有志4 小时前
深入浅出 MyBatis | CRUD 操作、配置解析
数据库·tomcat·mybatis
00Allen004 小时前
mybatis/mybatisplus
java·spring·mybatis
Echo flower5 小时前
mybatis-plus自动填充时间的配置类实现
java·数据库·mybatis
编码浪子6 小时前
Springboot3国际化
java·spring·mybatis
Yan.love6 小时前
【MyBatis 核心工作机制】注解式开发与动态代理原理
java·mybatis
油丶酸萝卜别吃17 小时前
MyBatis中XML文件的模板
xml·数据库·mybatis
菠萝咕噜肉i18 小时前
MyBatis是什么?为什么有全自动ORM框架还是MyBatis比较受欢迎?
java·mybatis·框架·半自动
向阳121818 小时前
mybatis 缓存
java·缓存·mybatis
一只淡水鱼6619 小时前
【mybatis】详解 # 和 $ 的区别,两者分别适用于哪种场景,使用 $ 不当会造成什么影响
sql·spring·mybatis·sql注入