永不言弃!
不忘初心:感恩的心!上进的心!

根据上篇的内容,简单测试了三种方式的对比,需要使用的,请自行根据需求优化。。。

上篇文字网址:https://www.cnblogs.com/ggll611928/p/17897005.html

 

三种方式:

1、常规方式,通过sql语句循环执行 

2、使用OracleBulkCopy

3、使用ArrayBind

 

后面:增加了扩展,使用存储过程+  ArrayBind

具体步骤如下:

 

1、创建测试表

CREATE TABLE T_TEST
(
  ID      NUMBER(9) not null,
  NAME    NVARCHAR2(30) not null,
  AGE     NUMBER(2),
  CREATEDATE DATE,
  REMARK  NVARCHAR2(50)
);
COMMENT ON COLUMN T_TEST.ID IS '测试编号';
COMMENT ON COLUMN T_TEST.NAME IS '测试姓名';
COMMENT ON COLUMN T_TEST.AGE IS '创建时间';
COMMENT ON COLUMN T_TEST.CREATEDATE IS '测试年龄';
COMMENT ON COLUMN T_TEST.REMARK IS '测试描述';

ALTER TABLE T_TEST ADD CONSTRAINT PK_T_TEST PRIMARY KEY (ID);

 

2、创建数据源

使用DataTable,模拟数据源

        /// <summary>
        /// 获取测试数据源
        /// </summary>
        /// <returns></returns>
        public DataTable GetTestTable(int type)
        {
            //创建数据源
            DataTable dt = new DataTable("t_test");
            dt.Columns.Add("id", typeof(int));
            dt.Columns.Add("name", typeof(string));
            dt.Columns.Add("age", typeof(int));
            dt.Columns.Add("createdate", typeof(DateTime));
             
            int i, k;
            if (type == 1)
            {
                i = 1;
                k = 100000;
            }
            else if (type == 2)
            {
                i = 100001;
                k = 200000;
            }
            else
            {
                i = 200001;
                k = 300000;
            }

            //添加数据到 DataTable  
            for (; i <= k; i++)
            { 
                DataRow row = dt.NewRow();
                row["id"] = i;
                row["name"] = i+ "-" + i;
                row["age"] = 18;
                row["createdate"] = DateTime.Now;
                dt.Rows.Add(row);
            }
            return dt;
        }

 

3、编写三种方式

3.1 方式一:常规方式

        /// <summary>
        /// 批量处理插入数据,使用常规方式
        /// </summary>
        /// <param name="dt">数据源</param>
        /// <returns></returns>
        public int Insert(DataTable dt)
        {
            int count = 0;
            string conString = orcHelper.GetConn();
            using (OracleConnection conn = new OracleConnection(conString))
            {
                if (conn.State != ConnectionState.Open)
                {
                    conn.Open();
                }
                using (OracleTransaction transaction = conn.BeginTransaction())
                {
                    using (OracleCommand cmd = conn.CreateCommand())
                    { 
                        cmd.Transaction = transaction;
                        string sql = @"insert into t_test(id, name, age, createdate) values(:id, :name, :age, :createdate)";
                        foreach (DataRow dw in dt.Rows)
                        {
                            OracleParameter[] parametersList = new OracleParameter[]
                            {
                                new OracleParameter(":id", int.Parse(dw["id"].ToString())),
                                new OracleParameter(":name", dw["name"].ToString()),
                                new OracleParameter(":age",int.Parse(dw["age"].ToString())),
                                new OracleParameter(":createdate",DateTime.Parse(dw["createdate"].ToString())),
                            };
                            cmd.CommandText = sql;
                            cmd.CommandType = CommandType.Text;
                            cmd.Parameters.Clear();
                            cmd.Parameters.AddRange(parametersList);

                            try
                            {
                                count = cmd.ExecuteNonQuery();
                                if (count < 0) { 
                                    transaction.Rollback();
                                    return count;
                                }
                            }
                            catch (Exception)
                            {
                                transaction.Rollback();
                                return count;
                            }
                        }
                        transaction.Commit();
                        return count;
                    }
                }
            }
        }

 

3.2 方式二:使用OracleBulkCopy

        /// <summary>
        /// 批量处理插入数据,使用OracleBulkCopy
        /// </summary>
        /// <param name="dt">数据源</param> 
        public bool InsertOracleBulkCopy(DataTable dt)
        { 
            string conString = orcHelper.GetConn();
            using (OracleConnection conn = new OracleConnection(conString))
            {
                if (conn.State != ConnectionState.Open)
                {
                    conn.Open();
                }

                using (OracleTransaction transaction = conn.BeginTransaction())
                {
                    //创建 OracleBulkCopy 对象,并指定数据库连接信息 
                    using (OracleBulkCopy bulkCopy = new OracleBulkCopy(conn))
                    { 
                        //数据库表名称
                        bulkCopy.DestinationTableName = dt.TableName;      
                        //指定批量插入的行数 
                        bulkCopy.BatchSize = dt.Rows.Count;             

                        //指定 DataTable 和数据表的列名映射关系
                        for (int i = 0; i < dt.Columns.Count; i++)
                        {
                            bulkCopy.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
                        }
                        try
                        {  
                            //将数据源添加到 OracleBulkCopy 对象中
                            bulkCopy.WriteToServer(dt);              
                            transaction.Commit();
                            return true; 
                        }
                        catch (Exception)
                        {
                            transaction.Rollback();
                            return false; 
                        }
                    }
                } 
            } 
        }

 

3.3 方式三:使用ArrayBind

        /// <summary>
        /// 批量处理插入数据,使用ArrayBind
        /// <param name="dt">数据源</param>
        /// </summary>
        public int InsertArrayBind(DataTable dt)
        {
            string conString = orcHelper.GetConn();
            using (OracleConnection conn = new OracleConnection(conString))
            {
                if (conn.State != ConnectionState.Open)
                {
                    conn.Open();
                }

                using (OracleTransaction transaction = conn.BeginTransaction())
                {
                    int recordCount = dt.Rows.Count, i = 0, count = 0;

                    using (OracleCommand cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = transaction;
                        cmd.CommandText = "insert into t_test(id, name, age, createdate) values(:id, :name, :age, :createdate)";
                        //指定单次需要处理的条数
                        cmd.ArrayBindCount = recordCount;
                        int[] p_col1 = new int[recordCount];
                        string[] p_col2 = new string[recordCount];
                        int[] p_col3 = new int[recordCount];
                        DateTime[] p_col4 = new DateTime[recordCount];

                        cmd.Parameters.Add(new OracleParameter("id", OracleDbType.Int32, p_col1, ParameterDirection.Input));
                        cmd.Parameters.Add(new OracleParameter("name", OracleDbType.Varchar2, p_col2, ParameterDirection.Input));
                        cmd.Parameters.Add(new OracleParameter("age", OracleDbType.Int32, p_col3, ParameterDirection.Input));
                        cmd.Parameters.Add(new OracleParameter("createdate", OracleDbType.Date, p_col4, ParameterDirection.Input));

                        foreach (DataRow dr in dt.Rows)
                        {
                            p_col1[i] = Convert.ToInt32(dr["id"].ToString());
                            p_col2[i] = dr["name"].ToString();
                            p_col3[i] = Convert.ToInt32(dr["age"].ToString());
                            p_col4[i] = Convert.ToDateTime(dr["createdate"].ToString());
                            i++;
                        }

                        try
                        {  
                            count = cmd.ExecuteNonQuery();
                            if (count > 0) { transaction.Commit(); } 
                        }
                        catch (Exception)
                        {
                            transaction.Rollback(); 
                        } 
                        return count;
                    }
                }
            }
        }

 

4、调用三种方式,进行测试

只需调用下面的方法,即可测试三种方式的对比效果

        /// <summary>
        /// 测试批量插入
        /// </summary>
        private void TestInsert()
        { 
            int count;
            long totalTime;
            string message = "", result;
            var sw = new Stopwatch();
             
            #region 1、使用常规方式进行批量添加数据
            DataTable dataTable = sysService.GetTestTable(1);
            message += "三种方式对比,每种循环的总记录数:" + dataTable.Rows.Count + "\n";

            sw.Start();
            count = sysService.Insert(dataTable);
            sw.Stop();
            totalTime = sw.ElapsedMilliseconds; 
            result = count > 0 ? "成功" : "失败";
            message += "\n方式一:常规方式--" + result + ",  使用总时间:" + totalTime ;

            #endregion

            #region 2、使用OracleBulkCopy进行批量添加数据 
            dataTable = sysService.GetTestTable(2); 

            sw.Start();
            bool isOk = sysService.InsertOracleBulkCopy(dataTable);
            sw.Stop();
            totalTime = sw.ElapsedMilliseconds; 
            result = isOk ? "成功" : "失败";
            message += "\n方式二:OracleBulkCopy--" + result + ",  使用总时间:" + totalTime ;

            #endregion

            #region 3、使用ArrayBind进行批量添加数据
            dataTable = sysService.GetTestTable(3); 

            sw.Start();
            count = sysService.InsertArrayBind(dataTable);
            sw.Stop();
            totalTime = sw.ElapsedMilliseconds; 
            result = count>0 ? "成功" : "失败";
            message += "\n方式三:ArrayBind--" + result + ",  使用总时间:" + totalTime;

            #endregion
             
            MessageBox.Show(message, "GrowlMsg"); 
        }

 

5、运行结果

 

执行完后,数据库中该表的总条数

 

重点注意:数据的完整性及合理性,如主键数据必须唯一,日期必须是日期格式等。

 

6、扩展:存储过程

使用存储过程 + ArrayBind,批量修改数据

 

6.1 创建测试用的存储过程

主要实现修改数据

CREATE OR REPLACE PROCEDURE p_test_yy( 
   p_Id    IN  t_test.ID%TYPE,
   p_Name  IN  t_test.NAME%type,
   p_ErrCode    OUT NUMBER,
   p_ErrText    OUT VARCHAR2
     ) AS
     v_cnt    NUMBER;
begin
   
       select count(*) into v_cnt from t_test where id = p_Id;

         if v_cnt is null or v_cnt = 0 then
                p_ErrCode := -1;
                p_ErrText :='编号:'||p_Id||'-信息不存在!';
                return;
         end if;
         
         -- 模拟错误数据
         if p_Id = 10 or p_Id = 11 then 
                p_ErrCode := -1;
              p_ErrText :='编号:'||p_Id||'-重复!';
                return;
         end if;
         
         update t_test set createdate=sysdate where id = p_Id;
          p_ErrCode := p_Id;
          p_ErrText := '编号:'||p_Id||'-修改日期成功!';
         commit;
             
    exception
  when others then
     p_ErrCode := -ABS(sqlcode); 
     P_ErrText := '发生错误,错误信息为:'||SUBSTR(SQLERRM, 1, 200);
     rollback;
         
end p_test_yy;

 

6.2 重要代码

        /// <summary>
        /// 批量处理数据,使用存储过程 + ArrayBind
        /// <param name="dt">数据源</param>
        /// </summary>
        public int InsertArrayBindProcedure(DataTable dt)
        {
            string conString = orcHelper.GetConn();
            using (OracleConnection conn = new OracleConnection(conString))
            {
                if (conn.State != ConnectionState.Open)
                {
                    conn.Open();
                }

                using (OracleTransaction transaction = conn.BeginTransaction())
                {
                    int recordCount = dt.Rows.Count, count = 0;

                    using (OracleCommand cmd = conn.CreateCommand())
                    {
                        cmd.Transaction = transaction;
                        cmd.CommandText = "p_test_yy";
                        cmd.BindByName = true;
                        cmd.CommandType = CommandType.StoredProcedure;

                        //指定单次需要处理的条数
                        cmd.ArrayBindCount = recordCount;
                        var columnId = dt.AsEnumerable().Select(row => row.Field<object>("id")).ToArray();
                        var columnName = dt.AsEnumerable().Select(row => row.Field<object>("name")).ToArray();

                        cmd.Parameters.Add(new OracleParameter("p_Id", OracleDbType.Int32, columnId, ParameterDirection.Input));
                        cmd.Parameters.Add(new OracleParameter("p_Name", OracleDbType.Varchar2, columnName, ParameterDirection.Input));
                        cmd.Parameters.Add(
                            new OracleParameter("p_ErrCode", OracleDbType.Int32, ParameterDirection.Output)
                            { ArrayBindSize = new int[] { recordCount } });
                        cmd.Parameters.Add(
                            new OracleParameter("p_ErrText", OracleDbType.Varchar2, ParameterDirection.Output)
                            { ArrayBindSize = new int[] { recordCount } });

                        try
                        {
                            count = cmd.ExecuteNonQuery();
                            //正常获取p_ErrCode的全部数据
                            object objCode = cmd.Parameters["p_ErrCode"].Value; 
                            OracleDecimal[] oDecimalCodes = (OracleDecimal[]) objCode;
                            //只能获取p_ErrText的第一条数据
                            object objText = cmd.Parameters["p_ErrText"].Value;
                            OracleString[] oDecimalTexts = (OracleString[])objText;

                            int codeCount = oDecimalCodes.AsEnumerable().ToList().Where(t => t < 1).Count();
                            if (codeCount > 0)
                            {
                                count = 0;
                                transaction.Rollback();
                                return count;
                            }

                            count = oDecimalCodes.Count();
                            transaction.Commit(); 
                        }
                        catch (Exception)
                        {
                            transaction.Rollback();
                        }
                        return count;
                    }
                }
            }
        }

 

6.3 调用

其中GetTestTable,在上面右介绍,此处不再说明

        /// <summary>
        /// 测试存储过程批量处理数据
        /// </summary>
        private void TestProcedure() {
            int count;
            long totalTime;
            string message = "", result;
            var sw = new Stopwatch();

            DataTable dataTable = sysService.GetTestTable(1);
            message += "循环的总记录数:" + dataTable.Rows.Count + "\n";

            sw.Start();
            count = sysService.InsertArrayBindProcedure(dataTable);
            sw.Stop();
            totalTime = sw.ElapsedMilliseconds;
            result = count > 0 ? "成功" : "失败";
            message += "\n测试存储过程批量处理数据--" + result + ",  使用总时间:" + totalTime;

            MessageBox.Show(message, "GrowlMsg");
        }

 

6.4 调试

根据下图,可以看到

存储过程返回的第一个参数p_ErrCode,可以正常获取全部数据

但是,第二个参数p_ErrText,只能获取第一条的数据

原因目前还没弄清除,有需求的自己研究。。。

故需要使用存储过程批量处理数据时,执行前一定确定数据的完整性,这样批量执行就不会出错!!!

 

 

 

 

posted on 2023-12-12 17:26  永不言弃!  阅读(213)  评论(0编辑  收藏  举报