MyBatisPlus是MyBatis的增强工具。在其基础上不做改变,提高效率。
配置:
mybatisplus继承了MyBatis原生配置和特有配置。
mybatis-plus:
type-aliases-package: com.xxx.domain.po //需手动指定
mapper-locations: "classpath*:mapper/**/*.xml"
global-config:
db-config:
id-type: auto
update-strategy: not_null
configuration:
map-underscore-to-camel-case: true
cache-enable: false
依赖:
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.5.3.1version>
dependency>
定义Mapper:
myBatisPlus提供了Mapper接口,其中定义了CRUD功能。
public interface UserMapper extends BaseMapper<User> {}
MyBatis通过扫描实体类,并基于反射获取实体类信息作为数据库表信息。
约定:
AUTO:数据库ID自增
NONE:无状态,该类型为未设置主键类型
INPUT:insert前自行set主键值
ASSIGN_ID:分配ID(主键类型为Numer或String),使用接口IdentifierGenerator的nextId(雪花算法)
ASSIGN_UUID:分配UUID,主键类型为String,使用接口IdentifierGenerator的nextUUID
ID_WORKER:分布式全局唯一ID
UUID:32位UUID字符串
ID_WORKER_STR:分布式全局唯一ID字符串类型
@TableField:字段注解(非主键)使用场景
成员变量名与数据库字段名不一致
成员变量是以isXXX命名,按照JavaBean规范,MyBatisPlus识别字段时会把is去掉,导致与数据库不符
成员变量名与数据库一致,但与数据库关键字冲突,给字段名添加``转义
value:字段名
exist:是否数据库表字段
condition:字段where实体查询比较条件,有值设置则按设置的值为准,没有则位默认全局的$s=#{%s}
update:字段update set部分注入
insertStrategy:注入策略,NOT NULL
updateStragey:更新策略:IGNOED
whereStrategy:查询策略:NOT EMPTY
fill:字段自动填充
select:是否进行select查询
keepGlobalFormat:是都保持使用全局的format进行处理
jdbcType:JDBC类型
typeHandler:类型处理器
numericScale:指定小数点后保留位数
关于jdbcType和typeHandler及numericScale说明:numericScale只生效update,jdbcType和typeHandler如果不配合@TableName#autoResultMap=true一起使用,也只生效与update,对于typeHandler如果字段类型和set进去的类型位equals关系,则只需让你的typeHandler让MyBatis加载到即可,不需要使用注解
@Test
void testQueryWrapper() {
QueryWrapper<User> queryWrapper = new QueryWrapper<User>()
.select("id", "username", "info", "balance")
.like("username", "o")
.ge("balance", 1000);
userMapper.selectList(queryWrapper);
}
@Test
void testLambdaQueryWrapper() {
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.lambda().select(User::getId)
.like(User::getUsername, "o")
.ge(User::getBalance, 1000);
userMapper.selectList(wrapper);
}
@Test
void updateWrapper() {
User user = new User();
user.setBalance(2000);
QueryWrapper<User> queryWrapper = new QueryWrapper<User>().eq("username", "aric");
userMapper.update(user, queryWrapper);
}
@Test
void testUpdateWrapper() {
UpdateWrapper<User> wrapper = new UpdateWrapper<User>().setSql("balance = balance - 200").in("id", List.of(1, 2, 3));
userMapper.update(null, wrapper);
}
@Test
void testCustomWrapper(){
QueryWrapper<User> wrapper = new QueryWrapper<User>()
.like("username", "o")
.ge("balance", 1000);
List<User> users = userMapper.findByCustom(wrapper);
}
@Test
void testUpdateCustomWrapper(){
List<Integer> ids = List.of(1, 2, 3);
int amount = 200;
QueryWrapper<User> wrapper = new QueryWrapper<User>().in("id", ids);
userMapper.updateBalanceByWrapper(amount, wrapper);
}
List<User> findByCustom(@Param("ew") QueryWrapper<User> wrapper);
@Update("update user set balance = balance - #{amount} ${ew.customSqlSegment}")
void updateBalanceByWrapper(@Param("amount") int amount, @Param("ew") QueryWrapper<User> wrapper);
<select id="findByCustom" resultType="User">
select * from tb_user ${ew.customSqlSegment}
select>
public interface IUserService extends IService<User> {
}
@Service
//需实现IService中的方法所以继承对应的ServiceImpl
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
}
@Test
void testLambdaQuery() {
User user = userService.lambdaQuery()
.eq(User::getUsername, "xxx")
.one();
}
@Test
void testUpdateBalance(Long balance, Long id) {
userService.lambdaUpdate()
.set(User::getBalance, balance)
.set(balance == 0, User::getStatus, 2)
.eq(id != null, User::getId, id)
.update();
}
为避免service循环依赖,在serviceImpl层使用DBaseMapper或者静态工具DB。
MyBatisPlus提供逻辑删除,无需改变方法调用的方式,而是底层修改CRUD语句,只需在yml文件中配置逻辑删除字段和值即可。
mybatis-plus:
global-config:
db-config:
logic-delete-field: flag #全局逻辑删除的实体字段名,类型为boolean或integer
logic-delete-value: 1 #逻辑删除值
logic-not-delete-value: 0 #逻辑未删除值
如果被删除数据量太大,建议把删除数据迁移到其他表
直接用枚举类替换状态字段。需要把java的枚举对象转化成数据库的存储类型。之前需要自已定义TypeHandler,现在只需要在枚举类中加@EnumValue注解,并在配一个类型处理器即可。
@Getter
public enum UserStatus {
NORMAL(1, "正常"),
FREEZE(2, "冻结"),
;
@EnumValue
private final int value;
@JsonValue
private final String desc;
UserStatus(int value, String desc) {
this.value = value;
this.desc = desc;
}
}
mybatis-plus:
configuration:
default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandler
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jsonartifactId>
dependency>
@TableName(value = "tb_user", autoResultMap = true)
public class User {
@TableField(typeHandler = JacksonTypeHandler.class)
private UserInfo info;
}
@Data
@AllArgsConstructor(staticName = "of")
@NoArgsConstructor
public class UserInfo {
private Integer age;
private String intro;
private String gender;
}
MyBatisPlus提供一个基于AES算法的加密工具。
void contextLoads() {
String randomKey = AES.generateRandomKey(); //生成16位随机AES密钥
String username = AES.encrypt("root", randomKey);
String password = AES.encrypt("root", randomKey);
}
MyBatisPlus基于MyBatis的Interceptor实现了一个基础拦截器,并在内部保存了MyBatisPlus的内置拦截器集合。
TenantLineInnerInterceptor:多租户插件
DynamicTableNameInnerInterceptor:动态表名插件
PaginationInnerInterceptor:分页插件
OptimisticLockerInnerInterceptor:乐观锁插件
IllegalSQLInnerInterceptor:SQL性能规范插件,并检测拦截垃圾SQL
BlockArrackInnerInterceptor:防止全表更新和删除插件
@Configuration
public class MyBatisConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor (){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); //创建核心拦截器
PaginationInnerInterceptor innerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL); //创建插件
innerInterceptor.setMaxLimit(1000L); //上限
interceptor.addInnerInterceptor(innerInterceptor);
return interceptor;
}
}
void testPageQuery() {
int pageNo = 1, pageSize = 5;
Page<User> p = Page.of(pageNo, pageSize);
p.addOrder(new OrderItem("balance", false));
Page<User> page = userService.page(p);
}