public class Submission {
private SubmissionId id;
private CodeSnippet code;
private SubmissionStatus status;
public void judge(JudgeEngine engine) {
JudgeResult result = engine.judge(this);
this.status = result.isAccepted() ? ACCEPTED : REJECTED;
}
}
@Service
public class SubmissionService {
@Autowired private SubmissionRepository repository;
@Autowired private JudgeEngineFactory engineFactory;
@Transactional
public void submitAndJudge(SubmitCommand cmd) {
Submission submission = Submission.create(cmd);
JudgeEngine engine = engineFactory.create(cmd.language());
submission.judge(engine); // 业务规则在领域对象里
repository.save(submission);
}
}
业务规则在 Submission.judge() 里,Service 只协调,不实现规则。
步骤 2:Identity Map——避免重复查询
@Component
public class UserIdentityMap {
private final Map<UserId, CfUser> cache = new ConcurrentHashMap<>();
public CfUser get(UserId id, Function<UserId, CfUser> loader) {
return cache.computeIfAbsent(id, loader);
}
public void clear() { cache.clear(); }
}
@Service
public class SubmissionQueryService {
@Autowired private UserIdentityMap userMap;
@Autowired private UserMapper userMapper;
public List<SubmissionDto> listByLesson(long lessonId) {
List<Submission> submissions = submissionMapper.selectByLesson(lessonId);
return submissions.stream().map(s -> {
// 同一用户多次出现也只查一次
CfUser user = userMap.get(s.getUserId(), id -> userMapper.selectById(id.value()));
return SubmissionDto.of(s, user.getNickname());
}).toList();
}
}
一个请求内,同一用户只查一次数据库,后续从 Identity Map 拿。
步骤 3:Unit of Work——批量提交变更
@Component
public class UnitOfWork {
private final List<Object> newObjects = new ArrayList<>();
private final List<Object> dirtyObjects = new ArrayList<>();
private final List<Object> removedObjects = new ArrayList<>();
public void registerNew(Object obj) { newObjects.add(obj); }
public void registerDirty(Object obj) { dirtyObjects.add(obj); }
public void registerRemoved(Object obj) { removedObjects.add(obj); }
@Transactional
public void commit() {
// 统一在事务内批量执行
newObjects.forEach(this::insert);
dirtyObjects.forEach(this::update);
removedObjects.forEach(this::delete);
clear();
}
}
判题平台里,一次提交要改 Submission、PracticeRecord、UserStat 三张表,Unit of Work 收集所有变更,最后一次事务提交。