没接触过MyBatisPlus,昨天去B站找视频看,根据“狂神说Java”这个up主(此处穿插广告!这个up主的所有视频都很适合新手,通俗易懂,并且也有很多扩展,可以关注一波~~)发布的“MyBatisPlus最新完整教程通俗易懂”视频进行了学习,今天发现全都忘得差不多了(蛤蛤蛤)!所以再来刷一遍视频,自己跟着写一下代码,边复习边感受MyBatisPlus的魅力!此处只是用来记录学习过程!不说废话了,我开始了!
首先呢,是去官网了解一下MyBatisPlus(此处抛个链接 MyBatisPlus官网指南)),之前一直听说这个可以省去很多的CRUD语句,简化开发,然后昨天看了看,果然名不虚传,而且我超级喜欢那个“代码生成器”,让我大开眼界!!
# 配置数据库 MySQL5
spring.datasource.url=jdbc:mysql://localhost:3306/mybatisplus?useSSL-false&useUnicode=true&characterEncoding=utf-8
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.34version>
dependency>
<dependency>
<groupId>org.projectlomokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.0.5version>
dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
//在对应的接口上继承BaseMapper类
@Repository
public interface UserMapper extends BaseMapper<User>{
//所有的CRUD都已经编写完成!
}
}
@MapperScan("com.wmr.mapper")
@SpringBootApplication
public class MybatisplusApplication {
public static void main(String[] args) {
SpringApplication.run(MybatisplusApplication.class, args);
}
}
@SpringBootTest
class MybatisplusApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
List<User> users = userMapper.selectList(null);
users.forEach(System.out::println);
}
# 配置日志,可以看到控制台输出的SQL执行语句
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
@Test
public void insertTest(){
User user = new User();
user.setName("zhangsan");
user.setAge(18);
user.setEmail("[email protected]");
int insert = userMapper.insert(user);
System.out.println(insert);
}
在视频中介绍了一些主键生成策略以及雪花算法。(这里指路分布式唯一id生成方案)
主键生成策略中介绍了一个注解@TableId(type = IdType.AUTO)
这个注解的参数中idType是个枚举类型,用来设置数据库中的主键生成方式。需要将注解加到实体类里面:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
枚举类型的各个参数介绍:
AUTO(0),//数据库自增
NONE(1),//未设置主键
INPUT(2),//手动输入
ID_WORKER(3),//默认的全局唯一id
UUID(4),//全局唯一id uuid
ID_WORKER_STR(5);//ID_WORKER字符串表示法
@Test
public void updateTest() {
User user = new User();
user.setName("lisi");
user.setAge(19);
user.setId(3l);
int i = userMapper.updateById(user);
System.out.println(i);
}
关于自动填充处理,视频中主要扩展了对于数据库的设计需要“创建时间”和“更新时间”,这两个字段一般是表的必备,并且需要自动化。
方式一数据库级别(有些项目或者公司不允许动数据库,这种方式就不可以了)
修改数据库中的表,添加两个字段,并且“更新时间”需要设定“根据当前时间戳更新”,然后对实体类进行更新,之后即可测试。
(失败了!原因是我用的MySQL5.5,不支持同一个表中两个字段的默认值都为CURRENT_TIMESTAMP~~哭了,所以我还是来尝试方式二吧!)
方式二代码级别
给数据库添加两个字段之后,不需要设置任何默认值:
之后对实体类进行更新,并且加上关于字段的注解,表示在插入的时候填写内容和插入更新都填写:
//字段添加填充内容
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
然后编写一个处理器来处理这个注解,这个处理器类需要实现MetaObjectHandler接口,然后把未完成的方法完成,具体看注释:
@Component//不要忘记把处理器加入到Ioc容器中
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时的填充策略
@Override
public void insertFill(MetaObject 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);
}
}
set version = newVersion where version = oldVersion
乐观锁:1、先查询,获得版本号version=1
--A线程
update user set name = "ran",version = version+1
where id = 2 and version = 1
--B线程抢先完成,这个时候version = 2,会导致A修改失败
update user set name = "ran",version = version+1
where id = 2 and version = 1
下面将进行乐观锁的测试,首先给表加一个version字段并设置默认值为1:
然后对实体类进行更新并加@Version注解:
@Version //MP的Version注解,代表这是一个乐观锁
private Integer version;
在一个配置类中注册乐观锁插件(官网有XML和SpringBoot的方式介绍):
@MapperScan("com.wmr.mapper")
//代表自动管理事务的注解
@EnableTransactionManagement
//代表这是一个配置类
@Configuration
public class MPConfig {
//注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
之后即可进行测试
乐观锁成功测试
//测试乐观锁成功
@Test
public void optimisticLockerTest(){
User user = userMapper.selectById(2l);
user.setName("aaa");
int i = userMapper.updateById(user);
System.out.println(i);
}
可以看看控制台,发现在执行时已经进行了version的判断
数据库已经成功更新,并将version的值置为2:
乐观锁失败测试(多线程)
//测试乐观锁失败,模拟多线程
@Test
public void optimisticLockerTest2(){
//线程一
User user = userMapper.selectById(1l);
user.setName("bbb");
//模拟另一个线程执行插队操作
User user2 = userMapper.selectById(1l);
user2.setName("ccc");
userMapper.updateById(user2);
userMapper.updateById(user);//如果没有乐观锁就会覆盖插队线程的值
}
执行结果:
会发现最终结果是插队线程设定的值而不是线程一,如没有设置乐观锁,那么插队线程的值就会被覆盖。
//注册分页插件
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
然后就可以通过Page对象直接使用了(注意是MP的Page对象)!
//测试分页查询
public void pageTest(){
//参数一:当前页
//参数二:页面大小
Page<User> page = new Page<>(1,3);
userMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
}
物理删除:从数据库中删除
逻辑删除:在数据库中没有被移除,而是通过一个变量来让他失效
deleted = 0 ==> deleted = 1
首先在表中增加一个deleted字段,默认值为0.
然后更新实体类,并增加逻辑删除的注解:
@TableLogic //逻辑删除注解
private Integer deleted;
注册逻辑删除组件:
//注册逻辑删除组件
@Bean
public ISqlInjector SqlInjector() {
return new LogicSqlInjector();
}
在application.properties文件中进行逻辑删除的相关配置(现在的版本与现在的步骤不同,详见官网文档):
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
之后进行测试,可以看到即使使用的是删除方法,执行的却是更新操作:
但是之后再对同一条记录进行查询,已经查不到了,但是数据库中还是有记录的,只不过deleted变成了1,这个可以用来实现管理员功能,管理员依旧可以查看用户删除的信息,类似于一个“垃圾桶”:
//Wrapper测试
@Test
void contextLoads3() {
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("name","aaa");
User user = userMapper.selectOne(queryWrapper);
System.out.println(user);
}
wrapper可以进行各种各样的条件查询,MP真的很强大,一些简单的单表SQL已经不需要我们编写和配置xml文件,直接调用方法就可以实现。
这是我觉得让我这个菜鸟发现新大陆的东西!
试用成功,我好爱这个功能嗷!吹爆!
这篇太长了,另外写一篇把代码自动生成器的配置总结一下~