搭配官网食用更加。
(见官网)
(见官网)
新建数据库并插入数据
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
——————————————————————————————————————————————————————————————
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, '[email protected]'),
(2, 'Jack', 20, '[email protected]'),
(3, 'Tom', 28, '[email protected]'),
(4, 'Sandy', 21, '[email protected]'),
(5, 'Billie', 24, '[email protected]');
新建SpringBoot工程并导入依赖
新建Spring Boot工程,略…
导入依赖
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.4.3version>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
连接数据库(配置文件)
properties.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useUnicode=true
username: root
password: 1234
java类的编写
创建实体类User.java
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
private String email;
private Date createTime;
private Date updateTime;
}
创建Mapper类,UserMapper.java
@Mapper // 此处可以不标注Mapper,二在启动类上使用@ScanMapper来进行扫描
public interface UserMapper extends BaseMapper<User> {}
测试类中测试
@SpringBootTest
class MybatisPlusApplicationTests {
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
userMapper.selectList(null).forEach(System.out::println);
}
}
控制台输出:
User(id=1, name=Jone, age=18, email=[email protected])
User(id=2, name=Jack, age=20, email=[email protected])
User(id=3, name=Tom, age=28, email=[email protected])
User(id=4, name=Sandy, age=21, email=[email protected])
User(id=5, name=Billie, age=24, email=[email protected])
自此已经完成了最简单的MP的使用,但是在并无法得知sql是怎样的。
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
控制台输出增加:
==> Preparing: SELECT id,name,age,email,create_time,update_time FROM user
==> Parameters:
<== Columns: id, name, age, email, create_time, update_time
<== Row: 1, Jone, 18, [email protected], null, null
<== Row: 2, Jack, 20, [email protected], null, null
<== Row: 3, Tom, 28, [email protected], null, null
<== Row: 4, Sandy, 21, [email protected], null, null
<== Row: 5, Billie, 24, [email protected], null, null
<== Total: 5
这样就可以知道查询的过程是什么样的。
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
userMapper.insert(new User().setAge(3).setEmail("[email protected]").setName("ljq"));//此处链式操作需要在实体类上增加注解@Accessors(chain = true)
userMapper.selectList(null).forEach(System.out::println);
}
上述插入操作,不需要设置主键id的值,在插入时会生成唯一id值,然后插入到数据库中。日志:
==> Preparing: INSERT INTO user ( id, name, age, email ) VALUES ( ?, ?, ?, ? )
==> Parameters: 1432591579369041922(Long), ljq(String), 3(Integer), 504863638@qq.com(String)
<== Updates: 1
在实体类的主键字段上标注
@TableId(type = IdType.AUTO)
数据库的主键设置为自增
alter table user modify id bigint auto_increment comment '主键ID';
在实体类的主键字段上标注即可。
@TableId(type = IdType.AUTO)
雪花算法:
snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。其核心思想是:使用41bit作为毫秒数,10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最后还有一个符号位,永远是0。可以保证几乎全球唯一!
IdType
值 | 描述 |
---|---|
AUTO | 数据库ID自增 |
NONE | 无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT) |
INPUT | insert前自行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方法) |
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
//通过id单个删除,id为Long时需要在后面加上L
userMapper.deleteById(1432591579369041922L);
//通过id批量删除
userMapper.deleteBatchIds(Arrays.asList(1432594905707966465L,1432598944994582529L));
//通过map删除,key为表中字段名称,value为字段名称对应的将要删除的数据,删除所有符合条件的数据。
HashMap<String , Object> map = new HashMap<>();
map.put("name", "ljq");
userMapper.deleteByMap(map);
//通过Wrapper删除,具体使用可以查看下面wrapper的使用
userMapper.delete(wapper);
}
删除分为物理删除与逻辑删除
在数据表中添加字段deleted
alter table user
add deleted int default 1 not null comment '逻辑删除标识:
已删除:0
未删除:1';
配置文件
mybatis-plus:
global-config:
db-config:
logic-delete-value: 0 # 逻辑删除所应该有的表示值
logic-not-delete-value: 1 # 逻辑未删除所应该有的表示值
# logic-delete-field: deleted # 如果设置了字段,不需要再在实体类上添加注解
实体类中添加相应的属性,并在属性上添加注解@TableLogic
@TableLogic
private Integer deleted;
执行删除操作
后,实际上是执行了更新操作
。
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
//通过对应的id进行更新
userMapper.updateById(new User().setId(1432598947737657346L).setName("ljq").setEmail("[email protected]"));
}
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
//根据id查数据
userMapper.selectById(1L);
//根据Id批量查询数据
userMapper.selectBatchIds(Arrays.asList(1L, 2L));
//根据条件批量查询
HashMap<String, Object> map = new HashMap<>();
map.put("age", 28);
List<User> userList = userMapper.selectByMap(map);
//根据wrapper条件个性化查询,wrapper处解释
}
用来写一些复杂的SQL语句,官方页面里面有非常多的条件,直接去官网查看每个所代表的含义。
使用示例
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.isNotNull("name")
.ge("age", 21);
userMapper.selectList(wrapper);
}
分页方法:
配置MP配置类,将插件注册到容器中。MybatisPlusConfig.java
@Component
public class MyBatisPlusConfig {
@Bean
public MybatisPlusInterceptor paginationInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
直接使用Page对象
@Autowired
UserMapper userMapper;
@Test
void contextLoads() {
Page<User> page = new Page<>(/*当前页*/2, /*页面大小*/2);
userMapper.selectPage(page, null);//查询的值放入Page对象中
page.getRecords().forEach(System.out::println);//通过Page对象来操作
}
这个功能就是为了节约人力,根据一定条件来填充相应的值。
比如自动填充创建时间、修改时间等。
mysql5.7以上支持创建时间函数(默认值)已经更新时添加、更新。但是更改数据库不为一个较好的处理方式。
数据库中新增字段create_time、update_time
将实体类中也添加这两个属性,保持与数据库的同步。
private Date createTime;
private Date updateTime;
添加两个字段
实体类同步属性,并在属性字段上添加注解
@TableField(fill = FieldFill.INSERT)//插入时自动填充
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)//更新或者插入时填充
private Date updateTime;
自定义MetaObjectHandler的实现类
@Component
@Slf4j
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
log.info("insert...");
this.fillStrategy(metaObject, "createTime", new Date());
this.fillStrategy(metaObject, "updateTime", new Date());
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("update...");
this.fillStrategy(metaObject, "updateTime", LocalDateTime.now());
}
}
自此插入时间时即可发现,已经可以自动填充两个时间。
当要更新一条记录的时候,希望这条记录没有被别人更新
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
MP配置文件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
@Version
private Integer version;
MybatisPlusInterceptor(since 3.4.0)
核心插件,MP使用插件只需要将需要使用的功能添加到该插件对象中。
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(/*此处添加功能*/);
return interceptor;
}
注意:
使用多个功能需要注意顺序关系,建议使用如下顺序
- 多租户,动态表名
- 分页,乐观锁
- sql性能规范,防止全表更新与删除
总结: 对sql进行单次改造的优先放入,不对sql进行改造的最后放入
MyBatis-Plus 从 3.0.3
之后移除了代码生成器与模板引擎的默认依赖,需要手动添加相关依赖:
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-generatorartifactId>
<version>3.4.1version>
dependency>
<dependency>
<groupId>org.apache.velocitygroupId>
<artifactId>velocity-engine-coreartifactId>
<version>2.3version>
dependency>
随意命名。
将需要的条件设置到AutoGenerator对象中。
public class AutoCode {
public static void main(String[] args) { // 需要构建一个 代码自动生成器 对象
AutoGenerator mpg = new AutoGenerator();
// 配置策略
// 1、全局配置
GlobalConfig gc = new GlobalConfig();
String projectPath = System.getProperty("user.dir");
gc.setOutputDir(projectPath + "/src/main/java");
gc.setAuthor("LiuJiaqi");
gc.setOpen(false);
gc.setFileOverride(false);
// 是否覆盖
gc.setServiceName("%sService");
// 去Service的I前缀
gc.setIdType(IdType.ASSIGN_ID);
gc.setDateType(DateType.ONLY_DATE);
gc.setSwagger2(true);
mpg.setGlobalConfig(gc);
//2、设置数据源
DataSourceConfig dsc = new DataSourceConfig();
dsc.setUrl("jdbc:mysql://localhost:3306/mybatis_plus?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai");
dsc.setDriverName("com.mysql.jdbc.Driver");
dsc.setUsername("root");
dsc.setPassword("4033");
dsc.setDbType(DbType.MYSQL);
mpg.setDataSource(dsc);
//3、包的配置
PackageConfig pc = new PackageConfig();
pc.setModuleName("test");
pc.setParent("com.ljq");
pc.setEntity("entity");
pc.setMapper("mapper");
pc.setService("service");
pc.setController("controller");
mpg.setPackageInfo(pc);
//4、策略配置
StrategyConfig strategy = new StrategyConfig();
strategy.setInclude("user");
// 设置要映射的表名
strategy.setNaming(NamingStrategy.underline_to_camel);
strategy.setColumnNaming(NamingStrategy.underline_to_camel);
strategy.setEntityLombokModel(true);
// 自动lombok;
strategy.setLogicDeleteFieldName("deleted");
// 自动填充配置
TableFill gmtCreate = new TableFill("create_time", FieldFill.INSERT);
TableFill gmtModified = new TableFill("update_time", FieldFill.INSERT_UPDATE);
ArrayList<TableFill> tableFills = new ArrayList<>();
tableFills.add(gmtCreate);
tableFills.add(gmtModified);
strategy.setTableFillList(tableFills);
// 乐观锁
strategy.setVersionFieldName("version");
strategy.setRestControllerStyle(true);
strategy.setControllerMappingHyphenStyle(true);
//localhost:8080/hello_id_2
mpg.setStrategy(strategy);
mpg.execute(); //执行
}
}
配置详情
推荐遇见狂神说java(疯狂证明不是白嫖)