Mybatis-plus

embedded/2024/10/20 13:53:03/

Springboot3+Mybatis3.5

    • 基本框架
      • 环境
      • 依赖导入
      • 配置文件
      • 实体类
      • 业务类结构
    • 基本功能——提供的mapper接口及实现
      • 插入
      • 删除——返回受影响行数
      • 修改数据
      • 查询方法
      • 自定义mapper(和mybatis一样)
    • 相关功能——提供的Service方法
      • Service层搭建
      • 相关方法
        • 添加记录
        • 插入或更新(看是否有id)
    • 常用注解
    • 条件构造器
      • 类的基本结构
      • 逻辑条件
      • 条件查询——QueryWrapper
      • 删除条件——QueryWrapper
      • 更新操作
      • 模拟条件组装
    • 其他功能
      • Lamda表达式——防止mysql名称写错,直接使用实体类字段
      • 分页插件
      • 乐观锁和悲观锁
      • 通用枚举
      • 代码生成器
      • MybatisX插件
      • 多数据源[官网](https://github.com/baomidou/dynamic-datasource)
        • 适用场景
    • 相关概念
      • 雪花算法
        • 核心思想
        • 优点

基本框架

环境

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.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/mybatisplus?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=false#mysql8需要添加serverTimeZone=GMT%2B8username: rootpassword: 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)

mybatis_216">自定义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 mapperPUBLIC "-//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.mailfrom t_userwhere 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)
    //        删除状态:successList<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 {@Beanpublic 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.mailfrom t_userwhere age > #{age}</select>

方法调用

	@Testpublic 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;//  指定的逻辑删除存储字段@TableLogicprivate Integer isDeleted;@Versionprivate Integer version;private Sex sex;@Getterpublic enum Sex{MALE(1,"男"),FEMALE(2,"女");@EnumValueprivate 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 #启用动态数据源,默认trueprimary: master #设置默认的数据源或者数据源组,默认值即为masterstrict: false #严格匹配数据源,默认false. true未匹配到指定数据源时抛异常,false使用默认数据源grace-destroy: false #是否优雅关闭数据源,默认为false,设置为true时,关闭数据源时如果数据源中还存在活跃连接,至多等待10s后强制关闭datasource:master:url: jdbc:mysql://xx.xx.xx.xx:3306/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driver # 3.2.0开始支持SPI可省略此配置slave_1:url: jdbc:mysql://xx.xx.xx.xx:3307/dynamicusername: rootpassword: 123456driver-class-name: com.mysql.jdbc.Driverslave_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碰撞,且效率高


http://www.ppmy.cn/embedded/129008.html

相关文章

SpringCloud第三章:客户端负载均衡与服务调用

正常本章节应该讲解Netflix Ribbon&#xff0c;由于从Netflix Eureka Client 3.0版本开始内置Ribbon实现机制&#xff0c;不需要单独依赖Ribbon&#xff0c;如果引入Ribbon会报错 java.lang.IllegalStateException: No instances available for XXXXXX&#xff0c;并且想要修改…

1/2∥w∥^2 :这是w 的二次项,偏导数为 w

此公式出现在线性可分支持向量机基于拉格朗日函数L(w,b,α)对w求导的公式中。为什么 1 2 ∥ w ∥ 2 \frac{1}{2} \|\mathbf{w}\|^2 21​∥w∥2 对 w \mathbf{w} w 的偏导数是 w \mathbf{w} w。这个问题涉及到向量的微分运算。 1. 复习&#xff1a;向量的范数 我们首先来看…

DBdoctor推出无Agent轻量级纳管解决方案

目录 背景 DBdoctor推出无Agent轻量级纳管解决方案 方案优势&#xff1a; 实例纳管方式&#xff1a; 无Agent纳管可体验哪些功能&#xff1f; 1.全量SQL审核功能 2.实例巡检功能 3.性能洞察功能 4.基础监控功能 总结 背景 在数字化时代&#xff0c;数据库作为信息系…

pdf文件怎样一张纸打印四页

在日常工作和学习中&#xff0c;我们经常会遇到需要将PDF文件中的多页内容合并打印到一张纸上的情况&#xff0c;比如将四页内容打印到一张A4纸上&#xff0c;以节省纸张和成本。同时&#xff0c;在打开pdf文件的方式&#xff0c;一般都是通过电脑浏览器打印&#xff0c;因此对…

学习鸿蒙Next 之路 http

关于学习鸿蒙开发之http的请求 首先还是老样子先上代码&#xff0c;然后我再说出我的看法 先创建一个请求的函数 function RequestHttp&#xff08;url&#xff1a;string&#xff0c;data&#xff1f;:Object|string&#xff09;{ } 先展示get请求&#xff0c;之前在unity的开…

iOS 18.1的开发者预览版Beta 7版本测评,是否值得升级

10月14日苹果悄咪咪地放出了iOS 18.1的开发者预览版Beta 7&#xff0c;版本号是22B5075a。这啥意思呢&#xff1f;意味着下个星期&#xff0c;我们就能迎来iOS 18.7的准正式版啦&#xff01;苹果官方说得好好的&#xff0c;iOS 18.1正式版系统会在10月29日和大家见面。咱们就坐…

字符串及正则表达式

目录 字符串 字符串常用方法&#xff1a; 格格式化字符串的三种方式&#xff1a; 格式化字符串的详细格式&#xff1a; 字符串的编码&#xff1a; 字符串的解码&#xff1a; 数据的验证&#xff1a; 字符串拼接的几种方式&#xff1a; 字符串去重&#xff1a; 正则表达…

成语积累学习

识文断字&#xff1a;有一点文化知识 雨后春笋&#xff1a;春雨过后快速生长的竹笋&#xff1b;比喻大量涌现的新生事物 味同嚼蜡&#xff1a;如同咀嚼白蜡一样&#xff0c;毫无味道。形容文章或言辞枯燥乏味。 差强人意&#xff1a;大体上让人满意 八面玲珑&#xff1a;处…