经验之谈

</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;
    }



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值