</pre>1 关于返回集合类型结构</h1><div>我们经常返回集合类型如List<T> 这样的结果集,但是当没有结果时,我们应当返回一个空集合(empty),而不是返回null。</div><div>这样在后续的使用中,不用担心空指针异常的问题,后面遍历的时候也不用判断是否为空了。</div><div></div><div>常见做法: </div><div><pre name="code" class="java">private List<Condition> conditions = Collections.emptyList();
List<BlockContent> bcs = Lists.newArrayList();
</pre>1 关于返回集合类型结构</h1><div>我们经常返回集合类型如List<T> 这样的结果集,但是当没有结果时,我们应当返回一个空集合(empty),而不是返回null。</div><div>这样在后续的使用中,不用担心空指针异常的问题,后面遍历的时候也不用判断是否为空了。</div><div></div><div>常见做法: </div><div><pre name="code" class="java">private List<Condition> conditions = Collections.emptyList();
List<BlockContent> bcs = Lists.newArrayList();
2 关于嵌套
场景:拿到一个集合,先判断他是否为空,再去遍历,然后又有一层if,这样就会有3层嵌套。
建议:类似于 for if 的嵌套最好不要超过3层,否则不便于阅读,也不便于业务的理解。
3 代码无注释
一致以为代码中写注释是一件非常必须且必要的事情,现在接触了"
无注释代码的概念",值得学习。
无注释代码的概念不是不写代码,而是只写少量的代码(比如在复杂方法写一两句注释描述其职能),更多的时候以下面的方式"写注释":
1 方法命名使用简单的动宾结构,以求规范、简洁明了
2 方法抽取:一个方法职责单一,只完成一个单独的功能
3 方法命名:业务层(service)以业务命名,数据控制层(dao\repository)以存在命名
4 编程注意
1. 尽量减少数据库的访问次数
1.1 1+N问题:
在批量更新时不用先从数据库选出目标结果集,然后在一个一个记录的更新,这样的话数据库的访问次数将会很多。
使用一条更新语句更新多条,在mongo中,提供updateMulti(query,update,clacc)方法。
public void setReportStatusAndDealTime(
Set<String> ids, ReportStatus queryStatus, ReportStatus targetStatus,
Date dealTime, long tenant) {
operations.updateMulti(
Query.query(where("tenant").is(tenant)
.and("reportStatus").is(queryStatus)
.and("_id").in(ids)),
Update.update("reportStatus", targetStatus)
.set("dealTime", dealTime),
ReportContent.class);
}
1.2 添加已存在的问题
N:先按照重复条件查询,若有结果,提示已存在,否则保存
Y:先保存,然后返旧的数据,若旧数据不为null,说明存在,再更新回去,然后提示已存在;不为null,即保存成功。
适用于重复情况不经常出现的情况。可以减少一次数据库查询。在mongo有findAndModify方法
public ReportContent addReportOrIncReportCount(ReportContent reportContent) {
Query query = Query.query(where("tenant").is(TenantHandler.getStrictTenant())
.and("sourceId").is(reportContent.getSourceId())
.and("scopeCode").is(reportContent.getScopeCode()));
Update update = getUpdate(reportContent);
return operations.findAndModify(
query, update,
options().upsert(true).returnNew(false),
ReportContent.class);
}
在service:
public void report(ReportContent content, ReportInfo info) {
if (CollectionUtils.isEmpty(forbidSettingService.findByCode(content.getScopeCode()))) {
throw WafI18NException.of("屏蔽范围不存在", com.nd.social.common.constant.ErrorCode.INVALID_ARGUMENT);
}
Date reportTime = new Date();
String contentId = ObjectId.get().toString();
content.setId(contentId);
content.setReportStatus(ReportStatus.UNTREATED);
content.setLastReportTime(reportTime);
content = repository.addReportOrIncReportCount(content);
if (content != null) {
contentId = content.getId();
if (ReportStatus.BLOCKED == content.getReportStatus()) {
update(content);
throw WafI18NException.of("已被屏蔽的举报内容不能被再次举报", ErrorCode.INVALID_ARGUMENT);
}
}
info.setReportTime(reportTime);
info.setReportContentId(contentId);
info.setDealTime(null);
info.setId(null);
reportInfoService.add(info);
}
5 mongo索引优化
在程序开发完毕后,进行压测;弱爆结果不理想,考虑使用索引优化。
一般选择高散列程度的键做索引,或者在组合索引中,把高散列程度的键放在前面
@Document(collection = "#{T(com.nd.social.common.handler.TenantHandler).getTablePrefix().concat('block_content')}")
@CompoundIndexes(
@CompoundIndex(name = "idx_bc_t_sc_s", def = "{'tenant':1,'scope.code':1,'sourceId':1}", unique = true)
)
@TypeAlias("BlockContent")
public class BlockContent extends BaseContent {
// ... ...
}
6 三层结构
1 domain类
1.1 若公共属性较多,可以抽取出为基类(BaseDomain),然后在子类中自定义自身的属性。
1.2 属性
必填:不为空(null empty) 长度限制
选填:长度限制
不填:设置默认值,重要字段值要在后台设置,防止用户设定
2 repository :spring data
BlockContentRepository -- 常规spring data操作
BlockContentRepositoryCustom -- 自定义操作接口 实现复杂的常规springdata难以实现的操作
BlockContentRepositoryImpl -- 自定义接口实现
@Repository
public interface BlockContentRepository extends BaseTenantRepository<BlockContent, String>, BlockContentRepositoryCustom {
List<BlockContent> findByIdInAndBlockStatusAndTenant(Set<String> ids, BlockStatus status, long tenant);
}
public interface BlockContentRepositoryCustom {
Items<BlockContent> listByScopeCode(Set<String> scopeCodes, ListParam<BlockContent> listParam, Long tenant);
void setBlockStatusAndRecoverTime(Set<String> ids, long tenant, Date recoverTime);
BlockContent addBlock(BlockContent blockContent, long tenant);
}
public class BlockContentRepositoryImpl extends SimpleMongoRepository<BlockContent, String> implements BlockContentRepositoryCustom {
private MongoOperations operations;
private MongoEntityInformation<BlockContent, String> entityInformation;
<strong> @Autowired
public BlockContentRepositoryImpl(MongoRepositoryFactory factory, MongoOperations mongoOperations) {
super(factory.<BlockContent, String>getEntityInformation(BlockContent.class), mongoOperations);
this.operations = mongoOperations;
this.entityInformation = factory.<BlockContent, String>getEntityInformation(BlockContent.class);
}</strong>
public void setBlockStatusAndRecoverTime(Set<String> ids, long tenant, Date recoverTime) {
Query query = Query.query(
where("_id").in(ids)
.and("tenant").is(tenant)
.and("blockStatus").is(BlockStatus.BLOCKED));
operations.updateMulti(
query,
Update.update("blockStatus", BlockStatus.RECOVER)
.set("recoverTime", recoverTime),
BlockContent.class
);
}
jpa的定制接口实现:
public class ProjectRepositoryImpl extends SimpleJpaRepository<Project, String>, implements ProjectRepositoryCustomer {
@Autowired
public ProjectRepositoryImpl(EntityManager entityManager) {
super(JpaMetamodelEntityInformation.getEntityInformation(Project.class, entityManager), entityManager);
}
}
mongo的定制接口实现:
public class BlockContentRepositoryImpl extends SimpleMongoRepository<BlockContent, String> implements BlockContentRepositoryCustom {
private MongoOperations operations;
private MongoEntityInformation<BlockContent, String> entityInformation;
@Autowired
public BlockContentRepositoryImpl(MongoRepositoryFactory factory, MongoOperations mongoOperations) {
super(factory.<BlockContent, String>getEntityInformation(BlockContent.class), mongoOperations);
this.operations = mongoOperations;
this.entityInformation = factory.<BlockContent, String>getEntityInformation(BlockContent.class);
}
}
如果只是为了修改原有的方法,可以这样:
@Repository
public class ProjectRepositoryImpl extends SimpleJpaRepository<Project, String> { @Autowired
public ProjectRepositoryImpl(EntityManager entityManager) {
super(JpaMetamodelEntityInformation.getEntityInformation(Project.class, entityManager), entityManager);
}
@Repository
public class ForbidSettingRepositoryImpl extends SimpleMongoRepository<ForbidSetting, String> {
private MongoOperations mongoOperations;
@Autowired
public ForbidSettingRepositoryImpl(MongoRepositoryFactory factory, MongoOperations mongoOperations) {
super(factory.<ForbidSetting, String>getEntityInformation(ForbidSetting.class), mongoOperations);
this.mongoOperations = mongoOperations;
}