乐观锁认为绝大部分情况下,不会同时修改数据,所以乐观锁不上锁,只是在更新的时候检查一下,在此期间是否修改了数据。要实现乐观锁我们需要给表新增一个 列,每次更新 都加 1,实现代码如下:
1.数据表和实体类新增 字段
// User.java
public class User {
private Long id;
private String name;
private String email;
private Long version; // 版本号
// 省略其他属性和方法...
}
2.业务层实现
// UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public ResponseEntity getUserById(Long userId) {
User user = userMapper.selectById(userId);
if (user == null) {
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
// 生成 ETag
String etag = ""user-" + user.getVersion() + """;
HttpHeaders headers = new HttpHeaders();
headers.setETag(etag);
return new ResponseEntity(user, headers, HttpStatus.OK);
}
@Override
@Transactional
public void updateUser(Long userId, User updatedUser, String ifMatch) {
// 获取当前数据库中的用户信息
User currentUser = userMapper.selectById(userId);
// 如果没有提供 If-Match,则允许更新
if (ifMatch == null) {
// 版本号递增
updatedUser.setVersion(updatedUser.getVersion() + 1);
// 更新用户信息
userMapper.updateById(updatedUser);
return;
}
// 校验 If-Match 请求头
String currentEtag = ""user-" + currentUser.getVersion() + """;
if (!currentEtag.equals(ifMatch)) {
throw new BusinessException("冲突:资源已被另一个请求修改");
}
// 版本号递增
updatedUser.setVersion(updatedUser.getVersion() + 1);
// 更新用户信息
userMapper.updateById(updatedUser);
}
}
假如有两个事务并发的事务 A 和事务 B,加上乐观锁后,如果事务 A 正在更新一行数据,而事务 B 在相同数据上进行读操作,事务 B 会选择等待,直到事务 A 完成。这是因为在 Read 隔离级别下,读取的事务会持有读锁,允许其他事务并行读取,但会阻止写入。
如果事务 A 正在更新一行数据,而事务 B 也尝试更新相同数据,事务 B 就会抛出异常(例如 tion)而不是等待。这是因为在 Read 隔离级别下,写入操作会持有写锁,不允许其他事务并行写入相同的数据。
3. 实现
// UserController.java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{userId}")
public ResponseEntity getUser(@PathVariable Long userId) {
return userService.getUserById(userId);
}
@PutMapping("/{userId}")
public ResponseEntity updateUser(
@PathVariable Long userId,
@RequestBody User updatedUser,
@RequestHeader(value = HttpHeaders.IF_MATCH, required = false) String ifMatch) {
try {
userService.updateUser(userId, updatedUser, ifMatch);
return new ResponseEntity("更新用户成功", HttpStatus.OK);
} catch (BusinessException e) {
return new ResponseEntity(e.getMessage(), HttpStatus.CONFLICT);
}
}
}
希望你觉得这篇文章有用。如果有任何问题或意见,请随时留言,感谢阅读!
———END———
限 时 特 惠: 本站每日持续更新海量各大内部创业教程,永久会员只需109元,全站资源免费下载 点击查看详情
站 长 微 信: nanadh666
声明:1、本内容转载于网络,版权归原作者所有!2、本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。3、本内容若侵犯到你的版权利益,请联系我们,会尽快给予删除处理!