写入数据

表格存储提供了单行插入、单行更新和批量写入的写入方式用于写入数据到数据表。当要写入数据到数据表时,您需要指定完整主键以及要增删改的属性列。在高并发应用中写入数据时,您可以配置行存在性条件或者列条件实现按照指定条件更新数据。

如果需要了解表格存储各场景的应用案例,请参见快速玩转Tablestore入门与实战

写入方式

表格存储提供的数据写入接口包括PutRow、UpdateRowBatchWriteRow。写入数据时,请根据实际场景选择相应写入方式。

写入方式

说明

适用场景

插入单行数据

调用PutRow接口新写入一行数据。如果该行已存在,则表格存储会先删除原行数据(原行的所有列以及所有版本的数据),再写入新行数据。

适用于要写入数据较少的场景。

更新单行数据

调用UpdateRow接口更新一行数据,支持增加和删除一行中的属性列,删除属性列指定版本的数据,或者更新已存在的属性列值。如果更新的行不存在,则新增一行数据。

适用于更新已写入数据的场景,例如删除属性列、删除某个数据版本、修改属性列值等。

批量写入数据

调用BatchWriteRow接口在一次请求中进行批量写入操作或者一次对多张表进行写入。

BatchWriteRow操作由多个PutRow、UpdateRow、DeleteRow子操作组成,构造子操作的过程与使用PutRow接口、UpdateRow接口和DeleteRow接口时相同。

适用于要写入、删除或者更新大量数据以及要同时进行增删改数据的场景。

前提条件

插入单行数据

调用PutRow接口新写入一行数据。如果该行已存在,则先删除原行数据(原行的所有列以及所有版本的数据),再写入新行数据。

接口

/// <summary>
/// 指定数据表名称、主键和属性,写入一行数据。返回本次操作消耗的CapacityUnit。
/// </summary>
/// <param name="request">插入数据的请求</param>
/// <returns>本次操作消耗的CapacityUnit</returns>
public PutRowResponse PutRow(PutRowRequest request);

/// <summary>
/// PutRow的异步形式。
/// </summary>
public Task<PutRowResponse> PutRowAsync(PutRowRequest request);                    

参数

参数

说明

tableName

数据表名称。

primaryKey

行的主键。主键包括主键列名、主键类型和主键值。

重要
  • 设置的主键个数和类型必须和数据表的主键个数和类型一致。

  • 当主键为自增列时,只需将自增列的值设置为占位符。更多信息,请参见主键列自增

attribute

行的属性列。每一项的顺序是属性名、属性类型(可选)、属性值、时间戳(可选)。

  • 属性名即属性列的名称,属性类型即属性列的数据类型。更多信息,请参见命名规则和数据类型

    属性类型可以是INTEGER、STRING(UTF-8编码字符串)、BINARY、BOOLEANDOUBLE五种。

  • 时间戳即数据的版本号,可以由系统自动生成或者自定义,如果不设置此参数,则默认由系统自动生成。更多信息,请参见数据版本和生命周期

    • 当由系统自动生成数据的版本号时,系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。

    • 当自定义数据的版本号时,版本号需要为64位的毫秒单位时间戳且在有效版本范围内。

condition

使用条件更新,可以设置原行的存在性条件或者原行中某列的列值条件。更多信息,请参见条件更新

说明
  • 从.NET SDK 2.2.0版本开始Condition不仅支持行条件,也支持列条件。

  • Condition.IGNORECondition.EXPECT_EXISTCondition.EXPECT_NOT_EXIST从.NET SDK 3.0.0版本开始被废弃,请替换为new Condition (RowExistenceExpectation.IGNORE)new Condition (RowExistenceExpectation.EXPECT_EXIST)new Condition (RowExistenceExpectation.EXPECT_NOT_EXIST)

  • RowExistenceExpectation.IGNORE表示无论此行是否存在均会插入新数据,如果之前行已存在,则写入数据时会覆盖原有数据。

  • RowExistenceExpectation.EXPECT_EXIST表示只有此行存在时才会插入新数据,写入数据时会覆盖原有数据。

  • RowExistenceExpectation.EXPECT_NOT_EXIST表示只有此行不存在时才会插入数据。

示例

插入一行数据

以下示例用于插入一行数据。

//定义行的主键,必须与创建表时的TableMeta中定义的一致。
var primaryKey = new PrimaryKey();
primaryKey.Add("pk0", new ColumnValue(0));
primaryKey.Add("pk1", new ColumnValue("abc"));

//定义要写入该行的属性列。
var attribute = new AttributeColumns();
attribute.Add("col0", new ColumnValue(0));
attribute.Add("col1", new ColumnValue("a"));
attribute.Add("col2", new ColumnValue(true));

try
{
    //构造插入数据的请求对象,RowExistenceExpectation.IGNORE表示无论此行是否存在均会插入新数据。
    var request = new PutRowRequest("SampleTable", new Condition(RowExistenceExpectation.IGNORE),
                            primaryKey, attribute);

    //调用PutRow接口插入数据。
    otsClient.PutRow(request);

    //如果没有抛出异常,则说明执行成功。
    Console.WriteLine("Put row succeeded.");
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Put row failed, exception:{0}", ex.Message);
}                    

详细代码请参见PutRow@GitHub

插入数据时使用列条件和行条件

以下示例用于当行存在且col0大于24时才执行插入操作。

//定义行的主键,必须与创建表时的TableMeta中定义的一致。
var primaryKey = new PrimaryKey();
primaryKey.Add("pk0", new ColumnValue(0));
primaryKey.Add("pk1", new ColumnValue("abc"));

//定义要写入该行的属性列。
AttributeColumns attribute = new AttributeColumns();
attribute.Add("col0", new ColumnValue(0));
attribute.Add("col1", new ColumnValue("a"));
attribute.Add("col2", new ColumnValue(true));

//当col0列的值大于24时,允许再次插入行,覆盖掉原值。
try
{
    var request = new PutRowRequest("SampleTable", new Condition(RowExistenceExpectation.EXPECT_EXIST),
                            primaryKey, attribute);
    request.Condition.ColumnCondition = new RelationalCondition("col0",
                                        CompareOperator.GREATER_THAN,
                                        new ColumnValue(24));
    otsClient.PutRow(request);

    Console.WriteLine("Put row succeeded.");
}
catch (Exception ex)
{
    Console.WriteLine("Put row failed. error:{0}", ex.Message);
}                   

详细代码请参见ConditionPutRow@GitHub

异步插入数据

以下示例用于异步插入多行数据。

重要

每一个异步调用都会启动一个线程,如果连续启动了很多异步调用,且每个都耗时比较大时,可能会出现超时。

try
{
    var putRowTaskList = new List<Task<PutRowResponse>>();
    for (int i = 0; i < 100; i++)
    {
        //定义行的主键,必须与创建表时的TableMeta中定义的一致。
        var primaryKey = new PrimaryKey();
        primaryKey.Add("pk0", new ColumnValue(i));
        primaryKey.Add("pk1", new ColumnValue("abc"));

        //定义要写入该行的属性列。
        var attribute = new AttributeColumns();
        attribute.Add("col0", new ColumnValue(i));
        attribute.Add("col1", new ColumnValue("a"));
        attribute.Add("col2", new ColumnValue(true));

        var request = new PutRowRequest("SampleTable", new Condition(RowExistenceExpectation.IGNORE),
                                        primaryKey, attribute);

        putRowTaskList.Add(otsClient.PutRowAsync(request));
    }

    //等待每个异步调用返回,并打印出消耗的CU值。
    foreach (var task in putRowTaskList)
    {
        task.Wait();
        Console.WriteLine("consumed read:{0}, write:{1}", task.Result.ConsumedCapacityUnit.Read,
                            task.Result.ConsumedCapacityUnit.Write);
    }

    //如果没有抛出异常,则说明执行成功。
    Console.WriteLine("Put row async succeeded.");
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Put row async failed. exception:{0}", ex.Message);
}                   

详细代码请参见PutRowAsync@GitHub

更新单行数据

调用UpdateRow接口更新一行数据,可以增加和删除一行中的属性列,删除属性列指定版本的数据,或者更新已存在的属性列的值。如果更新的行不存在,则新增一行数据。

说明

UpdateRow请求中只包含删除指定的列且该行不存在时,则该请求不会新增一行数据。

接口

/// <summary>
/// 更新指定行的数据,如果该行不存在,则新增一行;若该行存在,则根据请求的内容在该行中新增、修改或者删除指定列的值。
/// </summary>
/// <param name="request">请求实例</param>
public UpdateRowResponse UpdateRow(UpdateRowRequest request);

/// <summary>
/// UpdateRow的异步形式。
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Task<UpdateRowResponse> UpdateRowAsync(UpdateRowRequest request);            

参数

参数

说明

tableName

数据表名称。

primaryKey

行的主键。主键包括主键列名、主键类型和主键值。

重要

设置的主键个数和类型必须和数据表的主键个数和类型一致。

condition

使用条件更新,可以设置原行的存在性条件或者原行中某列的列值条件。更多信息,请参见条件更新

attribute

更新的属性列。

  • 增加或更新数据时,需要设置属性名、属性值、属性类型(可选)、时间戳(可选)。

    属性名即属性列的名称,属性类型即属性列的数据类型。更多信息,请参见命名规则和数据类型

    时间戳即数据的版本号,可以由系统自动生成或者自定义,如果不设置此参数,则默认由系统自动生成。更多信息,请参见数据版本和生命周期

    • 当由系统自动生成数据的版本号时,系统默认将当前时间的毫秒单位时间戳(从1970-01-01 00:00:00 UTC计算起的毫秒数)作为数据的版本号。

    • 当自定义数据的版本号时,版本号需要为64位的毫秒单位时间戳且在有效版本范围内。

  • 删除属性列特定版本的数据时,只需要设置属性名和时间戳。

    时间戳是64位整数,单位为毫秒,表示某个特定版本的数据。

  • 删除属性列时,只需要设置属性名。

    说明

    删除一行的全部属性列不等同于删除该行,如果需要删除该行,请使用DeleteRow操作。

示例

以下示例用于更新一行数据。

//定义行的主键,必须与创建表时的TableMeta中定义的一致。
PrimaryKey primaryKey = new PrimaryKey();
primaryKey.Add("pk0", new ColumnValue(0));
primaryKey.Add("pk1", new ColumnValue("abc"));

//定义要写入该行的属性列。
UpdateOfAttribute attribute = new UpdateOfAttribute();
attribute.AddAttributeColumnToPut("col0", new ColumnValue(0));
attribute.AddAttributeColumnToPut("col1", new ColumnValue("b")); // 将原先的值'a'改为'b'
attribute.AddAttributeColumnToPut("col2", new ColumnValue(true));

try
{
    //构造更新行的请求对象,RowExistenceExpectation.IGNORE表示无论此行是否存在都执行更新。
    var request = new UpdateRowRequest("SampleTable", new Condition(RowExistenceExpectation.IGNORE),
                                primaryKey, attribute);
    //调用UpdateRow接口更新数据。
    otsClient.UpdateRow(request);

    //如果没有抛出异常,则说明执行成功。
    Console.WriteLine("Update row succeeded.");
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Update row failed, exception:{0}", ex.Message);
}           

详细代码请参见UpdateRow@GitHub

批量写入数据

调用BatchWriteRow接口在一次请求中进行批量写入操作或者一次对多张表进行写入。

BatchWriteRow操作由多个PutRow、UpdateRow、DeleteRow子操作组成,构造子操作的过程与使用PutRow接口、UpdateRow接口和DeleteRow接口时相同。

BatchWriteRow的各个子操作独立执行,表格存储会分别返回各个子操作的执行结果。

注意事项

  • 由于批量写入可能存在部分行失败的情况,失败行的Index及错误信息在返回的BatchWriteRowResponse中,但并不抛出异常。因此调用BatchWriteRow接口时,需要检查返回值,可通过BatchWriteRowResponseisAllSucceed方法判断是否全部成功;如果不检查返回值,则可能会忽略掉部分操作的失败。

  • 当服务端检查到某些操作出现参数错误时,BatchWriteRow接口可能会抛出参数错误的异常,此时该请求中所有的操作都未执行。

接口

/// <summary>
/// <para>批量插入,修改或删除一个或多个表中的若干行数据。</para>
/// <para>BatchWriteRow操作可视为多个PutRow、UpdateRow、DeleteRow操作的集合,各个操作独立执行,独立返回结果,独立计算服务能力单元。</para>
/// <para>与执行大量的单行写操作相比,使用BatchWriteRow操作可以有效减少请求的响应时间,提高数据的写入速率。</para>
/// </summary>
/// <param name="request">请求实例</param>
/// <returns>响应实例</returns>
public BatchWriteRowResponse BatchWriteRow(BatchWriteRowRequest request);

/// <summary>
/// BatchWriteRow的异步形式。
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public Task<BatchWriteRowResponse> BatchWriteRowAsync(BatchWriteRowRequest request);            

示例

以下示例用于批量写入100行数据。

var TableName = "SampleTable";
//构造批量写的请求对象,设置100行数据的主键。
var request = new BatchWriteRowRequest();
var rowChanges = new RowChanges(TableName);
for (int i = 0; i < 100; i++)
{
    PrimaryKey primaryKey = new PrimaryKey();
    primaryKey.Add("pk0", new ColumnValue(i));
    primaryKey.Add("pk1", new ColumnValue("abc"));

    //定义要写入该行的属性列。
    UpdateOfAttribute attribute = new UpdateOfAttribute();
    attribute.AddAttributeColumnToPut("col0", new ColumnValue(0));
    attribute.AddAttributeColumnToPut("col1", new ColumnValue("a"));
    attribute.AddAttributeColumnToPut("col2", new ColumnValue(true));

    rowChanges.AddUpdate(new Condition(RowExistenceExpectation.IGNORE), primaryKey, attribute);
}

request.Add(TableName, rowChanges);

try
{
    //调用BatchWriteRow接口写入数据。
    var response = otsClient.BatchWriteRow(request);
    var tableRows = response.TableRespones;
    var rows = tableRows[TableName];

    //批量操作可能部分成功部分失败,需要检查每行的状态是否成功,详见示例代码的GitHub链接。
}
catch (Exception ex)
{
    //如果抛出异常,则说明执行失败,处理异常。
    Console.WriteLine("Batch put row failed, exception:{0}", ex.Message);
}           

详细代码请参见BatchWriteRow@GitHub

常见问题

相关文档

  • 当要在高并发应用中实现按照指定条件更新数据时,您可以通过条件更新实现。更多信息,请参见条件更新

  • 当要为在线应用提供实时统计功能时,例如统计帖子的PV(实时浏览量)等,您可以通过原子计数器实现。更多信息,请参见原子计数器

  • 写入数据后,即可根据需要读取或者删除表中数据。更多信息,请参见读取数据删除数据