栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mybatis

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mybatis

文章目录
  • 1. Mapper CRUD 接口
    • 1.1 Insert -- 添加User -- 默认 ID_WORKER 全局唯一id
    • 扩展 :主键(id)生成策略 -- 插入时自动生成id
      • 1) ID_WORKER 全局唯一id -- 雪花算法
      • 2) 设置主键生成策略
    • 1.2 Update -- 更新id为 3 的User数据
    • 扩展 :自动填充 -- 插入、更新时自动填充数据
      • 1) 实体类字段属性上需要增加注解
      • 2) 编写处理器来处理这个注解
    • 插件:乐观锁 -- 当要更新一条记录的时候,希望这条记录没有被别人更新
      • 1) 在配置类注册组件
      • 2)实体类加对应的字段添加注解
    • 1.3 Select
    • 插件:分页 -- 对查询数据进行分页处理
      • 1) 在配置类注册组件
      • 2) 测试
      • 3) 自定义的 mapper 使用分页
    • 1.4 Delete
    • 扩展:逻辑删除
      • 1) 配置类注册组件
      • 2) 配置文件设置逻辑未删除值和已删除值
      • 3)实体类字段添加注解
    • 插件:性能分析插件
      • 1) 导入插件

1. Mapper CRUD 接口
  • 通用 CRUD 封装baseMapper (opens new window)接口,为 Mybatis-Plus 启动时自动解析实体表关系映射转换为 Mybatis 内部对象注入容器
  • 泛型 T 为任意实体对象
  • Wrapper updateWrapper 实体对象封装操作类(可以为 null,里面的 entity 用于生成 where 语句)
  • 参数 Serializable 为任意类型主键 Mybatis-Plus 不推荐使用复合主键约定每一张表都有自己的唯一 id 主键
  • 对象 Wrapper 为 条件构造器
1.1 Insert – 添加User – 默认 ID_WORKER 全局唯一id

语法:

// 插入一条记录
int insert(T entity); 

insert插入操作会自动生成id,返回受影响的行数,id会自动回填值User对象

数据库插入的id的默认值为:全局的唯一id

// 测试插入
@Test
public void testInsert(){
  User user = new User();
  user.setName("mybatis_plus");
  user.setAge(3);
  user.setEmail("12345678@qq.com");
  int result = userMapper.insert(user); // 帮我们自动生成id
  System.out.println(result); // 受影响的行数
  System.out.println(user); // 发现,id会自动回填
}
扩展 :主键(id)生成策略 – 插入时自动生成id
字段描述
AUTO数据库ID自增
NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
INPUTinsert前自行set主键值
ASSIGN_ID分配ID(主键类型为Number(Long和Integer)或String)(since 3.3.0),使用接口- IdentifierGenerator的方法nextId(默认实现类为DefaultIdentifierGenerator雪花算法)
ASSIGN_UUID分配UUID,主键类型为String(since 3.3.0),使用接口IdentifierGenerator的方法- nextUUID(默认default方法)
ID_WORKER分布式全局唯一ID 长整型类型(please use ASSIGN_ID)
UUID32位UUID字符串(please use ASSIGN_UUID)
ID_WORKER_STR分布式全局唯一ID 字符串类型(please use ASSIGN_ID)
1) ID_WORKER 全局唯一id – 雪花算法

分布式系统唯一id生成:https://www.cnblogs.com/haoxinyue/p/5208136.html

雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为
毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味
着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯
一!

2) 设置主键生成策略

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

public class User {
    @TableId(type = IdType.UUID)
    private Long id;
    private String name;
    private Integer age;
    private String email;
}
1.2 Update – 更新id为 3 的User数据

语法:

// 根据 whereWrapper 条件,更新记录
int update(@Param(Constants.ENTITY) T updateEntity, @Param(Constants.WRAPPER) Wrapper whereWrapper);
// 根据 ID 修改
int updateById(@Param(Constants.ENTITY) T entity);

updateById 但是参数是一个对象!Update 通过条件自动拼接动态sql

// 测试更新
@Test
public void testUpdate(){
  User user = new User();
  // 通过条件自动拼接动态sql
  user.setId(3L);//long类型
  user.setName("mybayis_plus");
  user.setAge(18);
  // 注意:updateById 但是参数是一个对象!
  int i = userMapper.updateById(user);
  System.out.println(i);
}
扩展 :自动填充 – 插入、更新时自动填充数据

自动填充创建时间、修改时间!这些个操作一遍都是自动化完成的,我们不希望手动更新!

阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需
要自动化!

1) 实体类字段属性上需要增加注解
  • DEFAULT 默认不处理
  • INSERT 插入时填充字段
  • UPDATE 更新时填充字段
  • INSERT_UPDATE 插入和更新时填充字段
// 字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;

@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
2) 编写处理器来处理这个注解
@Slf4j
@Component // 一定不要忘记把处理器加到IOC容器中!
public class MymetaObjectHandler implements metaObjectHandler {

// 插入时的填充策略
@Override
public void insertFill(metaObject metaObject) {
log.info("start insert fill.....");
// setFieldValByName(String fieldName, Object fieldVal, metaObject
metaObject
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}

// 更新时的填充策略
@Override
public void updateFill(metaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
插件:乐观锁 – 当要更新一条记录的时候,希望这条记录没有被别人更新

乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,
再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:

  • 取出记录时,获取当前version(版本)
  • 更新时,带上这个version
  • 执行更新时, set version = newVersion where version = oldVersion
    newVersion = oldVersion + 1 自动装配
  • 如果version不对,就更新失败

1.支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
2.整数类型下 newVersion = oldVersion + 1
3.newVersion 会回写到 entity 中
4.仅支持 updateById(id) 与 update(entity, wrapper) 方法
5.在 update(entity, wrapper) 方法下, wrapper 不能复用!!!

1) 在配置类注册组件
// 扫描我们的 mapper 文件夹
@MapperScan("com.yanyu.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
2)实体类加对应的字段添加注解
@Version //乐观锁Version注解
private Integer version;
1.3 Select

语法:

// 根据 ID 查询
T selectById(Serializable id);
// 根据 entity 条件,查询一条记录
T selectOne(@Param(Constants.WRAPPER) Wrapper queryWrapper);

// 查询(根据ID 批量查询)
List selectBatchIds(@Param(Constants.COLLECTION) Collection idList);
// 根据 entity 条件,查询全部记录
List selectList(@Param(Constants.WRAPPER) Wrapper queryWrapper);
// 查询(根据 columnMap 条件)
List selectByMap(@Param(Constants.COLUMN_MAP) Map columnMap);
// 根据 Wrapper 条件,查询全部记录
List> selectMaps(@Param(Constants.WRAPPER) Wrapper queryWrapper);
// 根据 Wrapper 条件,查询全部记录。注意: 只返回第一个字段的值
List selectObjs(@Param(Constants.WRAPPER) Wrapper queryWrapper);

// 根据 entity 条件,查询全部记录(并翻页)
IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage> selectMapsPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);
 

查询测试:

// 测试查询
@Test
public void testSelectById(){
User user = userMapper.selectById(1L);
System.out.println(user);
}

// 测试批量查询!
@Test
public void testSelectByBatchId(){
List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}

// 按条件查询之一使用map操作
@Test
public void testSelectByBatchIds(){
HashMap map = new HashMap<>();
// 自定义查询
map.put("name","mybatis_plus");
map.put("age",3);
List users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
插件:分页 – 对查询数据进行分页处理 1) 在配置类注册组件
@Configuration
@MapperScan("scan.yanyu.mapper")
public class MybatisPlusConfig {

@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
2) 测试

语法:

// 根据 entity 条件,查询全部记录(并翻页)
IPage selectPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
// 根据 Wrapper 条件,查询全部记录(并翻页)
IPage> selectMapsPage(IPage page, @Param(Constants.WRAPPER) Wrapper queryWrapper);
// 根据 Wrapper 条件,查询总记录数
Integer selectCount(@Param(Constants.WRAPPER) Wrapper queryWrapper);

测试:

  • 入参的 IPage 不能为null,因为 返回的IPage == 入参的IPage
  • IPage.setRecords 返回的 List;
// 测试分页查询
@Test
public void testPage(){
// 参数一:当前页
// 参数二:页面大小
// 使用了分页插件之后,所有的分页操作也变得简单的!
 Page page = new Page<>(2,5);
 userMapper.selectPage(page,null);
 page.getRecords().forEach(System.out::println);
 System.out.println(page.getTotal());
}
3) 自定义的 mapper 使用分页

如果返回类型是 IPage 则入参的 IPage 不能为null,因为 返回的IPage == 入参的IPage
如果返回类型是 List 则入参的 IPage 可以为 null(为 null 则不分页),但需要你手动 入参的
IPage.setRecords(返回的 List);

IPage selectPageVo(IPage page, Integer state);
// or (class MyPage extends Ipage{ private Integer state; })
MyPage selectPageVo(MyPage page);
// or
List selectPageVo(IPage page, Integer state);
---------------------------------------------------------