修改操作
根据ID更新操作
这里MP作了优化,需要改什么值你就set什么值,不改的值不需要管。
//修改操作
@Test
public void testUpdate(){
User user = new User();
user.setId(2L); //只需要修改ID属性,会自动找
user.setAge(20); //直接修改对象传入即可更新
userMapper.updateById(user); //直接传入一个对象
}
⚠️update时底层生成的sql自动是动态sql:UPDATE user SET age=? WHERE id=?
⭐️MP的自动填充功能
项目中经常会遇到一些数据每次都使用相同的方式填充,例如一条记录的创建时间,更新时间等。除了每次自己手动set外,还可以使用MyBatis Plus的自动填充功能完成这些字段的赋值工作。
第一步:在实体上添加注解
@Data
public class User {
......
@TableField(fill = FieldFill.INSERT) //插入时
private Date createTime;
//@TableField(fill = FieldFill.UPDATE)
@TableField(fill = FieldFill.INSERT_UPDATE) //插入和更新时
private Date updateTime;
}
第二步:创建配置类实现MetaObjectHandler
接口及其中的方法。
@Component //别忘
public class MyMetaObjectHandler implements MetaObjectHandler {
//使用MP执行添加操作时执行这个方法
@Override
public void insertFill(MetaObject metaObject) {
this.setFieldValByName("createTime", new Date(), metaObject);
this.setFieldValByName("updateTime", new Date(), metaObject);
}
//使用MP执行更新操作时执行这个方法
@Override
public void updateFill(MetaObject metaObject) {
this.setFieldValByName("updateTime", new Date(), metaObject);
}
}
之后再执行相关操作就会自动将这两个字段填充好。
什么是元数据(meta data)?
描述数据的数据,例如用户数据表中,用户的ID、年龄、姓名就是元数据。
😣乐观锁
乐观锁主要解决丢失更新问题,当要更新一条记录的时候,希望这条记录没有被别人更新,也就是说实现线程安全的数据更新。
MySQL读写问题回顾
读问题
不考虑事务隔离性,可能会产生读问题。分为脏读、不可重复读、幻读。
事务就好比操作系统中的原语,是一个最小的原子操作,隔离性是指一个事务的执行不能被其他事务干扰。
- 脏读:指当一个事务对数据进行了修改,且修改还没有提交到数据库中,这时另外一个事务也访问这个数据,然后使用了这个数据,读错了错误的数据。
- 不可重复读:是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,由于第二个事务的修改,那么第一个事务两次读到的的数据可能是不一样的,称为不可重复读。
- 幻读:是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行。同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据。那么操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样。
写问题
写问题主要是指丢失更新问题,只有在并发的情况下才可能出现这种问题。多个人同时修改同一条记录,最后提交的数据覆盖了另一个提交的数据。(同时写)
有悲观锁和乐观锁两种解决方法。
悲观锁(不推荐)
悲观锁即一个用户修改记录时,其余所有人都不准修改直到该用户修改完毕。
乐观锁
乐观锁通过引入版本号这个概念来解决丢失更新问题。
乐观锁实现方式
- 取出记录时,获取当前
version
- 更新时,带上这个
version
- 执行更新时,
set version = newVersion where version = oldVersion
- 如果
version
不对,就更新失败
Mybatis中的乐观锁
MP提供了非常方便的乐观锁实现方法,具体实现步骤:
-
在数据库中添加
version
字段ALTER TABLE `user` ADD COLUMN `version` INT
-
实体类添加
version
字段并注解//乐观锁版本号 @Version @TableField(fill = FieldFill.INSERT) private Integer version; //整数类型下version自动+1
-
元对象处理器接口添加
version
的insert
默认值@Override public void insertFill(MetaObject metaObject) { ... //version的默认值设置为1 this.setFieldValByName("version", 1, metaObject); }
-
在配置类中将乐观锁插件注册为Bean
@EnableTransactionManagement @Configuration @MapperScan("com.atguigu.mybatis_plus.mapper") //启动类中不用再写 public class MybatisPlusConfig { //乐观锁插件 @Bean public OptimisticLockerInterceptor optimisticLockerInterceptor() { return new OptimisticLockerInterceptor(); } }
-
测试
//测试乐观锁:先查再改 @Test public void testOptimisticLocker(){ User user = userMapper.selectById(1373929950268137474L); user.setAge(200); //修改后乐观锁版本号变成+1 userMapper.updateById(user); }