zoukankan      html  css  js  c++  java
  • net+Oracle开发过程中遇到的小问题

    最新的项目开始使用Oracle后,5个月之间遇到一些在SqlServer中没有遇到的问题,这里记录并贴上一些常用的解决办法。

    Oracle相关

    一、数据库不同版本还原

    刚开始我们一直使用Oracle12C进行开发,到上线服务器时说12C与可能不太稳定,有些问题不好定位就转用11g,这里牵扯到12C导出的DMP文件导入到11G上的问题,导出导入语句:

    exp 账号/密码@STO_DataBase file=D:STO_DataBase.dmp full=y
    imp 账号/密码@STO_DataBase file=D:DataBackUpSTO_DataBase.dmp full=y
    

    导入报异常版本不一样,无法导入,这里用一款小工具可以解决问题下载地址

    此处输入图片的描述

    二、数据库创建

    数据库文件大小受DB_BLOCK_SIZE决定,默认是8K对应的数据库文件是32G,所以创建数据库时数据库的大小不要设置最大值最好设置成无限大,可以多设置几个数据库文件,以免数据库大小不够用引起数据库异常。创建语句:

    //创建表空间
    CREATE TABLESPACE STO_Data  
    LOGGING  
    DATAFILE 
    'D:DataBaseDbFileSTO_DATA.DBF',
    'D:DataBaseDbFileSTO_DATA1.DBF',  
    'D:DataBaseDbFileSTO_DATA2.DBF'  
    SIZE 512M   
    AUTOEXTEND ON   
    NEXT 512M MAXSIZE unlimited
    EXTENT MANAGEMENT LOCAL;
    //创建临时表空间
    CREATE TEMPORARY TABLESPACE STO_Temp  
    TEMPFILE 'D:DataBaseDbFileSTO_Temp.DBF'  
    SIZE 512M  
    AUTOEXTEND ON  
    NEXT 512M MAXSIZE unlimite
    EXTENT MANAGEMENT LOCAL;  
    //创建用户
    CREATE USER 用户名 IDENTIFIED BY 用户名密码
    DEFAULT TABLESPACE STO_Data  
    TEMPORARY TABLESPACE STO_Temp  
    //用户赋权限  
    grant connect,resource,dba  to 用户名 
    

    三、常见问题

    (1)存储过程参数

    存储过程的参数命名最好可以按照规则来否则会有问题,例如:

    create or replace procedure Proc_Test(IN_CompanyName       in varchar2, 
                                          OUT_Table        out sys_refcursor) as
    
    begin open OUT_Table for select * from Waybill_Pickup t where t.companyname=IN_CompanyName;
      
    end Proc_Test;
    

    如果参数使用的和数据库中的表字段一样会引起失效,例如:

    create or replace procedure Proc_Test(CompanyName       in varchar2, 
                                          OUT_Table        out sys_refcursor) as
    
    begin open OUT_Table for select * from Waybill_Pickup t where t.companyname=CompanyName;
      
    end Proc_Test;
    

    (2)定期释放Temp文件空间

    长时间使用会使Temp文件越来越大,而引起某些操作异常。

    alter tablespace STO_TEMP shrink space;
    

    (3)索引失效

    Oracle批量插入如果是用Oracle.DataAccess.Client.OracleBulkCopy 类,数据在插入过程中会引起索引失效,如果是业务表就会引起业务查询非常缓慢。但是插入效率很高,如果数据库使用读写分离,或者接口采用读写分离的两个表可以通过此方法进行插入,如果遇到索引失效可用以下语句查看和修复。

    //查看失效索引
    select * from user_indexes where Status='UNUSABLE'
    //重建失效索引
    begin
      FOR cur in (select INDEX_NAME from user_indexes where Status='UNUSABLE') loop  
         execute immediate  'alter index '|| cur.INDEX_NAME||' rebuild' ;
      END LOOP;  
    end;
    

    (4)遇到问题如何排查

    当Oracle遇到内部问题出现异常和挂机后的排查步骤(Oracle服务器)

    1. 查找日志D:appAdministratordiag dbmssto_databasestodatabasealert
    2. 查询跟踪文件D:appAdministratordiag dbmssto_databasestodatabase race
    3. 然后定位问题解决问题

    参考文档

    当时遇到的问题是:数据库直接Down掉了,连接时报没有监听程序。重启服务器后过一会数据库就挂掉了
    检查Oracle日志:
    D:appAdministratordiag dbmssto_databasestodatabasealert
    查看Log文件,在日志文件中找到错误信息提示:
    此处输入图片的描述

    检查跟踪文件
    D:appAdministratordiag dbmssto_databasestodatabase race
    在跟踪文件中查看错误信息引起的原因:
    根据错误查找出引起错误的SQL语句,最后定位到是单条语句超过65535个参数引起,由于.net中使用了DbDataAdapter进行保存数据,他类似于拼接的Sql语句,更改批次提交数解决问题。

    .net相关

    一、处理传参和LONG RAW类型

    DbCommand处理Oracle数据库默认参数绑定是按次序且不能查询LONG RAW类型,处理SqlServer数据库不用处理,
    所以在初始化DbCommand时需要加入如下代码

    (cmd as Oracle.DataAccess.Client.OracleCommand).BindByName=true;
    (cmd as Oracle.DataAccess.Client.OracleCommand).InitialLONGFetchSize = -1; 
    

    二、批量插入

    (1)OracleBulkCopy

    OracleBulkCopy在Oracle.DataAccess.DLL中,速率很快,但不进行主键和唯一键检查,经常会将唯一索引弄坏,并且在插入过程中普通索引也会失效。

    /// <summary>
    /// 批量插入数据库
    /// </summary>
    /// <param name="datatable"></param>
    /// <returns></returns>
    public string OracleBulkInsert(DataTable datatable)
    {
        OracleBulkCopy bulkCopy = new OracleBulkCopy(_connStr, OracleBulkCopyOptions.UseInternalTransaction);
        try
        {
            bulkCopy.DestinationTableName = datatable.TableName;
            bulkCopy.BulkCopyTimeout = 600000;
            bulkCopy.BatchSize = 50000;
            if (datatable != null && datatable.Rows.Count != 0)
                bulkCopy.WriteToServer(datatable);
            return "";
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (bulkCopy != null)
                bulkCopy.Close();
        }
    }
    

    DataTable在插入时应注意字段类型和顺序,可以用以下代码获得表结构

    /// <summary>
    /// 根据表名获取Table结构
    /// </summary>
    /// <param name="tableName">表名</param>
    /// <returns></returns>
    public  DataTable InitStructureByTable(string tableName)
    {
        DataTable dtColums = helper.GetDataSet("select column_name,data_type from user_tab_columns where table_name='" + tableName.ToUpper() + "' order by column_id", null).Tables[0];
        DataTable dtNew = new DataTable();
        dtNew.TableName = tableName;
        //匹配列数
        for (int j = 0; j < dtColums.Rows.Count; j++)
        {
            switch (dtColums.Rows[j][1].ToString().ToUpper())
            {
                case "DATE":
                    dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(DateTime)));
                    break;
                case "NUMBER":
                    dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(double)));
                    break;
                default:
                    dtNew.Columns.Add(new DataColumn(dtColums.Rows[j][0].ToString(), typeof(string)));
                    break;
            }              
        }
        return dtNew;
    }
    

    (2)DbDataAdapter批量插入

    这种插入方式要比OracleBulkCopy要慢,相当于拼接了带参数的插入语句插入,注意UpdateBatchSize数值不要过大,否则可能由于单句Sql语句参数超过65535引起数据库崩溃。

    /// <summary>
    /// 批量插入数据库
    /// </summary>
    /// <param name="datatable"></param>
    /// <returns></returns>
    public  string BulkInsertCopy(DataTable datatable)
    {
        DbDataAdapter adapter = _factory.CreateDataAdapter();        
        DbCommand cmd = _factory.CreateCommand();
        DbCommandBuilder cb = _factory.CreateCommandBuilder();      
        try
        {
            adapter.UpdateBatchSize = 200;
            using (DbConnection conn = _factory.CreateConnection())
            {
                conn.ConnectionString = ConnectionString;                
                conn.Open();
                cmd.Connection = conn;
                //cmd.Transaction = conn.BeginTransaction();          
                cb.DataAdapter = adapter;                 
                adapter.SelectCommand = cmd;
                adapter.SelectCommand.CommandText = "select * from " + datatable.TableName;
                adapter.FillSchema(datatable, SchemaType.Source);
                adapter.Update(datatable);
                //cmd.Transaction.Commit();           
            }
            return "";
        }
        catch (Exception ex)
        {
            //cmd.Transaction.Rollback();
            return ex.Message;
        }
        finally
        {
            cmd.Dispose();
            cb.Dispose();
            adapter.Dispose();
        }
    }
    
  • 相关阅读:
    docker-compose 命令不存在
    linux安装rabbitmq ssm集成rabbitmq
    tomcat参数错误 服务器400
    无限极分内 自联查询
    图片移入变大 点击图片切换 点击按钮显示图片
    js正则表达式基本书写
    随鼠标移动
    输入电话号码
    添加新句子
    窗口的弹出与关闭
  • 原文地址:https://www.cnblogs.com/kaoleba/p/8328928.html
Copyright © 2011-2022 走看看