热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【翻译】FlinkTableAPI&SQL自定义Source&Sink

本文翻译自官网:https:ci.apache.orgprojectsflinkflink-docs-release-1.10devtablesourceSinks.htmlTab

本文翻译自官网:https://ci.apache.org/projects/flink/flink-docs-release-1.10/dev/table/sourceSinks.html

TableSource 提供访问存储在外部系统(数据库、key-value 存款,消息队列)或文件中的数据的权限。TableSource 在 TableEnvironment 中注册后,就可以在 Table API 或 SQL 查询中访问了。

TableSink 将表发送到外部存储系统,例如数据库,key-value 存储,消息队列,或文件系统(使用不同的编码(格式),e.g.: CSV,Parquet,or ORC)。

TableFactory 允许将与外部系统的连接的声明与实际实现分开。TableFactory 从标准化的基于字符串的属性创建 table sources 和 sinks 的已配置实例。可以使用描述符或 SQL客户端的YAML配置文件以编程方式生成属性。

请查看通用 concepts and API 页面,以详细了解如何注册TableSource以及如何通过TableSink发出表。 有关如何使用工厂的示例,请参见 内置的源,接收器和格式页面。

  • Define a TableSource 定义TableSource
    • Defining a BatchTableSource 定义 BatchTableSource
    • Defining a StreamTableSource 定义 StreamTableSource
    • Defining a TableSource with Time Attributes 定义带时间属性的TableSource
    • Defining a TableSource with Projection Push-Down 定义投影下推定义TableSource
    • Defining a TableSource with Filter Push-Down 定义过滤下推的TableSource
    • Defining a TableSource for Lookups 定义用于查找的TableSource
  • Define a TableSink 定义TableSink
    • BatchTableSink
    • AppendStreamTableSink
    • RetractStreamTableSink
    • UpsertStreamTableSink
  • Define a TableFactory
    • Use a TableFactory in the SQL Client 在SQL 客户端中使用TableFactory
    • Use a TableFactory in the Table & SQL AP 在Table & SQL API 中使用TableFactory

Define a TableSource

 TableSource是一个通用接口,可让Table API和SQL查询访问存储在外部系统中的数据。 它提供了表的 schema  以及与该表的 schema  映射到行的记录。 根据是在流查询还是批处理查询中使用TableSource,记录是作为 DataSet 或 DataStream产生。

如果在流查询中使用TableSource,则必须实现StreamTableSource接口;如果在批处理查询中使用TableSource,则必须实现BatchTableSource接口。 TableSource还可以同时实现两个接口,并且可以在流查询和批处理查询中使用。

StreamTableSource和BatchTableSource扩展了定义以下方法的基本接口TableSource:

TableSource[T] {

  def getTableSchema: TableSchema

  def getReturnType: TypeInformation[T]

  def explainSource: String

}
  •  getTableSchema():返回产生的表的 schema,即表的字段名称和类型。 字段类型是使用Flink的DataType定义的(请参见Table API类型和SQL类型)。 请注意,返回的TableSchema不应包含反映物理TableSource schema 的计算列。
  • getReturnType():返回DataStream(StreamTableSource)或DataSet(BatchTableSource)的物理类型以及TableSource生成的记录。
  • describeSource():返回描述TableSource的字符串。 此方法是可选的,仅用于显示的目的。

TableSource接口将逻辑表 schema 与返回的DataStream或DataSet的物理类型分开。 因此,表 schema 的所有字段(getTableSchema())必须映射到具有相应物理返回类型(getReturnType())类型的字段。 默认情况下,此映射是基于字段名称完成的。 例如,一个TableSource用两个字段[name:String,size:Integer]定义一个表 schema,它需要一个TypeInformation,其中至少有两个字段分别称为name和size,类型分别为String和Integer。 这可能是PojoTypeInfo或RowTypeInfo,它们具有两个名为name和size且具有匹配类型的字段。

 但是,某些类型(例如Tuple或CaseClass类型)确实支持自定义字段名称。 如果TableSource返回具有固定字段名称类型的DataStream或DataSet,则它可以实现DefinedFieldMapping接口以将表 schema 中的字段名称映射到物理返回类型的字段名称。

Defining a BatchTableSource

 BatchTableSource接口扩展了TableSource接口并定义了另一个方法:

BatchTableSource[T] extends TableSource[T] {

  def getDataSet(execEnv: ExecutionEnvironment): DataSet[T]
}
  • getDataSet(execEnv):返回带有表数据的DataSet。 DataSet的类型必须与TableSource.getReturnType()方法定义的返回类型相同。 可以使用DataSet API的常规数据源创建DataSet。 通常,BatchTableSource是通过包装InputFormat或批处理连接器来实现的。

Defining a StreamTableSource

 StreamTableSource接口扩展了TableSource接口并定义了另一个方法:

StreamTableSource[T] extends TableSource[T] {

  def getDataStream(execEnv: StreamExecutionEnvironment): DataStream[T]
}
  • getDataStream(execEnv):返回带有表数据的DataStream。 DataStream的类型必须与TableSource.getReturnType()方法定义的返回类型相同。 通过使用DataStream API的常规数据源可以创建DataStream。 通常,通过包装SourceFunction或流连接器来实现StreamTableSource。

Defining a TableSource with Time Attributes

 流表API和SQL查询的基于时间的操作(例如窗口聚合或 joins )需要显式指定的时间属性。

TableSource在其表 schema 中将时间属性定义为Types.SQL_TIMESTAMP类型的字段。 与模式中的所有常规字段相反,时间属性不得与表源的返回类型中的物理字段匹配。 相反,TableSource通过实现某个接口来定义时间属性。

Defining a Processing Time Attribute

 处理时间属性通常在流查询中使用。 处理时间属性返回访问该属性的 operator 的当前 wall-clock 时间。 TableSource通过实现DefinedProctimeAttribute接口来定义处理时间属性。 该接口如下所示:

DefinedProctimeAttribute {

  def getProctimeAttribute: String
}
  • getProctimeAttribute():返回处理时间属性的名称。 指定的属性必须在表 schema 中定义为Types.SQL_TIMESTAMP类型,并且可以在基于时间的操作中使用。 DefinedProctimeAttribute table source 通过返回null来定义无处理时间属性。

注意:StreamTableSource和BatchTableSource都可以实现DefinedProctimeAttribute并定义处理时间属性。 如果是BatchTableSource,则在表扫描期间,使用当前时间戳初始化处理时间字段。

Defining a Rowtime Attribute

 行时间属性是TIMESTAMP类型的属性,在流查询和批处理查询中以统一的方式处理。

可以通过指定SQL_TIMESTAMP类型的表 schema 字段声明为rowtime属性

  • 字段名称
  • 一个TimestampExtractor,用于计算属性的实际值(通常从一个或多个其他字段)
  • 一个WatermarkStrategy,它指定如何为rowtime属性生成水印。

TableSource通过实现DefinedRowtimeAttributes接口来定义行时间属性。 该接口如下所示:

DefinedRowtimeAttributes {

  def getRowtimeAttributeDescriptors: util.List[RowtimeAttributeDescriptor]
}
  • getRowtimeAttributeDescriptors():返回RowtimeAttributeDescriptor的列表。 RowtimeAttributeDescriptor描述具有以下属性的行时间属性:
    • attributeName:表 schema 中的行时间属性的名称。 必须使用Types.SQL_TIMESTAMP类型定义该字段。
    • timestampExtractor:时间戳提取器从具有返回类型的记录中提取时间戳。 例如,它可以将Long字段转换为时间戳,或者解析String编码的时间戳。 Flink带有一组内置的TimestampExtractor实现,用于常见用例。 也可以提供自定义实现。
    • watermarkStrategy:水印策略定义了如何为rowtime属性生成水印。 Flink随附了一组针对常见用例的内置WatermarkStrategy实现。 也可以提供自定义实现。

注意:尽管getRowtimeAttributeDescriptors()方法返回描述符列表,但目前仅支持单个rowtime属性。 我们计划将来删除此限制,并支持具有多个rowtime属性的表。

注意:StreamTableSource和BatchTableSource都可以实现DefinedRowtimeAttributes并定义行时间属性。 无论哪种情况,都使用TimestampExtractor提取rowtime字段。 因此,实现StreamTableSource和BatchTableSource并定义rowtime属性的TableSource为流查询和批处理查询提供了完全相同的数据。

Provided Timestamp Extractors

Flink为常见用例提供TimestampExtractor实现。
当前可以使用以下TimestampExtractor实现:

  • ExistingField(fieldName):从现有的LONG,SQL_TIMESTAMP或时间戳格式的STRING字段中提取rowtime属性的值。 这样的字符串的一个示例是“ 2018-05-28 12:34:56.000”。
  • StreamRecordTimestamp():从DataStream StreamRecord的时间戳中提取rowtime属性的值。 请注意,此TimestampExtractor不适用于batch table sources。

可以通过实现相应的接口来定义自定义TimestampExtractor。

Provided Watermark Strategies

Flink为常见用例提供WatermarkStrategy实现。

当前有以下WatermarkStrategy实现:

  • AscendingTimestamps:递增时间戳的水印策略。 时间戳不正确的记录将被视为late。
  • BoundedOutOfOrderTimestamps(delay):一种针对指定时间延迟最多乱序的时间戳的水印策略。
  • PreserveWatermarks():一种策略,指定应从基础DataStream中保留水印。

可以通过实现相应的接口来定义自定义的WatermarkStrategy。

Defining a TableSource with Projection Push-Down

 TableSource通过实现ProjectableTableSource接口来支持投影下推。 该接口定义了一个方法:

ProjectableTableSource[T] {

  def projectFields(fields: Array[Int]): TableSource[T]
}
  • projectFields(fields):返回具有调整后的物理返回类型的TableSource的副本。 fields参数提供TableSource必须提供的字段的索引。 索引与物理返回类型的TypeInformation有关,而不与逻辑表 schame 有关。 复制的TableSource必须调整其返回类型以及返回的DataStream或DataSet。 复制的TableSource的TableSchema不得更改,即它必须与原始TableSource相同。 如果TableSource实现了DefinedFieldMapping接口,则必须将字段映射调整为新的返回类型。

注意:为了使Flink可以将投影下推 table source 与其原始形式区分开,必须重写explainSource方法以包括有关投影字段的信息。

ProjectableTableSource为项目平面字段添加了支持。 如果TableSource定义了具有嵌套模式的表,则可以实现NestedFieldsProjectableTableSource以将投影扩展到嵌套字段。 NestedFieldsProjectableTableSource的定义如下:

NestedFieldsProjectableTableSource[T] {

  def projectNestedFields(fields: Array[Int], nestedFields: Array[Array[String]]): TableSource[T]
}
  • projectNestedField(fields,nestedFields):返回具有调整后的物理返回类型的TableSource的副本。 物理返回类型的字段可以删除或重新排序,但不得更改其类型。 该方法的协定与ProjectableTableSource.projectFields()方法的协定基本上相同。 另外,nestedFields参数包含字段列表中每个字段索引的查询到的所有嵌套字段的路径列表。 所有其他嵌套字段都不需要在TableSource生成的记录中读取,解析和设置。

请注意,不得更改投影字段的类型,但未使用的字段可以设置为null或默认值。

Defining a TableSource with Filter Push-Down

 FilterableTableSource接口增加了对将过滤器下推到TableSource的支持。 扩展此接口的TableSource能够过滤记录,以使返回的DataStream或DataSet返回较少的记录。

该接口如下所示:

FilterableTableSource[T] {

  def applyPredicate(predicates: java.util.List[Expression]): TableSource[T]

  def isFilterPushedDown: Boolean
}
  • applyPredicate(predicates):返回具有添加的谓词的TableSource的副本。 谓词参数是“提供”给TableSource的连接谓词的可变列表。 TableSource接受通过从列表中删除谓词来评估谓词。 列表中剩余的谓词将由后续的过滤器运算符评估。
  • isFilterPushedDown():如果之前调用了applyPredicate()方法,则返回true。 因此,对于从applyPredicate()调用返回的所有TableSource实例,isFilterPushedDown()必须返回true。

注意:为了使Flink能够将过滤器下推 table source 与其原始形式区分开来,必须重写explainSource方法以包括有关下推式过滤器的信息。

Defining a TableSource for Lookups

 注意:这是一项实验功能。 将来的版本中可能会更改接口。 仅Blink planner支持。

LookupableTableSource接口增加了对通过查找方式通过键列访问表的支持。 当用于与维表联接以丰富某些信息时,这非常有用。 如果要在查找模式下使用TableSource,则应在时态表联接语法中使用源。

该接口如下所示:

LookupableTableSource[T] extends TableSource[T] {

  def getLookupFunction(lookupKeys: Array[String]): TableFunction[T]

  def getAsyncLookupFunction(lookupKeys: Array[String]): AsyncTableFunction[T]

  def isAsyncEnabled: Boolean
}
  • getLookupFunction(lookupkeys):返回一个TableFunction,该函数用于通过查找键查找匹配的行。 lookupkeys是联接相等条件下的LookupableTableSource的字段名称。 返回的TableFunction的eval方法参数应按照定义的lookupkeys的顺序排列。 建议在varargs中定义参数(例如,eval(Object ... lookupkeys)以匹配所有情况。 TableFunction的返回类型必须与TableSource.getReturnType()方法定义的返回类型相同。
  • getAsyncLookupFunction(lookupkeys):可选。 与getLookupFunction类似,但AsyncLookupFunction异步查找匹配的行。 AsyncLookupFunction的基础将通过Async I / O调用。 返回的AsyncTableFunction的eval方法的第一个参数应该定义为java.util.concurrent.CompletableFuture以异步收集结果(例如eval(CompletableFuture > result,Object ... lookupkeys))。 如果TableSource不支持异步查找,则此方法的实现可能会引发异常。
  • isAsyncEnabled():如果启用了异步查找,则返回true。 如果isAsyncEnabled返回true,则需要实现getAsyncLookupFunction(lookupkeys)。

Define a TableSink

 TableSink指定如何将表发送到外部系统或位置。 该接口是通用的,因此它可以支持不同的存储位置和格式。 批处理表和流式表有不同的表接收器。

通用接口如下所示:

TableSink[T] {

  def getOutputType: TypeInformation

  def getFieldNames: Array[String]

  def getFieldTypes: Array[TypeInformation]

  def configure(fieldNames: Array[String], fieldTypes: Array[TypeInformation]): TableSink[T]
}

调用TableSink#configure方法将表的 schema(字段名称和类型)传递给TableSink。 该方法必须返回TableSink的新实例,该实例被配置为发出提供的Table模式。 请注意,提供的TableSchema不应包含计算列以反映物理TableSink的模式。

BatchTableSink

定义一个外部TableSink以发出一个批处理表。
该接口如下所示: 

BatchTableSink[T] extends TableSink[T] {

  def emitDataSet(dataSet: DataSet[T]): Unit
}

AppendStreamTableSink

定义一个外部TableSink来发出仅具有插入更改的流表。
该接口如下所示:

AppendStreamTableSink[T] extends TableSink[T] {

  def emitDataStream(dataStream: DataStream[T]): Unit
}

如果还通过更新或删除更改来修改表,则将引发TableException。 

RetractStreamTableSink

 定义一个外部TableSink以发出具有插入,更新和删除更改的流表。

该接口如下所示:

RetractStreamTableSink[T] extends TableSink[Tuple2[Boolean, T]] {

  def getRecordType: TypeInformation[T]

  def emitDataStream(dataStream: DataStream[Tuple2[Boolean, T]]): Unit
}

该表将被转换为 accumulate  和撤消消息流,这些消息被编码为Java Tuple2。 第一个字段是指示消息类型的布尔标志(true表示插入,false表示删除)。 第二个字段保存请求的类型的记录。

UpsertStreamTableSink

定义一个外部TableSink以发出具有插入,更新和删除更改的流表。

该接口如下所示:

UpsertStreamTableSink[T] extends TableSink[Tuple2[Boolean, T]] {

  def setKeyFields(keys: Array[String]): Unit

  def setIsAppendOnly(isAppendOnly: Boolean): Unit

  def getRecordType: TypeInformation[T]

  def emitDataStream(dataStream: DataStream[Tuple2[Boolean, T]]): Unit
}

该表必须具有唯一的键字段(原子的或复合的)或 append-only 。 如果表没有唯一键并且不是append-only ,则将引发TableException。 该表的唯一键由UpsertStreamTableSink#setKeyFields()方法配置。

该表将转换为upsert和delete消息流,它们被编码为Java Tuple2。 第一个字段是指示消息类型的布尔标志。 第二个字段保存请求的类型T的记录。

具有 true 布尔值字段的消息是已配置密钥的upsert消息。 带有 false 标志的消息是已配置密钥的删除消息。 如果表是 append-only,则所有消息都将具有true标志,并且必须将其解释为插入。

Define a TableFactory

 TableFactory允许从基于字符串的属性创建与表相关的不同实例。 调用所有可用的工厂以匹配给定的属性集和相应的工厂类。

工厂利用 Java’s Service Provider Interfaces(SPI)进行发现。 这意味着每个依赖项和JAR文件都应在 META_INF/services 资源目录中包含一个文件org.apache.flink.table.factories.TableFactory,该文件列出了它提供的所有可用表工厂。

每个表工厂都需要实现以下接口:

package org.apache.flink.table.factories

trait TableFactory {

  def requiredContext(): util.Map[String, String]

  def supportedProperties(): util.List[String]
}
  • requiredContext():指定已为此工厂实现的上下文。 该框架保证仅在满足指定的属性和值集的情况下才与此工厂匹配。 典型的属性可能是connector.type,format.type或update-mode。 属性键(例如connector.property-version和format.property-version)保留用于将来的向后兼容情况。
  • supportedProperties():此工厂可以处理的属性键的列表。 此方法将用于验证。 如果传递了该工厂无法处理的属性,则将引发异常。 该列表不得包含上下文指定的键。

为了创建特定实例,工厂类可以实现org.apache.flink.table.factories中提供的一个或多个接口:

BatchTableSourceFactory: Creates a batch table source.
BatchTableSinkFactory: Creates a batch table sink.
StreamTableSourceFactory: Creates a stream table source.
StreamTableSinkFactory: Creates a stream table sink.
DeserializationSchemaFactory: Creates a deserialization schema format.
SerializationSchemaFactory: Creates a serialization schema format.

工厂的发现分为多个阶段:

Discover all available factories. 发现所有可用的工厂。
Filter by factory class (e.g., StreamTableSourceFactory). 按工厂分类过滤 
Filter by matching context. 通过匹配上下文进行过滤。 
Filter by supported properties. 按支持的属性过滤。
Verify that exactly one factory matches, otherwise throw an AmbiguousTableFactoryException or NoMatchingTableFactoryException. 验证一个工厂是否完全匹配,否则抛出AmbiguousTableFactoryException或NoMatchingTableFactoryException。

以下示例说明如何为自定义流源提供附加的connector.debug属性标志以进行参数化。

import java.util
import org.apache.flink.table.sources.StreamTableSource
import org.apache.flink.types.Row

class MySystemTableSourceFactory extends StreamTableSourceFactory[Row] {

  override def requiredContext(): util.Map[String, String] = {
    val context = new util.HashMap[String, String]()
    context.put("update-mode", "append")
    context.put("connector.type", "my-system")
    context
  }

  override def supportedProperties(): util.List[String] = {
    val properties = new util.ArrayList[String]()
    properties.add("connector.debug")
    properties
  }

  override def createStreamTableSource(properties: util.Map[String, String]): StreamTableSource[Row] = {
    val isDebug = java.lang.Boolean.valueOf(properties.get("connector.debug"))

    # additional validation of the passed properties can also happen here

    new MySystemAppendTableSource(isDebug)
  }
}

Use a TableFactory in the SQL Client

 在SQL Client环境文件中,先前提供的工厂可以声明为:

tables:
 - name: MySystemTable
   type: source
   update-mode: append
   connector:
     type: my-system
     debug: true

将YAML文件转换为扁平化的字符串属性,并使用描述与外部系统的连接的那些属性来调用表工厂:

update-mode=append
connector.type=my-system
connector.debug=true

注意:属性例如table.#.name或tables.#.type是SQL Client的特定属性,不会传递给任何工厂。 根据执行环境的不同,type属性决定是否需要发现BatchTableSourceFactory / StreamTableSourceFactory(对于 source),BatchTableSinkFactory / StreamTableSinkFactory(对于 sink)还是两者都被发现。

Use a TableFactory in the Table & SQL API

 对于使用说明性Scaladoc / Javadoc的类型安全的编程方法,Table&SQL API在org.apache.flink.table.descriptor中提供了描述符,这些描述符可转换为基于字符串的属性。 请参阅 sources,sink 和  format 的内置描述符作为参考。

可以通过扩展ConnectorDescriptor类来定义自定义描述符。

import org.apache.flink.table.descriptors.ConnectorDescriptor
import java.util.HashMap
import java.util.Map

/**
  * Connector to MySystem with debug mode.
  */
class MySystemConnector(isDebug: Boolean) extends ConnectorDescriptor("my-system", 1, false) {
  
  override protected def toConnectorProperties(): Map[String, String] = {
    val properties = new HashMap[String, String]
    properties.put("connector.debug", isDebug.toString)
    properties
  }
}
The descriptor can then be used to create a table with the table environment.

val tableEnv: StreamTableEnvironment = // ...

tableEnv
  .connect(new MySystemConnector(isDebug = true))
  .withSchema(...)
  .inAppendMode()
  .createTemporaryTable("MySystemTable")

 

欢迎关注Flink菜鸟公众号,会不定期更新Flink(开发技术)相关的推文

【翻译】Flink Table API & SQL 自定义 Source & Sink

 


推荐阅读
  • 一、Hadoop来历Hadoop的思想来源于Google在做搜索引擎的时候出现一个很大的问题就是这么多网页我如何才能以最快的速度来搜索到,由于这个问题Google发明 ... [详细]
  • Android Studio Bumblebee | 2021.1.1(大黄蜂版本使用介绍)
    本文介绍了Android Studio Bumblebee | 2021.1.1(大黄蜂版本)的使用方法和相关知识,包括Gradle的介绍、设备管理器的配置、无线调试、新版本问题等内容。同时还提供了更新版本的下载地址和启动页面截图。 ... [详细]
  • mysql-cluster集群sql节点高可用keepalived的故障处理过程
    本文描述了mysql-cluster集群sql节点高可用keepalived的故障处理过程,包括故障发生时间、故障描述、故障分析等内容。根据keepalived的日志分析,发现bogus VRRP packet received on eth0 !!!等错误信息,进而导致vip地址失效,使得mysql-cluster的api无法访问。针对这个问题,本文提供了相应的解决方案。 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 本文详细介绍了MysqlDump和mysqldump进行全库备份的相关知识,包括备份命令的使用方法、my.cnf配置文件的设置、binlog日志的位置指定、增量恢复的方式以及适用于innodb引擎和myisam引擎的备份方法。对于需要进行数据库备份的用户来说,本文提供了一些有价值的参考内容。 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
  • MyBatis错题分析解析及注意事项
    本文对MyBatis的错题进行了分析和解析,同时介绍了使用MyBatis时需要注意的一些事项,如resultMap的使用、SqlSession和SqlSessionFactory的获取方式、动态SQL中的else元素和when元素的使用、resource属性和url属性的配置方式、typeAliases的使用方法等。同时还指出了在属性名与查询字段名不一致时需要使用resultMap进行结果映射,而不能使用resultType。 ... [详细]
  • sklearn数据集库中的常用数据集类型介绍
    本文介绍了sklearn数据集库中常用的数据集类型,包括玩具数据集和样本生成器。其中详细介绍了波士顿房价数据集,包含了波士顿506处房屋的13种不同特征以及房屋价格,适用于回归任务。 ... [详细]
  • 本文介绍了计算机网络的定义和通信流程,包括客户端编译文件、二进制转换、三层路由设备等。同时,还介绍了计算机网络中常用的关键词,如MAC地址和IP地址。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • 本文详细介绍了git常用命令及其操作方法,包括查看、添加、提交、删除、找回等操作,以及如何重置修改文件、抛弃工作区修改、将工作文件提交到本地暂存区、从版本库中删除文件等。同时还介绍了如何从暂存区恢复到工作文件、恢复最近一次提交过的状态,以及如何合并多个操作等。 ... [详细]
author-avatar
乐橙味_367
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有