好吧,考虑关注文档 link 以及 spring 数据测试 (link) 实际上对最终解决方案的贡献为 0。
考虑以下实体
@RedisHash(value = "myservice/lastactivity")
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class LastActivityCacheEntity implements Serializable {
@Id
@Indexed
@Size(max = 50)
private String user;
private long lastLogin;
private long lastProfileChange;
private long lastOperation;
}
假设:
-
我们不想在每次更新时都进行复杂的读写练习。
entity = lastActivityCacheRepository.findByUser(userId);
lastActivityCacheRepository.save(LastActivityCacheEntity.builder()
.user(entity.getUser())
.lastLogin(entity.getLastLogin())
.lastProfileChange(entity.getLastProfileChange())
.lastOperation(entity.getLastOperation()).build());
如果会弹出大约 100 行怎么办?然后在每个更新实体上获取并保存,效率很低,但仍然可以解决。
-
我们实际上并不希望使用 opsForHash + ObjectMapper + 配置 bean 方法进行复杂的练习 - 这很难实现和维护(例如 link)
所以我们要使用类似的东西:
@Autowired
private final RedisKeyValueTemplate redisTemplate;
void partialUpdate(LastActivityCacheEntity update) {
var partialUpdate = PartialUpdate
.newPartialUpdate(update.getUser(), LastActivityCacheEntity.class);
if (update.getLastLogin() > 0)
partialUpdate.set("lastlastLogin", update.getLastLogin());
if (update.getLastProfileChange() > 0)
partialUpdate.set("lastProfileChange", update.getLastProfileChange());
if (update.getLastOperation() > 0)
partialUpdate.set("lastOperation", update.getLastOperation());
redisTemplate.update(partialUpdate);
}
问题是 - 它不适用于这种情况。
也就是说,值会更新,但您以后无法通过存储库实体查找查询新属性:某些 lastActivityCacheRepository.findAll() 将返回未更改的属性。
解决办法如下:
LastActivityCacheRepository.java:
@Repository
public interface LastActivityCacheRepository extends CrudRepository<LastActivityCacheEntity, String>, LastActivityCacheRepositoryCustom {
Optional<LastActivityCacheEntity> findByUser(String user);
}
LastActivityCacheRepositoryCustom.java:
public interface LastActivityCacheRepositoryCustom {
void updateEntry(String userId, String key, long date);
}
LastActivityCacheRepositoryCustomImpl.java
@Repository
public class LastActivityCacheRepositoryCustomImpl implements LastActivityCacheRepositoryCustom {
@Autowired
private final RedisKeyValueTemplate redisKeyValueTemplate;
@Override
public void updateEntry(String userId, String key, long date) {
redisKeyValueTemplate.update(new PartialUpdate<>(userId, LastActivityCacheEntity.class)
.set(key, date));
}
}
最后是工作示例:
void partialUpdate(LastActivityCacheEntity update) {
if ((lastActivityCacheRepository.findByUser(update.getUser()).isEmpty())) {
lastActivityCacheRepository.save(LastActivityCacheEntity.builder().user(update.getUser()).build());
}
if (update.getLastLogin() > 0) {
lastActivityCacheRepository.updateEntry(update.getUser(),
"lastlastLogin",
update.getLastLogin());
}
if (update.getLastProfileChange() > 0) {
lastActivityCacheRepository.updateEntry(update.getUser(),
"lastProfileChange",
update.getLastProfileChange());
}
if (update.getLastOperation() > 0) {
lastActivityCacheRepository.updateEntry(update.getUser(),
"lastOperation",
update.getLastOperation());
}
感谢Chris Richardson 和他的src
如果您不想在updateEntry 方法中将字段名称键入为字符串,则可以在实体类@FieldNameConstants 上使用lombok 注释。这会为您创建字段名称常量,然后您可以像这样访问您的字段名称:
...
if (update.getLastOperation() > 0) {
lastActivityCacheRepository.updateEntry(update.getUser(),
LastActivityCache.Fields.lastOperation, // <- instead of "lastOperation"
update.getLastOperation());
...
这使得重构字段名称更加防错。