Elasticsearch 8.9 服务端接收创建索引和查询索引信息源码

本文主要是介绍Elasticsearch 8.9 服务端接收创建索引和查询索引信息源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  • 一、创建索引
    • 1、接收创建索引的RestCreateIndexAction
    • 2、Master执行创建索引的类TransportCreateIndexAction
    • 3、创建一个任务(创建索引的),放入一个队列
    • 4、执行创建索引时会先搜索模版
    • 5、创建索引的build,更新集群状态
      • (1) initializeEmpty初始化索引的分片,副本等
      • (2) 添加索引信息到indicesRouting
      • (3) 创建一个新的集群状态返回
  • 二、查询索引信息
    • 1 接收查询索引信息的RestCreateIndexAction
    • 2、实际查询的TransportGetIndexAction.java的doMasterOperation方法
      • (1)查询的索引信息都是从集群状态中ImmutableOpenMap<String, IndexMetadata>得到的

至于下面创建索引和查询索引信息的入口如何找到的,可以Elasticsearch 8.9启动时构建接收Rest请求的hander过程源码

一、创建索引

1、接收创建索引的RestCreateIndexAction

public class RestCreateIndexAction extends BaseRestHandler {@Overridepublic List<Route> routes() {return List.of(new Route(PUT, "/{index}"));}@Overridepublic RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {CreateIndexRequest createIndexRequest;//下面是区分es7和es8,创建索引的结构有一点区别,但是不用细究if (request.getRestApiVersion() == RestApiVersion.V_7) {createIndexRequest = prepareRequestV7(request);} else {createIndexRequest = prepareRequest(request);}//这个会通知让master执行创建索引操作return channel -> client.admin().indices().create(createIndexRequest, new RestToXContentListener<>(channel));}
}    

channel -> client.admin().indices().create(createIndexRequest, new RestToXContentListener<>(channel))至于这个如何通知master执行的,可以看一下Elasticsearch 8.9 Master节点处理请求源码

2、Master执行创建索引的类TransportCreateIndexAction

@Overrideprotected void masterOperation(Task task,final CreateIndexRequest request,final ClusterState state,final ActionListener<CreateIndexResponse> listener) {createIndexService.createIndex(updateRequest,listener.map(response -> new CreateIndexResponse(response.isAcknowledged(), response.isShardsAcknowledged(), indexName)));}
    / *在集群状态下创建索引,并等待指定数量的分片副本变为活动状态(如 {@link CreateIndexClusterStateUpdateRequestwaitForActiveShards()} 中指定),然后再在侦听器上发送响应。* 如果索引创建已成功应用于集群状态,则 {@link ShardsAcknowledgedResponseisAcknowledged()} 将返回 true* 否则它将返回 false,并且不会等待启动的分片({@link ShardsAcknowledgedResponseisShardsAcknowledged()} 也将为 false)。* 如果集群状态下的索引创建成功,并且在超时之前启动了必要的分片副本,则 {@link ShardsAcknowledgedResponseisShardsAcknowledged()} 将返回 true* 否则如果操作超时,则返回 false*/public void createIndex(final CreateIndexClusterStateUpdateRequest request, final ActionListener<ShardsAcknowledgedResponse> listener) {logger.trace("createIndex[{}]", request);onlyCreateIndex(request, listener.delegateFailureAndWrap((delegate, response) -> {//如果确认创建索引,则等待活动分片的数量满足要求。if (response.isAcknowledged()) {//省略代码//等待索引的分片活跃ActiveShardsObserver.waitForActiveShards(clusterService,new String[] { request.index() },request.waitForActiveShards(),request.ackTimeout(),delegate.map(shardsAcknowledged -> {//省略代码return ShardsAcknowledgedResponse.of(true, shardsAcknowledged);}));} else {//如果超时等待分片启动,记录日志。//最后返回一个ShardsAcknowledgedResponse对象,表示索引创建没有成功。logger.trace("index creation not acknowledged for [{}]", request);delegate.onResponse(ShardsAcknowledgedResponse.NOT_ACKNOWLEDGED);}}));}

3、创建一个任务(创建索引的),放入一个队列

 private void onlyCreateIndex(final CreateIndexClusterStateUpdateRequest request, final ActionListener<AcknowledgedResponse> listener) {//省略代码//调用submitUnbatchedTask方法提交一个任务。该任务是一个AckedClusterStateUpdateTask对象,该对象继承自ClusterStateUpdateTask类,用于执行集群状态更新任务。submitUnbatchedTask("create-index [" + request.index() + "], cause [" + request.cause() + "]",new AckedClusterStateUpdateTask(Priority.URGENT, request, delegate.clusterStateUpdate()) {//在execute方法中,会调用applyCreateIndexRequest方法来处理创建索引的请求。@Overridepublic ClusterState execute(ClusterState currentState) throws Exception {return applyCreateIndexRequest(currentState, request, false, null, delegate.reroute());}//省略代码});}
private void submitUnbatchedTask(@SuppressWarnings("SameParameterValue") String source, ClusterStateUpdateTask task) {clusterService.submitUnbatchedStateUpdateTask(source, task);}
 @Deprecated@SuppressForbidden(reason = "this method is itself forbidden")public void submitUnbatchedStateUpdateTask(String source, ClusterStateUpdateTask updateTask) {masterService.submitUnbatchedStateUpdateTask(source, updateTask);}
@Deprecatedpublic void submitUnbatchedStateUpdateTask(String source, ClusterStateUpdateTask updateTask) {createTaskQueue("unbatched", updateTask.priority(), unbatchedExecutor).submitTask(source, updateTask, updateTask.timeout());}

createTaskQueue返回的队列再执行submitTask方法

 public <T extends ClusterStateTaskListener> MasterServiceTaskQueue<T> createTaskQueue(String name,Priority priority,ClusterStateTaskExecutor<T> executor) {return new BatchingTaskQueue<>(name,this::executeAndPublishBatch,insertionIndexSupplier,queuesByPriority.get(priority),executor,threadPool);}
 @Overridepublic void submitTask(String source, T task, @Nullable TimeValue timeout) {final var executed = new AtomicBoolean(false);final Scheduler.Cancellable timeoutCancellable;if (timeout != null && timeout.millis() > 0) {timeoutCancellable = threadPool.schedule(new TaskTimeoutHandler(timeout, source, executed, task),timeout,ThreadPool.Names.GENERIC);} else {timeoutCancellable = null;}queue.add(new Entry<>(source,task,insertionIndexSupplier.getAsLong(),threadPool.relativeTimeInMillis(),executed,threadPool.getThreadContext().newRestorableContext(true),timeoutCancellable));if (queueSize.getAndIncrement() == 0) {perPriorityQueue.execute(processor);}}

4、执行创建索引时会先搜索模版

public ClusterState applyCreateIndexRequest(ClusterState currentState,CreateIndexClusterStateUpdateRequest request,boolean silent,BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer,ActionListener<Void> rerouteListener) throws Exception {//对请求的设置进行规范化和验证。//省略代码//并尝试匹配v2模板final String v2Template = MetadataIndexTemplateService.findV2Template(currentState.metadata(),name,isHiddenFromRequest != null && isHiddenFromRequest);//如果找到了v2模板,则使用该模板和请求指定的设置创建索引。if (v2Template != null) {return applyCreateIndexRequestWithV2Template(currentState,request,silent,v2Template,metadataTransformer,rerouteListener);} else {          //没有找到v2模板,则检查v1模板,如果没有找到任何模板,则使用请求指定的索引设置创建索引。final List<IndexTemplateMetadata> v1Templates = MetadataIndexTemplateService.findV1Templates(currentState.metadata(),request.index(),isHiddenFromRequest);//如果v1Templates不存在,则根据请求指定的索引设置创建索引(下面的v1Templates的size为0)return applyCreateIndexRequestWithV1Templates(currentState,request,silent,v1Templates,metadataTransformer,rerouteListener);}}

这里是因为模版版本的不同,因为模版不一样,所以需要把请求中的索引信息和模版中的索引信息合并一下,最后调用applyCreateIndexWithTemporaryService创建索引

 private ClusterState applyCreateIndexRequestWithV2Template(final ClusterState currentState,final CreateIndexClusterStateUpdateRequest request,final boolean silent,final String templateName,final BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer,final ActionListener<Void> rerouteListener) throws Exception {//创建索引return applyCreateIndexWithTemporaryService(currentState,request,silent,null,tmpImd,mappings,indexService -> resolveAndValidateAliases(request.index(),// data stream aliases are created separately in MetadataCreateDataStreamService::createDataStreamisDataStream ? Set.of() : request.aliases(),isDataStream ? List.of() : MetadataIndexTemplateService.resolveAliases(currentState.metadata(), templateName),currentState.metadata(),xContentRegistry,// the context is used ony for validation so it's fine to pass fake values for the shard id and the current timestampindexService.newSearchExecutionContext(0, 0, null, () -> 0L, null, emptyMap()),IndexService.dateMathExpressionResolverAt(request.getNameResolvedAt()),systemIndices::isSystemName),Collections.singletonList(templateName),metadataTransformer,rerouteListener);}
  private ClusterState applyCreateIndexRequestWithV1Templates(final ClusterState currentState,final CreateIndexClusterStateUpdateRequest request,final boolean silent,final List<IndexTemplateMetadata> templates,final BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer,final ActionListener<Void> rerouteListener) throws Exception {//应用临时服务创建索引(applyCreateIndexWithTemporaryService),包括当前状态(currentState)、请求(request)、是否静默(silent)、临时索引元数据(tmpImd)、索引映射(mappings)、解析和验证别名等。return applyCreateIndexWithTemporaryService(currentState,request,silent,null,tmpImd,mappings == null ? List.of() : List.of(mappings),indexService -> resolveAndValidateAliases(request.index(),request.aliases(),MetadataIndexTemplateService.resolveAliases(templates),currentState.metadata(),// the context is only used for validation so it's fine to pass fake values for the// shard id and the current timestampxContentRegistry,indexService.newSearchExecutionContext(0, 0, null, () -> 0L, null, emptyMap()),IndexService.dateMathExpressionResolverAt(request.getNameResolvedAt()),systemIndices::isSystemName),templates.stream().map(IndexTemplateMetadata::getName).collect(toList()),metadataTransformer,rerouteListener);
}

5、创建索引的build,更新集群状态

 private ClusterState applyCreateIndexWithTemporaryService(final ClusterState currentState,final CreateIndexClusterStateUpdateRequest request,final boolean silent,final IndexMetadata sourceMetadata,final IndexMetadata temporaryIndexMeta,final List<CompressedXContent> mappings,final Function<IndexService, List<AliasMetadata>> aliasSupplier,final List<String> templatesApplied,final BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer,final ActionListener<Void> rerouteListener) throws Exception {//省略代码//创建索引并返回更新后的集群状态,在创建索引时,会考虑一些参数,如阻塞状态、索引元数据、分配策略等ClusterState updated = clusterStateCreateIndex(currentState,request.blocks(),indexMetadata,metadataTransformer,allocationService.getShardRoutingRoleStrategy());//省略代码   return updated;
}
 /*** 应用提供的块将索引创建为群集状态。最终群集状态将包含基于活动节点的更新路由表。*/static ClusterState clusterStateCreateIndex(ClusterState currentState, //集群状态Set<ClusterBlock> clusterBlocks, //集群阻塞IndexMetadata indexMetadata, //索引元数据BiConsumer<Metadata.Builder, IndexMetadata> metadataTransformer, //元数据转换器ShardRoutingRoleStrategy shardRoutingRoleStrategy //分片路由角色策略) {//是否存在元数据转换器来创建新的元数据对象final Metadata newMetadata;if (metadataTransformer != null) {//如果存在元数据转换器,则使用转换器将索引元数据应用到当前的元数据上,生成新的元数据对象;Metadata.Builder builder = Metadata.builder(currentState.metadata()).put(indexMetadata, false);metadataTransformer.accept(builder, indexMetadata);newMetadata = builder.build();} else {//否则,直接将索引元数据添加到当前的元数据中newMetadata = currentState.metadata().withAddedIndex(indexMetadata);}//索引名称和集群阻塞创建集群阻塞构建器,并更新阻塞信息String indexName = indexMetadata.getIndex().getName();ClusterBlocks.Builder blocks = createClusterBlocksBuilder(currentState, indexName, clusterBlocks);blocks.updateBlocks(indexMetadata);//使用新的元数据对象和更新后的集群阻塞信息构建一个更新后的集群状态对象ClusterState updatedState = ClusterState.builder(currentState).blocks(blocks).metadata(newMetadata).build();//根据分片路由角色策略和更新后的集群状态的路由表构建器,将索引添加为新的索引,RoutingTable.Builder routingTableBuilder = RoutingTable.builder(shardRoutingRoleStrategy, updatedState.routingTable()).addAsNew(updatedState.metadata().index(indexName));//并返回更新后的集群状态对象return ClusterState.builder(updatedState).routingTable(routingTableBuilder.build()).build();}

注意上面的.addAsNew(updatedState.metadata().index(indexName))

//向构建器中添加一个新的索引元数据,其中initializeAsNew会初始化索引,初始化分片和副本信息public Builder addAsNew(IndexMetadata indexMetadata) {//检查索引的状态是否为"OPEN"if (indexMetadata.getState() == IndexMetadata.State.OPEN) {//创建一个新的IndexRoutingTable.Builder对象,并使用给定的索引元数据进行初始化。然后将该对象添加到构建器中,并返回构建器本身org.elasticsearch.cluster.routing.IndexRoutingTable.Builder indexRoutingBuilder = new org.elasticsearch.cluster.routing.IndexRoutingTable.Builder(shardRoutingRoleStrategy,indexMetadata.getIndex()).initializeAsNew(indexMetadata);//添加索引add(indexRoutingBuilder);}return this;}

其中initializeAsNew初始化这个索引,包括索引在集群上的分片,节点等

(1) initializeEmpty初始化索引的分片,副本等

  public Builder initializeAsNew(IndexMetadata indexMetadata) {return initializeEmpty(indexMetadata, new UnassignedInfo(UnassignedInfo.Reason.INDEX_CREATED, null), null);}
 private Builder initializeEmpty(IndexMetadata indexMetadata,//索引元数据UnassignedInfo unassignedInfo,//未分配信息@Nullable IndexRoutingTable previousIndexRoutingTable //之前的索引路由表作为参数。) {assert indexMetadata.getIndex().equals(index);assert previousIndexRoutingTable == null || previousIndexRoutingTable.size() == indexMetadata.getNumberOfShards();//如果已经存在分片(shards),则抛出异常,表示无法初始化具有新分片的索引if (shards != null) {throw new IllegalStateException("trying to initialize an index with fresh shards, but already has shards created");}//根据索引元数据的分片数量,创建一个索引分片路由表数组shards = new IndexShardRoutingTable.Builder[indexMetadata.getNumberOfShards()];//遍历要分配的分片for (int shardNumber = 0; shardNumber < indexMetadata.getNumberOfShards(); shardNumber++) {//根据索引和分片编号创建一个分片ID,并获取之前的节点信息ShardId shardId = new ShardId(index, shardNumber);final var previousNodes = getPreviousNodes(previousIndexRoutingTable, shardNumber);//确定主分片的恢复源(RecoverySource)类型final RecoverySource primaryRecoverySource;if (indexMetadata.inSyncAllocationIds(shardNumber).isEmpty() == false) {// we have previous valid copies for this shard. use them for recoveryprimaryRecoverySource = ExistingStoreRecoverySource.INSTANCE;} else if (indexMetadata.getResizeSourceIndex() != null) {// this is a new index but the initial shards should merged from another indexprimaryRecoverySource = LocalShardsRecoverySource.INSTANCE;} else {// a freshly created index with no restrictionprimaryRecoverySource = EmptyStoreRecoverySource.INSTANCE;}//使用索引分片路由表构建器(IndexShardRoutingTable.Builder)创建主分片和副本分片的路由信息,并添加到索引分片路由表中IndexShardRoutingTable.Builder indexShardRoutingBuilder = IndexShardRoutingTable.builder(shardId);for (int i = 0; i <= indexMetadata.getNumberOfReplicas(); i++) {boolean primary = i == 0;indexShardRoutingBuilder.addShard(ShardRouting.newUnassigned(shardId,primary,primary ? primaryRecoverySource : PeerRecoverySource.INSTANCE,withLastAllocatedNodeId(unassignedInfo, previousNodes, i),shardRoutingRoleStrategy.newEmptyRole(i)));}//构建好的索引分片路由表数组赋值给shardsshards[shardNumber] = indexShardRoutingBuilder;}return this;}

(2) 添加索引信息到indicesRouting

 public Builder add(IndexRoutingTable.Builder indexRoutingTableBuilder) {add(indexRoutingTableBuilder.build());return this;
}
 private ImmutableOpenMap.Builder<String, IndexRoutingTable> indicesRouting;
public Builder add(IndexRoutingTable indexRoutingTable) {if (indicesRouting == null) {throw new IllegalStateException("once build is called the builder cannot be reused");}indicesRouting.put(indexRoutingTable.getIndex().getName(), indexRoutingTable);return this;
}

(3) 创建一个新的集群状态返回

ClusterState.builder(updatedState).routingTable(routingTableBuilder.build()).build()

routingTable的实现

 		public Builder routingTable(RoutingTable routingTable) {this.routingTable = routingTable;return this;}

routingTableBuilder.build()的实现

		public RoutingTable build() {if (indicesRouting == null) {throw new IllegalStateException("once build is called the builder cannot be reused");}RoutingTable table = new RoutingTable(version, indicesRouting.build());indicesRouting = null;return table;}

最后一个build()

	public ClusterState build() {if (UNKNOWN_UUID.equals(uuid)) {uuid = UUIDs.randomBase64UUID();}final RoutingNodes routingNodes;//是否可以重用之前状态的路由节点(routingNodes),如果条件满足,则将之前状态的路由节点赋值给routingNodes;否则,将routingNodes设为null。if (previous != null && routingTable.indicesRouting() == previous.routingTable.indicesRouting() && nodes == previous.nodes) {// routing table contents and nodes haven't changed so we can try to reuse the previous state's routing nodes which are// expensive to computeroutingNodes = previous.routingNodes;} else {routingNodes = null;}return new ClusterState(clusterName,version,uuid,metadata,routingTable,nodes,transportVersions,blocks,customs.build(),fromDiff,routingNodes);}

二、查询索引信息

1 接收查询索引信息的RestCreateIndexAction

public class RestGetIndicesAction extends BaseRestHandler {@Overridepublic RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {// starting with 7.0 we don't include types by default in the response to GET requestsif (request.getRestApiVersion() == RestApiVersion.V_7&& request.hasParam(INCLUDE_TYPE_NAME_PARAMETER)&& request.method().equals(GET)) {deprecationLogger.compatibleCritical("get_indices_with_types", TYPES_DEPRECATION_MESSAGE);}String[] indices = Strings.splitStringByCommaToArray(request.param("index"));final GetIndexRequest getIndexRequest = new GetIndexRequest();getIndexRequest.indices(indices);getIndexRequest.indicesOptions(IndicesOptions.fromRequest(request, getIndexRequest.indicesOptions()));getIndexRequest.local(request.paramAsBoolean("local", getIndexRequest.local()));getIndexRequest.masterNodeTimeout(request.paramAsTime("master_timeout", getIndexRequest.masterNodeTimeout()));getIndexRequest.humanReadable(request.paramAsBoolean("human", false));getIndexRequest.includeDefaults(request.paramAsBoolean("include_defaults", false));getIndexRequest.features(GetIndexRequest.Feature.fromRequest(request));final var httpChannel = request.getHttpChannel();//这个是上面创建索引类似return channel -> new RestCancellableNodeClient(client, httpChannel).admin().indices().getIndex(getIndexRequest, new RestChunkedToXContentListener<>(channel));}
}

2、实际查询的TransportGetIndexAction.java的doMasterOperation方法

 @Overrideprotected void doMasterOperation(Task task,final org.elasticsearch.action.admin.indices.get.GetIndexRequest request,String[] concreteIndices,final ClusterState state,final ActionListener<GetIndexResponse> listener) {Map<String, MappingMetadata> mappingsResult = ImmutableOpenMap.of();Map<String, List<AliasMetadata>> aliasesResult = Map.of();Map<String, Settings> settings = Map.of();Map<String, Settings> defaultSettings = Map.of();Map<String, String> dataStreams = Map.copyOf(state.metadata().findDataStreams(concreteIndices).entrySet().stream().collect(Collectors.toUnmodifiableMap(Map.Entry::getKey, v -> v.getValue().getName())));Feature[] features = request.features();boolean doneAliases = false;boolean doneMappings = false;boolean doneSettings = false;for (Feature feature : features) {checkCancellation(task);switch (feature) {case MAPPINGS:if (doneMappings == false) {mappingsResult = state.metadata().findMappings(concreteIndices, indicesService.getFieldFilter(), () -> checkCancellation(task));doneMappings = true;}break;case ALIASES:if (doneAliases == false) {aliasesResult = state.metadata().findAllAliases(concreteIndices);doneAliases = true;}break;case SETTINGS:if (doneSettings == false) {Map<String, Settings> settingsMapBuilder = new HashMap<>();Map<String, Settings> defaultSettingsMapBuilder = new HashMap<>();for (String index : concreteIndices) {checkCancellation(task);Settings indexSettings = state.metadata().index(index).getSettings();if (request.humanReadable()) {indexSettings = IndexMetadata.addHumanReadableSettings(indexSettings);}settingsMapBuilder.put(index, indexSettings);if (request.includeDefaults()) {Settings defaultIndexSettings = settingsFilter.filter(indexScopedSettings.diff(indexSettings, Settings.EMPTY));defaultSettingsMapBuilder.put(index, defaultIndexSettings);}}settings = Collections.unmodifiableMap(settingsMapBuilder);defaultSettings = Collections.unmodifiableMap(defaultSettingsMapBuilder);doneSettings = true;}break;default:throw new IllegalStateException("feature [" + feature + "] is not valid");}}listener.onResponse(new GetIndexResponse(concreteIndices, mappingsResult, aliasesResult, settings, defaultSettings, dataStreams));}

(1)查询的索引信息都是从集群状态中ImmutableOpenMap<String, IndexMetadata>得到的

    private final ImmutableOpenMap<String, IndexMetadata> indices;public Map<String, MappingMetadata> findMappings(String[] concreteIndices,Function<String, Predicate<String>> fieldFilter,Runnable onNextIndex) {assert Transports.assertNotTransportThread("decompressing mappings is too expensive for a transport thread");assert concreteIndices != null;if (concreteIndices.length == 0) {return ImmutableOpenMap.of();}ImmutableOpenMap.Builder<String, MappingMetadata> indexMapBuilder = ImmutableOpenMap.builder();Set<String> indicesKeys = indices.keySet();Stream.of(concreteIndices).filter(indicesKeys::contains).forEach(index -> {onNextIndex.run();//这里查询的是上面的ImmutableOpenMap<String, IndexMetadata> indices;IndexMetadata indexMetadata = indices.get(index);Predicate<String> fieldPredicate = fieldFilter.apply(index);indexMapBuilder.put(index, filterFields(indexMetadata.mapping(), fieldPredicate));});return indexMapBuilder.build();}
Settings indexSettings = state.metadata().index(index).getSettings();

state.metadata().index(index) 也是ImmutableOpenMap<String, IndexMetadata> indices

  public IndexMetadata index(String index) {return indices.get(index);}

这篇关于Elasticsearch 8.9 服务端接收创建索引和查询索引信息源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/362099

相关文章

Linux系统中查询JDK安装目录的几种常用方法

《Linux系统中查询JDK安装目录的几种常用方法》:本文主要介绍Linux系统中查询JDK安装目录的几种常用方法,方法分别是通过update-alternatives、Java命令、环境变量及目... 目录方法 1:通过update-alternatives查询(推荐)方法 2:检查所有已安装的 JDK方

MySQL逻辑删除与唯一索引冲突解决方案

《MySQL逻辑删除与唯一索引冲突解决方案》本文探讨MySQL逻辑删除与唯一索引冲突问题,提出四种解决方案:复合索引+时间戳、修改唯一字段、历史表、业务层校验,推荐方案1和方案3,适用于不同场景,感兴... 目录问题背景问题复现解决方案解决方案1.复合唯一索引 + 时间戳删除字段解决方案2:删除后修改唯一字

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

MySql基本查询之表的增删查改+聚合函数案例详解

《MySql基本查询之表的增删查改+聚合函数案例详解》本文详解SQL的CURD操作INSERT用于数据插入(单行/多行及冲突处理),SELECT实现数据检索(列选择、条件过滤、排序分页),UPDATE... 目录一、Create1.1 单行数据 + 全列插入1.2 多行数据 + 指定列插入1.3 插入否则更

IntelliJ IDEA2025创建SpringBoot项目的实现步骤

《IntelliJIDEA2025创建SpringBoot项目的实现步骤》本文主要介绍了IntelliJIDEA2025创建SpringBoot项目的实现步骤,文中通过示例代码介绍的非常详细,对大家... 目录一、创建 Spring Boot 项目1. 新建项目2. 基础配置3. 选择依赖4. 生成项目5.

Linux线程之线程的创建、属性、回收、退出、取消方式

《Linux线程之线程的创建、属性、回收、退出、取消方式》文章总结了线程管理核心知识:线程号唯一、创建方式、属性设置(如分离状态与栈大小)、回收机制(join/detach)、退出方法(返回/pthr... 目录1. 线程号2. 线程的创建3. 线程属性4. 线程的回收5. 线程的退出6. 线程的取消7.

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu

创建Java keystore文件的完整指南及详细步骤

《创建Javakeystore文件的完整指南及详细步骤》本文详解Java中keystore的创建与配置,涵盖私钥管理、自签名与CA证书生成、SSL/TLS应用,强调安全存储及验证机制,确保通信加密和... 目录1. 秘密键(私钥)的理解与管理私钥的定义与重要性私钥的管理策略私钥的生成与存储2. 证书的创建与