C#:几种数据库的大数据批量插入

C#.NET中如何批量插入大量数据到数据库中 主要给大家介绍C#.net中如何批量插入大量数据到数据库中,本文涉及到C#.net中批量插入数据到数据库中方面的内容,对C#.net批量插入数据到数据库中感兴趣的朋友可以参考下本 立即下载
每天都是不一样,积极的去感受生活

C#:几种数据库的大数据批量插入 - faib

在之前只知道SqlServer支持数据批量插入,殊不知道Oracle、SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解决方法。

    首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前一篇文章中已经提到过了。

 

    /// <summary>
    /// 提供数据批量处理的方法。
    /// </summary>
    public interface IBatcherProvider : IProviderService
    {
        /// <summary>
        /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        /// </summary>
        /// <param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>
        /// <param name="batchSize">每批次写入的数据量。</param>
        void Insert(DataTable dataTable, int batchSize = 10000);
    }

 

    一、SqlServer数据批量插入

    SqlServer的批量插入很简单,使用SqlBulkCopy就可以,以下是该类的实现:

 

    /// <summary>
    /// 为 System.Data.SqlClient 提供的用于批量操作的方法。
    /// </summary>
    public sealed class MsSqlBatcher : IBatcherProvider
    {
        /// <summary>
        /// 获取或设置提供者服务的上下文。
        /// </summary>
        public ServiceContext ServiceContext { get; set; }

        /// <summary>
        /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        /// </summary>
        /// <param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>
        /// <param name="batchSize">每批次写入的数据量。</param>
        public void Insert(DataTable dataTable, int batchSize = 10000)
        {
            Checker.ArgumentNull(dataTable, "dataTable");
            if (dataTable.Rows.Count == 0)
            {
                return;
            }
            using (var connection = (SqlConnection)ServiceContext.Database.CreateConnection())
            {
                try
                {
                    connection.TryOpen();
                    //给表名加上前后导符
                    var tableName = DbUtility.FormatByQuote(ServiceContext.Database.Provider.GetService<ISyntaxProvider>(), dataTable.TableName);
                    using (var bulk = new SqlBulkCopy(connection, SqlBulkCopyOptions.KeepIdentity, null)
                        {
                            DestinationTableName = tableName, 
                            BatchSize = batchSize
                        })
                    {
                        //循环所有列,为bulk添加映射
                        dataTable.EachColumn(c => bulk.ColumnMappings.Add(c.ColumnName, c.ColumnName), c => !c.AutoIncrement);
                        bulk.WriteToServer(dataTable);
                        bulk.Close();
                    }
                }
                catch (Exception exp)
                {
                    throw new BatcherException(exp);
                }
                finally
                {
                    connection.TryClose();
                }
            }
        }
    }

 

     SqlBulkCopy的ColumnMappings中列的名称受大小写敏感限制,因此在构造DataTable的时候应请注意列名要与表一致。

     以上没有使用事务,使用事务在性能上会有一定的影响,如果要使用事务,可以设置SqlBulkCopyOptions.UseInternalTransaction。

 

     二、Oracle数据批量插入

     System.Data.OracleClient不支持批量插入,因此只能使用Oracle.DataAccess组件来作为提供者。

 

    /// <summary>
    /// Oracle.Data.Access 组件提供的用于批量操作的方法。
    /// </summary>
    public sealed class OracleAccessBatcher : IBatcherProvider
    {
        /// <summary>
        /// 获取或设置提供者服务的上下文。
        /// </summary>
        public ServiceContext ServiceContext { get; set; }

        /// <summary>
        /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        /// </summary>
        /// <param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>
        /// <param name="batchSize">每批次写入的数据量。</param>
        public void Insert(DataTable dataTable, int batchSize = 10000)
        {
            Checker.ArgumentNull(dataTable, "dataTable");
            if (dataTable.Rows.Count == 0)
            {
                return;
            }
            using (var connection = ServiceContext.Database.CreateConnection())
            {
                try
                {
                    connection.TryOpen();
                    using (var command = ServiceContext.Database.Provider.DbProviderFactory.CreateCommand())
                    {
                        if (command == null)
                        {
                            throw new BatcherException(new ArgumentException("command"));
                        }
                        command.Connection = connection;
                        command.CommandText = GenerateInserSql(ServiceContext.Database, command, dataTable);
                        command.ExecuteNonQuery();
                    }
                }
                catch (Exception exp)
                {
                    throw new BatcherException(exp);
                }
                finally
                {
                    connection.TryClose();
                }
            }
        }

        /// <summary>
        /// 生成插入数据的sql语句。
        /// </summary>
        /// <param name="database"></param>
        /// <param name="command"></param>
        /// <param name="table"></param>
        /// <returns></returns>
        private string GenerateInserSql(IDatabase database, DbCommand command, DataTable table)
        {
            var names = new StringBuilder();
            var values = new StringBuilder();
            //将一个DataTable的数据转换为数组的数组
            var data = table.ToArray();

            //设置ArrayBindCount属性
            command.GetType().GetProperty("ArrayBindCount").SetValue(command, table.Rows.Count, null);

            var syntax = database.Provider.GetService<ISyntaxProvider>();
            for (var i = 0; i < table.Columns.Count; i++)
            {
                var column = table.Columns[i];

                var parameter = database.Provider.DbProviderFactory.CreateParameter();
                if (parameter == null)
                {
                    continue;
                }
                parameter.ParameterName = column.ColumnName;
                parameter.Direction = ParameterDirection.Input;
                parameter.DbType = column.DataType.GetDbType();
                parameter.Value = data[i];

                if (names.Length > 0)
                {
                    names.Append(",");
                    values.Append(",");
                }
                names.AppendFormat("{0}", DbUtility.FormatByQuote(syntax, column.ColumnName));
                values.AppendFormat("{0}{1}", syntax.ParameterPrefix, column.ColumnName);

                command.Parameters.Add(parameter);
            }
            return string.Format("INSERT INTO {0}({1}) VALUES ({2})", DbUtility.FormatByQuote(syntax, table.TableName), names, values);
        }
    }

     以上最重要的一步,就是将DataTable转为数组的数组表示,即object[][],前数组的上标是列的个数,后数组是行的个数,因此循环Columns将后数组作为Parameter的值,也就是说,参数的值是一个数组。而insert语句与一般的插入语句没有什么不一样。

 

     三、SQLite数据批量插入

     SQLite的批量插入只需开启事务就可以了,这个具体的原理不得而知。

 

    public sealed class SQLiteBatcher : IBatcherProvider
    {
        /// <summary>
        /// 获取或设置提供者服务的上下文。
        /// </summary>
        public ServiceContext ServiceContext { get; set; }

        /// <summary>
        /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        /// </summary>
        /// <param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>
        /// <param name="batchSize">每批次写入的数据量。</param>
        public void Insert(DataTable dataTable, int batchSize = 10000)
        {
            Checker.ArgumentNull(dataTable, "dataTable");
            if (dataTable.Rows.Count == 0)
            {
                return;
            }
            using (var connection = ServiceContext.Database.CreateConnection())
            {
                DbTransaction transcation = null;
                try
                {
                    connection.TryOpen();
                    transcation = connection.BeginTransaction();
                    using (var command = ServiceContext.Database.Provider.DbProviderFactory.CreateCommand())
                    {
                        if (command == null)
                        {
                            throw new BatcherException(new ArgumentException("command"));
                        }
                        command.Connection = connection;

                        command.CommandText = GenerateInserSql(ServiceContext.Database, dataTable);
                        if (command.CommandText == string.Empty)
                        {
                            return;
                        }

                        var flag = new AssertFlag();
                        dataTable.EachRow(row =>
                            {
                                var first = flag.AssertTrue();
                                ProcessCommandParameters(dataTable, command, row, first);
                                command.ExecuteNonQuery();
                            });
                    }
                    transcation.Commit();
                }
                catch (Exception exp)
                {
                    if (transcation != null)
                    {
                        transcation.Rollback();
                    }
                    throw new BatcherException(exp);
                }
                finally
                {
                    connection.TryClose();
                }
            }
        }

        private void ProcessCommandParameters(DataTable dataTable, DbCommand command, DataRow row, bool first)
        {
            for (var c = 0; c < dataTable.Columns.Count; c++)
            {
                DbParameter parameter;
                //首次创建参数,是为了使用缓存
                if (first)
                {
                    parameter = ServiceContext.Database.Provider.DbProviderFactory.CreateParameter();
                    parameter.ParameterName = dataTable.Columns[c].ColumnName;
                    command.Parameters.Add(parameter);
                }
                else
                {
                    parameter = command.Parameters[c];
                }
                parameter.Value = row[c];
            }
        }

        /// <summary>
        /// 生成插入数据的sql语句。
        /// </summary>
        /// <param name="database"></param>
        /// <param name="table"></param>
        /// <returns></returns>
        private string GenerateInserSql(IDatabase database, DataTable table)
        {
            var syntax = database.Provider.GetService<ISyntaxProvider>();
            var names = new StringBuilder();
            var values = new StringBuilder();
            var flag = new AssertFlag();
            table.EachColumn(column =>
                {
                    if (!flag.AssertTrue())
                    {
                        names.Append(",");
                        values.Append(",");
                    }
                    names.Append(DbUtility.FormatByQuote(syntax, column.ColumnName));
                    values.AppendFormat("{0}{1}", syntax.ParameterPrefix, column.ColumnName);
                });
            return string.Format("INSERT INTO {0}({1}) VALUES ({2})", DbUtility.FormatByQuote(syntax, table.TableName), names, values);
        }
    }

 

     四、MySql数据批量插入

 

    /// <summary>
    /// 为 MySql.Data 组件提供的用于批量操作的方法。
    /// </summary>
    public sealed class MySqlBatcher : IBatcherProvider
    {
        /// <summary>
        /// 获取或设置提供者服务的上下文。
        /// </summary>
        public ServiceContext ServiceContext { get; set; }

        /// <summary>
        /// 将 <see cref="DataTable"/> 的数据批量插入到数据库中。
        /// </summary>
        /// <param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>
        /// <param name="batchSize">每批次写入的数据量。</param>
        public void Insert(DataTable dataTable, int batchSize = 10000)
        {
            Checker.ArgumentNull(dataTable, "dataTable");
            if (dataTable.Rows.Count == 0)
            {
                return;
            }
            using (var connection = ServiceContext.Database.CreateConnection())
            {
                try
                {
                    connection.TryOpen();
                    using (var command = ServiceContext.Database.Provider.DbProviderFactory.CreateCommand())
                    {
                        if (command == null)
                        {
                            throw new BatcherException(new ArgumentException("command"));
                        }
                        command.Connection = connection;

                        command.CommandText = GenerateInserSql(ServiceContext.Database, command, dataTable);
                        if (command.CommandText == string.Empty)
                        {
                            return;
                        }
                        command.ExecuteNonQuery();
                    }
                }
                catch (Exception exp)
                {
                    throw new BatcherException(exp);
                }
                finally
                {
                    connection.TryClose();
                }
            }
        }

        /// <summary>
        /// 生成插入数据的sql语句。
        /// </summary>
        /// <param name="database"></param>
        /// <param name="command"></param>
        /// <param name="table"></param>
        /// <returns></returns>
        private string GenerateInserSql(IDatabase database, DbCommand command, DataTable table)
        {
            var names = new StringBuilder();
            var values = new StringBuilder();
            var types = new List<DbType>();
            var count = table.Columns.Count;
            var syntax = database.Provider.GetService<ISyntaxProvider>();
            table.EachColumn(c =>
                {
                    if (names.Length > 0)
                    {
                        names.Append(",");
                    }
                    names.AppendFormat("{0}", DbUtility.FormatByQuote(syntax, c.ColumnName));
                    types.Add(c.DataType.GetDbType());
                });

            var i = 0;
            foreach (DataRow row in table.Rows)
            {
                if (i > 0)
                {
                    values.Append(",");
                }
                values.Append("(");
                for (var j = 0; j < count; j++)
                {
                    if (j > 0)
                    {
                        values.Append(", ");
                    }
                    var isStrType = IsStringType(types[j]);
                    var parameter = CreateParameter(database.Provider, isStrType, types[j], row[j], syntax.ParameterPrefix, i, j);
                    if (parameter != null)
                    {
                        values.Append(parameter.ParameterName);
                        command.Parameters.Add(parameter);
                    }
                    else if (isStrType)
                    {
                        values.AppendFormat("'{0}'", row[j]);
                    }
                    else
                    {
                        values.Append(row[j]);
                    }
                }
                values.Append(")");
                i++;
            }
            return string.Format("INSERT INTO {0}({1}) VALUES {2}", DbUtility.FormatByQuote(syntax, table.TableName), names, values);
        }

        /// <summary>
        /// 判断是否为字符串类别。
        /// </summary>
        /// <param name="dbType"></param>
        /// <returns></returns>
        private bool IsStringType(DbType dbType)
        {
            return dbType == DbType.AnsiString || dbType == DbType.AnsiStringFixedLength || dbType == DbType.String || dbType == DbType.StringFixedLength;
        }

        /// <summary>
        /// 创建参数。
        /// </summary>
        /// <param name="provider"></param>
        /// <param name="isStrType"></param>
        /// <param name="dbType"></param>
        /// <param name="value"></param>
        /// <param name="parPrefix"></param>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <returns></returns>
        private DbParameter CreateParameter(IProvider provider, bool isStrType, DbType dbType, object value, char parPrefix, int row, int col)
        {
            //如果生成全部的参数,则速度会很慢,因此,只有数据类型为字符串(包含'号)和日期型时才添加参数
            if ((isStrType && value.ToString().IndexOf('\'') != -1) || dbType == DbType.DateTime)
            {
                var name = string.Format("{0}p_{1}_{2}", parPrefix, row, col);
                var parameter = provider.DbProviderFactory.CreateParameter();
                parameter.ParameterName = name;
                parameter.Direction = ParameterDirection.Input;
                parameter.DbType = dbType;
                parameter.Value = value;
                return parameter;
            }
            return null;
        }
    }

 

     MySql的批量插入,是将值全部写在语句的values里,例如,insert batcher(id, name) values(1, '1', 2, '2', 3, '3', ........ 10, '10')。

 

     五、测试

     接下来写一个测试用例来看一下使用批量插入的效果。

 

        [Test]
        public void TestBatchInsert()
        {
            Console.WriteLine(TimeWatcher.Watch(() =>
                InvokeTest(database =>
                    {
                        var table = new DataTable("Batcher");
                        table.Columns.Add("Id", typeof(int));
                        table.Columns.Add("Name1", typeof(string));
                        table.Columns.Add("Name2", typeof(string));
                        table.Columns.Add("Name3", typeof(string));
                        table.Columns.Add("Name4", typeof(string));

                        //构造100000条数据
                        for (var i = 0; i < 100000; i++)
                        {
                            table.Rows.Add(i, i.ToString(), i.ToString(), i.ToString(), i.ToString());
                        }

                        //获取 IBatcherProvider
                        var batcher = database.Provider.GetService<IBatcherProvider>();
                        if (batcher == null)
                        {
                            Console.WriteLine("不支持批量插入。");
                        }
                        else
                        {
                            batcher.Insert(table);
                        }

                        //输出batcher表的数据量
                        var sql = new SqlCommand("SELECT COUNT(1) FROM Batcher");
                        Console.WriteLine("当前共有 {0} 条数据", database.ExecuteScalar(sql));

                    })));
        }

 

      以下表中列出了四种数据库生成10万条数据各耗用的时间

数据库

耗用时间

MsSql00:00:02.9376300
Oracle00:00:01.5155959
SQLite00:00:01.6275634
MySql00:00:05.4166891
PCL RANSAC拟合分割多条直线【2026最新版】 使用RANSAC算法拟合分割多条直线,输出每一条直线的拟合参数到控制台,并保存直线点云到本地文件夹。博客长期更新,本文最新更新时间为:2026年5月24日。 阅读详情

相关推荐

西门子 S7-200 SMART 系列六:手把手教你配置S7-200 SMART Modbus RTU

最新发表:https://www.ics-pedia.com/%e8%a5%bf%e9%97%a8%e5%ad%90-s7-200-smart-%e7%b3%bb%e5%88%97%e5%85%ad%ef%bc%9a%e6%89%8b%e6%8a%8a%e6%89%8b%e6%95%99%e4%bd%a0%e9%85%8d%e7%bd%aes7-200-smart-modbus-rtu%e5%ae%9e%e4%be%8b/

John_09040211的博客 3282

Dapper 批量添加、修改

1、方法一 Controller控制器,代码如下 public ActionResult SaveAction() { List list = new List(); for (int i = 0; i

KingCruel的专栏 1万+

【ESP32-IDF】I2S音频协议实战:从PDM麦克风到PCM扬声器的全链路解析

本文深入解析ESP32-S3的I2S音频协议,从PDM麦克风采集到PCM扬声器输出的全链路实现。详细介绍了硬件PDM转PCM、Standard模式配置及混合模式协同工作,提供实战代码与性能优化建议,助力开发者高效完成嵌入式音频项目开发。

pea55的博客 889

C# .NET 8 SQL 批量插入 Dapper、BulkCopy 和表值参数

在 .NET 应用程序中处理大型数据集通常需要将数据高效地插入到 SQL Server 中。本文探讨了使用 C# 和 .NET 8 批量插入数据的三种流行技术:Dapper、SqlBulkCopy 和表值参数 (TVP)。我们将比较它们的性能、易用性和对不同场景的适用性。

技术探索驿站 2252

HFSS螺旋线圈的优化设计与高效仿真实践

本文详细介绍了HFSS螺旋线圈的优化设计与高效仿真实践,涵盖核心参数设置、参数化建模、仿真加速技巧及结果分析。通过HFSS软件实现螺旋线圈的高效仿真,特别适用于无线充电和RFID系统设计,提升设计效率与性能验证准确性。

weixin_30235225的博客 445

Cesium+Vue3教程(003):基于Vue3的Cesium自定义地图和地图叠加

在 Cesium 中,是用于加载地表影像图层的核心接口。通过它,您可以将各种地图服务(如卫星影像、街道地图、自定义瓦片等)加载到 Cesium 的地球上。Cesium 提供了多个内置的。

WwLK123的博客 635

C# 使用DapperExtensions实现大批数据插入

要插入5万多条数据 第一、使用Dapper,遥遥无期 public static int InsertByTran(List<Model.LidarPointDeformation> list, string lidarcode) { string connectionString = DataBaseApp.GetBusinessDbStringByLidarcode(lidarcode); using (SqlConnec

whu_xxie的专栏 3603

某东x-api-eid-token风控参数分析与破解

x-api-eid-token是京东的风控参数,在接口当中,如果没有该参数,有一定的概率能请求成功,但是在请求一段时间后,会报403权限失败的,该参数主要通过jsTk.do这个接口生成,并且会将其存储到cookie当中。

zhouzhou_98的博客 1552

C# Dapper批量插入大量数据优化

以三万条数据为例: Dapperr的Excute方法执行插入语句的本质是一条一条的插入,当数据量非常大是会很慢,三万条用了十几分钟 将一组数据一块插入就会相当的快,三万条用了12秒 优化前的批量导入: //_vfsContext.Conn.Open(); //var tran = _vfsContext.Conn.BeginTransaction(IsolationLevel.Seria...

DoWhatYouSay的博客 1万+

第77步 时间序列建模实战:多因素预测 vol-2(以决策树回归为例)

第77步 时间序列建模实战:多因素预测 vol-2(以决策树回归为例)

Jet4505的博客 1008

基于STM32、HAL库的IP2736U_EF快充协议芯片简介及驱动程序设计

@param connected: 连接状态指针 (1=已连接, 0=未连接)= 0x2736) // 检查厂商ID。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。* @param hip: IP2736U句柄指针。

corlin6688的博客 430

Dapper的入门(多表批量插入)

简介: 不知道博客怎么去写去排版,查了好多相关博客,也根据自己做过项目总结,正好最近搭个微服务框架,顺便把搭建微服务框架所运用的知识都进行博客梳理,为了以后复习,就仔细琢磨写一下自己在微服务框架中对Dapepr的理解以及项目中应用。 dapper只是一个代码文件,完全开源,你可以在项目里任何位置,来实现数据到对象ORM操作(当然先引用Dapper文件),体积小速度快。使用好处增删改查比较快,不用自己写sql,因为这都是重复技术含量低的工作,还有程序中大量的数据库中读取数据然后创建model,...

zp19860529的博客 3853

宇树G1开发实践--PPT汇报(基础版)

本文介绍了一套基于宇树G1人形机器人的PPT自动演示系统,可实现"一键启动、自动演讲"功能。系统通过多线程同步技术,将音频播放与机器人动作完美结合,支持12种预设社交互动动作。硬件依赖宇树G1机器人、外接音响和网络连接,软件采用Python SDK和ALSA音频工具。核心功能包括音频文件自动排序、外接音响播放控制、机器人动作执行及音画同步。使用时需配置网络接口和音频设备号,运行后自动按顺序播放音频并执行随机动作。系统特别强调了安全注意事项,并提供了常见问题解决方案,适用于展会、汇报等需要

m0_47999117的博客 510

C#:几种数据库的大数据批量插入 - faib

在之前只知道SqlServer支持数据批量插入,殊不知道Oracle、SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解决方法。 首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前一篇文章中已经提到过了。 ...

184

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C#:几种数据库的大数据批量插入(转)

在之前只知道SqlServer支持数据批量插入,殊不知道Oracle、SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解决方法。 首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前一篇文章中已经提到过了。 /// <summa...

weixin_30810239的博客 98

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

c#几种数据库的大数据批量插入(SqlServer、Oracle、SQLite和MySql)

转自:https://www.zhangshengrong.com/p/OgN5BjdXnW/ c#几种数据库的大数据批量插入(SqlServer、Oracle、SQLite和MySql) 在之前只知道SqlServer支持数据批量插入,殊不知道Oracle、SQLite和MySql也是支持的,不过Oracle需要使用Orace.DataAccess驱动,今天就贴出几种数据库的批量插入解决方法。 首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前

u014094704的博客 4476

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

上一篇: sqlserver 2005 install
下一篇: 异步调用四大方法
lianchengzhang
博客等级 码龄18年 22粉丝 47原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值