zoukankan      html  css  js  c++  java
  • Mybatis.NET Oracle 线上神奇问题:Value does not fall within the expected range.

    1、错误现象

      在向数据库查询一条数据的时候报如下错误:

    1    Value does not fall within the expected range.
    2    at Oracle.ManagedDataAccess.Client.OracleParameter.set_Value(Object value)
    3    at MyBatis.DataMapper.Data.DefaultPreparedCommand.ApplyParameterMap(IDbProvider dbProvider, IDbCommand command, RequestScope request, IStatement statement, Object parameterObject)
    4    at MyBatis.DataMapper.Data.DefaultPreparedCommand.Create(RequestScope request, ISession session, IStatement statement, Object parameterObject)
    5    at MyBatis.DataMapper.MappedStatements.MappedStatement.Execute[T](Object preEvent, Object postEvent, ISession session, Object parameterObject, Func`3 requestRunner)
    6    at MyBatis.DataMapper.MappedStatements.MappedStatement.ExecuteInsert(ISession session, Object parameterObject)
    7    at MyBatis.DataMapper.DataMapper.Insert(String statementId, Object parameterObject)

     错误信息也很简单。在向OracleParameter的属性Value赋值时报错。

    2、找不出的错误原因

      源码如下:

      

     1 [Category("Data"), Description(""), DefaultValue((string) null)]
     2 public override object Value
     3 {
     4     get => 
     5         this.m_value;
     6     set
     7     {
     8         if (((value != null) && (value != DBNull.Value)) && (this.m_enumType == PrmEnumType.NOTSET))
     9         {
    10             Type type = value.GetType();
    11             if (((type == typeof(sbyte)) || (type == typeof(ushort))) || ((type == typeof(uint)) || (type == typeof(ulong))))
    12             {
    13                 throw new ArgumentException();
    14             }
    15             object obj2 = OraDb_DbTypeTable.s_table[type];
    16             if ((obj2 == null) && type.IsArray)
    17             {
    18                 obj2 = OraDb_DbTypeTable.s_table[type.GetElementType()];
    19             }
    20             if (obj2 == null)
    21             {
    22                 throw new ArgumentException();
    23             }
    24             this.m_oraDbType = (OracleDbType) obj2;
    25             this.m_bSetDbType = false;
    26             this.m_enumType = PrmEnumType.VALUE;
    27         }
    28         this.m_value = value;
    29     }
    30 }
    31  

      从源码可以看到,报错可能出现在两个地方:if (((type == typeof(sbyte)) || (type == typeof(ushort))) || ((type == typeof(uint)) || (type == typeof(ulong))))【更老的驱动版本bool类型也不支持】 和 if (obj2 == null)。出现这个错误说明无法将C#类型映射为Oracle类型。

      首先检查第一处可能,发现插入报错的类中使用的类型有DateTime,DateTime?,long,int,string。发现第一处不满足。

      检查第二次可能,第二处取类型是从 OraDb_DbTypeTable 获取到的。源码如下:

      

     1 internal static void InsertTableEntries()
     2 {
     3     s_table.Add(typeof(byte), OracleDbType.Byte);
     4     s_table.Add(typeof(byte[]), OracleDbType.Raw);
     5     s_table.Add(typeof(char), OracleDbType.Varchar2);
     6     s_table.Add(typeof(char[]), OracleDbType.Varchar2);
     7     s_table.Add(typeof(DateTime), OracleDbType.TimeStamp);
     8     s_table.Add(typeof(short), OracleDbType.Int16);
     9     s_table.Add(typeof(int), OracleDbType.Int32);
    10     s_table.Add(typeof(long), OracleDbType.Int64);
    11     s_table.Add(typeof(float), OracleDbType.Single);
    12     s_table.Add(typeof(double), OracleDbType.Double);
    13     s_table.Add(typeof(decimal), OracleDbType.Decimal);
    14     s_table.Add(typeof(string), OracleDbType.Varchar2);
    15     s_table.Add(typeof(TimeSpan), OracleDbType.IntervalDS);
    16     s_table.Add(typeof(OracleBFile), OracleDbType.BFile);
    17     s_table.Add(typeof(OracleBinary), OracleDbType.Raw);
    18     s_table.Add(typeof(OracleBlob), OracleDbType.Blob);
    19     s_table.Add(typeof(OracleClob), OracleDbType.Clob);
    20     s_table.Add(typeof(OracleDate), OracleDbType.Date);
    21     s_table.Add(typeof(OracleDecimal), OracleDbType.Decimal);
    22     s_table.Add(typeof(OracleIntervalDS), OracleDbType.IntervalDS);
    23     s_table.Add(typeof(OracleIntervalYM), OracleDbType.IntervalYM);
    24     s_table.Add(typeof(OracleRefCursor), OracleDbType.RefCursor);
    25     s_table.Add(typeof(OracleString), OracleDbType.Varchar2);
    26     s_table.Add(typeof(OracleTimeStamp), OracleDbType.TimeStamp);
    27     s_table.Add(typeof(OracleTimeStampLTZ), OracleDbType.TimeStampLTZ);
    28     s_table.Add(typeof(OracleTimeStampTZ), OracleDbType.TimeStampTZ);
    29     s_table.Add(typeof(OracleXmlType), OracleDbType.XmlType);
    30     s_table.Add(typeof(bool), OracleDbType.Boolean);
    31     s_table.Add(typeof(DateTimeOffset), OracleDbType.TimeStampTZ);
    32 }

      发现里面没有DateTime?,难道是这个地方不行。那也不对啊,其它地方同样类型是可以保存到数据库的啊。继续找下去在 MyBatis.DataMapper.Data.DefaultPreparedCommand.ApplyParameterMap 找到了信息。源码如下:

      

     1 public virtual void SetParameter(IDataParameter dataParameter, object parameterValue, string dbType)
     2 {
     3     if (parameterValue != null)
     4     {
     5         dataParameter.Value = parameterValue;
     6     }
     7     else
     8     {
     9         dataParameter.Value = DBNull.Value;
    10     }
    11 }

      如果值为null,会自动赋值为 DBNull.Value 也就会不会报错。既然都不会出现问题,可问题又会出现在哪里呢?

    3、柳暗花明

      在本地尝试各种方法后仍然不能重现,只能让领导将生产程序包拷贝一份下来进行尝试。

      包拿到之后,进行必要配置启动,出现了新的诡异问题 Redis报错 :No connection is available to service this operation。仔细检查Redis配置发现问题。抓下内存快照看看实际配置信息是什么:

      

       看到这个一脸懵逼,Password竟然是null,明明已经配置了啊。查看了加载配置的源码,发现根本不会解析Password配置,还有这种操作,这程序包是有多老。弄好了Redis,启动保存数据,果然不行。反编译生产源码,发现惊天一幕:

      

       Id的类型竟然ulong。我擦这是多久没有更新了。原因至此是找到了。

    4、吐槽

      这个服务是公司内部自己用的,很古老了。以前都是手工拷贝程序包发布的。最近由于公司发生了些意外事情,原来服务器不能用,需要部署新的服务器上。由于古老,不知道老大当时拿了多么古老的程序包部署了。

     
  • 相关阅读:
    use imagination
    tar
    简单抓取安居客房产数据,并保存到Oracle数据库
    svn的安装(整合apache、ldap)包括错误解决post commit FS processing had error
    SVN安装中遇到的问题
    Linux环境源码编译安装SVN
    [转]SVN安装问题The Apache Portable Runtime (APR) library cannot be found
    深入浅出数据分析-脑图
    Python3.5在Windows 7下连接ORACLE数据库
    Python3.5之TuShare
  • 原文地址:https://www.cnblogs.com/gsjlovenet/p/11658289.html
Copyright © 2011-2022 走看看