一、编写插入方法的测试代码
@SpringBootTest
class MybatisplusApplicationTests {
//将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
//查询全部用户,这里需要传递一个Wrapper(条件构造器),后面讲解
List users = userMapper.selectList(null);
users.forEach(System.out::println);
}
//测试插入方法
@Test
public void testInsert(){
//插入方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据,注意这里不给id传数据
user.setName("张三");
user.setAge(19);
user.setEmail("[email protected]");
//调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
int result = userMapper.insert(user);
System.out.println(result); //result表示受影响的行数
//再次打印刚刚创建的对象
System.out.println(user);
}
}
二、运行测试方法,控制台打印结果
发现我们并没有给User对象传递id的参数,系统默认给生成了一个id
三、这里就涉及到了许多的主键生成策略
先拓展一个分布式唯一id生成方案汇总:https://www.cnblogs.com/haoxinyue/p/5208136.html (cnblogs.com)
现在我们系统中默认是用的雪花算法
1、认识什么是雪花算法
2、系统当前默认的主键策略是雪花策略,我们还可以通过注解@TableId设置其他的策略
通过学习注解@TableId,我们可以了解到可以个性化修改主键的生成策略
点进IdType,发现可以有以下的选择:
一、上一小节讲过了系统当前默认的雪花算法策略,可以回顾一下
二、AUTO表示自增策略,使用方法如下
1、首先在实体类的属性上加上注解@TableId,将Type赋值了AUTO
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
2、在数据库中同步操作,将指定的id字段也修改为自增,不然就会报错
注意:修改完表,一定记得点击保存,不然IDEA还是会报错!!!!!!
3、在测试类中测试
@SpringBootTest
class MybatisplusApplicationTests {
//将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
@Autowired
private UserMapper userMapper;
//测试插入方法
@Test
public void testInsert(){
//插入方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据,注意这里不给id传数据
user.setName("里弗斯");
user.setAge(13);
user.setEmail("[email protected]");
//调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
int result = userMapper.insert(user);
System.out.println(result); //result表示受影响的行数
//再次打印刚刚创建的对象
System.out.println(user);
}
}
控制台打印结果:
原本数据库共有6条数据,测试代码中我没有给里弗斯这条数据传id,现在因为我设置了主键自增策略,所以他就自动被赋值为7
三、剩余的策略解释
一、当前数据库的数据
二、编写测试更新的代码
@SpringBootTest
class MybatisplusApplicationTests {
//将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
@Autowired
private UserMapper userMapper;
//测试更新
@Test
public void testUpdate(){
//更新方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据
user.setId(1L);
user.setName("詹姆斯");
user.setAge(38);
//注意:这里的通过id更新数据,需要传进一个User对象
userMapper.updateById(user);
}
}
三、执行代码,控制台打印结果
MybatisPlus的强大之处是在于它可以根据我们传递进去的参数,自动生成动态SQL
四、观察数据库中数据也成功更新
一、为什么要使用自动填充?
每一张数据表中,几乎都会有创建时间、修改时间,但是这些字段在阿里巴巴开发手册中明确规定了,比如gmt_create、gmt_modified几乎所有的表都需要配置上,而且必须实现自动化填充!!!!!!
二、实现自动填充的两种方式
1、数据库级别
(1)在表中新增gmt_create、gmt_modified字段,别忘记修改完点击保存
记得更新时间勾选上更具当前的时间戳更新数据
(2)再次执行更新数据,先在实体类中把字段同步
private Date gmt_create;
private Date gmt_modified;
//测试更新
@Test
public void testUpdate(){
//更新方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据
user.setId(1L);
user.setName("詹姆斯");
user.setAge(35);
//注意:这里的通过id更新数据,需要传进一个User对象
userMapper.updateById(user);
}
查询数据库更新时间列,的确根据当前更新的时间发生了改变
2、代码级别
(1)删除数据库对创建和更新使劲按字段的默认值或者自动更新操作
(2)在实体类的字段上增加注解
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
//使用注解@TableField,设置该字段是在什么情况下自动填充更新,默认是不更新
@TableField(fill = FieldFill.INSERT)
private Date gmt_create;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date gmt_modified;
}
(3)编写处理器来处理这些注解
原理就是我们手动创建一个处理器,并通过@Component注解将该处理器添加到Spring容器中,当我们对某个表中的指定字段做插入或者更新操作的时候,处理器就会对指定的字段填充响应的数据
@Slf4j //可以查看日志信息
@Component //将该类声明为Spring的组件,添加到IOC容器中,才能有效
public class MyMetaObjectHandler implements MetaObjectHandler {
//插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("insertFull start.....");
//调用setFieldValByName方法,把指定的字段填充成希望的数据
this.setFieldValByName("gmt_create",new Date(),metaObject);
this.setFieldValByName("gmt_modified",new Date(),metaObject);
}
//更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("updateFull start.....");
//更新操作,只更新gmt_modified字段即可
this.setFieldValByName("gmt_modified",new Date(),metaObject);
}
}
(4)测试执行插入或者更新操作的代码
@SpringBootTest
class MybatisplusApplicationTests {
//将UserMapper自动装配到测试类中,因为继承了父类BaseMapper,所有的方法都来自父类
@Autowired
private UserMapper userMapper;
//测试插入方法
@Test
public void testInsert(){
//插入方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据,注意这里不给id传数据
user.setName("恩比德");
user.setAge(66);
user.setEmail("[email protected]");
//调用BaseMapper封装的insert方法,把user对象传进去,返回一个受影响的行数
int result = userMapper.insert(user);
System.out.println(result); //result表示受影响的行数
//再次打印刚刚创建的对象
System.out.println(user);
}
//测试更新
@Test
public void testUpdate(){
//更新方法中需要传递一个User对象
User user = new User();
//通过set方法往对象中传数据
user.setId(2L);
user.setName("库里");
user.setAge(28);
//注意:这里的通过id更新数据,需要传进一个User对象
userMapper.updateById(user);
}
}
(5)观察数据库表时间的更新状态,操作成功!
一、推出这款插件的意图
多线程下,当更新一条记录的时候,希望这条记录没有被别人更新
二、乐观锁的实现方式
1、取出记录时,获取当前的version
2、更新时,带上这个version
3、执行更新时
update XXX set name = "张三",version = newVersion where version = oldVersion
4、如果version不对,那么就更新失败
假设有两条线程,A线程和B线程,两个线程都取出了记录,假设这个原始的version = 1,
如果线程B抢先线程A先更新了数据,version发生了改变,那么线程A再执行更新数据的时候就会发现version不对,更新失败!
三、测试使用乐观锁插件
1、首先在数据库表中增加一个version字段
2、实体类中更新字段,并且在version字段上面增加注解@Version,标记该字段加上了乐观锁
@Version //乐观锁注解
private Integer version;
3、注册组件
在项目下新建一个config包,下面新建一个mybatisplus的核心配置类,注意这里把扫描mybatis的Mapper接口注解从主启动类中挪到了
mybatisplus的核心配置类下,注册乐观锁的方法,死代码将来直接用
@MapperScan("com.guohui.mapper") //扫描mapper文件夹,编写的mapper接口才能生效
@Configuration //声明该类是一个配置类
public class MybatisPlusConfig {
//注册乐观锁插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
4、测试乐观锁
(1)单线程下,测试更新数据,肯定能成功将数据更新
//测试乐观锁一:单线程下数据可以更新成功
@Test
public void testOptimisticLocker(){
//1、通过id查到某个user对象
User user = userMapper.selectById(1l);
//2、对这个对象进行更新操作
user.setName("阿里巴巴");
user.setAge(99);
//3、执行一下更新操作,把上面的user对象传进去,此时的对象中的version是1
userMapper.updateById(user);
}
数据库中对应数据的version成功更新,默认是执行version+1
(2)多线程下,测试同时更新一行数据,会更新失败
//测试乐观锁二:多线程下数据会更新失败
@Test
public void testOptimisticLocker01() {
User user1 = userMapper.selectById(2l);
user1.setName("东七七");
user1.setAge(43);
//此时另一个模拟线程过来插队
User user2 = userMapper.selectById(2l);
user2.setName("西六六");
user2.setAge(34);
userMapper.updateById(user2);
userMapper.updateById(user1);
}
(4)查看并分析控制台的执行日志
@Test
public void testSelect(){
//1.查询单个用户,直接把id传进去即可
User user = userMapper.selectById(1l);
System.out.println(user);
//2.批量查询用户
List users = userMapper.selectBatchIds(Arrays.asList(1, 2, 3, 4));
users.forEach(System.out::println);
//3.通过map来按照条件查询,它可以自动帮我们将map中的数据拼接成动态的SQL
Map map = new HashMap<>();
map.put("name","詹姆斯");
List userList = userMapper.selectByMap(map);
userList.forEach(System.out::println);
}
分页在网站中的使用十分频繁,MybatisPlus也内置了分页的插件,所以可以直接拿来使用
一、使用方法
1、在MybatisPlusConfig核心配置文件中注册分页插件
@MapperScan("com.guohui.mapper") //扫描mapper文件夹,编写的mapper接口才能生效
@Configuration //声明该类是一个配置类
public class MybatisPlusConfig {
//注册分页插件
@Bean
public PaginationInnerInterceptor paginationInnerInterceptor(){
return new PaginationInnerInterceptor();
}
}
2、测试类中,直接使用Page对象即可
//测试分页查询
@Test
public void testPage(){
Page page = new Page<>(1,5); //两个参数的作用:查询第一页,显示5条数据
userMapper.selectPage(page, null); //调用selectPage,第二个参数暂时空着
page.getRecords().forEach(System.out::println);
}
//测试删除
@Test
public void testDelete(){
//通过id删除,DELETE FROM user WHERE id = ?
userMapper.deleteById(8l);
//批量删除,DELETE FROM user WHERE id IN(?,?,?)
userMapper.deleteBatchIds(Arrays.asList(4,5,6));
//通过map自定义删除,动态拼接SQL,DELETE FROM user WHERE id = ?
Map map = new HashMap<>();
map.put("id",7);
userMapper.deleteByMap(map);
}
一、首先先了解两个概念
1、物理删除
从数据库中直接移除
2、逻辑删除
在数据库中没有被移除,而是通过一个变量来让他失效!比如说deleted = 0变为deleted = 1
二、测试逻辑删除
1、在数据库表中增加一个deleted字段,默认值为0
2、实体类pojo中更新字段,并且增加逻辑删除的注解
@TableLogic //逻辑删除注解
private Integer deleted;
3、在application.properties中配置逻辑删除
#配置逻辑删除,删除了deleted字段为1,没有删除的为0
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
4、测试删除
(1)数据库原数据
(2)执行删除操作
//测试逻辑删除
@Test
public void testDelete(){
//通过id删除,DELETE FROM user WHERE id = ?
userMapper.deleteById(1l);
}
注意:我们虽然执行的是删除的方法,但是它实际执行的是更新的SQL
(3)查看数据库更新数据
发现我们这条数据依旧存在,但是deleted的值发生了改变
更加有意思的是,我们再对第一条数据执行查询操作的时候,他会自动帮助我们把deleted = 0拼接上去,所以这条数据就无法查询到。换句话说,逻辑删除的插件会让系统自动过滤掉被逻辑删除的数据
至此,关于MybatisPlus对Mybatis的CRUD扩展的介绍就结束了,你已经掌握了对常规的增删改查的功能,后续会继续更新,欢迎交流和指正!