有个自身迭代出现了问题,无法理解啊

sbhanhan 2018-10-27 12:10:41
 private string GET_GYS_GYSID(string province,int _ix)
{
Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
string str = _ix.ToString().PadLeft(3, '0');//001
if (!gysbll.Exists(province + str))
{
return province + str;
}
else
{
_ix = _ix + 1;
str = _ix.ToString().PadLeft(3, '0');//001
return GET_GYS_GYSID(province,_ix);
}

}


这个方法,我想的是判断这个字段是否存在,如果不存在直接输出,如果存在的话,数字加1然后输出,这个迭代总是出问题,该怎么处理
...全文
1032 19 打赏 收藏 转发到动态 举报
写回复
用AI写文章
19 条回复
切换为时间正序
请发表友善的回复…
发表回复
kusirp21 2018-11-13
  • 打赏
  • 举报
回复
从本身这段代码上来看,在业务设计存在很大的问题。

先说一下自身代码上的问题,确实如22楼所说,递归时可能存在数据库连接层上的浪费,第二是递归本身的资源浪费。

Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
如,这句代码是使用已经存在的连接还是每次新连数连接?如果是新建连接,那么不论是你循环还是递归,都是会造成数据库连接池资源的耗尽!即算使用已经存在连接的连接,但是你本身的GYS对象也会大量堆积到堆中,造成内存的快速增长。

递归与循环的不同之处在于,递归的实现是要保留现场的!所以在系统中的递归运算调用的深层是有限的(win7应该是63层),而循环却没有这个限制!循环多少次都可以的!这是递归的缺点所限制的。

再说代码,代本身上是没大问题,就是多写了一句无用的语句或是代码运算上多了一点而已。

/// 这是一个完整的递归方式!
private string GET_GYS_GYSID(Oracle.BLL.GYS gysbll, int _ix)
{
string str = (_ix%1000).ToString("AH000"); // 3.ToString("AH000")的运行结果是“AH003"
if (!gysbll.Exists(str)) return str; // 因为存在return,所以不必再写else,注意结果
return GET_GYS_GYSID(gysbll, _ix++); // 把gysbll作为参数输入时,防止递归中创建的大量GYS对象。
}


但是即使是这样,我们也无未能突破递归调用的限制,换句话来出,如果需要超出限制次数的查询,该方法会出现问题的。不用考虑什么死循环,本身递归层次就会引发exception!

然后说一下数据库设计:
1,你查询的是不是主键?如果不是,在没有索引的情况下,查询速度比较慢。如果是,这么写入会引发聚集索引重排!数据量大一点麻烦会很大!
2,业务中是否有多线程?如果有,你查询完毕和在你插入时,两条线程交叉进行,必然会存在一个失败!

单凭这两点的问题都能说明你系统设计存在极大缺陷!那么再进行优化的意义也不大了!

如果不考虑以上两点,可以考虑给你优化建议:
1)批量查询,获得数据库中部分不存在的AH000编号。并做列表(队列也行)返回。
2)多线程加锁,每个线程随机获得一个AH000编号,并将编号从列表中删除(这个等于在缓存中干这个事)。
3)指定时间再次执行1)补充列表中的数据。2)步骤中某个线程可能未使用或者其他线程删除的用来回收。
千杯不醉-sen 2018-11-13
  • 打赏
  • 举报
回复

        private string GET_GYS_GYSID(string province, int _ix)
        {
            if(_ix < 0 || _ix > 999)
            {
                // 不知你要如何处理
            }
            string fieldName = province + _ix.ToString().PadLeft(3, '0');
            Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
            if (gysbll.Exists(fieldName))
            {
                return GET_GYS_GYSID(province, _ix + 1);
            }
            return fieldName;
        }
tq1086 2018-11-09
  • 打赏
  • 举报
回复
觉得有两个问题。1) 如果_ix对应的记录不存在,递归会一直进行,直到栈空间耗尽。2) 每次递归都建立GSY对象,造成CPU和内存使用上的浪费。不如改成

private string GET_GYS_GYSID(string province, int _ix)
{
Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
return do_GET_SYS_GYSID(gysbll, province, _ix);
}

private string do_GET_GYS_GYSID(Oracle.BLL.GYS gysbll string province, int _ix)
{
if (_ix > 999)
{
throw new RuntimeException("blablabla");
}

string str = _ix.ToString().PadLeft(3, '0');//001
if (!gysbll.Exists(province + str))
{
return province + str;
}

return do_GET_GYS_GYSID(gysbll, province, _ix + 1)
}
攻城狮! 2018-10-29
  • 打赏
  • 举报
回复
不错啊,但是地柜有啥用呢
正怒月神 2018-10-29
  • 打赏
  • 举报
回复
我看下来好像没发现什么问题 这个递归有什么问题呢?
weixin_43552078 2018-10-29
  • 打赏
  • 举报
回复
IOS越狱工具:absinthewin2.0.2下载
  • 打赏
  • 举报
回复
很明显,比如说移动总公司发号,每一个省有不同的号段,那么它至少设计一个存储表来为每一个省保存号段信息(包括当前最后发号的号码)。 你的设计显然是意识到统计数据表“最大值”不太科学。但是从数据库表建模上本身就不科学。还没有学会按照实际需求来建表,而是滥用什么“万能字符串”字段来勉强应付编程工作。
  • 打赏
  • 举报
回复
在你的数据库设计中,可以为“最后一次保存编号”或者“最大编号”单独设置一个存储表(数据库表),然后直接访问这个表来编流水号。这是性能问题。 回到你的递归算法,当存在相同记录时进行递归,本身不会有什么“正确性”问题。你没有写出到底出了什么问题(在#1楼反而问别人自己的代码出了什么问题),那就需要你先把问题说明白,学会调试数据。
  • 打赏
  • 举报
回复
 private string GET_GYS_GYSID(string province,int _ix)
        {
            Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
            string str = _ix.ToString().PadLeft(3, '0');//001
            if (gysbll.Exists(province + str))
            {
                _ix = _ix + 1;
                str = _ix.ToString().PadLeft(3, '0');//001
            }
        return province + str;
        }
正怒月神 2018-10-29
  • 打赏
  • 举报
回复
引用 18 楼 weixin_43119128 的回复:
是这样的,我这边有源码,还有工具,域名,找个师傅能不能搭建个平台,急求。。在线等
你随便找个稍微做过网站的就会发布了。 只是最后在映射一下你的域名
sbhanhan 2018-10-27
  • 打赏
  • 举报
回复
引用 2 楼 xuzuning 的回复:
11 行有 _ix = _ix + 1;
所以你 12 行的注释就写错了 str = _ix.ToString().PadLeft(3, '0');//001 应是 002

这样在递归调用 GET_GYS_GYSID(province,_ix) 时 _ix 总是有不同的值
不然,整个就陷入死循环了



是的 进入死循环了 该怎么写才对呢?
xuzuning 2018-10-27
  • 打赏
  • 举报
回复
11 行有 _ix = _ix + 1;
所以你 12 行的注释就写错了 str = _ix.ToString().PadLeft(3, '0');//001 应是 002

这样在递归调用 GET_GYS_GYSID(province,_ix) 时 _ix 总是有不同的值
不然,整个就陷入死循环了
sbhanhan 2018-10-27
  • 打赏
  • 举报
回复
出现什么问题了啊??
jhone99 2018-10-27
  • 打赏
  • 举报
回复
不需要递归,直接用sql截取数值部分查最大值,

select max(substr(字段, 开始位置, 长度)) from my_table

试试看,手头没有oracle,未测试
xuzuning 2018-10-27
  • 打赏
  • 举报
回复
你写的并没有太大问题,只是 若 AH998 存在,会返回 AH999
那么 AH999 存在的话,该返回什么呢? AH1000 吗?
显然超出了预期的长度,假定超长会被截断那么 AH1000 就变成了 AH100

其实你只要查询出该列的最大值 max(字段) 就可以了,并不需要递归检查
sbhanhan 2018-10-27
  • 打赏
  • 举报
回复
感谢,我再解释一下
 private string GET_GYS_GYSID(string province,int _ix)
{
Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
string str = _ix.ToString().PadLeft(3, '0');//001
if (!gysbll.Exists(province + str))//你是要判断province的没存在?还是要判断province + str的存在?
{
return province + str;
}
else
{
_ix = _ix + 1;
//str = _ix.ToString().PadLeft(3, '0');//001 //这句没有意义
return GET_GYS_GYSID(province,_ix);
}

}


我们在数据库中的格式是AH001这样的,我要向数据库中插入AH001,AH002,AH003 这样的值
我首先定义一个数值AH001 判断数据库中是否存在,如果不存在就插入到数据库,如果存在我就加1得到AH002,如果AH002依然存在再加1,以此类推,应该怎么写


xuzuning 2018-10-27
  • 打赏
  • 举报
回复
给 _ix 一个上限
既然你有 str = _ix.ToString().PadLeft(3, '0'),那么 _ix 就不会大于 999
如果到了就直接返回,而不进入递归
jhone99 2018-10-27
  • 打赏
  • 举报
回复
只是说总是有问题,你的问题具体说是什么?
jhone99 2018-10-27
  • 打赏
  • 举报
回复
 private string GET_GYS_GYSID(string province,int _ix)
{
Oracle.BLL.GYS gysbll = new Oracle.BLL.GYS();
string str = _ix.ToString().PadLeft(3, '0');//001
if (!gysbll.Exists(province + str))//你是要判断province的没存在?还是要判断province + str的存在?
{
return province + str;
}
else
{
_ix = _ix + 1;
//str = _ix.ToString().PadLeft(3, '0');//001 //这句没有意义
return GET_GYS_GYSID(province,_ix);
}

}


你是要判断province的没存在?还是要判断province + str的存在?

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧