当我获得带有
GlobalData
的 get(Class<T> clazz)
实例时,结果实体中的 data
为 null。
过滤掉日志后,发现有一个searize错误,导致
globalDataRepository.insert(data);
行抛出异常,但同时,错误的数据已经被@Cachable
中DataModelRepository
的机制缓存了。
get(Class<T> clazz)
public <T extends GlobalPersistable> T get(Class<T> clazz) {
int datatype = PersistableConverter.getDataType(clazz);
GlobalData data = globalDataRepository.select(datatype);
if (data == null) {
synchronized (this) {
if ((data = globalDataRepository.select(datatype)) == null) {
try {
data = new GlobalData<>();
data.setType(datatype);
data.setData(clazz.newInstance());
data = globalDataRepository.insert(data);
} catch (Exception e) {
log.error("", e);
return null;
}
}
}
}
return (T) data.getData();
}
GlobalData
:
@Data
@Entity
@Table(name = "global_data")
public class GlobalData<T extends Persistable> implements DataModel<Integer> {
@Id
private int type;
@Column(columnDefinition = "MEDIUMBLOB")
@Convert(converter = PersistableConverter.class)
private Persistable data;
@Override
public Integer getPK() {
return type;
}
@SuppressWarnings("unchecked")
public T getData() {
return (T) data;
}
}
存储库:
public interface DataModelRepository<T extends DataModel<PK>, PK> extends AppRepository<T, PK> {
String CACHE_NAME = "repository";
@Cacheable(cacheNames = CACHE_NAME, key = "#root.target.class.getInterfaces()[0].getSimpleName() + '@' + #pk", unless = "#result==null")
default T select(PK pk) {
return findById(pk).orElse(null);
}
@CachePut(cacheNames = CACHE_NAME, key = "#root.target.class.getInterfaces()[0].getSimpleName() + '@' + #entity.getPK()")
default T insert(T entity) {
return saveAndFlush(entity);
}
@Override
@CacheEvict(cacheNames = CACHE_NAME, key = "#root.target.class.getInterfaces()[0].getSimpleName() + '@' + #entity.getPK()")
void delete(@Nonnull T entity);
}
如果
insert
抛出异常,如何删除缓存?或者缓存实体直到插入正确完成?
如果该方法抛出异常,您可以捕获它并调用cancel方法。
这是我想到的最快的方法。 例如
public <T extends GlobalPersistable> method(String key) {
try {
return callMethodWithCacheable(key);
} catch (Exception e) {
callMethodWithEvict(key);
return null;
}
}
另一种方法是在调用 saveAndFlush 的方法中捕获异常并返回 Either (https://medium.com/disney-streaming/option-either-state-and-io-imperative-programming-in-a- function-world-8e176049af81#:~:text=In%20theory%2C%20Either%20can%20represent,a%20failure%20of%20type%20A%20.),如果 Either 包含填充的左侧位置,则调用删除方法
例如
public <T extends GlobalPersistable> method(String key) {
Either<Error, Success> successErrorEither = SafeExecution.exec(() -> callMethodWithCacheable(key));
if (successErrorEither.isLeft()) {
callMethodWithEvict(key);
return null; //In this point for me is better return Optional
} else {
return successErrorEither.getRight();
}
}