序
本文主要研究一下nacos config的deleteConfig
ConfigController
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/controller/ConfigController.java
@Controller
@RequestMapping(Constants.CONFIG_CONTROLLER_PATH)
public class ConfigController {
private static final Logger log = LoggerFactory.getLogger(ConfigController.class);
private static final String NAMESPACE_PUBLIC_KEY = "public";
public static final String EXPORT_CONFIG_FILE_NAME = "nacos_config_export_";
public static final String EXPORT_CONFIG_FILE_NAME_EXT = ".zip";
public static final String EXPORT_CONFIG_FILE_NAME_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
private final transient ConfigServletInner inner;
private final transient PersistService persistService;
private final transient ConfigSubService configSubService;
//......
/**
* 同步删除某个dataId下面所有的聚合前数据
*
* @throws NacosException
*/
@RequestMapping(method = RequestMethod.DELETE)
@ResponseBody
public Boolean deleteConfig(HttpServletRequest request, HttpServletResponse response,
@RequestParam("dataId") String dataId, //
@RequestParam("group") String group, //
@RequestParam(value = "tenant", required = false, defaultValue = StringUtils.EMPTY)
String tenant,
@RequestParam(value = "tag", required = false) String tag) throws NacosException {
ParamUtils.checkParam(dataId, group, "datumId", "rm");
ParamUtils.checkParam(tag);
String clientIp = RequestUtil.getRemoteIp(request);
if (StringUtils.isBlank(tag)) {
persistService.removeConfigInfo(dataId, group, tenant, clientIp, null);
} else {
persistService.removeConfigInfoTag(dataId, group, tenant, tag, clientIp, null);
}
final Timestamp time = TimeUtils.getCurrentTime();
ConfigTraceService.logPersistenceEvent(dataId, group, tenant, null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, dataId, group, tenant, tag, time.getTime()));
return true;
}
/**
* @author klw
* @Description: delete configuration based on multiple config ids
* @Date 2019/7/5 10:26
* @Param [request, response, dataId, group, tenant, tag]
* @return java.lang.Boolean
*/
@RequestMapping(params = "delType=ids", method = RequestMethod.DELETE)
@ResponseBody
public RestResult<Boolean> deleteConfigs(HttpServletRequest request, HttpServletResponse response,
@RequestParam(value = "ids")List<Long> ids) {
String clientIp = RequestUtil.getRemoteIp(request);
final Timestamp time = TimeUtils.getCurrentTime();
List<ConfigInfo> configInfoList = persistService.removeConfigInfoByIds(ids, clientIp, null);
if(!CollectionUtils.isEmpty(configInfoList)){
for(ConfigInfo configInfo : configInfoList) {
ConfigTraceService.logPersistenceEvent(configInfo.getDataId(), configInfo.getGroup(),
configInfo.getTenant(), null, time.getTime(), clientIp,
ConfigTraceService.PERSISTENCE_EVENT_REMOVE, null);
EventDispatcher.fireEvent(new ConfigDataChangeEvent(false, configInfo.getDataId(),
configInfo.getGroup(), configInfo.getTenant(), time.getTime()));
}
}
return ResultBuilder.buildSuccessResult(true);
}
//......
}
- deleteConfig方法主要是调用persistService.removeConfigInfo或者persistService.removeConfigInfoTag;deleteConfigs方法主要是调用persistService.removeConfigInfoByIds
PersistService
nacos-1.1.3/config/src/main/java/com/alibaba/nacos/config/server/service/PersistService.java
@Repository
public class PersistService {
@Autowired
private DynamicDataSource dynamicDataSource;
private DataSourceService dataSourceService;
private static final String SQL_FIND_ALL_CONFIG_INFO = "select data_id,group_id,tenant_id,app_name,content,type from config_info";
private static final String SQL_TENANT_INFO_COUNT_BY_TENANT_ID = "select count(1) from tenant_info where tenant_id = ?";
private static final String SQL_FIND_CONFIG_INFO_BY_IDS = "SELECT ID,data_id,group_id,tenant_id,app_name,content,md5 FROM config_info WHERE ";
private static final String SQL_DELETE_CONFIG_INFO_BY_IDS = "DELETE FROM config_info WHERE ";
/**
* @author klw
* @Description: constant variables
*/
public static final String SPOT = ".";
@PostConstruct
public void init() {
dataSourceService = dynamicDataSource.getDataSource();
jt = getJdbcTemplate();
tjt = getTransactionTemplate();
}
//......
/**
* 删除配置信息, 物理删除
*/
public void removeConfigInfo(final String dataId, final String group, final String tenant, final String srcIp,
final String srcUser) {
tjt.execute(new TransactionCallback<Boolean>() {
final Timestamp time = new Timestamp(System.currentTimeMillis());
@Override
public Boolean doInTransaction(TransactionStatus status) {
try {
ConfigInfo configInfo = findConfigInfo(dataId, group, tenant);
if (configInfo != null) {
removeConfigInfoAtomic(dataId, group, tenant, srcIp, srcUser);
removeTagByIdAtomic(configInfo.getId());
insertConfigHistoryAtomic(configInfo.getId(), configInfo, srcIp, srcUser, time, "D");
}
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
return Boolean.TRUE;
}
});
}
/**
* 删除配置;数据库原子操作,最小sql动作,无业务封装
*
* @param dataId dataId
* @param group group
* @param tenant tenant
* @param tag tag
* @param srcIp ip
* @param srcUser user
*/
public void removeConfigInfoTag(final String dataId, final String group, final String tenant, final String tag,
final String srcIp,
final String srcUser) {
String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
String tagTmp = StringUtils.isBlank(tag) ? StringUtils.EMPTY : tag;
try {
jt.update("DELETE FROM config_info_tag WHERE data_id=? AND group_id=? AND tenant_id=? AND tag_id=?", dataId,
group,
tenantTmp, tagTmp);
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* @author klw
* @Description: delete config info by ids
* @Date 2019/7/5 16:45
* @Param [ids, srcIp, srcUser]
* @return List<ConfigInfo> deleted configInfos
*/
public List<ConfigInfo> removeConfigInfoByIds(final List<Long> ids, final String srcIp, final String srcUser) {
if(CollectionUtils.isEmpty(ids)){
return null;
}
ids.removeAll(Collections.singleton(null));
return tjt.execute(new TransactionCallback<List<ConfigInfo>>() {
final Timestamp time = new Timestamp(System.currentTimeMillis());
@Override
public List<ConfigInfo> doInTransaction(TransactionStatus status) {
try {
String idsStr = Joiner.on(",").join(ids);
List<ConfigInfo> configInfoList = findConfigInfosByIds(idsStr);
if (!CollectionUtils.isEmpty(configInfoList)) {
removeConfigInfoByIdsAtomic(idsStr);
for(ConfigInfo configInfo : configInfoList){
removeTagByIdAtomic(configInfo.getId());
insertConfigHistoryAtomic(configInfo.getId(), configInfo, srcIp, srcUser, time, "D");
}
}
return configInfoList;
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
});
}
/**
* 删除配置;数据库原子操作,最小sql动作,无业务封装
*
* @param dataId dataId
* @param group group
* @param tenant tenant
* @param srcIp ip
* @param srcUser user
*/
private void removeConfigInfoAtomic(final String dataId, final String group, final String tenant,
final String srcIp,
final String srcUser) {
String tenantTmp = StringUtils.isBlank(tenant) ? StringUtils.EMPTY : tenant;
try {
jt.update("DELETE FROM config_info WHERE data_id=? AND group_id=? AND tenant_id=?", dataId, group,
tenantTmp);
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
public void removeTagByIdAtomic(long id) {
try {
jt.update("DELETE FROM config_tags_relation WHERE id=?", id);
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* 更新变更记录;数据库原子操作,最小sql动作,无业务封装
*
* @param id id
* @param configInfo config info
* @param srcIp ip
* @param srcUser user
* @param time time
* @param ops ops type
*/
private void insertConfigHistoryAtomic(long id, ConfigInfo configInfo, String srcIp, String srcUser,
final Timestamp time, String ops) {
String appNameTmp = StringUtils.isBlank(configInfo.getAppName()) ? StringUtils.EMPTY : configInfo.getAppName();
String tenantTmp = StringUtils.isBlank(configInfo.getTenant()) ? StringUtils.EMPTY : configInfo.getTenant();
final String md5Tmp = MD5.getInstance().getMD5String(configInfo.getContent());
try {
jt.update(
"INSERT INTO his_config_info (id,data_id,group_id,tenant_id,app_name,content,md5,src_ip,src_user,gmt_modified,op_type) VALUES(?,?,?,?,?,?,?,?,?,?,?)",
id, configInfo.getDataId(), configInfo.getGroup(), tenantTmp, appNameTmp, configInfo.getContent(),
md5Tmp, srcIp, srcUser, time, ops);
} catch (DataAccessException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* @author klw
* @Description: find ConfigInfo by ids
* @Date 2019/7/5 16:37
* @Param [ids]
* @return java.util.List<com.alibaba.nacos.config.server.model.ConfigInfo>
*/
public List<ConfigInfo> findConfigInfosByIds(final String ids) {
if(StringUtils.isBlank(ids)){
return null;
}
StringBuilder sql = new StringBuilder(SQL_FIND_CONFIG_INFO_BY_IDS);
sql.append("id in (");
List<Long> paramList = new ArrayList<>();
String[] tagArr = ids.split(",");
for (int i = 0; i < tagArr.length; i++) {
if (i != 0) {
sql.append(", ");
}
sql.append("?");
paramList.add(Long.valueOf(tagArr[i]));
}
sql.append(") ");
try {
return this.jt.query(sql.toString(), paramList.toArray(), CONFIG_INFO_ROW_MAPPER);
} catch (EmptyResultDataAccessException e) { // 表明数据不存在, 返回null
return null;
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
/**
* @author klw
* @Description: Delete configuration; database atomic operation, minimum SQL action, no business encapsulation
* @Date 2019/7/5 16:39
* @Param [id]
* @return void
*/
private void removeConfigInfoByIdsAtomic(final String ids) {
if(StringUtils.isBlank(ids)){
return;
}
StringBuilder sql = new StringBuilder(SQL_DELETE_CONFIG_INFO_BY_IDS);
sql.append("id in (");
List<Long> paramList = new ArrayList<>();
String[] tagArr = ids.split(",");
for (int i = 0; i < tagArr.length; i++) {
if (i != 0) {
sql.append(", ");
}
sql.append("?");
paramList.add(Long.valueOf(tagArr[i]));
}
sql.append(") ");
try {
jt.update(sql.toString(), paramList.toArray());
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
}
}
//......
}
- removeConfigInfo方法在事务中执行removeConfigInfoAtomic、removeTagByIdAtomic、insertConfigHistoryAtomic;removeConfigInfoTag方法直接从config_info_tag表删除对应的数据;removeConfigInfoByIds方法在事务中执行findConfigInfosByIds、removeConfigInfoByIdsAtomic、removeTagByIdAtomic、insertConfigHistoryAtomic方法
- removeConfigInfoAtomic方法直接从config_info表删除数据;removeTagByIdAtomic方法直接从config_tags_relation表删除数据;insertConfigHistoryAtomic方法往his_config_info插入数据
- findConfigInfosByIds方法根据id从config_info表查询记录;removeConfigInfoByIdsAtomic至二级根据id从config_info表删除记录
小结
ConfigController的deleteConfig方法主要是调用persistService.removeConfigInfo或者persistService.removeConfigInfoTag;deleteConfigs方法主要是调用persistService.removeConfigInfoByIds