CSDN大牛较多,本人小白,若交流,本人欢迎,若言语偏颇,请绕行。
这二天,工作比较空闲,就看了一些基础的C++语法知识,收获颇多,下面只讲switch case语句的一些语法细节。请大家坚持看完,第五大点是重点,经测试连C++ Primer都给出了错误的讲解。若为大牛,请直接拖到文章最后看最后一大点。
一、case标号内是否可以使用continue代替break?
答案是否定的。continue只用于循环语句中,作用是中止本次循环;break语句才能中断switch case控制流(return、goto等且不算作正常的中断)。
二、default只可以写在所有case标号之后吗?
答案也是否定的。default可以写在任何位置且作用不变,只是看起来很别扭而已,你可以理解default是一个特别的case,并不代表着一个switch的结束。
这是新手经常会误解的知识点,总觉得default之后,switch就结束了,这是一种固定思维带来的错误推断。
三、下面的代码是正确的吗?
char ch;
switch(ch)
{
case:
default:
}
答案是不正确。一个标号不能独立不能独立存在,它必须位于语句之前。如果是空语句,你写成如下形式。
char ch;
switch(ch)
{
case:
;
default:
{} // ;,{}可以互换
}
四、下面的代码是正确的吗?若正确,执行结果是什么?若不正确,为什么?
char ch = 'f';
switch(ch)
{
default:
cout << "I'm default." << endl;
ch = 'b';
case 'a':case 'b':case 'c': case 'd':
{
cout << ch << endl;
break;
}
cout << "Do I run?" << endl;
}
代码是正确的。运行结果是:
I'm default.
b
五、这一题是我想要说的重点,因为连C++ Primer中文版(第四版)这本书也讲解错误。详情见C++ Primer中文版(第四版)176页6.6.5小节的第一句。(原文为:“对于switch结构,只能在它的最后一个case标号或者default标号后面定义变量:……”)
下面的这几段代码是正确的吗?如果不正确为什么?
5.1 char ch = 'f';
switch(ch)
{
default:
break;
case 'f':
break;
case 'a':
int temp = 0;
break;
}
代码是正确的,g++编译通过。
5.2 char ch = 'f';
switch(ch)
{
case 'f':
break;
case 'a':
break;
default:
int temp = 0;
break;
}
代码是正确的,g++编译通过。
5.3 char ch = 'f';
switch(ch)
{
default:
break;
case 'b':
break;
case 'f':
int temp = 0;
break;
case 'a':
break;
}
代码是错误的,g++编译未通过。
通过上面的三个例子,“对于switch结构,只能在它的最后一个case标号或者default标号后面定义变量”这句话似乎是正确的。请看下一例。
5.4 char ch = 'f';
switch(ch)
{
default:
int temp = 0;
break;
case 'f':
break;
case 'a':
break;
}
代码是错误的,g++编译未通过。所以说C++ Primer的前半句是正确的,而后半句是错误的。应该改成“对于switch结构,只能在它的最后一个标号(switch和case)后面定义变量”。
解释这个问题,请见第二点,default本质上与case并无不同,你可以把他看成范围较大的case。
现在再解释一下,为什么只能在switch结构的最后一个标号后面定义变量?
答:拿5.3的代码为例,大家都知道temp的生命周期为开始定义的位置至这个块语句的结束(也就是到‘}‘这个位置)。要知道switch case语句为块语句,也就是temp变量会在块结束之前一直存在,那么case 'b'中当然可以使用这个变量。但是如果说ch = 'b',这时程序会直接跳到case 'b'而不会跳到temp变量的声明定义处的case 'f'中,此处若使用变量temp,那么temp就是未定义就使用了。为了避免这种情况的发生,所以C++规定“对于switch结构,只能在它的最后一个标号后面定义变量”,这样就有效避免了变量未定义就使用的问题的发生。
C++博大精深,望勿浮躁,共勉。
一大早九接到开发商的电话,说数据库的CPU使用率为100%,应用相应迟缓。急匆匆的赶到现场发现进行了基本的检查后发现是latch: cache buffers chains 作祟,护理过程还算顺利,这里总结下处理思路,以便下次查看。
故障分析思路
查看等待事件,判断故障起因
SQL>select * from (select sid,event,p1,p2,p3,p1text,WAIT_TIME,SECONDS_IN_WAIT from v$session_wait where wait_class# <> 6
order by wait_time desc) where rownum <=10;
确认为latch: cache buffers chains引起的故障后,查看latch的命中率
SQL> SELECT *
FROM (SELECT addr, child#, gets, misses, sleeps, immediate_gets igets,
immediate_misses imiss, spin_gets sgets
FROM v$latch_children
WHERE NAME = 'cache buffers chains'
ORDER BY sleeps DESC)
WHERE ROWNUM < 11;
各列名称意义如下
NAME:latch名称
IMMEDIATE_GETS:以Immediate模式latch请求数
IMMEDIATE_MISSES:请求失败数
GETS:以Willing to wait请求模式latch的请求数
MISSES:初次尝试请求不成功次数
SPIN_GETS:第一次尝试失败,但在以后的轮次中成功
SLEEP[x]:成功获取前sleeping次数
WAIT_TIME:花费在等待latch的时间
这里需要注意MISSES/GETS如果在达10%左右,则说明有比较严重的latch争用除了查询v$latch_children视图,还可以通过v$latch视图查看latch命中率,语句如下
SQL>SELECT name, gets, misses, sleeps,
immediate_gets, immediate_misses
FROM v$latch
WHERE name = 'cache buffers chains';
查看热点对象和访问信息,TCH列表示对象被访问的次数
SQL> SELECT *
FROM ( SELECT addr,
ts#,
file#,
dbarfil,
dbablk,
tch
FROM x$bh
ORDER BY tch DESC)
WHERE ROWNUM < 11;
通过对象的文件号和块号查看具体对象信息
SQL>select owner, segment_name, partition_name, tablespace_name
from dba_extents
where relative_fno = &v_dba_rfile
and &v_dba_block between block_id and block_id + blocks - 1;
查看引起latch: cache buffers chains的sql,这里会提供
SQL> select * from (select
count(*),
sql_id,
nvl(o.object_name,ash.current_obj#) objn,
substr(o.object_type,0,10) otype,
3 4 5 6 CURRENT_FILE# fn,
CURRENT_BLOCK# blockn
from v$active_session_history ash
, all_objects o
where event like 'latch: cache buffers chains'
and o.object_id (+)= ash.CURRENT_OBJ#
group by sql_id, current_obj#, current_file#,
current_block#, o.object_name,o.object_type
order by count(*) desc )where rownum <=10;
根据上面得到的sql_id信息查看sql全文
SQL>select sql_fulltext from v$sqlarea where sql_id='&sqlid';
查看SQL的执行计划
SQL>SELECT * FROM table(DBMS_XPLAN.DISPLAY_CURSOR(('&sql_id',0));
在认为sql执行计划不准确的情况也可以通过sql_id查看sql的address和hash_value查看sql的实际执行计划
SQL>SELECT address, hash_value FROM v$sql
WHERE sql_id='&sql_id';
SQL>SELECT operation, options, object_name, cost FROM v$sql_plan
WHERE address = '&addr' AND hash_value = 'hash_v';
当某个会话长时间持有latch时,可以通过联合v$latchholder和v$session视图查看sql信息
SQL>SELECT s.sql_hash_value,s.sql_id,s.address, l.name
FROM V$SESSION s, V$LATCHHOLDER l
WHERE s.sid = l.sid;
故障处理思路
1、根据sql执行计划判断该执行计划是否正确,sql执行过长往往意味着过长时间的持有latch。
2、优化nested loop join,如果有可能使用hash join代替nested loop join。也可以利用对热块索引进行hash分区,或者使用hash簇的方式减缓热块现象。
3、调整表的pctfree值,将数据尽可能的分布到多个块中
4、调整应用
5、等。呵呵当出现latch争用时,故障时刻确实没有较好的方式解决,找到病因才是关键。
关于热块,可以参阅笔者的如下文章
参考至:https://sites.google.com/site/embtdbo/wait-event-documentation/oracle-latch-cache-buffers-chains
http://space.itpub.net/354732/viewspace-697317
http://www.toadworld.com/KNOWLEDGE/KnowledgeXpertforOracle/tabid/648/TopicID/RCBCL/Default.aspx
http://blog.163.com/wghbeyond@126/blog/static/351661812010619073376/
本文原创,转载请注明出处、作者
如有错误,欢迎指正
邮箱:czmcj@163.com
已有 0 人发表留言,猛击->>这里<<-参与讨论
ITeye推荐
- —软件人才免语言低担保 赴美带薪读研!—
我们新建报表MasterDetailOneReport_A.rptdesign,空白模板,示例数据库,sql选择查询数据集。
新建数据集Orders:
select *
from orders
新建数据集SingleOrderDetail
select *
from orderdetails
where ordernumber = ?
数据集参数默认值为10101。
新建静态文本报表参数ordernumber,默认值:10101
在报表编辑器中插入2行5列的表,在第一行分别拖入Orders数据集中如下的数据列:
合并第二行的前四列,在第五列中插入一个1行5列的表,分别拖入SingleOrderDetail的数据集:
作适当的美化,布局,最终如下:
选中表,编辑数据集绑定:
绑定数据集SingleOrderDetail参数至row["ORDERNUMBER"]
这样就完成了一个内嵌的报表,预览如下:
9.2 表外的嵌套
同上例子,我们新建报表MasterDetailOneReport_B.rptdesign,空白模板,示例数据库,sql选择查询数据集。
新建数据集Orders:
select *
from orders
新建数据集SingleOrderDetail
select *
from orderdetails
where ordernumber = ?
数据集参数默认值为10101。
新建静态文本报表参数ordernumber,默认值:10101
我们插入两个2行1列的网格:
第一个网格,第一行插入文本:
这个案例用于描述怎么从一个数据项,外嵌产生另一个报表,传入一个参数,方法如下:
reportContext.setGlobalVariable("ordernum", dataSetRow["ORDERNUMBER"]);
dataSetRow["ORDERNUMBER"]
第二行插入一个1行5列的表,分别拖入Orders数据集的数据列:
其中ordernumber数据项用的表达式生成器,输入
reportContext.setGlobalVariable("ordernum", dataSetRow["ORDERNUMBER"]);
dataSetRow["ORDERNUMBER"]
第二个网格,第一行输入文本:
这个表格用于从环境标量中获取参数,用于表的数据集的参数,方法如下:
reportContext.getGlobalVariable("ordernum");
第二行插入1行5列的表,分别拖入SingleOrderDetail数据集的数据列:
编辑表的绑定:
输入表达式生成器文本:reportContext.getGlobalVariable("ordernum");
预览,效果如下:
9.3 参数的传递
一、第一种方法:
1、在jsp的URL里面添加所要传递的参数:
http://localhost:8080/birt-web/frameset?__report=test.rptdesign&sample=parameter
2、在报表当中添加同名报表参数sample,数据集带有占位符参数,然后可以添加data set参数关联到报表参数sample,这样data set参数就可以得到从jsp页面传递过来的参数从而作为查询条件。
二、第二种方法:
1、在jsp的URL里面添加所要传递的参数:
http://localhost:8080/birt-web/frameset?__report=test.rptdesign&id=3
2、在报表当中添加同名报表参数id
3、点击 Date Sets,在点中间的"Script"标签,选择BeforeOpen,写上
var id = params["id"].value;
if(id!=null){
this.queryText=this.queryText+" where id='"+id+"'";
}
三、第三种方法:
BIRT VIEWER本身虽然支持在里面书写java code,但不宜用于request setParameter,getParameter,或者session的方法,但提供了一个接口在jsp或者servelet中通过AppContextKey和AppContextValue键值对来传递,BIRT viewer能自动识别出。
Map<String, String> map=new HashMap<String, String>();
String name=request.getParameter("name");
String stime =request.getParameter("stime ");
String age=request.getParameter("age");
String sex=request.getParameter("sex");
HashMap appContext = new HashMap( );
appContext.put("stime",stime);
appContext.put("name",name);
appContext.put("age",age);
appContext.put("sex",sex);
request.getSession().setAttribute( "AppContextKey","numberWhere");
request.getSession().setAttribute("AppContextValue", appContext);
request.getRequestDispatcher( "/frameset?__report=testreport.rptdesign").forward(request,response);
在