MyBatis-Plus
简称MP,是一个MyBatis的增强工具,在原有的基础上只做增强不做改变,为简化开发,提升效率而生
特点
- “润物无声”:只做增强不做改变,引入它不会对现有的工程产生影响。
- “效率至上”:只需要简单配置,即可CRUD操作
- “丰富功能”:热加载,代码生成,分页,性能分析等功能一应俱全
入门案例MP–查找所有
创建springboot 2.0以上版本(版本在2.0以下的,jdbc中的配置数据会有所不同,具体之后会说明),创建数据库,mybatis_plus 包含相关的字段(id,name,age,email)
- 首先在pom.xml引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</dependency>
<!--mybatis-plus 持久层-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- lombok用来简化实体类-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
- 创建实体(这里用User 表中的id ,name,age,email 做相关操作实例)
import lombok.Data;
@Data
public class User {
// 在添加lombok插件后,使用data注解,省去get,set
private Long id;
private String name;
private Integer age;
private String email;
}
- 创建UserMapper,让它继承内置的BaseMapper
//核心代码,让UserMapper继承内置的BaseMapper (内置CRUD方法)
@Repository
public interface UserMapper extends BaseMapper<User> {
}
BaseMapper中自带了CRUD方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package com.baomidou.mybatisplus.core.mapper;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import org.apache.ibatis.annotations.Param;
public interface BaseMapper<T> extends Mapper<T> {
int insert(T entity);
int deleteById(Serializable id);
int deleteByMap(@Param("cm") Map<String, Object> columnMap);
int delete(@Param("ew") Wrapper<T> wrapper);
int deleteBatchIds(@Param("coll") Collection<? extends Serializable> idList);
int updateById(@Param("et") T entity);
int update(@Param("et") T entity, @Param("ew") Wrapper<T> updateWrapper);
T selectById(Serializable id);
List<T> selectBatchIds(@Param("coll") Collection<? extends Serializable> idList);
List<T> selectByMap(@Param("cm") Map<String, Object> columnMap);
T selectOne(@Param("ew") Wrapper<T> queryWrapper);
Integer selectCount(@Param("ew") Wrapper<T> queryWrapper);
List<T> selectList(@Param("ew") Wrapper<T> queryWrapper);
List<Map<String, Object>> selectMaps(@Param("ew") Wrapper<T> queryWrapper);
List<Object> selectObjs(@Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<T>> E selectPage(E page, @Param("ew") Wrapper<T> queryWrapper);
<E extends IPage<Map<String, Object>>> E selectMapsPage(E page, @Param("ew") Wrapper<T> queryWrapper);
}
- 编写测试,运行结果
首先在SpringBoot中的启动类添加MapperScan扫描UserMapper的路径
@MapperScan("com.zeus.demomp.mapper")
public class DemompApplication {
public static void main(String[] args) {
SpringApplication.run(DemompApplication.class, args);
}
}
然后在test目录下进行测试,首先添加自动注入@AutoWired将UserMapper注入,编写查找所有的测试方法
class DemompApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
//查找全部
public void fillAll() {
List<User> users = userMapper.selectList(null);
System.out.println(users);
}
}
结果如图:
这里引用了lombok进行实体的简化,省去get,set方法等等
在Spring版本不同,jdbc配置信息区别
添加操作
@Test
public void insert(){
User user=new User();
user.setName("niuzai");
user.setAge(12);
user.setEmail("[email protected]");
//返回影响行数
int i = userMapper.insert(user);
System.out.println(i);
}
特别注意,在MP中主键生成的策略
也可以使用在实体类中的id上做注解配置主键生成策略
@TableId(type=IdType.XXX)
例如
ASSIGN_ID 自动分配19位的id
ASSIGN_UUID
AUTO 自动增长
INPUT 自己输入
修改
@Test
public void updateByID(){
User user=new User();
user.setId(1385515096112947202L);
user.setName("niushi");
int i = userMapper.updateById(user);
System.out.println(i);
}
自动填充
为了测试,先在数据库的表中添加create_time ,update_time字段
在实体类添加对应属性,然后在属性上进行添加自动填充的属性注释
@TableField(fill = FieldFill.INSERT )
private Date createTime;
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date updateTime;
然后创建类,实现接口添加两个方法,重写MetaObjectHandler中的insertFill和updateFill
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
//mp执行添加操作时自动填充往create_time字段中添加时间
this.setFieldValByName("createTime",new Date(),metaObject);
}
@Override
public void updateFill(MetaObject metaObject) {
//mp执行更新和添加时都要自动填充时间,因为在user实体类中进行了相关操作
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
乐观锁
主要适用场景:当更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新;
乐观锁实现方式:
取出记录时,获取当前的version,更新时,带上version,执行更新时,set version= new Version where version =old version
如果版本不对,就更新失败。
补充:使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据。
实现案例
- 首先在数据库中的字段里添加version字段
- 在实体类中添加version,并在其上方添加@version注释
//通过version控制修改更新,进行乐观锁操作
@Version
private Integer version;
- 在insert时也自动填入默认版本值
@Override
public void insertFill(MetaObject metaObject) {
//mp执行添加操作时自动填充往create_time字段中添加时间
this.setFieldValByName("createTime",new Date(),metaObject);
//添加数据时默认数据版本为1
this.setFieldValByName("version",1,metaObject);
}
- 创建配置config,注入Bean,配置乐观锁
@Configuration
@MapperScan("com.zeus.demomp.mapper")
public class MpConfig {
//配置乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor(){
return new OptimisticLockerInterceptor();
}
}
- 进行测试,先进行查询后进行更新操作,比较version值是否更新
public void testOptimisticLocker(){
//先通过查询
User user = userMapper.selectById(1385609705744887809L);
//再修改值
user.setName("LG");
//进行更新操作
userMapper.updateById(user);
}