记一次新建操作(insert)的优化过程
程序员文章站
2022-07-13 08:07:34
...
1.插入操作的sql语句
Mysql的 insert常用方法——插入后返回插入成功后的主键
<operation name="insert" paramtype="object">
<sql>
<![CDATA[
INSERT INTO ucdp_budget_plan
(gmt_create,gmt_modified,biz_date,status,name,biz_code,scene_code,lasted_operator,plan_type,bu_info,total,budget_elements,assign_config,notify_time,digest,environment)
VALUES
(CURRENT_TIMESTAMP,CURRENT_TIMESTAMP,?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)
]]>
</sql>
<sqlmap>
<![CDATA[
INSERT INTO ucdp_budget_plan(gmt_create,gmt_modified,biz_date,status,name,biz_code,scene_code,lasted_operator,plan_type,bu_info,total,budget_elements,assign_config,notify_time,digest,environment)
VALUES(CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, #bizDate#, #status#,#name#, #bizCode#, #sceneCode#, #lastedOperator#, #planType#,#buInfo#,#total#, #budgetElements#, #assignConfig#, #notifyTime#,#digest#,#environment#)
<selectKey resultClass="long" keyProperty="id" type="post">
SELECT LAST_INSERT_ID()
</selectKey>
]]>
</sqlmap>
</operation>
上面的方法利用的是mysql的LAST_INSERT_ID()函数会返回当前连接上次插入记录的自增主键。
2.Repo层的一写多读模式,层层优化
- 最原始语句
public long insert(BudgetPlanBO budgetPlanBO) {
LoggerUtil.debug(LOGGER, "insert", budgetPlanBO);
return ucdpBudgetPlanDAO.insert(BudgetPlanConvertor.convertBOtoDO(budgetPlanBO));
}
- 添加唯一索引防重插功能
public long insert(BudgetPlanBO budgetPlanBO) {
LoggerUtil.debug(LOGGER, "insert", budgetPlanBO);
try {
return ucdpBudgetPlanDAO.insert(BudgetPlanConvertor.convertBOtoDO(budgetPlanBO));
} catch (DuplicateKeyException e) {
return ucdpBudgetPlanDAO.queryByUniqueId(budgetPlanBO.getPlanType().name(), budgetPlanBO.getBizDate(),
budgetPlanBO.getBizCode()).getId();
}
}
以上的日志打印存在严重问题,不仅在线上环境打不了日志,而且打出来的日志没有具体参数,没有排查的实际帮助意义。
- 优化日志版
public long insert(BudgetPlanBO budgetPlanBO) {
LoggerUtil.info(LOGGER, "[createBudget]插入预算:{0}", budgetPlanBO);
try {
//same as above.
} catch (DuplicateKeyException e) {
//same as above.
}
}
存在两个问题:
以上语句只是一次创建,在实际项目中一个接口要进行200+次的批量创建。开发环境没问题,但在预发环境中批量创建出现了部分成功部分失败的问题。唯一索引的搜索,使得本语句变成了一写多读的情况。就会导致一直返回0,因为写连接跟读连接不是同一个,解决方法是通过开启事务,强制使用同一连接进行读写。除非一定要获取插入id的情况,否则不推荐使用事务来获取插入id。
- 添加事务版
public long insert(BudgetPlanBO budgetPlanBO) {
LoggerUtil.info(LOGGER, "[createBudget]插入预算:{0}", budgetPlanBO);
return this.ucdpMngTransactionTemplate.execute(new TransactionCallback<Long>() {
@Override
public Long doInTransaction(TransactionStatus transactionStatus) {
try {
return ucdpBudgetPlanDAO.insert(BudgetPlanConvertor.convertBOtoDO(budgetPlanBO));
} catch (DuplicateKeyException e) {
return ucdpBudgetPlanDAO.queryByUniqueId(budgetPlanBO.getPlanType().name(), budgetPlanBO.getBizDate(),
budgetPlanBO.getBizCode()).getId();
} catch (Throwable e) {
LoggerUtil.error(LOGGER, "[insert]插入预算异常, Exception={0}", JSON.toJSONString(e));
transactionStatus.setRollbackOnly();
throw new UcdpMngException(e.getMessage());
}
}
});
}
推荐阅读
-
记一次Elasticsearch OOM的优化过程——基于segments force merge 和 store type 转为 niofs
-
记一次ubuntu的误操作(ubuntu删除compiz后恢复过程)
-
记一次动态规划优化的过程
-
记一次新建操作(insert)的优化过程
-
记一次SPA项目打包优化的过程
-
【CentOS 7】记一次迁移 Docker 容器存储目录的操作过程
-
记一次Android下载过程的内存优化
-
记一次新建操作(insert)的优化过程
-
记一次Elasticsearch OOM的优化过程——基于segments force merge 和 store type 转为 niofs
-
记一次新建操作(insert)的优化过程