📢📢📢📣📣📣
哈喽!大家好,我是【一心同学】,一位上进心十足的【Java领域博主】!😜😜😜
✨【一心同学】的写作风格:喜欢用【通俗易懂】的文笔去讲解每一个知识点,而不喜欢用【高大上】的官方陈述。
✨【一心同学】博客的领域是【面向后端技术】的学习,未来会持续更新更多的【后端技术】以及【学习心得】。
✨如果有对【后端技术】感兴趣的【小可爱】,欢迎关注【一心同学】💞💞💞
❤️❤️❤️感谢各位大可爱小可爱!❤️❤️❤️
前言
本篇博客将详细介绍MyBatis-Plus中的常用注解以及其注意事项,并会对其常用的属性进行举例说明,而不常用的属性大家可根据描述信息进行了解。
一、@TableName
1.1 介绍
描述:表名注解,映射数据库的表名
使用位置:实体类
属性值
属性类型必须指定默认值描述valueString否""表名schemaString否""schemakeepGlobalPrefixboolean否false是否保持使用全局的 tablePrefix 的值(当全局 tablePrefix 生效时)resultMapString否""xml 中 resultMap 的 id(用于满足特定类型的实体类对象绑定)autoResultMapboolean否false是否自动构建 resultMap 并使用(如果设置 resultMap 则不会进行 resultMap 的自动构建与注入)excludePropertyString[]否{}需要排除的属性名 @since 3.3.1
1.2 使用
使用场景:当我们的实体类名跟我们的数据库表名不一致时,可根据@TableName来指定数据库表名。
例如:
我们的数据库表名是叫做person,但我们的Java实体类中却叫做User。
解决映射冲突:
添加注解@TableName(value = "person")
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
private Long id;
private String name;
private Integer age;
private String email;
}
二、@TableId
2.1 介绍
描述:主键注解
使用位置:实体类主键字段
属性值
属性类型必须指定默认值描述valueString否""主键字段名typeEnum否IdType.NONE指定主键类型
IdType属性
值描述AUTO数据库自增NONE无状态,该类型为未设置主键类型(注解里等于跟随全局,全局里约等于 INPUT)雪花算法实现INPUT需要开发者手动赋值ASSIGN_IDMP 分配 ID,Long、Integer、StringASSIGN_UUID分配 UUID,Strinig
我们讲解在IdType中两个最常见的属性:AUTO和INPUT
2.2 AUTO属性
- 使用前提:需要在数据库中将主键设置为自增。
- 生成ID算法:【雪花算法】,基本可以保证全球唯一ID值。
- 特点:生成的ID值在原来的ID基础上自增,并且会将ID值回填到我们的Java对象中。
注意:对主键使用了AUTO,那么我们自行注入的ID值将会被自动生成的ID覆盖。
代码演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
}
测试:
我们在插入时自定义ID值。
@Test
void test4() {
// 我们没有自定义id,它会帮我们自动生成id
Person person =new Person();
person.setId(2L);
person.setName("一心同学");
person.setAge(18);
person.setEmail("[email protected]");
int result=personMapper.insert(person);
System.out.println(result);// 受影响的行数
System.out.println(person);//可以发现,id会自动回填
}
结果:
发现1:可以发现MP并没有采纳我们的ID值,因为其注入语句中根本就没有我们的主键id,而是选择用【雪花算法】自动生成的ID值。
发现2:自动生成的ID值自动回填到我们的Java对象中了。
2.3 INPUT属性
生成ID算法:【雪花算法】,基本可以保证全球唯一ID值。
特点:开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。
注意:并不会回填到我们的Java对象中。
代码演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.INPUT)
private Long id;
private String name;
private Integer age;
private String email;
}
(1)自定义ID测试
@Test
void test4() {
//我们自定义ID,则会使用我们的ID,否则自动生成ID
Person person =new Person();
person.setId(5L);
person.setName("一心同学2");
person.setAge(18);
person.setEmail("[email protected]");
int result=personMapper.insert(person);
System.out.println(result);// 受影响的行数
System.out.println(person);
}
结果:可以发现,MP是采用我们自定义的ID值的。
(2)不定义ID值测试
@Test
void test4() {
//我们自定义ID,则会使用我们的ID,否则自动生成ID
Person person =new Person();
person.setName("一心同学3");
person.setAge(18);
person.setEmail("[email protected]");
int result=personMapper.insert(person);
System.out.println(result);// 受影响的行数
System.out.println(person);//发现不会回填!
}
结果:可以发现,当我们没有进行ID的定义时,MP将会通过自增的方式给主键赋值,并且不会将赋完的值注入到我们的Java对象。
但在我们数据库中是有Id值的,只是没回填到Java对象而已。
2.4 AUTO与INPUT对比
AUTO与INPUT对比
Type算法特点是否覆盖自定义值是否回填AUTO雪花算法生成的ID值在原来的ID基础上自增是是INPUT雪花算法开发者没有手动赋值,则数据库通过自增的方式给主键赋值,如果开发者手动赋值,则存入该值。否否
三、@TableField
3.1 介绍
描述:字段注解(非主键)
属性值
属性类型必须指定默认值描述valueString否""数据库字段名existboolean否true是否为数据库表字段conditionString否""字段
where
实体查询比较条件,有值设置则按设置的值为准,没有则为默认全局的
%s=#{%s}
,参考(opens new window)updateString否""字段
update set
部分注入,例如:当在version字段上注解
update="%s+1"
表示更新时会
set version=version+1
(该属性优先级高于
el
属性)insertStrategyEnum否FieldStrategy.DEFAULT举例:NOT_NULL
insert into table_a(<if test="columnProperty != null">column</if>) values (<if test="columnProperty != null">#{columnProperty}</if>)
updateStrategyEnum否FieldStrategy.DEFAULT举例:IGNORED
update table_a set column=#{columnProperty}
whereStrategyEnum否FieldStrategy.DEFAULT举例:NOT_EMPTY
where <if test="columnProperty != null and columnProperty!=''">column=#{columnProperty}</if>
fillEnum否FieldFill.DEFAULT字段自动填充策略selectboolean否true是否进行 select 查询keepGlobalFormatboolean否false是否保持使用全局的 format 进行处理jdbcTypeJdbcType否JdbcType.UNDEFINEDJDBC 类型 (该默认值不代表会按照该值生效)typeHandlerClass<? extends TypeHandler>否UnknownTypeHandler.class类型处理器 (该默认值不代表会按照该值生效)numericScaleString否""指定小数点后保留的位数
FieldStrategy 属性
值描述IGNORED忽略判断NOT_NULL非 NULL 判断NOT_EMPTY非空判断(只对字符串类型字段,其他类型字段依然为非 NULL 判断)DEFAULT追随全局配置
FieldFill属性值
值描述DEFAULT默认不处理INSERT插入时填充字段UPDATE更新时填充字段INSERT_UPDATE插入和更新时填充字段
看到上面这么多属性,是不是突然就懵了,不要怕!【一心同学】在这里,对于上面的属性,在我们开发中一些是不常用的,【一心同学】在这里用代码演示几个常见的属性,大家务必掌握。
3.2 普通属性
代码演示:
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.*;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName(value = "person")
public class User {
@TableId(type=IdType.AUTO)
private Long id;
// 当该字段名称与数据库名字不一致
@TableField(value = "name")
private String name;
// 不查询该字段
@TableField(select = false)
private Integer age;
// 是否为数据库表字段,设置为false,则插入时不会对其操作
@TableField(exist = false)
private String email;
}
3.3 自动填充属性
步骤一:数据库增加两个属性,create_time和update_time。
步骤二:实体类字段属性添加注解。
// 第一次添加填充
@TableField(fill= FieldFill.INSERT)
private Date createTime;
// 第一次添加的时候填充,但之后每次更新也会进行填充
@TableField(fill=FieldFill.INSERT_UPDATE)
private Date updateTime;
步骤三:编写处理器来处理这个注解
注意:在处理器类上方添加注解@Component!
package com.yixin.mybatis_plus.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.util.Date;
@Slf4j
@Component // 一定不要忘记把处理器加到IOC容器中!
public class MyMetaObjectHandler implements MetaObjectHandler {
// 插入时的填充策略
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill.....");
// setFieldValByName(String fieldName, Object fieldVal, MetaObject metaObject
this.setFieldValByName("createTime",new Date(),metaObject);
this.setFieldValByName("updateTime",new Date(),metaObject);
}
// 更新时的填充策略
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill.....");
this.setFieldValByName("updateTime",new Date(),metaObject);
}
}
测试:
@Test
void test9() {
// 我们没有自定义id,它会帮我们自动生成id
User person =new User();
person.setName("一心同学呀");
person.setAge(20);
person.setEmail("[email protected]");
int result=personsMapper.insert(person);
System.out.println(result);// 受影响的行数
System.out.println(person);//可以发现,id会自动回填
}
数据库
四、乐观锁
4.1 介绍
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试
悲观锁:故名思意十分悲观,它总是认为总是出现问题,无论干什么都会上锁!再去操作!
乐观锁实现方式:
取出记录时,获取当前 version
更新时,带上这个version
执行更新时, set version = newVersion where version = oldVersion
如果version不对,就更新失败
代码解释:
乐观锁:1、先查询,获得版本号 version = 1
-- A
update person set name = "yixin", version = version + 1
where id = 2 and version = 1
-- B 线程抢先完成,这个时候 version = 2,会导致 A 修改失败!
update person set name = "yixin", version = version + 1
where id = 2 and version = 1
4.2 注意事项
- 支持的数据类型只有:int,Integer,long,Long,Date,Timestamp,LocalDateTime
- 整数类型下 newVersion = oldVersion + 1
- newVersion 会回写到 entity 中
- 仅支持 updateById(id) 与 update(entity, wrapper) 方法
- 在 update(entity, wrapper) 方法下, wrapper 不能复用
4.3 实现乐观锁
步骤一:给数据库中增加version字段!
步骤二:实体类添加对应的字段。
package com.yixin.mybatis_plus.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.Version;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private Integer age;
private String email;
@Version //乐观锁Version注解
private Integer version;
}
步骤三:注册组件。
package com.yixin.mybatis_plus.config;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 扫描我们的 mapper 文件夹
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
}
4.4 测试
(1)测试乐观锁成功情况
@Test
void testOptimisticLocker() {
// 1、查询用户信息
Person person=personMapper.selectById(1L);
// 2、修改用户信息
person.setName("一心同学");
int result=personMapper.updateById(person);
System.out.println(result);// 受影响的行数
}
结果:****可以发现MP会自动帮我们进行乐观锁判定。
并且每修改一次,version就会+1。
(2)测试失败情况!多线程下!
@Test
void testOptimisticLocker2() {
// 线程 1
Person person=personMapper.selectById(3L);
person.setName("一心同学在写博客");
// 模拟另外一个线程执行了插队操作
Person person2=personMapper.selectById(3L);
person2.setName("一心同学在吃饭");
personMapper.updateById(person2);
int result=personMapper.updateById(person);// 如果没有乐观锁就会覆盖插队线程的值!
System.out.println(result);// 受影响的行数
}
数据库:
也就是说我们的线程一没有执行成功。
五、逻辑删除
5.1 介绍
物理删除 :从数据库中直接移除
逻辑删除 :再数据库中没有被移除,而是通过一个变量来让他失效! deleted = 0 => deleted = 1
管理员可以查看被删除的记录!防止数据的丢失,类似于回收站!
5.2 实现逻辑删除
步骤一:在数据表中增加一个 deleted 字段。
步骤二:实体类中增加属性。
@TableLogic //逻辑删除private
Integer deleted;
步骤三:配置。
(1)在自定义配置类中添加逻辑删除组件
package com.yixin.mybatis_plus.config;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
import com.baomidou.mybatisplus.extension.plugins.OptimisticLockerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
// 扫描我们的 mapper 文件夹
@MapperScan("com.yixin.mybatis_plus.mapper")
@EnableTransactionManagement
@Configuration // 配置类
public class MyBatisPlusConfig {
// 注册乐观锁插件
@Bean
public OptimisticLockerInterceptor optimisticLockerInterceptor() {
return new OptimisticLockerInterceptor();
}
// 逻辑删除组件!
@Bean
public ISqlInjector sqlInjector() {
return new LogicSqlInjector();
}
}
(2)在application.properties添加配置
# 配置逻辑删除
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
5.3 测试
@Test
void test6() {
int result=personMapper.deleteById(5L);
System.out.println(result);// 受影响的行数
}
结果:
数据库:
数据库中并没有删除,而是将deleted从0变为1,实现了逻辑删除。(其实就是更新操作)
小结
以上就是【一心同学】整理的【MyBatis-Plus】的常用【注解】讲解,通过介绍和代码实现,相信大家基本已经掌握了,这一块的内容在我们平时的开发当中还是比较重要的,因为我们在开发当中用得最多的就是注解了,并且其能够大大提高我们的【工作效率】。
如果这篇【文章】有帮助到你,希望可以给【一心同学】点个赞👍,创作不易,相比官方的陈述,我更喜欢用【通俗易懂】的文笔去讲解每一个知识点,如果有对【后端技术】感兴趣的小可爱,也欢迎关注❤️❤️❤️ 【一心同学】❤️❤️❤️,我将会给你带来巨大的【收获与惊喜】💕💕!
版权归原作者 一心同学 所有, 如有侵权,请联系我们删除。