一. 插入
1. insert: 插入
1. 案例
-
方式1
@Test void test01(){ User user = new User(8L, "user08", 23, "user08@qq.com"); userMapper.insert(user); }
-
方式2
@Test void test02(){ User user = new User(); user.setName("user02"); user.setAge(8); user.setEmail("user02@qq.com"); // 自动生成id userMapper.insert(user); }
数据库插入的id默认值为: 全局的唯一id
2. 主键生成策略
1. 雪花算法
-
说明
SnowFlake 算法,是 Twitter 开源的分布式 id 生成算法。其核心思想就是:使用一个 64 bit 的 long 型的数字作为全局唯一 id。在分布式系统中的应用十分广泛,且ID 引入了时间戳,基本上保持自增的
这 64 个 bit 中,其中 1 个 bit 是不用的,然后用其中的 41 bit 作为毫秒数,用 10 bit 作为工作机器 id,12 bit 作为序列号。
-
案例
@Data @AllArgsConstructor @NoArgsConstructor public class User { /** * IdType.AUTO: 数据库ID自增 (数据库字段一定要设置为自增的, 否则会报错) * IdType.NONE: 未设置主键 * IdType.INPUT: 手动输入, 一旦手动输入id后, 就需要自己配置id了 * IdType.ID_WORKER: 默认的全局ID(数字) * IdType.UUID: 全局唯一ID uuid * IdType.ID_WORKER_STR: ID_WORKER的字符串(字符串) */ @TableId(type = IdType.AUTO) private Long id; private String name; private Integer age; private String email; }
二. 修改
1. update: 修改
-
案例
// 通过id更改 @Test public void test03(){ User user = new User(); // 通过条件动态拼接SQL user.setId(8L); user.setName("user1"); user.setEmail("user1@qq.com"); // updateById的参数是一个对象 userMapper.updateById(user); }
2. 自动填充
创建时间, 修改时间, 这些操作一般都是自动化完成的, 我们不希望手动更新.
1. 数据库级别(工作中不允许修改数据库)
-
在表中新增create_time, update_time
-
再次测试插入方法, 我们需要先把实体类同步
private Date createTime; private Date updateTime;
-
测试
@Test void test02(){ User user = new User(); user.setName("user03"); user.setAge(8); user.setEmail("user03@qq.com"); userMapper.insert(user); }
@Test public void test03(){ User user = new User(); // 通过条件动态拼接SQL user.setId(6L); user.setName("user1"); user.setEmail("user1@qq.com"); // updateById的参数是一个对象 userMapper.updateById(user); }
2. 代码级别
-
删除数据库中的设置
-
实体类上的属性增加注解
// 字段添加填充内容 // 插入的时候自动操作 @TableField(fill = FieldFill.INSERT) private Date createTime; // 插入或更新的时候自动操作 @TableField(fill = FieldFill.INSERT_UPDATE) private Date updateTime;
-
编写处理器来处理这个注解
@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); } }
3. 乐观锁
1. 说明
-
乐观锁:
顾名思义十分乐观, 它总是认为不会出现问题, 无论干什么不去上锁! 如果出现了问题, 再次更新值测试
-
悲观锁:
顾名思义十分悲观, 它总是认为总会出现问题, 无论干什么都会上锁! 再去操作!
2. 乐观锁实现方式
-
取出记录时, 获取当前的version
-
更新时, 带上这个version
-
执行更新时, set version = newVersion Where version = oldVersion
-
如果version不对, 就更新失败
乐观锁: 1. 先查询, 获得版本号: version = 1 --A update user set name = "hjf", version = version + 1 where id = 2 and version = 1 --B线程抢先完成, 这个时候version=2, 会导致A修改失败 update user set name = "hjf", version = version + 1 where id = 2 and version = 1
3. 乐观锁插件
-
给数据库添加一个version字段, 初始值为1
-
实体类添加属性
@Version //乐观锁Version注解 private Integer version;
-
注册组件
// 可以将主启动类上面的MapperScan注解, 添加到这里 @MapperScan("com.hjf.mapper") // 扫描mapper文件夹 @EnableTransactionManagement // 自动开启事务的注解 @Configuration // 配置类 public class MyBatisPlusConfig { // 注册乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
-
测试
-
测试乐观锁成功!
@Test public void testOptimisticLocker1(){ // 1. 查询用户信息 User user = userMapper.selectById(6L); // 2. 修改用户信息 user.setName("用户02"); user.setEmail("user01@gmail.com"); // 3. 执行更新操作 userMapper.updateById(user); }
-
测试乐观锁失败!
@Test public void testOptimisticLocker2(){ // 线程1 User user1 = userMapper.selectById(7L); user1.setName("用户001"); user1.setEmail("user001@gmail.com"); // 模拟另一个线程执行了插队操作 User user2 = userMapper.selectById(7L); user2.setName("用户002"); user2.setEmail("user002@gmail.com"); userMapper.updateById(user2); //如果没有乐观锁, 这回覆盖插队线程的值, 有乐观锁, 则执行失败 userMapper.updateById(user1); }
user1修改失败
只有user2修改成功
-
三. 查询
1. insert: 查询
-
通过id查询
// 通过id查询 @Test public void testSelectById(){ User user = userMapper.selectById(7L); System.out.println(user); }
-
id批量查询
// id批量查询 @Test public void testSelectBatchByIds(){ List<User> userList = userMapper.selectBatchIds(Arrays.asList(5, 6, 7)); userList.forEach(System.out::println); }
-
按条件查询map
// 按条件查询: map @Test public void testSelectByMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("name", "用户002"); map.put("age", 8); // SELECT * FROM user WHERE name = ? AND age = ? List<User> userList = userMapper.selectByMap(map); userList.forEach(System.out::println); }
2. 分页查询
1. 方式
- 原始的limit进行分页
- pageHelper第三方插件
- Mybatis-plus也内置了分页插件
2. 分页插件
-
配置拦截器组件
// 注册分页插件 @Bean public PaginationInterceptor paginationInterceptor() { return new PaginationInterceptor(); }
-
使用
@Test public void testPage(){ /** * 参数1: 当前页 * 参数2: 页面大小 */ Page<User> page = new Page<>(2, 3); IPage<User> userIPage = userMapper.selectPage(page, null); System.out.println("------------------------"); // 获取当前页信息 page.getRecords().forEach(System.out::println); userIPage.getRecords().forEach(System.out::println); System.out.println("------------------------"); // 获取数据总数 System.out.println(page.getTotal()); System.out.println(userIPage.getTotal()); }
四. 删除
1. delete: 删除
-
通过id
// 根据id删除 @Test public void testDeleteById(){ userMapper.deleteById(7L); }
-
批量删除
// 批量参数 @Test public void testDeleteBatchIds(){ userMapper.deleteBatchIds(Arrays.asList(3,4)); }
-
条件删除
@Test public void testDeleteByMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("name", "用户002"); userMapper.deleteByMap(map); }
2. 逻辑删除
物理删除: 从数据库中直接删除
逻辑删除, 在数据库中没有被删除, 而是通过一个变量来让它失效! deleted = 0 => deleted = 1
-
在数据表中增加一个deleted字段
-
实体类中增加属性
@TableLogic // 逻辑删除注解 private Integer deleted;
-
配置逻辑删除组件
// 逻辑删除组件 @Bean public ISqlInjector iSqlInjector(){ return new LogicSqlInjector(); }
-
配置文件
# 配置逻辑删除 # 删除后的值 mybatis-plus.global-config.db-config.logic-delete-value=1 # 没有删除时的值 mybatis-plus.global-config.db-config.logic-not-delete-value=0
-
测试
@Test public void testDeleteById(){ userMapper.deleteById(5L); }
-
通过id 和 deleted = 1都不能查询到被逻辑删除后的数据
@Test public void testSelectById(){ User user = userMapper.selectById(5L); System.out.println(user); }
@Test public void testSelectByMap(){ HashMap<String, Object> map = new HashMap<>(); map.put("deleted", 1); List<User> userList = userMapper.selectByMap(map); userList.forEach(System.out::println); }
说明:
- 本文参考了狂神的Mybatis-Plus的课程
- 课程链接