插入操作
插入主键回填
1
2
3
4
5
6
7
8
9
|
@Test
void contextLoads() {
User user = new User();
user.setName("张三");
user.setAge(13);
user.setEmail("zhangsan@gmail.com");
userMapper.insert(user);
System.out.println(user);
}
|
控制台输出:
1
|
User(id=1323944814852505602, name=张三, age=13, email=zhangsan@gmail.com)
|
我们发现插入之后id会自动回填
主键生成策略
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
public @interface TableId {
/**
* 字段名(该值可无)
*/
String value() default "";
/**
* 主键类型
* {@link IdType}
*/
IdType type() default IdType.NONE;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
@Getter
public enum IdType {
/**
* 数据库ID自增
*/
AUTO(0), // 如果设置主键自增,数据库主键必须先得设置成自增
/**
* 该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)
*/
NONE(1),
/**
* 用户输入ID
* <p>该类型可以通过自己注册自动填充插件进行填充</p>
*/
INPUT(2),
/* 以下3种类型、只有当插入对象ID 为空,才自动填充。 */
/**
* 分配ID (主键类型为number或string),
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(雪花算法)
*
* @since 3.3.0
*/
ASSIGN_ID(3),
/**
* 分配UUID (主键类型为 string)
* 默认实现类 {@link com.baomidou.mybatisplus.core.incrementer.DefaultIdentifierGenerator}(UUID.replace("-",""))
*/
ASSIGN_UUID(4),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_ID}
*/
@Deprecated
ID_WORKER_STR(3),
/**
* @deprecated 3.3.0 please use {@link #ASSIGN_UUID}
*/
@Deprecated
UUID(4);
private final int key;
IdType(int key) {
this.key = key;
}
}
|
雪花算法
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为 毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味 着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯 一!
更新操作
1
2
3
4
5
6
7
8
9
10
11
12
|
/**
* 更新
*/
@Test
public void testUpdate() {
User user = new User();
user.setId(1L);
user.setName("徐达");
user.setEmail("xuda@gmail.com");
userMapper.updateById(user);
System.out.println(user);
}
|
自动填充
创建时间、修改时间!这些个操作一般都是自动化完成的,我们不希望手动更新!
阿里巴巴开发手册:所有的数据库表:gmt_create、gmt_modified几乎所有的表都要配置上!而且需要自动化!
数据库级别
1
2
3
4
5
|
CREATE TABLE `mytest` (
`text` varchar(255) DEFAULT '' COMMENT '内容',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
代码级别
1
2
3
|
ALTER TABLE `eden`.`user`
ADD COLUMN `create_time` datetime NULL COMMENT '创建时间' AFTER `email`,
ADD COLUMN `update_time` datetime NULL COMMENT '更新时间' AFTER `create_time`;
|
实体类字段属性上需要增加注解
1
2
3
4
5
|
// 字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
|
往容器中添加一个填充时间处理器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.eh.mp.config;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Date;
@Configuration
public class MPConfig {
@Bean
public MetaObjectHandler metaObjectHandler() {
return new MetaObjectHandler() {
// 插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
// 更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
};
}
}
|
乐观锁
乐观锁机制:
- 取出记录时,获取当前 version
- 更新时,带上这个version ,执行更新时, set version = newVersion where version = oldVersion 如果version不对,就更新失败
使用乐观锁插件
1
2
|
ALTER TABLE `eden`.`user`
ADD COLUMN `version` int(11) not NULL DEFAULT 1 COMMENT '版本号' AFTER `update_time`;
|
给实体类增加对应字段
1
2
|
@Version //乐观锁Version注解
private Integer version;
|
注册插件
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@EnableTransactionManagement // 如果更新失败就回滚
@MapperScan("com.eh.mp.dao")
@Configuration
public class MPConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
|
查询操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
/**
* 测试查询
*/
@Test
public void testSelect() {
userMapper.selectList(null).stream().forEach(System.out::println);
}
/**
* 测试批量查询
*/
@Test
public void testSelectByBatchIds() {
List<User> users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3));
users.forEach(System.out::println);
}
// 按条件查询之一使用map操作
@Test
public void testSelectByMap() {
HashMap<String, Object> map = new HashMap<>(); // 自定义要查询
map.put("name", "张三");
List<User> users = userMapper.selectByMap(map);
users.forEach(System.out::println);
}
|
分页查询
实现分页查询常见的方式有以下几种:
- 原始的 limit 进行分页
- pageHelper 第三方插件
- MP 其实也内置了分页插件
使用方式还是一样,往容器中注册分页插件
1
2
3
4
5
|
// 分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
|
直接使用Page对象即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
// 测试分页查询
@Test
public void testPage() {
// 参数一:当前页
// 参数二:页面大小
// 使用了分页插件之后,所有的分页操作也变得简单
Page<User> page = new Page<>(2, 2);
userMapper.selectPage(page, null);
page.getRecords().forEach(System.out::println);
System.out.println(page.getTotal());
}
|
删除操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// 测试删除
@Test
public void testDeleteById() {
userMapper.deleteById(1240620674645544965L);
}
// 通过id批量删除
@Test
public void testDeleteBatchId() {
userMapper.deleteBatchIds(Arrays.asList(1240620674645544961L, 1240620674645544962L));
}
// 通过map删除
@Test
public void testDeleteMap() {
HashMap<String, Object> map = new HashMap<>();
map.put("name", "狂神说Java");
userMapper.deleteByMap(map);
}
|
逻辑删除
往实体类中增加属性
1
2
|
@TableLogic //逻辑删除
private Integer deleted;
|
注册逻辑删除组件
1
2
|
// 逻辑删除组件!
@Bean public ISqlInjector sqlInjector() { return new LogicSqlInjector(); }
|
配置逻辑删除值
1
2
3
|
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
|