mybatis官网:https://baomidou.com/
建议安装 MybatisX 插件
数据库的表结构
1、引入xml配置
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.1</version>
</dependency>
2、连接数据库配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver #mysql版本8.0以上加 cj.
url: jdbc:mysql:///testdata
username: root
password: root
3、编写实体类
@Data //lombok的使用
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@TableId(type=IdType.AUTO) //设置ID主键
private int id;
private String name;
private Double price;
@TableField(fill = FieldFill.INSERT) //设置插入时间
private Date createTime;
@TableField(fill = FieldFill.UPDATE) //设置更新时间
private Date updateTime;
}
4、编写实体类对应的mapper接口
//只要继承BaseMapper即可。
@Repository
public interface BookMapper extends BaseMapper<Book> {
}
5、在配置类上面添加@MapperScan注解
//对应的mapper存放地址
@MapperScan("com.test.mapper")
@Configuration
public class MpConfig {
}
6、编写测试类
@SpringBootTest
class SpringBootMpApplicationTests {
@Autowired
BookMapper bookMapper;
@Test
void contextLoads() {
//id查询
Book book = bookMapper.selectById(11);
System.out.println(book);
//查询全部
List<Book> books = bookMapper.selectList(null);
books.forEach(System.out::println);
}
}
7、项目中的实用点小结
7.1、开启SQL打印日志
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
7.2、记录表的操作时间
7.2.1、在实体类表里面添加字段
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.UPDATE)
private Date updateTime;
7.2.2、添加以下类即可
@Slf4j
@Component
public class MyMetaObkectHandle implements MetaObjectHandler {
@Override//插入时的填充策略
public void insertFill(MetaObject metaObject) {
log.info("==插入时的填充策略 ······==");
//插入时填入创建时间
this.setFieldValByName("createTime",new Date(),metaObject);
//更新时填入修改时间
this.setFieldValByName("updateTime",new Date(),metaObject);
}
@Override//更新时的填充策略
public void updateFill(MetaObject metaObject) {
log.info("==更新时的填充策略 ······==");
//更新修改时间
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
7.3、乐观锁&分页
乐观锁:顾名思义十分乐观,他总是认为不会出现问题,无论干什么都不上锁!如果出现了问题,再次更新值测试
悲观锁:顾名思义十分悲观,他总是认为出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:
取出记录时,获取当前version
更新时,带上这个version
执行更新时,set version = newVersion where version = oldVersion
如果version不对,就更新失败
7.3.1、乐观锁实现方式
在数据库和实体类加入version字段
@Version//乐观锁version注解
private Integer version;
在配置类里加入配置类插件
// 注册乐观锁和分页插件(新版:3.4.1)
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
//乐观锁插件
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
//分页插件
mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return mybatisPlusInterceptor;
}
//乐观锁插件(旧版:3.0.5)
/* @Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}*/
//分页插件(旧版:3.0.5)
/* @Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}*/
乐观锁编写测试类
@Test
void testInterceptor() {
Book book1=bookMapper.selectById(18);
book1.setPrice(89.6);
Book book2=bookMapper.selectById(18);
book2.setPrice(90.8);
//先执行插队的更新业务
bookMapper.updateById(book2);
//在执行更新任务
bookMapper.updateById(book1);//如果没有乐观锁就会覆盖插队线程的值
}
执行结果,会自动带上version
分页编写测试类
@Test//测试分页查询
public void testPage(){
//使用了分页插件
Page<Book> page = new Page<>(2,5);//第二页,每页展示5条数据
bookMapper.selectPage(page,null);
page.getRecords().forEach(System.out::println);
System.out.println("总页数==>"+page.getTotal());
}
7.4、逻辑删除
删除: update user set deleted=1 where id = 1 and deleted=0
查找: select id,name,deleted from user where deleted=0
添加在数据库和实体类里添加字段deleted
在yml里面添加如下配置
mybatis-plus:
global-config:
db-config:
logic-delete-field: deleted # 全局逻辑删除的实体字段名(since 3.3.0,配置后可以忽略不配置步骤2)
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
测试
@Test//逻辑删除测试
public void testdeleted(){
bookMapper.deleteById(18);
Book book = bookMapper.selectById(18);
System.out.println(book);
}
查询条件构造器Wrapper
官方API:https://baomidou.com/pages/10c804/#select
测试类
@Test
public void selectWrapper1(){
//查询name不为空, price大于50的所有书籍
QueryWrapper<Book> wrapper=new QueryWrapper<>();
wrapper.isNotNull("name").ge("price",50);
List<Book> books = bookMapper.selectList(wrapper);
books.forEach(System.out::println);
//执行的SQL
// SELECT id,name,price,create_time,update_time,version,deleted FROM book WHERE deleted=0 AND (name IS NOT NULL AND price >= ?)
//==> Parameters: 50(Integer)
}
@Test
public void selectWrapper2(){
//模糊查询
QueryWrapper<Book> wrapper=new QueryWrapper<>();
wrapper.like("name","子");
List<Book> books = bookMapper.selectList(wrapper);
books.forEach(System.out::println);
//执行的SQL
// Preparing: SELECT id,name,price,create_time,update_time,version,deleted FROM book WHERE deleted=0 AND (name LIKE ?)
//==> Parameters: %子%(String)
}
@Test
public void selectWrapper3() {
//子条件查询
QueryWrapper<Book> wrapper = new QueryWrapper<>();
wrapper.inSql("id","select id from book where id>10 ");
List<Book> books = bookMapper.selectList(wrapper);
books.forEach(System.out::println);
//SELECT id,name,price,create_time,update_time,version,deleted FROM book WHERE deleted=0 AND (id IN (select id from book where id>10 ))
}