
暂无个人介绍
本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/archive/2011/01/27/1946227.html,如需转载请自行联系原作者。
set ANSI_NULLS ON set QUOTED_IDENTIFIER ON go CREATE PROCEDURE [dbo].[GetTreeDetails] @start int ,--数据页码 @limit int ,--每页显示数据条数 @totalCount int OUT ,--数据总条数 @flag int ,--数据总页数 @where nvarchar(200) AS declare @sql nvarchar(4000) declare @pageCount int if @flag=0 begin select @totalCount=count(*) from treeDetails set @pageCount=CEILING (@totalCount * 1.0 / @limit) if @start=0 set @sql=N'select top '+STR(@limit)+' * from treeDetails' else if @start=@pageCount-1 set @sql=N'select top '+STR(@limit)+' * from treeDetails where id not in (select top '+str(@start*@limit)+' id from treeDetails order by id) order by id' else set @sql=N'select top '+STR(@limit)+' * from treeDetails where id not in (select top '+str(@start*@limit)+' id from treeDetails order by id) order by id' end else begin declare @sql1 nvarchar(4000) declare @total int set @sql1=N'select @totalCount =count(*) from treeDetails where 1=1 ' + cast(@where as nvarchar(200)) Exec sp_executesql @sql1,N'@totalCount int=0 OUTPUT',@totalCount=@totalCount OUTPUT set @pageCount=CEILING(@totalCount * 1.0 / @limit) if @start=0 set @sql=N'select top ' +STR(@limit)+' * from treeDetails where 1=1 ' + cast(@where as nvarchar(200)) else if @start=@pageCount-1 set @sql=N'select * from treeDetails where id not in (select top '+str(@start*@limit)+' id from treeDetails where 1=1 '+cast(@where as nvarchar(200)) +') ' + cast(@where as nvarchar(200)) else set @sql=N'select top '+STR(@limit)+' * from treeDetails where id not in (select top '+str(@start*@limit)+' id from treeDetails where 1=1 '+ cast(@where as nvarchar(200)) +') '+ cast(@where as nvarchar(200)) end Exec sp_executesql @sql 方法1: 适用于 SQL Server 2000/2005 SELECT TOP 页大小 *FROM table1WHERE id NOT IN ( SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id )ORDER BY id 方法2: 适用于 SQL Server 2000/2005 SELECT TOP 页大小 *FROM table1WHERE id > ( SELECT ISNULL(MAX(id),0) FROM ( SELECT TOP 页大小*(页数-1) id FROM table1 ORDER BY id ) A )ORDER BY id 方法3: 适用于 SQL Server 2005 SELECT TOP 页大小 * FROM ( SELECT ROW_NUMBER() OVER (ORDER BY id) AS RowNumber,* FROM table1 ) AWHERE RowNumber > 页大小*(页数-1) 说明,页大小:每页的行数;页数:第几页。使用时,请把“页大小”和“页大小*(页数-1)”替换成数字。 其它的方案:如果没有主键,可以用临时表,也可以用方案三做,但是效率会低。 建议优化的时候,加上主键和索引,查询效率会提高。 通过SQL 查询分析器,显示比较:我的结论是: 分页方案二:(利用ID大于多少和SELECT TOP分页)效率最高,需要拼接SQL语句 分页方案一:(利用Not In和SELECT TOP分页) 效率次之,需要拼接SQL语句 分页方案三:(利用SQL的游标存储过程分页) 效率最差,但是最为通用 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2010/03/28/2087997.html
int _tmain(int argc, _TCHAR* argv[]) {char str[20],str2[20]; cout<<str<<endl; //由于分配了空间,没有写入数据,在输出地时候读没有写入数据的地址就回出现乱码 for(int i=0;i<20;i++) { str[i]='a';//if(i==10)//{// str[10]='\0';//字符串遇到了\0,就会结束,所以strlen(str)=10//} } str[19]='\0';//结束字符串,没有这一句就回出现乱码 strcpy(str2,str);//将一个字符串赋给列一个相等容量的字符串是会出现乱码的,因为字符串的最后一位必须是\0 cout<<str<<" , "<<sizeof(str)<<" , "<<strlen(str)<<" , "<<str2<<endl;int k = 5; k = k + (++k); cout<<k<<endl;int b1; cin>>b1;return 0; } 输出结果如下:char str[20]; 定义一个长度为20的字符数组,系统会分配20个连续的空间给str;开始的时候每个空间里面都没有值; str指向数组的第一个空间,str相当于一个常量指针,所以不能写str=?;sizeof(str)表式str所占的空间长度,char str[20]表示长度为20,也就是说sizeof(str)的值在定义的时候就已经定了, 就是字符创数组的长度。 strlen(str)表示str中字符的个数,这里有19个,最后一个\0不算。int k = 5; k = k + (++k); 最后k=12;这个的确不太好理解 理解:可以这样理解i++和++i: 对于一个表达式;如果有++i;就相当于在表达式之前加入一行代码i=i+1; 同理有i++;相当于在表达式后面加入一行代码i=i+1int k = 5; k = k + (++k);相当于int k=5;k=k+1;k=k+k; 测试题:递归实现猴子偷桃问题//猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。//第二天又将剩下的桃子吃掉一半,又多吃一个。以后每天都吃了前一天剩下的一半零一个。//到第10天,只剩下一个桃子了。编程试求第一天共摘了多少桃子。int Eat(int currentCount,int i) {if(i==10) {return currentCount; }else{ currentCount=(currentCount+1)*2; i++; }return Eat(currentCount,i); } cout<<Eat(1,10)<<endl; 得出第一天摘了1534个桃子。 最后一招猴子偷桃,竟然偷了1534个。 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2011/01/06/2087984.html
四种方式实现--从尾到头输出链表 方法一:借用栈倒序输出链表 方法二:先翻转链表,再顺序输出 方法三:递归实现,一个字妙,两个字很妙,三个字太妙了 方法四:用数组实现 方法一:借用栈倒序输出链表 因为栈是先进后出,把链表中的元素存进栈中,链表前面的元素在栈底,后面的元素在栈顶,链表后面的元素先出栈 方法二:先翻转链表,再按顺序打印(主要是想自己实现单链表的翻转,这种实现方式破坏了链表的结构,当然再翻转一下就还原了) 翻转链表的步骤: 1:将当前节点的next节点指向他以前的前一个节点 2:当前节点下移一位 3:如果是最后一个节点,就把它的next节点指向它以前的前一个节点,并推出循环 方法三:用递归实现 很诚实的说盗用了别人的思想,真的太妙了,完全能看出你是否真的体会了递归的原理 正如那位哥们所说,递归就是一个进栈出栈的过程,链表前面的元素先进栈,在栈底,后面的元素后进栈,在栈顶,先出栈,哈哈。。。 方法四:借用数组实现,跟用栈实现的方式差不多, LoveJenny说的实现方式跟这种方式是一样的,空间复杂度都是O(n) 源码 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2011/08/01/2124220.html
一直对搜索、过滤很好奇,觉得他们很有技术含量,只有非常NB的人才能做。很想知道他们的原理,实现这样的功能,设计是不是必须得非常NB非常奇特,代码是不是要写得非常好,性能非常高。总之这一切都不是我这样级别的人能做的。直到我看了《编程珠玑(第二版)》中的这么一段文字: “假定我们可以在执行搜索之前对文本内容进行预处理,那么我们可以建立一个撒列表(或者搜索树),为文档中的每个不同的单词建立索引,并为每个单词的每次出现存储一个链表,这样的逆向索引使得程序可以很快的找到给定的单词,为了查找短语,我们可以对其中包含的每个单词的链表进行交叉,但实现起来比较复杂,速度可能会很慢。(不过一些网页搜索引擎用的就是这样的方法)” 思路就这么简单,我靠!连有的搜索引擎也用这种思路。这种撒列的方式处理关键字过滤速度的确是蛮快,10000个字组织成一个撒列表也就几毫秒,只要你预分配的内存较好,基本上没什么操作,就是向内存中填数据。在撒列表中判断一个键是否存在的时间复杂度为O(1),其实还可以自己重写Dictionary<TKey, TValue>,关键字过滤的效率可能会更好点。 实现的思路比较简单: 1:处理关键字,生成一个关键字字典表 2:处理要过滤的文本,同样生成一个字典表 3:将文本,两个字典表三者进行比对 现在来测试下面一段文字(我上篇博客中的一段文字): "看云风博客关于解决12306并发问题的启发:我现在做骏卡接口,可能出现并发问题,就是一个订单可能向我们的接口发送多个请求,而我现在做的方法是去数据库中对应的表验证,看订单是否存在,如果存在就提示一下,如果不存在按流程走,但是这个样每来一个订单我都需要去数据库查,如果我在内存中维护一个订单集合,这样就能很快解决判断订单是否存在的问题,惯性思维太严重了,什么都去数据库查,这样的性能是最差的,其实很多问题在内存中就可以搞定的,最近还有一个特别感受,不要做井底之蛙,多看牛人的东西收获真的比自己埋头写代码进步快很多,其实很多时候我写的程序性能差,效率低都是因为方法的原因,没有找到好的方法,没有灵光一闪的感觉,用了最烂的方法解决问题" 测试代码: class Program {static void Main(string[] args) {string keys = "云风博客|并发问题|最烂的方法|内存|集合|数据库|性能";using (new OperationTimer("keyWords:")) { WordSearch ws = new WordSearch(keys);string str = "看云风博客关于解决12306并发问题的启发:我现在做骏卡接口,可能出现并发问题,就是一个订单可能向我们的接口发送多个请求,而我现在做的方法是去数据库中对应的表验证,看订单是否存在,如果存在就提示一下,如果不存在按流程走,但是这个样每来一个订单我都需要去数据库查,如果我在内存中维护一个订单集合,这样就能很快解决判断订单是否存在的问题,惯性思维太严重了,什么都去数据库查,这样的性能是最差的,其实很多问题在内存中就可以搞定的,最近还有一个特别感受,不要做井底之蛙,多看牛人的东西收获真的比自己埋头写代码进步快很多,其实很多时候我写的程序性能差,效率低都是因为方法的原因,没有找到好的方法,没有灵光一闪的感觉,用了最烂的方法解决问题"; ConsoleColor color = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("原文:"); Console.ForegroundColor = color; Console.WriteLine(str); Console.WriteLine(); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("过滤后:"); Console.ForegroundColor = color; Console.WriteLine(ws.Filter(str)); } Console.Read(); } } 输出结果截图: 另外送上一个简单实用的代码运行时间测试类,测试某段代码的运行时间可是很方便的哦 using System;using System.Diagnostics;namespace WordFilter {/// <summary>/// 测试代码运行时间帮组类/// </summary> public class OperationTimer : IDisposable {private string Text;private Int32 collectCount;private Stopwatch stopWatch;public OperationTimer(string txt) { PerpareForOperation();this.Text = txt; collectCount = GC.CollectionCount(0); stopWatch = new Stopwatch(); stopWatch.Start(); }public void Dispose() { stopWatch.Stop(); Console.WriteLine("{0} Milliseconds (GCs={1}) {2}", stopWatch.ElapsedMilliseconds, GC.CollectionCount(0) - collectCount, Text); }private static void PerpareForOperation() { GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect(); } } } 实现撒列的部分核心代码: public Dictionary<char, IList<char>> HandleKeyWords(IEnumerable<string> text, int size) { Dictionary<char, IList<char>> dicList = new Dictionary<char, IList<char>>(size);//预分配非常关键 int len, i;foreach (string s in text) {if (s == string.Empty) {continue; } len = s.Length - 1;for (i = 0; i < len; i++) {if (dicList.ContainsKey(s[i])) {if (dicList[s[i]] != null && !dicList[s[i]].Contains(s[i + 1])) { dicList[s[i]].Add(s[i + 1]); } }else { dicList.Add(s[i], new List<char>(2) { s[i + 1] }); } }if (!dicList.ContainsKey(s[len])) { dicList.Add(s[len], null); } }return dicList; } 我也想贴出全部代码,但是还有一些BUG,功能还有待完善,完善一些了会贴出源码的,在截一张图给大家看看 关键字过滤,希望能过滤掉大家不想听的,陈太汉祝大家新年快乐 作者:陈太汉 博客:http://www.cnblogs.com/hlxs/ 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2012/01/20/2328048.html
为什么类型和实例对象都要类型对象指针方法和类型所需的内存是在一起分配的,方法被类型和实例对象共享,在实例化一个对象的时候不会为方法分配内存,而调用方法时只能通过类型对象指针定位到方法表中相应的方法,进行调用 ==与Equals的区别:值类型他们的效果是一样的,因为值类型分配在线程栈上,存的就是值,直接比较的就是值引用类型:==判断是否指向同一个地址;Equals比较的是变量所指的内存中的数据是否相同 Dictionary时间复杂度:Add;ContainsKey;Remove;TryGetValue为O(1),只有ContainsValue为O(n);因为前者根据哈希算法直接定位到数组索引,而后者却要遍历数组做比较;Remove和Add并没有发生数组元素的移动,数组是预先分配好的,Add只是填充,而Remove只是将对应的元素都置为初始状态 不要把动态的内容存在不能修改的缓存中,如存在静态字段中,如果内容改了,缓存中内容却改不了,如果存在静态字段中,可以隔一段时间更新一下,或者让你的缓存依赖某个文件。总之要让自己可以控制缓存中的内容 int映射到FCL中System.Int32,string映射到FCL中System.String,他们没有区别,相当于using int=System.Int32 值类型赋值是逐一对字段赋值,将一个很大的结构体当做实参传递是很低效的,如果这个结构体有1000个字段,那就要赋值1000次,而引用类型赋值,只是修改指针指向,说明将Class修改成Struct并不一定能提升性能,struct的类型实例一定要小 拆箱其实是一个获得一个指针的过程,该指针指向对象的数据部分,紧接其后是一个赋值动作,拆箱就是把引用类型赋给值类型,其实是赋给一个中间变量,然后你就可以调用值类型的方法了 在foreach循环读取数组中的元素的同时添加或删除元素,都会报InvalidOperationException异常,因为添加和删除都会修改字段version的值,而MoveNext里面会判断version的值和数组元素的个数是否发生变化,如果发生变化就报这个异常 为什么类型和实例对象都要类型对象指针 方法和类型所需的内存是在一起分配的,方法被类型和实例对象共享,在实例化一个对象的时候不会 为方法分配内存,而调用方法时只能通过类型对象指针定位到方法表中相应的方法,进行调用 效率:静态方法>实例方法>虚方法 1:静态方法不需要判断对象是否为空,而实例方法需要判断调用该方法的对象是否为空 2:虚方法有一些额外代码,用于判断是调用父类的方法还是调用子类的实例方法。实例方法和虚方法都要进行非空检查,若为null,就会抛出你常见的NullReferenceException,而静态方法不需要进行非null检查,你见过调用静态方法抛这个异常吗? 金字塔、锥形结构、树形结构有很好的稳定性,能很好的分散压力负载 想了几十分钟没有找到好的解决方法,吃完饭后瞬间就找到了好的方案,感觉思路非常清晰,这就是正确的答案 一个简单的防攻击类 DataTable 转换成 List 作者:陈太汉 博客:http://www.cnblogs.com/hlxs/ 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2012/03/28/2420564.html
C#成员的初始化顺序你真的非常清楚吗,我发现有点坑爹,坑到爹突然有点搞不清楚什么状况。下面咱们开始分析,先看3个简单类。 public abstract class Base { public Base() { SetValue(); } public abstract void SetValue(); } public class Sub : Base { public string value; public Sub() { value = "chentaihan"; } public override void SetValue() { value = "陈太汉"; } } public class Sub1 : Base { public string value = "chentaihan"; public override void SetValue() { value = "陈太汉"; } } 如果执行下面这段代码会输出什么值呢,请不要往下看,先给出你自己的答案。 static class Program { static void Main(string[] args) { Sub sub = new Sub(); Console.WriteLine(sub.value); Sub1 sub1 = new Sub1(); Console.WriteLine(sub1.value); Console.Read(); } } 是的他很简单,但你确信你的答案就是对的吗?这么一个简单的问题我答错了,所以就有了这篇博客。 CLR VIA C#这本书告诉我们:成员在定义的时候初始化相当于在构造函数的最上面初始化,如果一个成员在定义的时候初始化,并在构造函数中赋值,那么在构造函数执行完成之后,该成员的值就是造函数中所赋的值,所以我得出的答案都是:chentaihan。但答案不是这样的。当运行结果出来时,我那个迷茫啊.....。 先来说说我的简单分析: 1:进入子类构造函数 2:Sub成员变量的内存被分配 3:调用父类构造函数 4:调用子类的方法SetValue(子类覆写了这个方法),value被赋值 5:正式执行子类构造函数,成员变量value再次被赋值 从上面5步我得出他们输出的结果一样,都是chentaihan。错在哪里呢? 于是我用Reflector查看了一下,得到的结果正如上面所说,他们的源码是一样的,如下所示。正如CLR VIA C#这本书说的那样,那为什么结果不一样呢,Reflector代码是一样的,执行的结果却不一样,怎么回事,怎么回事,那我只能说Reflector坑爹,它不能反映程序的真正执行逻辑,非要我用IL,我用的还不熟呢。 public class Sub : Base { public string value; public Sub() { value = "chentaihan"; } public override void SetValue() { value = "陈太汉"; } } 神马情况,他们的IL代码是不一样的,如图所示 看了这个图,我们知道答案是chentaihan,陈太汉。谁能告诉我怎么调用父类的构造函数和给value赋值的顺序不一样啊。该用的工具都用了,我该怎么证明这个结果,于是开始单步调试,于是发现了一个每天都发现了的秘密:成员初始化在构造函数之前执行。难怪这本书上说成员在定义的时候初始化相当于在构造函数的最上面初始化,Reflector也证实了这个答案。但是又绕进另一个坑爹的问题:构造函数还没有调用,内存还没有分配,怎么给成员变量赋值啊?这不是问题,从上图可以看出成员变量的赋值只是在父类的构造函数之前调用,肯定也是在子类的成员变量分配空间之后为成员变量赋值。好的,最后我们得出的结论是: 1:进入子类构造函数 2:Sub成员变量的内存被分配 3:为Sub成员变量赋值 4:调用父类构造函数 5:调用子类的方法SetValue(子类覆写了这个方法),value被赋值 6:正式执行子类构造函数,成员变量value再次被赋值 同意以上观点的人请放过我,别吐槽,不同意的请留言 这样的解释答案就很合理,但同时也说明成员变量在定义的时候初始化和在构造函数中赋值的意义是不一样的,至少执行顺序不一样,产生的结果可能也不一样。 作者:陈太汉 博客:http://www.cnblogs.com/hlxs/ 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2012/04/19/2456949.html
在/etc/rc.d/init.d/ 创建oracle10g文件 touch oracle chmod a+x oracle [root@test~]# vi /etc/rc.d/init.d/oracle #!/bin/bash #chkconfig:345 51 49 #description:starts the oracle database deamons # ORACLE_HOME=/oracle/product/10.2.0/db_1 ORACLE_OWNER=oracle case "$1" in start) echo -n "Starting oracle10g:" su - $ORACLE_OWNER -c "$ORACLE_HOME/bin/dbstart" su - $ORACLE_OWNER -c "$ORACLE_HOME/bin/lsnrctl start" touch /var/lock/subsys/oracle10g echo ;; stop) echo -n "shutting down oracle10g:" su - $ORACLE_OWNER -c "$ORACLE_HOME/bin/dbshut" su - $ORACLE_OWNER -c "$ORACLE_HOME/bin/lsnrctl stop" rm -f /var/lock/subsys/oracle10g echo ;; restart) echo -n "starting oracle10g:" $ stop $ start echo ;; *) echo "usage: oracle10g{start|stop|restart}" exit ;; esac exit 保存文件(按Esc,":wq"),退出以后,添加并启动察看服务。 /sbin/chkconfig --add oracle /sbin/chkconfig --list oracle 在su下 service oracle10g start //启动oracle服务 service oracle10g stop //停止oracle服务 注1: /var/lock/subsys目录的作用 很多程序需要判断是否当前已经有一个实例在运行,这个目录就是让程序判断是否有实例运行的标志,比如说xinetd,如果存在这个文件,表示已经有xinetd在运行了,否则就是没有,当然程序里面还要有相应的判断措施来真正确定是否有实例在运行。通常与该目录配套的还有/var/run目录,用来存放对应实例的PID,如果你写脚本的话,会发现这2个目录结合起来可以很方便的判断出许多服务是否在运行,运行的相关信息等等。 实际上,判断是否上锁就是判断这个文件,所以文件存在与否也就隐含了是否上锁。而这个目录的内容并不能表示一定上锁了,因为很多服务在启动脚本里用touch来创建这个加锁文件,在系统结束时该脚本负责清除锁,这本身就不可靠(比如意外失败导致锁文件仍然存在),我在脚本里一般是结合PID文件(如果有PID文件的话),从PID文件里得到该实例的PID,然后用ps测试是否存在该PID,从而判断是否真正有这个实例在运行,更加稳妥的方法是用进程通讯了,不过这样的话单单靠脚本就做不到了。(来自:http://www.hao32.com/unix-linux/39.html) 注2:创建完文件oracle10后,使用root用户创建并修改/etc/oratab文件,添加如下内容: orcl:/ORACLE/app/product/10.2.0/db_1:Y 注3:若遇到“服务不支持chkconfig”请检查配置文件中带有“#”号的行有没有写错。 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/09/29/2708587.html,如需转载请自行联系原作者。
RTP/RTCP的定义及用途,还是请大家自己google。对于wifi手机来说呢,RTP协议用来传送编码后的语音,RTCP协议用来传送控制信息,公司的RTCP附带了一些语音统计信息和jitter buffer的统计信息用来防止语音抖动。由于是公司的东西,我就不细说了。下面是这两个协议的具体实现代码: RTP和RTCP的头部信息如下,一会给出详细的字节图和编码过程。 RTP的头部信息: 复制代码 typedef struct _RTP_HEAD { unsigned char Version : 2; unsigned char Padding : 1; unsigned char Extension : 1; unsigned char Ccount : 4; unsigned char Marker : 1; unsigned char Ptype : 7; WORD Snumber; //16bits DWORD Timestamp; //32 DWORD Ssrc; //32 DWORD Csrc; //32 }RTP_HEAD,*pRTP_HEAD; RTCP的头部信息: 复制代码 typedef struct _RTCP_HEAD { unsigned char Version : 2; unsigned char Padding : 1; unsigned char PCount : 5; unsigned char Ptype; //8bits WORD Length; //16bits }RTCP_HEAD,*pRTCP_HEAD; 里面各个bit位表示的意思老规矩,不懂google之。 具体实现呢,不能给出公司的代码,只能给出尽量通用一些的代码,程序员对比bit图和程序源代码应该很容易就能理解: RTP的bit图和代码实现: 复制代码 // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 0 |V=2|P|X| CC |M| PT | sequence number | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 4 | timestamp | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 8 | synchronization source (SSRC) identifier | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // 12 | payload header | // | .... | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // | payload | // | .... | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ void RTPCompose( string& buffer, int payloadType, int sequenceNum, int timestamp, int ssrc, const char* payloadHeader, int payloadHeaderLength, const char* payload, int payloadLength ) { ASSERT( payload && payloadLength >= 0 ); buffer.resize( 12 + payloadHeaderLength + payloadLength ); buffer[0] = (char)(2<<6); // v=2, p=x=cc=0 buffer[1] = (char)(payloadType & 0x127); // 7-bits for payload type *((unsigned short*)&buffer[2]) = (unsigned short)sequenceNum; *((unsigned int*)&buffer[4]) = (unsigned int)timestamp; *((unsigned int*)&buffer[8]) = (unsigned int)ssrc; memcpy( &buffer[12], payloadHeader, payloadHeaderLength ); memcpy( &buffer[12+payloadHeaderLength], payload, payloadLength ); } 解码是编码的逆过程俺就不罗嗦了。 RTCP的bit图和代码实现: 复制代码 // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ //byte=0 |V=2|P| RC | PT=SR=200 | length | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 4 | SSRC of sender | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // 8 | NTP timestamp, most significant word | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 12 | NTP timestamp, least significant word | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 16 | RTP timestamp | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 20 | sender's packet count | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 24 | sender's octet count | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // 28 |V=2|P| SC | PT=SDES=202 | length | // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ // 32 | SSRC/CSRC_1 | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // 36 | CNAME=1 | length | user and domain name ... // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ void RTCPSRCompose( string& buffer, int receptionCount, int ssrc, int64 ntpTimestamp, int rtpTimestamp, int sentPackets, int sentBytes, const wstring& cname ) { const string& cnameUTF8 = ConvertToUTF8( cname ); int length = 8 + 20 + 4 + 6 + cnameUTF8.size( ); // 注意此处可能存在bug。 buffer.resize( length ); buffer[0] = (char)(2<<6); // V=2, P=RC=0 buffer[1] = (char)200; // PT=SR=200 *(unsigned short*)&buffer[2] = 6; // length (7 32-bit words, minus one) *(unsigned int*)&buffer[4] = (unsigned int)ssrc; *(unsigned int*)&buffer[8] = (unsigned int)(ntpTimestamp >> 32); // High 32-bits *(unsigned int*)&buffer[12] = (unsigned int)(ntpTimestamp & 0xFFFFFFFF); // Low 32-bits *(unsigned int*)&buffer[16] = (unsigned int)rtpTimestamp; *(unsigned int*)&buffer[20] = (unsigned int)sentPackets; *(unsigned int*)&buffer[24] = (unsigned int)sentBytes; buffer[28] = (char)(2<<6 & 1); // V=2, P=0, SC=1 *(unsigned short*)&buffer[30] = 0xFFFF; // 注意这里应该填写长度,由于我们并没有数据因此无法填写。请程序员按自己的 包长自己填写。 *(unsigned int*)&buffer[32] = (unsigned int)ssrc; buffer[36] = 1; // CNAME=1 buffer[37] = (char)cnameUTF8.size( ); memcpy( &buffer[38], cnameUTF8.c_str( ), cnameUTF8.size( ) ); // 同理此处请程序员自己填写 } 以上是较为简单的实现。实际应用中必然需要填写自己附加的信息。实际上这个项目的代码均为在linux下用纯c写的代码,而我上传得代码为windows 下的c++代码。由于c++中Cstring类的存在,使RTP/RTCP的代码简化了不少。如果是在linux下编程的朋友稍加修改后,即可使用。此处仅仅只是给出RTP/RTCP的一个最简单和相对比较通用的实现而已。 最后当然要唠叨一下TBCP突发通话消息如何通过RTCP包传送,很简单,将上面RTCP包中的RC项由subtype代替。其它按上一篇讲解的携带 TBCP消息的RTCP包的标准编写就可以了。注意,这个标准是别人定的,如果觉得不好,自己定一个也是可以的。这样就要编写自己的服务器端了。下次再讨论一下关于PTT的在线服务,创建群组列表等对PTT来说至关重要的问题的实现。 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/10/18/2729687.html,如需转载请自行联系原作者。
安装完asterisk 配置sip.conf文件 [8001] type=friend username=8001 accountcode=8001 secret=8001 context=from-exten-sip ;followed advance settings host=dynamic nat=yes qualify=2000 canreinvite=no callgroup=0, pickupgroup=0, setvar= call-limit=1 说明:(1)type:sip的类型。格式:type =user|peer|friend 。 peer用于认证呼出呼叫,如果想要一个用户(extension)中有多个电话,定义可以呼叫两个SIP peer 的extension。user用于认证呼入呼叫,用户通过上下文鉴定到达服务器。friend用于认证呼入呼出,相当于(peer+user)。 (2)username :格式:username =<username[@realm]>。如果Asterisk接受来自远程SIP的SIP INVITE请求的客户端,这字段指定验证的用户名。 (3)accountcode:格式:accountcode =<string>。此字段,是用来填充“accountcode“领域的CDR(呼叫详细记录)。 (4)secret:用于认证的密码。如果Asterisk是作为一个SIP代理服务器,那么这个SIP客户端必须使用此密码登录(一个共享密码)。如果Asterisk是一个SIP客户端作为一个远程SIP的SIP INVITE的服务器要求身份验证,那么这个字段是用来验证该Asterisk的SIP协议提请发送到远程SIP服务器。 (5)context:格式:context = <context_name>定义了指令的地点,用于控制电话的权限,以及如何处理此号码的呼入呼叫。如果类型为用户,上下文定义呼入呼叫使用。如果类型为节点,上下文定义呼出呼叫使用。如果类型为friend通过SIP实体定义呼入和呼出所使用的上下文。 (6)host:格式:host =dynamic|hostname|IPAddr。host参数指定了用户的主机名或SIP端点IP地址。配置host=dynamic将要求号码注册,可以让Asterisk知道如何找到电话。 (7)nat:格式:nat =yes|no。这个变量改变了Asterisk的防火墙后面客户端的行为。配置nat=yes,强迫Asterisk忽略号码的联系信息,使用收到的包的地址信息。 (8)qualify:格式:qualify =yes|no|milliseconds。检查客户端是否可到达,我们可以监视Asterisk服务器和电话之间的延时,使用qualify=yes,确认远端设备是否可达。qualify=yes可以用于监视任何远端设备,包括其它的Asterisk服务器。默认情况是Asterisk认为时延在2,000 ms (2 seconds)以内的设备可达。你可以配置Asterisk判断对端是否可达的时间,通过将yes替换为毫秒。 (9)canreinvite:格式:canreinvite =update|yes|no|nonat。在SIP协议,邀请用于发起呼叫,重定向媒体。在初始邀请后相同对话中发起的任何邀请都被视作重邀请(reinvite)。配置canreinvite=no让Asterisk媒体通道经过自己,而不允许RTP信息直接在端点之间传送。Asterisk在以下的任何情况下都不会发起重邀请:如果客户端的任何一方配置为canreinvite=no;如果客户端不能协商编码,Asterisk需要执行语音编码转换;如果客户端的任何一方配置为nat=yes;如果Asterisk在呼叫中需要监听双音多频(DTMF)音(用于呼叫前转或者其他功能)。配置canreinvite=yes“允许RTP媒体直接” 。canreinvite = nonat“允许reinvite当本地,否认reinvite当NAT” 。配置canreinvite=update“使用UPDATE,而不是邀请” 。配置canreinvite = nonat“更新时使用的地方,否认当NAT” 。 (10)callgroup:格式:callgroup =num1,num2-num3。定义了此分机的电话组。 (11)pickupgroup:同组可以接电话,按*8应用。 (12)setvar:格式:setvar = variable=value。通道变量被设置为从该节点/用户的所有通话 (13)call-limit :格式call-limit = number 。同时呼叫的数量 2. 此外除了自动生成的配置还有其他的配置 (1)allow:格式:allow =<codec>。按优先级的顺序允许编解码器。 (2)disallow :格式:disallow =all。不允许这个peer或用户定义的所有编解码器。 (3)allowguest :格式:allowguest = yes|no 。拒绝或允许来电。 (4)amaflags:分类的CDR记录。选择是默认情况下,省略,计费,文件。 (5)astdb:向Asterisk 的数据库里插入值。 (6)auth :格式:auth =<authname>。 (7)callerid :格式:callerid = <string>。当没有可用信息时使用call ID信息 (8)busylevel:格式:busylevel= number。同时通话的数量,直到用户/同行正忙 (9)callingpres:格式:callingpres =number|descriptive_text。设置电话的来电显示,有效描述的值是allowed_not_screened, allowed_passed_screen, allowed_failed_screen,allowed,prohib_not_screened,prohib_passed_screen, prohib_failed_screen, prohib, and unavailable. (10)?cid_number :格式:cid_number = <string>。设置对外显示的字符串 (11)defaultip:格式defaultip =Dotted.Quad.IP.Addr。默认的IP地址,如果客户端指定host=dynamic。如果客户端没有使用任何其他的IP地址注册使用此项。只适用于type=peer (12)directrtpsetup:格式directrtpsetup =yes|no。类似canreinvite,可以马上把媒体传递给像SIP代理器的另一方。 (13)dtmfmode:格式:dtmfmode =inband|info|rfc2833。客户如何对DTMF信令处理。默认rfc2833。配置dtmfmode = rfc2833,允许在呼叫中监听双音多频(DTMF)音(用于呼叫前转或者其他功能) (14)fromuser :格式:fromuser =<from_ID>。指定用户输入“from”来代替$CALLERID(number)。 (15)???fromdomain:格式:fromdomain = <domain>。 (16)fullcontac:格式:fullcontact = <sip:uri_contact>。 SIP URI的联系,实时同行。只适用于实时同行 (17)fullname :格式:fullname = "FullName"。设置对外来电显示(姓名)。 (18)incominglimitand outgoinglimit:格式:incominglimitand outgoinglimit = Number。限制同时呼叫SIP客户端的数量,仅仅适用于type=peer。 (19)insecure: very|yes|no|invite|port 。指定如何处理与peers的连接。 (20)language:这对于一个在Asterisk SIP帐户配置选项指定语言设置为这个客户端使用。通过使用此设置,您可能会得到本地化的声音在为不同的用户不同的语言提示。 (21)mailbox:格式 mailbox =mailbox。语音信箱。 (22)musicclass:在musiconhold.conf指定的类 (23)musiconhold:保持音乐。 (24)subscribemwi:指示Asterisk 在等待信息的时候不要发送NOITFY信息。确定Asterisk如何通知SIP客户端关于语音信箱的信息 (25) permit, deny , mask格式:permit=<ipaddress>/<network mask> deny=<ipaddress>/<network mask> IP地址和网络限制。允许或限制到达某些特定的网络。 (26)port:SIP端口的客户端 (27)progressinband:格式:progressinband =never|no|yes。 (28)promiscredir :格式:promiscredir = yes|no。是否允许支持302重定向。 (29)regseconds :格式:regseconds = seconds。SIP注册的秒数。 (30)sendrpid:格式:sendrpid =yes|no。确定是否发送Remote-Party-IDSIP header (31)subscribecontext:格式:subscribecontext =<context_name>。为SIP SUBSCRIBE设置特殊的context (32) trunkname:为中继定义一个名字 (33)trustrpid:格式:trustrpid =yes|no。设置Remote-Party-IDSIP header是否被信任。 (34)vmexten :格式vmexten = <string>拨号规则扩展到邮箱 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/10/19/2730482.html,如需转载请自行联系原作者。
一、获取asterisk安装包 wget http://downloads.asterisk.org/pub/telephony/asterisk/releases/asterisk-1.6.0.tar.gz 后面的版本号可以改变,可以安装的版本可以参考http://downloads.asterisk.org/pub/telephony/asterisk/releases/ 二、解压安装 1. [root@~]# tar -zxvf asterisk-1.6.1.9.tar.gz // 解压asterisk安装包 2.[root@~]# cd asterisk-1.6.1.9 // 进入asterisk安装包 3.[root@asterisk asterisk-1.6.1.9]# ./configure // 环境检测和预配置 4.[root@asterisk asterisk-1.6.1.9]# make clean //清理旧的编译中间文件 5.[root@asterisk asterisk-1.6.1.9]# make all // 从新编译所有文件 +--------- Asterisk Build Complete ---------+ + Asterisk has successfully been built, and + + can be installed by running: + + + + make install + +-------------------------------------------+ 安装到这里软件会提示使用make install 来安装asterisk [root@asterisk asterisk-1.6.1.9]# make install // 安装asterisk +---- Asterisk Installation Complete -------+ + + + YOU MUST READ THE SECURITY DOCUMENT + + + + Asterisk has successfully been installed. + + If you would like to install the sample + + configuration files (overwriting any + + existing config files), run: + + + + make samples + + + +----------------- or ---------------------+ + + + You can go ahead and install the asterisk + + program documentation now or later run: + + + + make progdocs + + + + **Note** This requires that you have + + doxygen installed on your local system + +-------------------------------------------+ [root@asterisk asterisk-1.6.1.9]# make samples // 安装配置模板 到这里askterisk安装完毕。 三、启动asterisk 1.输入asterisk,回车 2.输入asterisk -r 四、asterisk配置文件 asterisk.conf //asterisk的主配置文件 一般情况下不需要去改动 sip.conf //sip协议主要配置文件 extensions.conf //拨号规则配置文件 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/10/23/2735569.html,如需转载请自行联系原作者。
第2节 配置实例 主要包括的是服务器端的init.ora,listener.ora和tnsnames.ora文件以及客户端的tnsnames.ora文件。 针对本项目的双节点的群集设置,主要配置如下: hostname service name sid name instance_name ORACLE_HOME ======== =========== ======== ============= =============== node1 test1 rac rac1 rac1 /oracle/product/9201 node2 test2 rac rac2 rac2 /oracle/product/92012.1 init.ora所有节点的init.ora 文件必须配置如下: remote_listener='LISTENERS_RAC' rac1.local_listener="LISTENER_rac1” rac2.local_listener="LISTENER_rac2" # dispatchers="(pro=ipc)(dis=0)" db_name='rac' /**********可以不用*************/ rac1.instance_name='rac1' rac2.instance_name='rac2'2.2 show parameter 既然service_names在init.ora文件中没有规定,它缺省是db_name.db_domain。每一个节点列出它的主机名和instance_name。随着以上的设置,在你启动进程后,当你从第一个节点检查sql 会话时,你将会发现下面的信息: 1)节点一 SQL> show parameter db_name NAME TYPE VALUE db_name string rac SQL> show parameter db_domain NAME TYPE VALUE db_domain string SQL> show parameter service_names NAME TYPE VALUE service_names string rac SQL> show parameter instance_name NAME TYPE VALUE instance_name string rac1 SQL> show parameter listener NAME TYPE VALUE local_listener string LISTENER_rac1 mts_listener_address string mts_multiple_listeners boolean FALSE remote_listener string LISTENERS_RAC 2)节点二 SQL> show parameter db_name NAME TYPE VALUE db_name string rac SQL> show parameter db_domain NAME TYPE VALUE db_domain string SQL> show parameter service_names NAME TYPE VALUE service_names string rac SQL> show parameter instance_name NAME TYPE VALUE instance_name string rac2 SQL> show parameter listener NAME TYPE VALUE local_listener string LISTENER_rac2 mts_listener_address string mts_multiple_listeners boolean FALSE remote_listener string LISTENERS_RAC2.3 listener.ora test1 listener.ora file LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC)) ) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) ) ) ) SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = /oracle/product/9201) (PROGRAM = extproc) ) (SID_DESC = (ORACLE_HOME = /oracle/product/9201) (SID_NAME = rac1) ) ) Test2 listener.ora file LISTENER = (DESCRIPTION_LIST = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC)) ) (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) ) ) ) SID_LIST_LISTENER = (SID_LIST = (SID_DESC = (SID_NAME = PLSExtProc) (ORACLE_HOME = /oracle/product/9201) (PROGRAM = extproc) ) (SID_DESC = (ORACLE_HOME = /oracle/product/9201) (SID_NAME = rac2) ) ) 2.4 tnsnames.ora test1—test2 and client side tnsnames.ora file LISTENERS_RAC = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) ) LISTENER_RAC2 = (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) LISTENER_RAC1 = (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) RAC2 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = rac) (INSTANCE_NAME = rac2) ) ) RAC1 = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = rac) (INSTANCE_NAME = rac1) ) ) RAC = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) (LOAD_BALANCE = on) (FAILOVER=on) ) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = rac) (failover_mode=(type=select)(method=basic))/********TAF使用的配置**********/ ) ) EXTPROC_CONNECTION_DATA = (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC)) ) (CONNECT_DATA = (SID = PLSExtProc) (PRESENTATION = RO) ) ) ////////////////////////////////////////////////////////////// failover = (DESCRIPTION = (enable=broken) (LOAD_BALANCE = yes) (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) (CONNECT_DATA = (SERVICE_NAME = rac) (failover_mode=(type=select)(BACKUP=cletus)(method=basic)) ) ) //////////////////////////////////////////////////////////////////2.5 配置注释1) LISTENERS_RAC, LISTENER_rac1, LISTENER_rac2是net_service_name (连接描述) for remote_listener和local_listener.在客户端,你并不需要这些参数。 2) failover 是为透明应用失败切换(TAF)测试的net_service_name 。 3) RAC 是客户端的负载平衡的 net_service_name,如果你不需要配置TAF,这有另外一种设置客户端连接负载平衡的配置方法, 下面是另外一种办法: RAC_alternative = (DESCRIPTION = (ADDRESS_LIST = (LOAD_BALANCE = yes) (ADDRESS = (PROTOCOL = TCP)(HOST = test1)(PORT = 1521)) (ADDRESS = (PROTOCOL = TCP)(HOST = test2)(PORT = 1521)) ) (CONNECT_DATA = (SERVICE_NAME = rac) ) ) 注: (load_balance=yes)可以使Net程序以一种随机的顺序处理地址列表中的侦听器,平衡不同侦听器之间的负载。当被设成OFF,Net程序将以顺序的方式处理直到一个成功。这个参数必须在你的net service name (connect descriptor)正确的配置. 缺省情况下这个参数被设成ON, Load balancing能联系到ADDRESSes和DESCRIPTIONs的设置并且在ADDRESS_LIST里进行规定。如果你使用ADDRESS_LIST,(load_balance=yes)将会在(ADDRESS_LIST=)部分。如果你不使用ADDRESS_LIST, (load_balance=yes)将会在(description=)部分里,我建议不使用(ADDRESS_LIST=) 字句。 4)(failover=on)缺省是在ADDRESS_LISTs, DESCRIPTION_LISTs和一个DESCRIPTIONs的设置里,因此你不需要规定。它是作为connect-time-failover,请注意不要与透明应用切换(TAF)发生冲突。 5)(failover_mode=):在FAILOVER_MODE参数必须包括在一个net_service_name的CONNECT_DATA部分。 6)这儿在(failover_mode=)里没有(backup=failover), 7) There is no (backup=failover) in (failover_mode=), this 暗示着 (failover_mode=(type=select)(method=basic)(backup=failover)),它意味着无论是否failover发生,连接的会话将会切换到net_service_name又进行失败切换,当使用PRECONNECT来pre-establish连接时BACKUP应该被规定,需要详细的TAF信息,请参考Oracle官方文档。 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/11/19/2777876.html,如需转载请自行联系原作者。
1. Git概念 1.1. Git库中由三部分组成 Git 仓库就是那个.git 目录,其中存放的是我们所提交的文档索引内容,Git 可基于文档索引内容对其所管理的文档进行内容追踪,从而实现文档的版本控制。.git目录位于工作目录内。 1) 工作目录:用户本地的目录; 2) Index(索引):将工作目录下所有文件(包含子目录)生成快照,存放到一个临时的存储区域,Git 称该区域为索引。 3) 仓库:将索引通过commit命令提交至仓库中,每一次提交都意味着版本在进行一次更新。 1.2. 使用Git时的初始化事项 1.2.1. Git初始化配置 1) 配置使用git仓库的人员姓名 git config --global user.name "Your Name Comes Here" 2) 配置使用git仓库的人员email git config --global user.email you@yourdomain.example.com 1.2.2. Git文档忽略机制 工作目录中有一些文件是不希望接受Git 管理的,譬如程序编译时生成的中间文件等等。Git 提供了文档忽略机制,可以将工作目录中不希望接受Git 管理的文档信息写到同一目录下的.gitignore 文件中。 例如:工作目录下有个zh目录,如果不想把它加入到Git管理中,则执行: echo “zh” &gt; .gitignore git add . 有关gitignore 文件的诸多细节知识可阅读其使用手册:man gitignore 1.3. Git与Repo的比较 Git操作一般对应一个仓库,而Repo操作一般对应一个项目,即一个项目会由若干仓库组成。 例如,在操作整个Recket项目时使用Repo,而操作其中的某个仓库时使用Git。在包含隐藏目录.git的目录下执行git操作。 2. Git help Git help 获取git基本命令 (如果要知道某个特定命令的使用方法,例如:使用Git help clone,来获取git clone的使用方法) 3. Git本地操作基本命令 3.1. Git init 或者使用git init-db。 创建一个空的Git库。在当前目录中产生一个.git 的子目录。以后,所有的文件变化信息都会保存到这个目录下,而不像CVS那样,会在每个目录和子目录下都创建一个CVS目录。 在.git目录下有一个config文件,可以修改其中的配置信息。 3.2. Git add 将当前工作目录中更改或者新增的文件加入到Git的索引中,加入到Git的索引中就表示记入了版本历史中,这也是提交之前所需要执行的一步。 可以递归添加,即如果后面跟的是一个目录作为参数,则会递归添加整个目录中的所有子目录和文件。例如: git add dir1 ( 添加dir1这个目录,目录下的所有文件都被加入 ) Git add f1 f2 ( 添加f1,f2文件) git add . ( 添加当前目录下的所有文件和子目录 ) 3.3. Git rm 从当前的工作目录中和索引中删除文件。 可以递归删除,即如果后面跟的是一个目录做为参数,则会递归删除整个目录中的所有子目录和文件。例如: git rm –r * (进入某个目录中,执行此语句,会删除该目录下的所有文件和子目录) git rm f1 (删除文件f1,包含本地目录和index中的此文件记录) git rm --ached f1 (删除文件f1,不会删除本地目录文件,只删除index中的文件记录;将已经git add的文件remove到cache中,这样commit的时候不会提交这个文件, 适用于一下子添加了很多文件, 却又想排除其中个别几个文件的情况.) 3.4. Git commit 提交当前工作目录的修改内容。 直接调用git commit命令,会提示填写注释。通过如下方式在命令行就填写提交注释:git commit -m "Initial commit of gittutor reposistory"。 注意,和CVS不同,git的提交注释必须不能为空,否则就会提交失败。 git commit还有一个 -a的参数,可以将那些没有通过git add标识的变化一并强行提交,但是不建议使用这种方式。 每一次提交,git就会为全局代码建立一个唯一的commit标识代码,用户可以通过git reset命令恢复到任意一次提交时的代码。 git commit –-amend –m “message” (在一个commit id上不断修改提交的内容) 3.5. Git status 查看版本库的状态。可以得知哪些文件发生了变化,哪些文件还没有添加到git库中等等。 建议每次commit前都要通过该命令确认库状态。 最常见的误操作是, 修改了一个文件, 没有调用git add通知git库该文件已经发生了变化就直接调用commit操作, 从而导致该文件并没有真正的提交。这时如果开发者以为已经提交了该文件,就继续修改甚至删除这个文件,那么修改的内容就没有通过版本管理起来。如果每次在 提交前,使用git status查看一下,就可以发现这种错误。因此,如果调用了git status命令,一定要格外注意那些提示为 “Changed but not updated:”的文件。 这些文件都是与上次commit相比发生了变化,但是却没有通过git add标识的文件。 3.6. Git log 查看历史日志,包含每次的版本变化。每次版本变化对应一个commit id。 Git log -1 -1的意思是只显示一个commit,如果想显示5个,就-5。不指定的话,git log会从该commit一直往后显示。 Git log --stat –summary (显示每次版本的详细变化) 在项目日志信息中,每条日志的首行(就是那一串字符)为版本更新提交所进行的命名,我们可以将该命名理解为项目版本号。项目版本号应该是唯一的,默认由 Git 自动生成,用以标示项目的某一次更新。如果我们将项目版本号用作git-show 命令的参数,即可查看该次项目版本的更新细节。例如: 1) Git log 2)Git show 实际上,上述命令并非是真正的进行版本号自定义,只是制造了一个tag对象而已,这在进行项目版本对外发布时比较有用。 3.7. Git merge 把服务器上下载下来的代码和本地代码合并。或者进行分支合并。 例如:当前在master分支上,若想将分支dev上的合并到master上,则git merge dev 注意:git merge nov/eclair_eocket (是将服务器git库的eclair_eocket分支合并到本地分支上) git rebase nov/eclair_eocket (是将服务器git库的eclair_eocket分支映射到本地的一个临时分支上,然后将本地分支上的变化合并到这个临时分支,然后再用这个临时分支初始化本地分支) 3.8. Git diff 把本地的代码和index中的代码进行比较,或者是把index中的代码和本地仓库中的代码进行比较。 1) Git diff 比较工作目录和Index中的代码。 2) Git diff - - cached 比较index和本地仓库中的代码。 3.9. Git checkout 3.9.1. 切换到分支 1) 创建一个新分支,并切换到该分支上 Git checkout –b 新分支名 2)切换到某个已经建立的本地分支local_branch Git checkout local_branch (使用cat .git/HEAD后,显示refs:refs/heads/ local_branch) 3) 切换到服务器上的某个分支remote_branch Git checkout remote_branch (远程分支remote_branch可以通过 git branch –r 列出) 4) 切换到某个commit id Git checkout commit_id (使用cat .git/HEAD后,显示commit_id) 5) 切换到某个tag Git checkout tag (使用cat .git/HEAD后,显示tag) 注意: 除了1)和2)外,其余三种都只是切换到了一个临时的( no branch )状态 (this head is detached),这时用 git branch 可以看到处于(no branch)上, cat .git/HEAD 看到指向相应的commit id。 这个(no branch)只是临时存在的,并不是一个真正建立的branch。 如果此时执行2),则这个(no branch)就自动消失了;如果执行1), 则创建新分支 new branch,并把这个(no branch)挂到这个新分支上,此时cat .git/refs/heads/new_branch 可以看到已经指向了刚才那个commit id。 3.9.2. 用已有分支初始化新分支 执行下面的命令,在切换到某个已经建立的local branch或者某个remote branch或者某个commit id 或者某个tag的同时,创建新分支new_branch,并且挂到这个新分支上。 1) 切换到某个已经建立的本地分支local_branch,并且使用此分支初始化一个新分支new_branch。 git checkout –b new_branch local_branch 2) 切换到某个远程分支remote_branch,并且用此分支初始化一个新分支new_branch。 Git checkout –b new_branch remote_branch 3) 切换到某个commit id,并建立新分支new_branch Git checkout –b new_branch commit_id 4) 切换到某个tag,并建立新分支new_branch Git checkout –b new_branch tag 3.9.3. 还原代码 例如 “git checkout app/model/user.rb” 就会将user.rb文件从上一个已提交的版本中更新回来,未提交的工作目录中的内容全部会被覆盖。 3.10. Git-ls-files 查看当前的git库中有那些文件。 3.11. Git mv 重命名一个文件、目录或者链接。 例如:Git mv helloworld.c helloworld1.c (把文件helloworld.c 重命名为 helloworld1.c) 3.12. Git branch 3.12.1. 总述 在 git 版本库中创建分支的成本几乎为零,所以,不必吝啬多创建几个分支。当第一次执行git init时,系统就会创建一个名为“master”的分支。 而其它分支则通过手工创建。 下面列举一些常见的分支策略: 创建一个属于自己的个人工作分支,以避免对主分支 master 造成太多的干扰,也方便与他人交流协作; 当进行高风险的工作时,创建一个试验性的分支; 合并别人的工作的时候,最好是创建一个临时的分支用来合并,合并完成后再“fetch”到自己的分支。 对分支进行增、删、查等操作。 注意:分支信息一般在.git/refs/目录下,其中heads目录下为本地分支,remotes为对应服务器上的分支,tags为标签。 3.12.2. 查看分支 git branch 列出本地git库中的所有分支。在列出的分支中,若分支名前有*,则表示此分支为当前分支。 git branch –r 列出服务器git库的所有分支。 (可以继续使用命令 “ git checkout -b 本地分支名 服务器分支名”来获取服务器上某个分支的代码文件)。 3.12.3. 查看当前在哪个分支上 cat .git/HEAD 3.12.4. 创建一个分支 1) git branch 分支名 虽然创建了分支,但是不会将当前工作分支切换到新创建的分支上,因此,还需要命令“git checkout 分支名” 来切换, 2) git checout –b 分支名 不但创建了分支,还将当前工作分支切换到了该分支上。 3.12.5. 切换到某个分支:git checkout 分支名 切换到主分支:git checkout master 3.12.6. 删除分支 git branch –D 分支名 注意: 删除后,发生在该分支的所有变化都无法恢复。强制删除此分支。 3.12.7. 比较两个分支上的文件的区别 git diff master 分支名 (比较主分支和另一个分支的区别) 3.12.8. 查看分支历史 git-show-branch (查看当前分支的提交注释及信息) git-show-branch -all(查看所有分支的提交注释及信息)例如: * [dev] d2 ! [master] m2 -- * [dev] d2 * [dev^] d1 * [dev~2] d0 *+ [master] m2 在上述例子中, “--”之上的两行表示有两个分支dev和master, 且dev分支上最后一次提交的日志是“d2”,master分支上最后一次提交的日志是 “m2”。 “--”之下的几行表示了分支演化的历史,其中 dev表示发生在dev分支上的最后一次提交,dev^表示发生在dev分支上的倒数第二次提交。dev~2表示发生在dev分支上的倒数第三次提交。 3.12.9. 查看当前分支的操作记录 git whatchanged 3.12.10. 合并分支 法一: git merge “注释” 合并的目标分支 合并的来源分支 如果合并有冲突,git会有提示。 例如:git checkout master (切换到master分支) git merge HEAD dev~2 (合并master分支和dev~2分支)或者:git merge master dev~2 法二: git pull 合并的目标分支 合并的来源分支 例如: git checkout master (切换到master分支) git pull . dev~2(合并当前分支和dev~2分支) 3.13. Git rebase 一般在将服务器最新内容合并到本地时使用,例如:在版本C时从服务器上获取内容到本地,修改了本地内容,此时想把本地修改的内容提交到服务器上;但发现服务器上的版本已经变为G了,此时就需要先执行Git rebase,将服务器上的最新版本合并到本地。例如: 用下面两幅图解释会比较清楚一些,rebase命令执行后,实际上是将分支点从C移到了G,这样分支也就具有了从C到G的功能。 3.14. Git reset 库的逆转与恢复除了用来进行一些废弃的研发代码的重置外,还有一个重要的作用。比如我们从远程clone了一个代码库,在本地开发后,准备提交回远程。但是本地代码库在开发时,有功能性的commit,也有出于备份目的的commit等等。总之,commit的日志中有大量无用log,我们并不想把这些 log在提交回远程时也提交到库中。 因此,就要用到git reset。 git reset的概念比较复杂。它的命令形式:git reset [--mixed | --soft | --hard] [<commit-ish>] 命令的选项: --mixed 这个是默认的选项。如git reset [--mixed] dev^(dev^的定义可以参见2.6.5)。它的作用仅是重置分支状态到dev1^, 但是却不改变任何工作文件的内容。即,从dev1^到dev1的所有文件变化都保留了,但是dev1^到dev1之间的所有commit日志都被清除了, 而且,发生变化的文件内容也没有通过git add标识,如果您要重新commit,还需要对变化的文件做一次git add。 这样,commit后,就得到了一份非常干净的提交记录。 (回退了index和仓库中的内容) --soft相当于做了git reset –mixed,后,又对变化的文件做了git add。如果用了该选项, 就可以直接commit了。(回退了仓库中的内容) --hard这个命令就会导致所有信息的回退, 包括文件内容。 一般只有在重置废弃代码时,才用它。 执行后,文件内容也无法恢复回来了。(回退了工作目录、index和仓库中的内容) 例如: 切换到使用的分支上; git reset HEAD^ 回退第一个记录 git reset HEAD~2 回退第二个记录 如果想把工作目录下的文件也回退,则使用git reset - - hard HEAD^ 回退第一个记录 git reset - - hard HEAD~2 回退第二个记录 还可以使用如下方法: 将当前的工作目录完全回滚到指定的版本号,假设如下图,我们有A-G五次提交的版本,其中C的版本号是 bbaf6fb5060b4875b18ff9ff637ce118256d6f20,我们执行了'git reset bbaf6fb5060b4875b18ff9ff637ce118256d6f20'那么结果就只剩下了A-C三个提交的版本 3.15. Git revert 还原某次对版本的修改,例如:git revert commit_id (其中commit_id为commit代码时生成的一个唯一表示的字符串) 例如:(3.6中)git revert dfb02e6e4f2f7b573337763e5c0013802e392818 (执行此操作,则还原上一次commit的操作) 3.16. Git config 利用这个命令可以新增、更改Git的各种设置,例如 “git config branch.master.remote origin” 就将master的远程版本库设置为别名叫做origin版本库。 3.17. Git show 显示对象的不同类型。 3.18. Git tag 创建、列出、删除或者验证一个标签对象(使用GPG签名的)。 可以将某个具体的版本打上一个标签,这样就不需要记忆复杂的版本号哈希值字符串了,例如你可以使用 “git tag revert_version bbaf6fb5060b4875b18ff9ff637ce118256d6f20” 来标记这个被你还原的版本,那么以后你想查看该版本时,就可以使用 revert_version标签名,而不是哈希值了。 4. Git服务器操作命令(与服务器交互) 4.1. Git clone 取出服务器的仓库的代码到本地建立的目录中(与服务器交互) 通过git clone获取远端git库后,.git/config中的开发者信息不会被一起clone过来。仍然需要为本地库的.git/config文件添加开发者信息。此外,开发者还需要自己添加 . gitignore文件。 通过git clone获取的远端git库,只包含了远端git库的当前工作分支。如果想获取其它分支信息,需要使用 “git branch –r” 来查看, 如果需要将远程的其它分支代码也获取过来,可以使用命令 “ git checkout -b 本地分支名 远程分支名”,其中,远程分支名为 “git branch –r” 所列出的分支名, 一般是诸如“origin/分支名”的样子。如果本地分支名已经存在, 则不需要“-b”参数。 例如: 4.2. Git pull 从服务器的仓库中获取代码,和本地代码合并。(与服务器交互,从服务器上下载最新代码,等同于: Git fetch + Git merge) 从其它的版本库(既可以是远程的也可以是本地的)将代码更新到本地,例如:“git pull origin master ”就是将origin这个版本库的代码更新到本地的master主分支。 git pull可以从任意一个git库获取某个分支的内容。用法如下: git pull username@ipaddr:远端repository名远端分支名 本地分支名。这条命令将从远端git库的远端分支名获取到本地git库的一个本地分支中。其中,如果不写本地分支名,则默认pull到本地当前分支。 需要注意的是,git pull也可以用来合并分支。 和git merge的作用相同。 因此,如果你的本地分支已经有内容,则git pull会合并这些文件,如果有冲突会报警。 例如: 4.3. Git push 将本地commit的代码更新到远程版本库中,例如 “git push origin”就会将本地的代码更新到名为orgin的远程版本库中。 git push和git pull正好想反,是将本地某个分支的内容提交到远端某个分支上。用法: git pushusername@ipaddr:远端repository名本地分支名 远端分支名。这条命令将本地git库的一个本地分支push到远端git库的远端分支名中。 需要格外注意的是,git push好像不会自动合并文件。因此,如果git push时,发生了冲突,就会被后push的文件内容强行覆盖,而且没有什么提示。 这在合作开发时是很危险的事情。 例如: 4.4. Git fetch 从服务器的仓库中下载代码。(与服务器交互,从服务器上下载最新代码) 相当于从远程获取最新版本到本地,不会自动merge,比Git pull更安全些。 使用此方法来获取服务器上的更新。 例如:如果使用git checkout nov/eclair_rocket (nov/eclair_rocket为服务器上的分支名),则是获取上次使用git fetch命令时从服务器上下载的代码;如果先使用 git fetch ,再使用git checkout nov/eclair_rocket,则是先从服务器上获取最新的更新信息,然后从服务器上下载最新的代码。 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/11/26/2788752.html,如需转载请自行联系原作者。
1、 autoscan autoscan是用来扫描源代码目录生成configure.scan文件的。autoscan可以用目录名做为参数,但如果你不使用参数的话,那么autoscan将认为使用的是当前目录。autoscan将扫描你所指定目录中的源文件,并创建configure.scan文件。 2、 configure.scan configure.scan包含了系统配置的基本选项,里面都是一些宏定义。我们需要将它改名为configure.in 3、 aclocal aclocal是一个perl 脚本程序。aclocal根据configure.in文件的内容,自动生成aclocal.m4文件。aclocal的定义是:“aclocal - create aclocal.m4 by scanning configure.ac”。 4、 autoconf 使用autoconf,根据configure.in和aclocal.m4来产生configure文件。configure是一个脚本,它能设置源程序来适应各种不同的操作系统平台,并且根据不同的系统来产生合适的Makefile,从而可以使你的源代码能在不同的操作系统平台上被编译出来。 configure.in文件的内容是一些宏,这些宏经过autoconf 处理后会变成检查系统特性、环境变量、软件必须的参数的shell脚本。configure.in文件中的宏的顺序并没有规定,但是你必须在所有宏的最前面和最后面分别加上AC_INIT宏和AC_OUTPUT宏。 在configure.ini中: #号表示注释,这个宏后面的内容将被忽略。 AC_INIT(FILE) 这个宏用来检查源代码所在的路径。 AM_INIT_AUTOMAKE(PACKAGE, VERSION) 这个宏是必须的,它描述了我们将要生成的软件包的名字及其版本号:PACKAGE是软件包的名字,VERSION是版本号。当你使用make dist命令时,它会给你生成一个类似helloworld-1.0.tar.gz的软件发行包,其中就有对应的软件包的名字和版本号。 AC_PROG_CC 这个宏将检查系统所用的C编译器。 AC_OUTPUT(FILE) 这个宏是我们要输出的Makefile的名字。 我们在使用automake时,实际上还需要用到其他的一些宏,但我们可以用aclocal 来帮我们自动产生。执行aclocal后我们会得到aclocal.m4文件。 产生了configure.in和aclocal.m4 两个宏文件后,我们就可以使用autoconf来产生configure文件了。 5、 Makefile.am Makefile.am是用来生成Makefile.in的,需要你手工书写。Makefile.am中定义了一些内容: AUTOMAKE_OPTIONS 这个是automake的选项。在执行automake时,它会检查目录下是否存在标准GNU软件包中应具备的各种文件,例如AUTHORS、ChangeLog、NEWS等文件。我们将其设置成foreign时,automake会改用一般软件包的标准来检查。 bin_PROGRAMS 这个是指定我们所要产生的可执行文件的文件名。如果你要产生多个可执行文件,那么在各个名字间用空格隔开。 helloworld_SOURCES 这个是指定产生“helloworld”时所需要的源代码。如果它用到了多个源文件,那么请使用空格符号将它们隔开。比如需要helloworld.h,helloworld.c那么请写成helloworld_SOURCES= helloworld.h helloworld.c。 如果你在bin_PROGRAMS定义了多个可执行文件,则对应每个可执行文件都要定义相对的filename_SOURCES。 6、 automake 我们使用automake,根据configure.in和Makefile.am来产生Makefile.in。 选项--add-missing的定义是“add missing standard files to package”,它会让automake加入一个标准的软件包所必须的一些文件。 我们用automake产生出来的Makefile.in文件是符合GNU Makefile惯例的,接下来我们只要执行configure这个shell 脚本就可以产生合适的 Makefile 文件了。 7、 Makefile 在符合GNU Makefiel惯例的Makefile中,包含了一些基本的预先定义的操作: make 根据Makefile编译源代码,连接,生成目标文件,可执行文件。 make clean 清除上次的make命令所产生的object文件(后缀为“.o”的文件)及可执行文件。 make install 将编译成功的可执行文件安装到系统目录中,一般为/usr/local/bin目录。 make dist 产生发布软件包文件(即distribution package)。这个命令将会将可执行文件及相关文件打包成一个tar.gz压缩的文件用来作为发布软件的软件包。它会在当前目录下生成一个名字类似“PACKAGE-VERSION.tar.gz”的文件。PACKAGE和VERSION,是我们在configure.in中定义的AM_INIT_AUTOMAKE(PACKAGE, VERSION)。 make distcheck 生成发布软件包并对其进行测试检查,以确定发布包的正确性。这个操作将自动把压缩包文件解开,然后执行configure命令,并且执行make,来确认编译不出现错误,最后提示你软件包已经准备好,可以发布了。 make distclean 类似make clean,但同时也将configure生成的文件全部删除掉,包括Makefile。 五、过程图示 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/12/01/2797566.html,如需转载请自行联系原作者。
转:http://dbzone.iteye.com/blog/1042455 众所周知,Oracle参数compatible 主要用于启用Oracle针对某一版本的新特性。但此参数设置时,只能往上调,设置好之后不能往下降。 引用 You can advance the compatibility level of your database. If you do advance the compatibility of your database with the COMPATIBLE initialization parameter, there is no way to start the database using a lower compatibility level setting, except by doing a point-in-time recovery to a time before the compatibility was advanced. The default value for the COMPATIBLE parameter is the release number of the most recent major release. Note:For Oracle Database 10g Release 2 (10.2), the default value of the COMPATIBLE parameter is 10.2.0. The minimum value is 9.2.0. If you create an Oracle Database using the default value, you can immediately use all the new features in this release, and you can never downgrade the database. 比如可以将参数compatible从10.2.0.1.0设置成10.2.0.2.0,重启数据库后生效。 引用 SQL> alter system set compatible="10.2.0.2.0" scope=spfile; System altered. 重启数据库后alert日志会有如下显示,从alert日志中可以明显的看出,compatible升级之后,Oracle会修改控制文件和redolog 引用 Fri May 13 11:59:11 2011 alter database mount Fri May 13 11:59:15 2011 ALERT: Compatibility of the database is changed from 10.2.0.0.0 to 10.2.0.2.0. Setting recovery target incarnation to 1 Fri May 13 11:59:15 2011 Successful mount of redo thread 1, with mount id 200680975 Fri May 13 11:59:15 2011 Database mounted in Exclusive Mode Completed: alter database mount Fri May 13 11:59:32 2011 alter database open Fri May 13 11:59:32 2011 Switching redo format version from 10.2.0.0.0 to 10.2.0.2.0 at change 803371 Fri May 13 11:59:32 2011 Thread 1 opened at log sequence 10 Current log# 1 seq# 10 mem# 0: /oradata/mynewdb/redo01.log Successful open of redo thread 1 其实,Oracle还会修改数据文件头,从数据文件头的dump信息中可以看出存在compatible信息 引用 aux_file is NOT DEFINED V10 STYLE FILE HEADER: Compatibility Vsn = 169869568=0xa200100 Db ID=2596133541=0x9abddaa5, Db Name='XE' Activation ID=0=0x0 Control Seq=198940=0x3091c, File size=142080=0x22b00 File Number=1, Blksiz=8192, File Type=3 DATA 经过以上分析,要实现手工实现compatible降级,必须修改3个地方,即控制文件,数据文件头,redolog。 修改步骤如下,摸索着艰难前进,注意以下操作,除非特殊情况下,严禁在生产库操作: 1、在参数文件中将compatible重设为10.2.0.1.0,重启数据后出现参数文件和控制文件不匹配 引用 SQL> startup force ORACLE instance started. Total System Global Area 524288000 bytes Fixed Size 1262716 bytes Variable Size 159386500 bytes Database Buffers 356515840 bytes Redo Buffers 7122944 bytes ORA-00201: control file version 10.2.0.2.0 incompatible with ORACLE version 10.2.0.1.0 ORA-00202: control file: '/oradata/mynewdb/control01.ctl' 于是尝试修改控制文件,由于控制文件compatible设置是从参数文件获取的,可以通过重建控制文件的方法,将compatible从10.2.0.2.0降为10.2.0.1.0。 重建控制文件分为noresetlogs和resetlogs两种。 如果采用noresetlogs方法重建时,需要扫描redolog文件头,由于redolog文件头compatible为10.2.0.2.0,和参数文件compatible版本号不一致。由于控制文件采用resetlogs选项重建时,并不会扫描redolog头,于是我们采用resetlogs选项重建控制文件。 但是无论采用noresetlogs或者resetlogs选项重建控制文件,重建时都会进行数据文件头匹配,由于数据文件头compatible为10.2.0.2.0 所以重建控制文件时会出现以下错误: 引用 SQL> STARTUP NOMOUNT CREATE CONTROLFILE REUSE DATABASE "MYNEWDB" RESETLOGS NOARCHIVELOG MAXLOGFILES 5 MAXLOGMEMBERS 5 MAXDATAFILES 100 MAXINSTANCES 1 MAXLOGHISTORY 292 LOGFILE GROUP 1 '/oradata/mynewdb/redo01.log' SIZE 100M, GROUP 2 '/oradata/mynewdb/redo02.log' SIZE 100M, GROUP 3 '/oradata/mynewdb/redo03.log' SIZE 100M -- STANDBY LOGFILE DATAFILE '/oradata/mynewdb/system01.dbf', '/oradata/mynewdb/undotbs01.dbf', '/oradata/mynewdb/sysaux01.dbf' CHARACTER SET ZHS16GBK ; --ORACLE instance started. Total System Global Area 524288000 bytes Fixed Size 1262716 bytes Variable Size 167775108 bytes Database Buffers 348127232 bytes Redo Buffers 7122944 bytes SQL> CREATE CONTROLFILE REUSE DATABASE "MYNEWDB" RESETLOGS NOARCHIVELOG * ERROR at line 1: ORA-01503: CREATE CONTROLFILE failed ORA-01130: database file version 10.2.0.2.0 incompatible with ORACLE version 10.2.0.1.0 ORA-01110: data file 1: '/oradata/mynewdb/system01.dbf' 至此,我们只能通过修改数据文件头的compatible来达到降级的目的了 引用 BBED> find 0x0002200a File: /oradata/mynewdb/system01.dbf (1) Block: 1 Offsets: 24 to 535 Dba:0x00400001 ------------------------------------------------------------------------ 0002200a e28bcb0b 4d594e45 57444200 6a000000 80a20000 00200000 01000300 BBED> modify 0x0001200a File: /oradata/mynewdb/system01.dbf (1) Block: 1 Offsets: 24 to 535 Dba:0x00400001 ------------------------------------------------------------------------ 0001200a e28bcb0b 4d594e45 57444200 6a000000 80a20000 00200000 01000300 BBED> sum apply Check value for File 1, Block 1: current = 0xf4ba, required = 0xf4ba 修改完所有数据文件之后,用noresetlog重建控制文件,日志文件头和参数文件不匹配如期而至。 引用 SQL> STARTUP NOMOUNT CREATE CONTROLFILE REUSE DATABASE "MYNEWDB" NORESETLOGS NOARCHIVELOG MAXLOGFILES 5 MAXLOGMEMBERS 5 MAXDATAFILES 100 MAXINSTANCES 1 MAXLOGHISTORY 292 LOGFILE GROUP 1 '/oradata/mynewdb/redo01.log' SIZE 100M, GROUP 2 '/oradata/mynewdb/redo02.log' SIZE 100M, GROUP 3 '/oradata/mynewdb/redo03.log' SIZE 100M -- STANDBY LOGFILE DATAFILE '/oradata/mynewdb/system01.dbf', '/oradata/mynewdb/undotbs01.dbf', '/oradata/mynewdb/sysaux01.dbf' CHARACTER SET ZHS16GBK ;ORACLE instance started. Total System Global Area 524288000 bytes Fixed Size 1262716 bytes Variable Size 176163716 bytes Database Buffers 339738624 bytes Redo Buffers 7122944 bytes SQL> CREATE CONTROLFILE REUSE DATABASE "MYNEWDB" NORESETLOGS NOARCHIVELOG * ERROR at line 1: ORA-01503: CREATE CONTROLFILE failed ORA-00331: log version 0.0.0.0.0 incompatible with ORACLE version 10.2.0.1.0 ORA-01517: log member: '/oradata/mynewdb/redo01.log' 于是我们采用reselogs选项重建控制文件,终于成功 引用 SQL> CREATE CONTROLFILE REUSE DATABASE "MYNEWDB" RESETLOGS NOARCHIVELOG 2 MAXLOGFILES 5 3 MAXLOGMEMBERS 5 4 MAXDATAFILES 100 5 MAXINSTANCES 1 6 MAXLOGHISTORY 292 7 LOGFILE 8 GROUP 1 '/oradata/mynewdb/redo01.log' SIZE 100M, 9 GROUP 2 '/oradata/mynewdb/redo02.log' SIZE 100M, 10 GROUP 3 '/oradata/mynewdb/redo03.log' SIZE 100M 11 -- STANDBY LOGFILE 12 DATAFILE 13 '/oradata/mynewdb/system01.dbf', 14 '/oradata/mynewdb/undotbs01.dbf', 15 '/oradata/mynewdb/sysaux01.dbf' 16 CHARACTER SET ZHS16GBK 17 ; Control file created. 重建好控制文件后,在open resetlogs时提示需要recover,redolog文件头的版本号依然为10.2.0.2.0,于是recover出现了问题 引用 SQL> alter database open resetlogs; alter database open resetlogs * ERROR at line 1: ORA-01113: file 1 needs media recovery ORA-01110: data file 1: '/oradata/mynewdb/system01.dbf' SQL> recover database using backup controlfile; ORA-00279: change 823455 generated at 05/13/2011 12:05:45 needed for thread 1 ORA-00289: suggestion : /ora10g/oracle/product/10.2.0/db_1/dbs/arch1_11_748203362.dbf ORA-00280: change 823455 for thread 1 is in sequence #11 Specify log: {<RET>=suggested | filename | AUTO | CANCEL} /oradata/mynewdb/redo01.log ORA-00331: log version 10.2.0.2.0 incompatible with ORACLE version 10.2.0.1.0 ORA-00334: archived log: '/oradata/mynewdb/redo01.log' 出现这个错误之后,其实修复也很简单,只要再次通过bbed修复redolog文件头即可。 引用 BBED> dump offset 0 File: /oradata/mynewdb/redo01.log (0) Block: 1 Offsets: 0 to 511 Dba:0x00000000 ------------------------------------------------------------------------ 01220000 01000000 0a000000 00809db0 00000000 0002200a e28bcb0b 4d594e45 BBED> find 0x0002200a File: /oradata/mynewdb/redo01.log (0) Block: 1 Offsets: 20 to 511 Dba:0x00000000 ------------------------------------------------------------------------ 0002200a e28bcb0b 4d594e45 57444200 69000000 00200300 00020000 01000200 但由于bbed工具不会再次计算redolog的checksum值,所以修改之后该日志文件头也处于了checksum error状态 引用 BBED> sum apply Check value for File 0, Block 1: current = 0x0000, required = 0x0000 SQL> recover database using backup controlfile; ORA-00279: change 823455 generated at 05/13/2011 12:05:45 needed for thread 1 ORA-00289: suggestion : /ora10g/oracle/product/10.2.0/db_1/dbs/arch1_11_748203362.dbf ORA-00280: change 823455 for thread 1 is in sequence #11 Specify log: {<RET>=suggested | filename | AUTO | CANCEL} /oradata/mynewdb/redo01.log ORA-00367: checksum error in log file header ORA-00334: archived log: '/oradata/mynewdb/redo01.log' 其实Oracle 对checkvalue值的计算只是各个字节相对简单的与或运算,由于手头没有现成脚本,于是打算放弃使用该redolog,强制启用Oracle。 启用隐含参数_allow_resetlogs_corruption 引用 SQL> alter system set "_allow_resetlogs_corruption"=true scope=spfile; System altered. SQL> startup force mount ORACLE instance started. Total System Global Area 524288000 bytes Fixed Size 1262716 bytes Variable Size 180358020 bytes Database Buffers 335544320 bytes Redo Buffers 7122944 bytes Database mounted. SQL> recover database using backup controlfile until cancel; ORA-00279: change 823455 generated at 05/13/2011 12:05:45 needed for thread 1 ORA-00289: suggestion : /ora10g/oracle/product/10.2.0/db_1/dbs/arch1_11_748203362.dbf ORA-00280: change 823455 for thread 1 is in sequence #11 Specify log: {<RET>=suggested | filename | AUTO | CANCEL} cancel ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below ORA-01194: file 1 needs more recovery to be consistent ORA-01110: data file 1: '/oradata/mynewdb/system01.dbf' ORA-01112: media recovery not started 用reselogs选项打开Oracle。 引用 SQL> alter database open resetlogs; alter database open resetlogs * ERROR at line 1: ORA-01092: ORACLE instance terminated. Disconnection forced 实例异常终止,打开后台alert日志一看,2662错误如期而至 引用 Fri May 13 12:29:00 2011 Errors in file /ora10g/oracle/product/10.2.0/db_1/rdbms/log/mynewdb_ora_22033.trc: ORA-00600: internal error code, arguments: [2662], [0], [823461], [0], [823504], [4194313], [], [] Fri May 13 12:29:01 2011 Errors in file /ora10g/oracle/product/10.2.0/db_1/rdbms/log/mynewdb_ora_22033.trc: ORA-00600: internal error code, arguments: [2662], [0], [823461], [0], [823504], [4194313], [], [] Fri May 13 12:29:01 2011 Error 600 happened during db open, shutting down database USER: terminating instance due to error 600 Instance terminated by USER, pid = 22033 ORA-1092 signalled during: alter database open resetlogs.. ORA-600 [2662]主要是由于Oracle内部block的scn大于当前打开数据库的scn而引起的,主要有5个参数: 引用 ERROR: ORA-600 [2662] [a] [b] [c] [d] [e] VERSIONS: versions 6.0 to 10.1 DESCRIPTION: A data block SCN is ahead of the current SCN. The ORA-600 [2662] occurs when an SCN is compared to the dependent SCN stored in a UGA variable. If the SCN is less than the dependent SCN then we signal the ORA-600 [2662] internal error. ARGUMENTS: Arg [a] Current SCN WRAP Arg [b] Current SCN BASE Arg [c] dependent SCN WRAP Arg [d] dependent SCN BASE Arg [e] Where present this is the DBA where the dependent SCN came from. 一般情况下,产生ora-600 [2662],可以通过设置event 10015事件,手工递增scn,即数据库open时的scn。 event 10015事件设置需要针对每个场景计算出level 1,通过2662几个参数根据一定的规则可以计算出我们需要的level。 计算规则如下: Arg [c]*4得出一个数值,假设为V_Wrap 如果Arg [d]=0,则V_Wrap值为需要的level Arg [d] < 1073741824,V_Wrap+1为需要的level Arg [d] < 2147483648,V_Wrap+2为需要的level Arg [d] < 3221225472,V_Wrap+3为需要的level 本案例中[c]=0,所以level为0*4+1=1,即在数据mount状态下,设置如下参数即可 引用 SQL> ALTER SESSION SET EVENTS '10015 TRACE NAME ADJUST_SCN LEVEL 1'; Session altered. 但Oracle并不识别此event的设置,即并不递增scn值,在打开时,数据库依然报错 引用 Fri May 13 12:45:09 2011 SMON: enabling cache recovery Fri May 13 12:45:09 2011 Errors in file /ora10g/oracle/product/10.2.0/db_1/rdbms/log/mynewdb_ora_25610.trc: ORA-00600: internal error code, arguments: [2662], [0], [823467], [0], [823504], [4194313], [], [] Fri May 13 12:45:09 2011 Errors in file /ora10g/oracle/product/10.2.0/db_1/rdbms/log/mynewdb_ora_25610.trc: ORA-00600: internal error code, arguments: [2662], [0], [823467], [0], [823504], [4194313], [], [] Fri May 13 12:45:09 2011 也是尝试采用隐含参数_minimum_giga_scn,其取值方法和10015 event相同 引用 SQL> alter system set "_minimum_giga_scn"=1 scope=spfile; System altered. 再次尝试打开数据终于成功 引用 SQL> recover database using backup controlfile until cancel; ORA-00279: change 823463 generated at 05/13/2011 12:45:09 needed for thread 1 ORA-00289: suggestion : /ora10g/oracle/product/10.2.0/db_1/dbs/arch1_1_751034707.dbf ORA-00280: change 823463 for thread 1 is in sequence #1 Specify log: {<RET>=suggested | filename | AUTO | CANCEL} cancel ORA-01547: warning: RECOVER succeeded but OPEN RESETLOGS would get error below ORA-01194: file 1 needs more recovery to be consistent ORA-01110: data file 1: '/oradata/mynewdb/system01.dbf' ORA-01112: media recovery not started SQL> alter database open resetlogs; Database altered. 后台alert日志显示,scn已经递增成功。 引用 Fri May 13 12:47:37 2011 alter database open resetlogs Fri May 13 12:47:37 2011 RESETLOGS is being done without consistancy checks. This may result in a corrupted database. The database should be recreated. RESETLOGS after incomplete recovery UNTIL CHANGE 823463 Resetting resetlogs activation ID 200680610 (0xbf624a2) Online log /oradata/mynewdb/redo01.log: Thread 1 Group 1 was previously cleared Online log /oradata/mynewdb/redo02.log: Thread 1 Group 2 was previously cleared Fri May 13 12:47:39 2011 Setting recovery target incarnation to 6 Fri May 13 12:47:39 2011 引用 Advancing SCN to 1073741824 according to _minimum_giga_scn Fri May 13 12:47:39 2011 Assigning activation ID 200679734 (0xbf62136) Thread 1 opened at log sequence 1 Current log# 3 seq# 1 mem# 0: /oradata/mynewdb/redo03.log Successful open of redo thread 1 Fri May 13 12:47:39 2011 MTTR advisory is disabled because FAST_START_MTTR_TARGET is not set Fri May 13 12:47:39 2011 SMON: enabling cache recovery Fri May 13 12:47:39 2011 Successfully onlined Undo Tablespace 1. Dictionary check beginning Tablespace 'TEMPTS1' #3 found in data dictionary, but not in the controlfile. Adding to controlfile. Dictionary check complete Fri May 13 12:47:39 2011 SMON: enabling tx recovery Fri May 13 12:47:39 2011 ********************************************************************* WARNING: The following temporary tablespaces contain no files. This condition can occur when a backup controlfile has been restored. It may be necessary to add files to these tablespaces. That can be done using the SQL statement: ALTER TABLESPACE <tablespace_name> ADD TEMPFILE Alternatively, if these temporary tablespaces are no longer needed, then they can be dropped. Empty temporary tablespace: TEMPTS1 ********************************************************************* Database Characterset is ZHS16GBK replication_dependency_tracking turned off (no async multimaster replication found) Starting background process QMNC QMNC started with pid=16, OS id=401 Fri May 13 12:47:39 2011 LOGSTDBY: Validating controlfile with logical metadata Fri May 13 12:47:39 2011 LOGSTDBY: Validation complete Completed: alter database open resetlogs 可以看到数据库已经成功降级 引用 SQL> show parameter compatible NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ compatible string 10.2.0.1.0 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/p/3200734.html,如需转载请自行联系原作者。
我们可以通过视图v$session_wait来查看系统当前的等待事件,以及与等待事件相对应的资源的相关信息,从而可确定出产生瓶颈的类型及其对象。 v$session_wait的p1、p2、p3告诉我们等待事件的具体含义,根据事件不同其内容也不相同,下面就一些常见的等待事件如何处理以及如何定位热点对象和阻塞会话作一些介绍。 <1> db file scattered read DB 文件分散读取 (太多索引读,全表扫描-----调整代码,将小表放入内存) 这种情况通常显示与全表扫描相关的等待。当全表扫描被限制在内存时,它们很少会进入连续的缓冲区内,而是分散于整个缓冲存储器中。如果这个数目很大,就表明该表找不到索引,或者只能找到有限的索引。尽管在特定条件下执行全表扫描可能比索引扫描更有效,但如果出现这种等待时,最好检查一下这些全表扫描是否必要。因为全表扫描被置于LRU(Least Recently Used,最近最少适用)列表的冷端(cold end),所以应尽量存储较小的表,以避免一次又一次地重复读取它们。 ================================================== 该类事件的p1text=file#,p1是file_id,p2是block_id,通过dba_extents即可确定出热点对象(表或索引) select owner,segment_name,segment_type from dba_extents where file_id = &file_id and &block_id between block_id and block_id + &blocks - 1; ================================================== <2> db file sequential read DB 文件顺序读取 (表连接顺序不佳-----调整代码,特别是表连接) 这一事件通常显示单个块的读取(如索引读取)。这种等待的数目很多时,可能显示表的连接顺序不佳,或者不加选择地进行索引。对于大量事务处理、调整良好的系统,这一数值大多是很正常的,但在某些情况下,它可能暗示着系统中存在问题。你应当将这一等待统计量与Statspack 报告中的已知问题(如效率较低的SQL)联系起来。检查索引扫描,以保证每个扫描都是必要的,并检查多表连接的连接顺序。DB_CACHE_SIZE 也是这些等待出现频率的决定因素。有问题的散列区域(Hash-area)连接应当出现在PGA 内存中,但它们也会消耗大量内存,从而在顺序读取时导致大量等待。它们也可能以直接路径读/写等待的形式出现。 =================================================== 该类事件的p1text=file#,p1是file_id,p2是block_id,通过dba_extents即可确定出热点对象(表或索引) select owner,segment_name,segment_type from dba_extents where file_id = &file_id and &block_id between block_id and block_id + &blocks - 1; ================================================== <3> free buffer waits 释放缓冲区等待 (增大DB_CACHE_SIZE,加速检查点,调整代码) 这种等待表明系统正在等待内存中的缓冲,因为内存中已经没有可用的缓冲空间了。如果所有SQL 都得到了调优,这种等待可能表示你需要增大DB_BUFFER_CACHE。释放缓冲区等待也可能表示不加选择的SQL 导致数据溢出了带有索引块的缓冲存储器,没有为等待系统处理的特定语句留有缓冲区。这种情况通常表示正在执行相当多数量的DML(插入/更新/删除),并且数据库书写器(DBWR)写的速度不够快,缓冲存储器可能充满了相同缓冲器的多个版本,从而导致效率非常低。为了解决这个问题,可能需要考虑增加检查点、利用更多的DBWR 进程,或者增加物理磁盘的数量。 <4> buffer busy waits 缓冲区忙等待 (BUFFER热块)这是为了等待一个以非共享方式使用的缓冲区,或者正在被读入缓冲存储器的缓冲区。缓冲区忙等待不应大于1%。检查缓冲等待统计部分(或V$WAITSTAT): A、如果等待处于字段头部,应增加自由列表(freelist)的组数,或者增加pctused到pctfree之间的距离。 B、如果等待处于回退段(undo)头部块,可以通过增加回滚段(rollback segment)来解决缓冲区的问题; C、如果等待处于回退段(undo)非头部块上,就需要降低驱动一致读取的表中的数据密度,或者增大DB_CACHE_SIZE; D、如果等待处于数据块,可以将数据移到另一数据块以避开这个"热"数据块、增加表中的自由列表或使用LMT表空间; E、如果等待处于索引块,应该重建索引、分割索引或使用反向键索引。 为了防止与数据块相关的缓冲忙等待,也可以使用较小的块:在这种情况下,单个块中的记录就较少,所以这个块就不是那么"繁忙"。在执行DML(插入/更新 /删除)时,Oracle DBWR就向块中写入信息,包括所有对块状态"感兴趣"的用户(感兴趣的事务表,ITL)。为减少这一区域的等待,可以增加initrans,这样会在块中创建空间,从而使你能够使用多个ITL槽。你也可以增加该块所在表中的pctfree(当根据指定的initrans 建立的槽数量不足时,这样可以使ITL 信息数量达到maxtrans 指定的数量)。 <5> latch free (等待LATCH FREE)latch 是一种低级排队机制(它们被准确地称为相互排斥机制),用于保护系统全局区域(SGA)中共享内存结构。latch 就像是一种快速地被获取和释放的内存锁。latch 用于防止共享内存结构被多个用户同时访问。如果latch 不可用,就会记录latch 释放失败。大多数latch 问题都与以下操作相关:不能使用邦定变量(库缓存latch)、重复生成问题(重复分配latch)、缓冲存储器竞争问题(缓冲器存储LRU 链),以及缓冲存储器中的"热"块(缓冲存储器链)。也有一些latch 等待与bug(程序错误)有关,如果怀疑是这种情况,可以检查MetaLink 上的bug 报告。 该事件的热点对象可通过以下语句查找,其中&2值是v$session_wait中的P1RAW,x$bh中的字段Hladdr表示该block buffer在哪个cache buffer chain latch 上,可以通过v$latch_children定位哪些segment是热点块。 =================================================== select a.hladdr, a.file#, a.dbablk, a.tch, a.obj, b.object_name from x$bh a, dba_objects b where (a.obj = b.object_id or a.obj = b.data_object_id) and a.hladdr = &2 union select hladdr, file#, dbablk, tch, obj, null from x$bh where obj in (select obj from x$bh where hladdr = &2 minus select object_id from dba_objects minus select data_object_id from dba_objects) and hladdr = &2 order by 4; ==================================================== ***Latch 问题及可能解决办法 ------------------------------ * Library Cache and Shared Pool (未绑定变量---绑定变量,调整shared_pool_size) 每当执行SQL或PL/SQL存储过程,包,函数和触发器时,这个Latch即被用到.Parse操作中此Latch也会被频繁使用. * Redo Copy (增大_LOG_SIMULTANEOUS_COPIES参数) 重做拷贝Latch用来从PGA向重做日志缓冲区拷贝重做记录. * Redo Allocation (最小化REDO生成,避免不必要提交) 此Latch用来分配重做日志缓冲区中的空间,可以用NOLOGGING来减缓竞争. * Row Cache Objects (增大共享池) 数据字典竞争.过度parsing. * Cache Buffers Chains (_DB_BLOCK_HASH_BUCKETS应增大或设为质数) "过热"数据块造成了内存缓冲链Latch竞争. * Cache Buffers Lru Chain (调整SQL,设置DB_BLOCK_LRU_LATCHES,或使用多个缓冲区池) 扫描全部内存缓冲区块的LRU(最近最少使用)链时要用到内存缓冲区LRU链Latch.太小内存缓冲区、过大的内存缓冲区吞吐量、过多的内存中进行的排序操作、DBWR速度跟不上工作负载等会引起此Latch竞争。<6> enqueueenqueue 是一种保护共享资源的锁定机制。该锁定机制保护共享资源,如记录中的数据,以避免两个人在同一时间更新同一数据。enqueue 包括一个排队机制,即FIFO(先进先出)排队机制。注意:Oracle 的latch 机制不是FIFO。Enqueue 等待通常指的是ST enqueue、HW enqueue、TX4 enqueue 和TM enqueue。 A、ST enqueue 用于空间管理和字典管理的表空间的分配。利用LMT,或者试图对区域进行预分配,或者至少使下一个区域大于有问题的字典管理的表空间。 B、HW enqueue 与段的高水位标记一起使用;手动分配区域可以避免这一等待。 C、TX4 enqueue是最常见的enqueue 等待,通常是以下三个问题之一产生的结果: 第一个问题是唯一索引中的重复索引,需要执行提交(commit)/回滚(rollback)操作来释放enqueue。 第二个问题是对同一位图索引段的多次更新。因为单个位图段可能包含多个行地址(rowid),所以当多个用户试图更新同一段时,你需要执行提交或回滚操作,以释放enqueue。 第三个问题,也是最可能发生的问题是多个用户同时更新同一个块。如果没有自由的ITL槽,就会发生块级锁定。通过增大initrans 和/或maxtrans以允许使用多个ITL槽,或者增大表上的pctfree 值,就可以很轻松地避免这种情况。 D、TM enqueue 在DML 期间产生,以避免对受影响的对象使用DDL。如果有外来关键字,一定要对它们进行索引,以避免这种常见的锁定问题。 <7> log buffer space 日志缓冲空间 (写REDO慢-----增大log_buffer,redo log file放到快速磁盘上) 当日志缓冲(log buffer)写入重做日志(redo log)的速度比LGWR 的写入速度慢,或者是当日志转换(log switch)太慢时,就会发生这种等待。为解决这个问题,可以增大日志文件的大小,或者增加日志缓冲器的大小,或者使用写入速度更快的磁盘。甚至可以考虑使用固态磁盘,因为它们的速度很高。 <8> log file switch 日志文件转换 (归档慢-----增加或者扩大重做日志)有两种情况: A、log file switch (archiving needed) 当日志切换的时候由于日志组循环使用了一圈但日志归档还没有完成,通常是io有严重问题,可增大日志文件和增加日志组,调整log_archive_max_processes B、log file switch (checkpoint incomplete) 当日志切换的时候由于日志组循环使用了一圈但将被使用的日志组中的checkpoint还没有完成造成,通常是io有严重问题,可增大日志文件和增加日志组 <9> log file sync 日志文件同步 (提交太频繁----批量提交)当用户commit的时候通知lgwr写日志但lwgr正忙,造成的可能原因是commit太频繁或者lgwr一次写日志时间太长(可能是因为一次log io size 太大),可调整 _log_io_size,结合log_buffer,使得 (_log_io_size*db_block_size)*n = log_buffer,这样可避免和增大log_buffer引起冲突;放置日志文件于高速磁盘上 <10> library cache pin该事件通常是发生在先有会话在运行PL/SQL,VIEW,TYPES等object时,又有另外的会话执行重新编译这些object,即先给对象加上了一个共享锁,然后又给它加排它锁,这样在加排它锁的会话上就会出现这个等待。P1,P2可与x$kglpn和x$kglob表相关 X$KGLOB (Kernel Generic Library Cache Manager Object) X$KGLPN (Kernel Generic Library Cache Manager Object Pins) -- 查询X$KGLOB,可找到相关的object,其SQL语句如下 (即把V$SESSION_WAIT中的P1raw与X$KGLOB中的KGLHDADR相关连) select kglnaown,kglnaobj from X$KGLOB where KGLHDADR =(select p1raw from v$session_wait where event='library cache pin') -- 查出引起该等待事件的阻塞者的sid select sid from x$kglpn , v$session where KGLPNHDL in (select p1raw from v$session_wait where wait_time=0 and event like 'library cache pin%') and KGLPNMOD <> 0 and v$session.saddr=x$kglpn.kglpnuse -- 查出阻塞者正执行的SQL语句 select sid,sql_text from v$session, v$sqlarea where v$session.sql_address=v$sqlarea.address and sid=<阻塞者的sid> 这样,就可找到"library cache pin"等待的根源,从而解决由此引起的性能问题。 <11> library cache lock该事件通常是由于执行多个DDL操作导致的,即在library cache object上添加一个排它锁后,又从另一个会话给它添加一个排它锁,这样在第二个会话就会生成等待。可通过到基表x$kgllk中查找其对应的对象。 -- 查询引起该等待事件的阻塞者的sid、会话用户、锁住的对象 select b.sid,a.user_name,a.kglnaobj from x$kgllk a , v$session b where a.kgllkhdl in (select p1raw from v$session_wait where wait_time=0 and event = 'library cache lock') and a.kgllkmod <> 0 and b.saddr=a.kgllkuse 当然也可以直接从v$locked_objects中查看,但没有上面语句直观根据sid可以到v$process中查出pid,然后将其kill或者其它处理。 <12> db file parallel write与DBWR进程相关的等待,一般代表了I/O能力出现了问题. 通常与配置的多个DBWR进程或者DBWU的I/O slaves个数有关.当然也可能意味着设备上存在着I/O竞争 <13> db file single write表示在检查点发生时与文件头写操作相关的等待.通常与检查点同步数据文件头时文件号的紊乱有关. <14> direct path read 和 direct path write表示与直接I/O读相关的等待.当直接读数据到PGA内存时,direct path read 出现.这种类型的读请求典型地作为:排序IO(为排序不能在内存中完成的时候),并行Slave查询或者预先读请求等. 通常这种等待与I/O能力或者I/O竞争有关. <15> free buffer inspected表示在将数据读入数据调整缓存区的时候等待进程找到足够大的内在空间通常这类等待表示数据调整缓存区偏小. <16> library cache load lock表示在将对象装载到库高速缓存时出现了等待.这种事件通常代表着发生了负荷尔蒙很重的语句重载或者装载,可能由于SQL语句没有共享或者共享池区域编小造成的. <17> log file parallel write表示等待LGWR向操作系统请求I/O开始直到完成IO.在触发LGWR写的情况下如3秒、1/3、1MB、DBWR写之前可能发生.这种事件发生通常表示日志文件发生了I/O竞争或者文件所在的驱动器较慢 <18> log file single write表示写日志文件头块时出现了等待.一般都是发生在检查点发生时. <19> transaction表示发生了一个阻塞回滚操作的等待 <20> undo segment extension表示在等待回滚段的动态扩展.这表示可能事务量过大,同时也意味着可能回滚段的寝大小不是最优,MINEXTENTS设置得偏小.考虑减少事务,或者使用最小区数更大的回滚段. 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/p/3200798.html,如需转载请自行联系原作者。
一、Oracle数据字典 数据字典是Oracle存放有关数据库信息的地方,其用途是用来描述数据的。比如一个表的创建者信息,创建时间信息,所属表空间信息,用户访问权限信息等。当用户在对数据库中的数据进行操作时遇到困难就可以访问数据字典来查看详细的信息。 Oracle中的数据字典有静态和动态之分。静态数据字典主要是在用户访问数据字典时不会发生改变的,但动态数据字典是依赖数据库运行的性能的,反映数据库运行的一些内在信息,所以在访问这类数据字典时往往不是一成不变的。以下分别就这两类数据字典来论述。1. 静态数据字典 这类数据字典主要是由表和视图组成,应该注意的是,数据字典中的表是不能直接被访问的,但是可以访问数据字典中的视图。静态数据字典中的视图分为三类,它们分别由三个前缀够成:user_*、 all_*、 dba_*。 user_* 该视图存储了关于当前用户所拥有的对象的信息。(即所有在该用户模式下的对象) all_* 该试图存储了当前用户能够访问的对象的信息。(与user_*相比,all_* 并不需要拥有该对象,只需要具有访问该对象的权限即可) dba_* 该视图存储了数据库中所有对象的信息。(前提是当前用户具有访问这些数据库的权限,一般来说必须具有管理员权限) 从上面的描述可以看出,三者之间存储的数据肯定会有重叠,其实它们除了访问范围的不同以外(因为权限不一样,所以访问对象的范围不一样),其他均具有一致性。具体来说,由于数据字典视图是由SYS(系统用户)所拥有的,所以在却省情况下,只有SYS和拥有DBA系统权限的用户可以看到所有的视图。没有DBA权限的用户只能看到user_*和all_*视。如果没有被授予相关的SELECT权限的话,他们是不能看到 dba_*视图的。 由于三者具有相似性,下面以user_为例介绍几个常用的静态视图: user_users视图 主要描述当前用户的信息,主要包括当前用户名、帐户id、帐户状态、表空间名、创建时间等。例如执行下列命令即可返回这些信息。 select * from user_users user_tables视图 主要描述当前用户拥有的所有表的信息,主要包括表名、表空间名、簇名等。通过此视图可以清楚了解当前用户可以操作的表有哪些。执行命令为:select * from user_tables user_objects视图 主要描述当前用户拥有的所有对象的信息,对象包括表、视图、存储过程、触发器、包、索引、序列等。该视图比user_tables视图更加全面。例如, 需要获取一个名为“package1”的对象类型和其状态的信息,可以执行下面命令: select object_type,status from user_objects where object_name=upper(‘package1’);注意:upper的使用,数据字典里的所有对象均为大写形式,而PL/SQL里不是大小写敏感的,所以在实际操作中一定要注意大小写匹配。 user_tab_privs视图 该视图主要是存储当前用户下对所有表的权限信息。比如,为了了解当前用户对table1的权限信息,可以执行如下命令: select * from user_tab_privs where table_name=upper('table1') 了解了当前用户对该表的权限之后就可以清楚的知道,哪些操作可以执行,哪些操作不能执行。 前面的视图均为user_开头的,其实all_开头的也完全是一样的,只是列出来的信息是当前用户可以访问的对象而不是当前用户拥有的对象。对于dba_开头的需要管理员权限,其他用法也完全一样,这里就不再赘述了。 2. 动态数据字典 Oracle包含了一些潜在的由系统管理员如SYS维护的表和视图,由于当数据库运行的时候它们会不断进行更新,所以称它们为动态数据字典(或者是动态性能视图)。这些视图提供了关于内存和磁盘的运行情况,所以我们只能对其进行只读访问而不能修改它们。 Oracle中这些动态性能视图都是以v$开头的视图,比如v$access。下面就几个主要的动态性能视图进行介绍。 v$access 该视图显示数据库中锁定的数据库对象以及访问这些对象的会话对象(session对象)。 运行如下命令: select * from v$access 结果如下:(因记录较多,故这里只是节选了部分记录) SID OWNER OBJECT TYPE 27 DKH V$ACCESS CURSOR 27 PUBLIC V$ACCESS SYNONYM 27 SYS DBMS_APPLICATION_INFO PACKAGE 27 SYS GV$ACCESS VIEW v$session 该视图列出当前会话的详细信息。由于该视图字段较多,这里就不列详细字段,为了解详细信息,可以直接在sql*plus命令行下键入:desc v$session即可。 v$active_instance 该视图主要描述当前数据库下的活动的实例的信息。依然可以使用select语句来观察该信息。 v$context 该视图列出当前会话的属性信息。比如命名空间、属性值等。 3.小结 以上是Oracle的数据字典方面的基本内容,还有很多有用视图因为篇幅原因这里不能一一讲解,希望大家在平时使用中多留心。总之,运用好数据字典技术,可以让数据库开发人员能够更好的了解数据库的全貌,这样对于数据库优化、管理等有极大的帮助。 二、Oracle 中常用数据字典 下面列出的这些数据字典,均在 Oracle 11g R1 上,通过 Oracle Sql Developer 进行过测试的,全部通过。其中很多的数据字典都必须以 system 或者是 sysdba 用户登录才能够使用的。 ---数据库实例的基本信息 desc v$instance; select * from v$instance; --数据文件的基本信息 desc v$datafile; select * from v$datafile; desc dba_data_files; select file_name,file_id,tablespace_name,bytes,blocks, status,online_status from dba_data_files; --临时文件的基本信息 desc dba_temp_files; select file_name,file_id,tablespace_name,status, bytes/1024/1024 大小MB from dba_temp_files; --控制文件的基本信息 desc v$controlfile; select name,status,is_recovery_dest_file, block_size,file_size_blks from v$controlfile; --日志文件的基本信息 desc v$logfile; select group#,status,type,member,is_recovery_dest_file from v$logfile; --数据库的基本信息 desc v$database; select * from v$database; select dbid,name,created,resetlogs_time,log_mode, open_mode,checkpoint_change#,archive_change#, controlfile_created,controlfile_type, controlfile_sequence#,controlfile_change#, controlfile_time,protection_mode,database_role from v$database; --日志文件参数信息 show parameter log_archive_dest; --访问参数文件 desc v$parameter; select num,name,type,value,display_value, isdefault,isses_modifiable, issys_modifiable,isinstance_modifiable from v$parameter; select * from v$parameter; select name,value,description from v$parameter; --后台进程信息 desc v$bgprocess; select paddr,pserial#,name,description,error from v$bgprocess; --DBA 用户的所有的表的基本信息 desc dba_tables; desc dba_tab_columns; select owner,table_name,column_name,data_type,data_length, global_stats,data_upgraded,histogram from dba_tab_columns; --DBA 用户的所有的视图的基本信息 desc dba_views; select owner,view_name,read_only from dba_views; --DBA 用户的所有的同义词的基本信息 desc dba_synonyms; select owner,synonym_name,table_owner, table_name,db_link from dba_synonyms; --DBA 用户的所有的序列的信息 desc dba_sequences; select sequence_owner,sequence_name,min_value,max_value, cycle_flag from dba_sequences; --DBA 用户的所有的约束的信息 desc dba_constraints; select owner,constraint_name,constraint_type, table_name,status from dba_constraints; --DBA 用户的所有的索引的基本信息 desc dba_indexes; select owner,index_name,index_type,table_owner,table_name, table_type,uniqueness,compression,logging,status from dba_indexes; --DBA 用户的所有的触发器的基本信息 desc dba_triggers; select owner,trigger_name,trigger_type, table_owner,table_name,column_name from dba_triggers; --DBA 用户的所有的存储过程的基本信息 desc dba_source; select owner,name,type,line,text from dba_source; --DBA 用户的所有的段的基本信息 desc dba_segments; select owner,segment_name,segment_type, tablespace_name,blocks,extents from dba_segments; --DBA 用户的所有的区的基本信息 desc dba_extents select owner,segment_name,segment_type, tablespace_name,extent_id,file_id,blocks from dba_extents; --DBA 用户的所有的对象的基本信息 desc dba_objects; select owner,object_name,subobject_name, object_id,data_object_id,object_type, created,status,namespace from dba_objects; --当前用户可以访问的所有的基表 desc cat; select table_name from cat; --当前用户可以访问的所有的基表,视图,同义词 desc system.tab; select tname,tabtype,clusterid from system.tab; --构成数据字典的所有的表信息 desc dict; select table_name,comments from dict; -- 查询关于表空间的一些基本的数据字典 desc dba_tablespaces; select tablespace_name,block_size,status, logging,extent_management from dba_tablespaces; desc dba_free_space; select tablespace_name,file_id,block_id, bytes/1024/1024 大小MB,blocks,relative_fno from dba_free_space; --归档状态的一些基本信息 desc v$archived_log; select name,dest_id,blocks,block_size, archived,status,backup_count from v$archived_log; --关于内存结构的一些信息 desc v$sga; select name,value/1024/1024 大小MB from v$sga; desc v$sgastat; select pool,name,bytes from v$sgastat; desc v$db_object_cache; select owner,name,db_link,type,namespace,locks from v$db_object_cache; desc v$sql; select sql_text,sql_id,cpu_time from v$sql; 上面的呢就是 Oracle 中较常使用的数据字典了,需要提一下的是,上面有很多都是以 “dba_”开头的数据字典,比如有 dba_tables ,其实呢,这个是列出了数据库中所有的数据,比如使用 dba_tables 就会列出数据库中所有的数据表(n 多),但是您可以使用 user_tables 或者 all_tables 来代替 dba_tables,当然有一些是没有与之对应的,这样呢,就只会列出当前登录用户允许查看的数据表了,对于以“dba_”基本上都是有与之相对应的“user_”和“all_”,其中“user_”对应的是记录当前登陆用户的对象,而“all_”则是记录当前登陆用户的对象信息以及被授权访问的对象信息,而“dba_”是包含数据库实例的所有对象信息!!! 原文链接: http://9host.cn/oracle/200742218394112481.html http://www.cnblogs.com/QinBaoBei/archive/2010/04/11/1709580.html 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/archive/2010/06/29/1767591.html,如需转载请自行联系原作者。
今天看MVC自代的例子时,C#中有两个奇怪的问号: public AccountController(IFormsAuthentication formsAuth, IMembershipService service) { FormsAuth = formsAuth ?? new FormsAuthenticationService(); MembershipService = service ?? new AccountMembershipService(); }网上搜下,总结如下: 1. 可空类型修饰符(?): 引用类型可以使用空引用表示一个不存在的值,而值类型通常不能表示为空。 例如:string str=null; 是正确的,int i=null; 编译器就会报错。 为了使值类型也可为空,就可以使用可空类型,即用可空类型修饰符"?"来表示,表现形式为"T?" 例如:int? 表示可空的整形,DateTime? 表示可为空的时间。 T? 其实是System.Nullable<T>(泛型结构)的缩写形式,也就意味着当你用到T?时编译器编译 时会把T?编译成System.Nullable<T>的形式。 例如:int?,编译后便是System.Nullable<int>的形式。 2. 三元(运算符)表达式(?:): 例如:x?y:z 表示如果表达式x为true,则返回y;如果x为false,则返回z,是省略if{}else{}的简单形式。 3. 空合并运算符(??): 用于定义可空类型和引用类型的默认值。如果此运算符的左操作数不为null,则此运算符将返回左操作数,否则返回右操作数。 例如:a??b 当a为null时则返回b,a不为null时则返回a本身。 空合并运算符为右结合运算符,即操作时从右向左进行组合的。如,“a??b??c”的形式按“a??(b??c)”计算。 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/archive/2010/08/03/1790979.html,如需转载请自行联系原作者。
由于工作需要,最近在学习Ruby,现在主要在看两本书《Ruby on Rail程序设计技术详解》和《Ruby of book》。毕竟是要在工作中运用,而且时间还有限,所以我在看书和做例子的同时也简单记录下了一些基本知识点,方便用的时候查找。有兴趣的朋友欢迎一起交流学习: l 数组 1. 创建数组: 和其它很多编程语言一样,很容易创建一个数组,但要注意的是Ruby是一种弱类型的脚本语言,数组中各元素的类型可以互不相同,而且数组的长度可变: arr = [“one”,”two”,”three”] OR arr = Array.new #an empty array arr = Array.new(5) #[nil, nil, nil, nil, nil] arr = Array.new(5,”hello”) #[”hello”, ”hello”, ”hello”, ”hello”, ”hello”] 当创建一个数组时,如果其元素为string类型且使用单引号,而你又不想老输入单引号,那么我们可以使用下面的方法来创建(使用%W来创建用双引号括起来的字符串): arr = %w( this is an array of strings) #使用空格作为元素的分隔符 2.通过索引存取数组的值: 在Ruby中,数组索引可以是正整数(从前到后,从0开始)也可以是负整数(从后到前,从-1开始)还可以是范围(Range): arr = ['h','e','l','l','o',' ','w','o','r','l','d'] print arr[0,5] puts print arr[0..4] puts print arr[0...4] puts print arr[-5,5] --------Results-------- hello hello hell world Note: arr[-5,5]:前一个整数-5表示开始的索引,后面一个整数5表示数量 3..复制数组: 当使用”=”将一个数组变量赋值给另一个数组变量时,这两个数组变量引用的仍然是同一个数组,修改其中一个数组的值,另一个也会修改。我们可以使用Clone方法复制一个新数组: arr = [‘one’,’two’,’three’,] arr1= arr #arr和arr1引用的还是同一个数组,修改一个另一个也会修改 arr2=arr.clone #arr2是arr的一个新版本,修改arr2不影响arr 4..比较数组大小: 当使用 <=> 来比较两个数组a1和a2时,有三种情况: 1. a1 小于 a2, 返回 -1 2. a1 等于 a2, 返回 0 3. a1 大于 a2, 返回 1 那么,数组是如何比大小的呢? 当两个数组进行比较时,会把两个数组相同索引(从0开始)上的值拿来比较,如 [0,10,20]<=> [0,20,20], 则会返回-1,因为当索引为1时,10<20; 另外,如果比较的两个数组的元素是字符串,那么就比较它们的ASCII;如果一个数组比另一个长且其它元素都相同,那么数组长的‘大’。 然而,如果一个短数组里面的一个元素比另一个长数组里面的同位置的元素大,则认为短数组‘大’。 arr1=[1,2,3,4,5] arr2=[1,2,3,4,5] arr3=[1,2,3,4] arr4=[1,2,3,5] arr5=[1000,2000,3000] arr6=[1,2] arr7=[2,1] arr8=["hello", "world"] arr9=["Hello", "World"] p(arr1<=>arr2) # 0 p(arr3<=>arr1) # -1 p(arr4<=>arr3) # 1 p(arr5<=>arr4) # 1 p(arr7<=>arr6) # 1 p(arr8<=>arr7) # nil p(arr9<=>arr8) # -1 5.数组排序: Sort方法使用比较操作符 <=> 来比较一个数组中邻近的元素的大小,但是这个不能比较一个数组中包含有nil的值的情况; arr.sort{|a,b| a.to_s <=> b.to_s} 说明: 在这arr是一个数组对象,a和b代表相邻的两个元素。本方法使用了to_s方法把nil转换为一个空字符串,这样就可以对含有nil的数组进行排序了。此外,这个数组本身的值不会发生任何变在。 6.添加和删除数组元素: 向数组添加元素: unshift:向数组头部添加数组元素 push: 向数组头部尾数组元素 << : 向数组尾部添加一个数组元素 向数组删除元素: shift: 从头部删除数组元素,并返回被删除的元素 pop: 从尾删除数组元素,并返回被删除的元素 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/archive/2011/10/20/2218690.html,如需转载请自行联系原作者。
Examples All examples are designed to work on the live Watir demo form: http://bit.ly/watir-example.Loading RubyGems If you’re a first time Ruby user, you need to understand how to load Ruby gems such as Watir. You can require it via the -rubygems command line option or by using the RUBYOPT environment variable. You can also require it manually in your script:require 'rubygems' For more information see here.Including Watir gem to drive Internet Explorer on Windowsrequire 'watir'Including Watir-WebDriver gem to drive Firefox/Chrome on Windows/Mac/Linuxrequire 'watir-webdriver'Starting a new browser & and going to our sitebrowser = Watir::Browser.new browser.goto 'http://bit.ly/watir-example'Setting a text fieldbrowser.text_field(:name => 'entry.0.single').set 'Watir'Setting a multi-line text boxbrowser.text_field(:name => 'entry.1.single').set "I come here from Australia. \n The weather is great here."Setting and clearing a radio buttonbrowser.radio(:value => 'Watir').set browser.radio(:value => 'Watir').clearSetting and clearing check boxesbrowser.checkbox(:value => 'Ruby').set browser.checkbox(:value => 'Python').set browser.checkbox(:value => 'Python').clearClicking a buttonbrowser.button(:name => 'logon').clickClearing, getting and selecting selection list valuesbrowser.select_list(:name => 'entry.6.single').clear puts browser.select_list(:name => 'entry.6.single').options browser.select_list(:name => 'entry.6.single').select 'Chrome' Clicking a buttonbrowser.button(:name => 'submit').clickChecking for text in a pageputs browser.text.include? 'Your response has been recorded.'Checking the title of a pageputs browser.title == 'Thanks!' more info: http://watir.com/examples/ 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/archive/2012/03/06/2381346.html,如需转载请自行联系原作者。
xpath的语法 XPath 是XML的查询语言,和SQL的角色很类似。以下面XML为例,介绍XPath 的语法。 xpath 教程链接:http://www.w3school.com.cn/xpath/ <?xml version="1.0" encoding="ISO-8859-1"?> <catalog> <cd country="USA"> <title>Empire Burlesque</title> <artist>Bob Dylan</artist> <price>10.90</price> </cd> <cd country="UK"> <title>Hide your heart</title> <artist>Bonnie Tyler</artist> <price>9.90</price> </cd> <cd country="USA"> <title>Greatest Hits</title> <artist>Dolly Parton</artist> <price>9.90</price> </cd> </catalog> 定位节点 XML是树状结构,类似档案系统内数据夹的结构,XPath也类似档案系统的路径命名方式。不过XPath 是一种模式(Pattern),可以选出 XML档案中,路径符合某个模式的所有节点出来。例如要选catalog底下的cd中所有price元素可以用: /catalog/cd/price 如果XPath的开头是一个斜线(/)代表这是绝对路径。如果开头是两个斜线(//)表示文件中所有符合模式的元素都会被选出来,即使是处于树中不同的层级也会被选出来,即相对路径。以下的语法会选出文件中所有叫做cd的元素(在树中的任何层级都会被选出来): //cd 选择未知的元素 使用星号(Wildcards,*)可以选择未知的元素。下面这个语法会选出/catalog/cd 的所有子元素: /catalog/cd/* 以下的语法会选出所有catalog的子元素中,包含有price作为子元素的元素。 /catalog/*/price 以下的语法会选出有两层父节点,叫做price的所有元素。 /*/*/price 以下的语法会选择出文件中的所有元素。 //* 要注意的是,想要存取不分层级的元素,XPath语法必须以两个斜线开头(//),想要存取未知元素才用星号(*),星号只能代表未知名称的元素,不能代表未知层级的元素。 选择分支 使用中括号可以选择分支。以下的语法从catalog的子元素中取出第一个叫做cd的元素。XPath的定义中没有第0元素这种东西。 /catalog/cd[1] 以下语法选择catalog中的最后一个cd元素:(XPathj并没有定义 first() 这种函式喔,用上例的 [1]就可以取出第一个元素。 /catalog/cd[last()] 以下语法选出含有price子元素的所有/catalog/cd元素。 /catalog/cd[price] 以下语法选出price元素的值等于10.90的所有/catalog/cd元素 /catalog/cd[price=10.90] 以下语法选出price元素的值等于10.90的所有/catalog/cd元素 的price元素 /catalog/cd[price=10.90]/price 选择一个以上的路径 使用Or操作数(|)就可以选择一个以上的路径。例如: /catalog/cd/title | catalog/cd/artist 选择所有title以及artist元素 //title | //artist 选择所有title以及artist以及price元素 //title | //artist | //price 选择属性 在XPath中,除了选择元素以外,也可以选择属性。属性都是以@开头。例如选择文件中所有叫做country的属性。 //@country 选择所有含有country这个属性的cd元素: //cd[@country] 以下语法选择出含有属性的所有cd元素 //cd[@*] 以下语法选择出country属性值为UK的cd元 //cd[@country='UK'] 选择多个属性 //cd[@country='UK'][@name='hyddd'] 转载自:http://www.cnblogs.com/jianjialin/archive/2009/02/01/1382056.html 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/archive/2012/08/22/2651595.html,如需转载请自行联系原作者。
本文主要记录下在使用selenium2/webdriver时启动各种浏览器的方法、以及如何加载插件、定制浏览器信息(设置profile)等 环境搭建可参考我的另一篇文章:http://www.cnblogs.com/puresoul/p/3483055.html 一、Driver下载地址: http://docs.seleniumhq.org/download/ 二、启动firefox浏览器(不需要下载驱动,原生支持) 1、firefox安装在默认路径下: 1 //启动默认安装路径下的ff 2 public void StartFireFoxByDefault(){ 3 System.out.println("start firefox browser..."); 4 WebDriver driver = new FirefoxDriver(); //直接new一个FirefoxDriver即可 5 Navigation navigation = driver.navigate(); 6 navigation.to("http://www.baidu.com/"); 7 System.out.println("start firefox browser succeed..."); 8 } 2、firefox未安装在默认路径下: 1 public static void StartFireFoxNotByDefault(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.firefox.bin", //指定firefox的安装路径 4 "D:/Program Files/Mozilla Firefox/firefox.exe"); 5 WebDriver driver = new FirefoxDriver(); 6 Navigation navigation = driver.navigate(); 7 navigation.to("http://www.baidu.com/"); 8 System.out.println("start firefox browser succeed..."); 9 } 3、启动firefox时加载插件: 首先,要知道我们为什么需要加载插件?原因是webdriver在启动浏览器时,启动的一个干净的没有任务、插件及cookies信息的浏览器(即使你本机的firefox安装了某些插件,webdriver启动firefox也是没有这些插件的),但是有可能被测系统本身需要插件或者需要调试等等,此时可以用如下方法在启动firefox时加载插件,下面示例加载firebug插件: 1 public static void StartFireFoxLoadPlugin(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.firefox.bin", 4 "D:/Program Files/Mozilla Firefox/firefox.exe"); 5 File file = new File("files/firebug-2.0.7-fx.xpi"); 6 FirefoxProfile profile = new FirefoxProfile(); 7 try { 8 profile.addExtension(file); 9 } catch (IOException e) { 10 e.printStackTrace(); 11 } 12 profile.setPreference("extensions.firebug.currentVersion", "2.0.7"); 13 //active firebug extensions 14 profile.setPreference("extensions.firebug.allPagesActivation", "on"); 15 WebDriver driver = new FirefoxDriver(profile); 16 driver.get("http://www.baidu.com"); 17 System.out.println("start firefox browser succeed..."); 18 } 4、启动firefox时设置profile: 上面提到过webdriver启动firefox时是启动一个完全新的浏览器,我们除了可以使用上面提到的方法定制插件,webdriver还可以对profile进行定制(在firefox地址栏中输入about:config,可以查看firefox的参数),下面设置代理和默认下载路径: 1 public static void StartFireFoxByProxy(){ 2 String proxyIp = "10.17.171.11"; 3 int proxyPort = 8080; 4 System.out.println("start firefox browser..."); 5 System.setProperty("webdriver.firefox.bin", 6 "D:/Program Files/Mozilla Firefox/firefox.exe"); 7 8 FirefoxProfile profile = new FirefoxProfile(); 9 //设置代理参数 10 profile.setPreference("network.proxy.type", 1); 11 profile.setPreference("network.proxy.http", proxyIp); 12 profile.setPreference("network.proxy.http_port", proxyPort); 13 14 //设置默认下载路径 15 profile.setPreference("browser.download.folderList", 2); 16 profile.setPreference("browser.download.dir", "D:\\"); 17 18 WebDriver driver = new FirefoxDriver(profile); 19 driver.get("http://www.baidu.com"); 20 21 System.out.println("start firefox browser succeed..."); 22 } 5、启动本机器的firefox配置: 每次启动如果都像上面那样在代码里面配置profile比较麻烦,可以使用下面的方法启动本机器的firefox的配置,换句话说就是我们可以事先配置本机的firefox然后用webdriver启动它,这样本机上的firefox安装了什么插件都可以直接使用了,不需要在配置profile: 1 public static void StartLocalFirefox(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.firefox.bin", 4 "D:/Program Files/Mozilla Firefox/firefox.exe"); 5 ProfilesIni pi = new ProfilesIni(); 6 FirefoxProfile profile = pi.getProfile("default"); 7 WebDriver driver = new FirefoxDriver(profile); 8 driver.get("http://www.baidu.com/"); 9 System.out.println("start firefox browser succeed..."); 10 } 6、如果在机器B上要启动机器A上的firefox配置,可以先导出A的配置,然后加载: 1、将A机器上的Profiles文件夹”C:\Users\cloudchen\AppData\Local\Mozilla\Firefox\Profiles”给拷贝出来到某个目录 2、代码: 1 public static void StartFireFoxByOtherConfig(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.firefox.bin", 4 "D:/Program Files/Mozilla Firefox/firefox.exe"); 5 File file = new File("files\\lg6mie1i.default"); //profiles文件目录,这里我是放在工程目录下的files文件夹下 6 FirefoxProfile profile = new FirefoxProfile(file); 7 WebDriver driver = new FirefoxDriver(profile); 8 driver.get("http://www.baidu.com"); 9 System.out.println("start firefox browser succeed..."); 10 } PS:如果插件或其它东东未加载成功,可以检查下profile文件夹下是否包含插件信息。 三、启动chrome浏览器 1、启动chrome需要chromedriver的驱动: 1 public static void StartChrome(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.chrome.driver", "files\\chromedriver.exe"); //指定驱动路径 4 WebDriver driver = new ChromeDriver(); 5 driver.get("http://www.baidu.com/"); 6 System.out.println("start firefox browser succeed..."); 7 } 另,如果不想用setProperty的方式,可以将chromedriver.exe 放在”C:\Windows\System32”路径下或者path可以找到的路径下并重启电脑即可。 2、加载插件: 1 public static void StartChromeLoadPlugin(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.chrome.driver", "files\\chromedriver.exe"); 4 File file = new File ("files\\youtube.crx"); 5 ChromeOptions options = new ChromeOptions(); 6 options.addExtensions(file); 7 WebDriver driver = new ChromeDriver(options); 8 driver.get("http://www.baidu.com/"); 9 System.out.println("start firefox browser succeed..."); 10 } 3、设置profile: 未完待续 ... 四、启动IE浏览器 1、IE启动和chrome类似也需要下载相应的驱动: 1 public static void StartIE(){ 2 System.out.println("start firefox browser..."); 3 System.setProperty("webdriver.ie.driver", "files\\IEDriverServer.exe"); 4 WebDriver driver = new InternetExplorerDriver(); 5 driver.get("http://www.baidu.com/"); 6 System.out.println("start firefox browser succeed..."); 7 } 2、IE下没有插件加载 3、IE的放大比例为要设置100% 4、启动IE时,需关闭如下图中4个区域的保护模式: 5、对于第4点提到的关闭保护模式,还可以使用代码关闭: 1 //启动IE浏览器并关闭保护模式 2 public static void StartIEAndCloseProtectedMode(){ 3 System.out.println("start firefox browser..."); 4 System.setProperty("webdriver.ie.driver", "files\\IEDriverServer.exe"); 5 DesiredCapabilities dc = DesiredCapabilities.internetExplorer(); 6 dc.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); 7 8 //IE默认启动保护模式,要么手动在浏览器的设置中关闭保护模式,要么在代码中加上这一句,即可 9 dc.setCapability("ignoreProtectedModeSettings", true); 10 WebDriver driver = new InternetExplorerDriver(dc); 11 driver.get("http://www.baidu.com/"); 12 System.out.println("start firefox browser succeed..."); 13 } 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/p/4251536.html,如需转载请自行联系原作者。
一、Debug Sampler介绍: 使用Jmeter开发脚本时,难免需要调试,这时可以使用Jmeter的Debug Sampler,它有三个选项:JMeter properties,JMeter variables,System properties: 1、JMeter properties和System properties:通常都选false,这两个就是JMeter和系统的属性,在Jmeter的bin的jmeter.properties中定义,一般都不会变。 2、JMeter variables:这个是我们自已定义的变量,定义的方式有如下这些: a) 选中测试计划(Test plan),在右边的面板上添加User Defined Variables b) 选中线程组,右键选择 配置元件( config element)-->User Defined Variables c) 通过后置处理器生成的变量,可参考我的另一篇:Jmeter关联 d)使用csv参数化的变量,参数化可参考我另一篇:Jmeter参数化 二、综合示例:为了涵盖上面的四种情况,特意编写如下脚本: 1、在Test plan右侧面板添加变量:name=test,value=111 2、在sampler one(访问百度首页)下添加一个用户变量:name=hello,value=222 3、在sampler one 下使用后置处理器(正则表达式处理器),获取百度首页title的信息 4、参数化,变量名为username,值为:tom 5、运行结果: 三、总结: 1、Debug Sampler会把我们自定义的变量输出在response data中,方便我们调试的时候使用 2、在正式执行脚本时需要删除Debug Sample PS:Jmeter另一种调试工具:HTTP Mirror Server 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/p/4817832.html,如需转载请自行联系原作者。
测试计划与测试方案的关系对比: 测试计划 测试方案 目标 对测试全过程的组织、资源、原则等进行规定和 约束,并制订测试全过程各个阶段的任务以及时 间进度安排,提出对各项任务的评估、风险分析 和需求管理 描述需要测试的特性、测试的方法、测试环境的 规划、测试工具的设计和选择、测试用例的设计 方法、测试代码的设计方案。 关注点 组织管理层面的文件,从组织管理的角度对一次 测试活动进行规划 技术层面的文档,从技术的角度度一次测试活动 进行规划 具体内容 1、明确测试组织的组织形式: 1) 测试组织和其他部门关系,责任划分; 2) 测试组织内的机构和责任安排。 2、明确测试的测试对象(明确测试项,用于后 面划分任务,估计工作量等) 3、完成测试的需求跟踪 4、明确测试中需要遵守的原则: 1) 测试通过/失败标准; 2)测试挂起和回复的必要条件. 5、明确测试工作任务分配是测试计划的核心: 1)进行测试任务划分; 2)进行测试工作量估计; 3)人员资源和物资源分配; 4)明确任务的时间和进度安排; 5)风险的估计和规避措施; 6)明确测试结束后应交付的测试工作产品。 1、明确策略 2、细化测试特性(形成测试子项) 3、测试用例的规划 4、测试环境的规划 5、自动化测试框架的设计 6、测试工具的设计和选择 关系 测试方案需要在测试计划的指导下进行,测试计划提出“做啥”,而测试方案明确“咋做” 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/p/3359473.html,如需转载请自行联系原作者。
上一篇Jmeter之Bean shell使用(一)简单介绍了下Jmeter中的Bean shell,本文是对上文的一个补充,主要总结下常用的几种场景和方法,相信这些基本可以涵盖大部分的需求。本节内容如下: 一、操作变量 二、操作属性 三、自定义函数 四、引用外部java文件 五、引用外部class文件 六、引用外部Jar包 七、其它用法(接受参数, log等) 一、操作变量:通过使用Bean shell内置对象vars可以对变量进行存取操作 a) vars.get("name"):从jmeter中获得变量值 b) vars.put("key","value"):数据存到jmeter变量中 二、操作属性:通过使用Bean shell内置对象props 可以对属性进行存取操作 a) props.get("START.HMS"); 注:START.HMS为属性名,在文件jmeter.properties中定义 b) props.put("PROP1","1234"); 三、自定义函数: 在BeanShell中,我们可以使用java语言自定义函数来处理特定的逻辑,结合BeanShell的内置对象进行变量的存取,方便我们进行测试提高脚本的灵活性。 示例: 1、在Test Plan中添加一个变量:hello = kitty 2、Debug sampler-1和Debug sampler-2什么都不处理,用来查询对比beahshell处理前后的结果 3、BeanShell Sampler中的脚本如下: 4、运行结果: Debug sampler-1中显示:hello=kitty BeanShell sampler中 返回结果为:success Debug sampler-1中显示:hello=world,jmeter=111111 四、引用外部java文件: 有没有觉得上面(三)中自定义函数这样的方式太麻烦并且也不美观?而且如果我们已经有现成的java源文件或者class文件时,我们有没有什么办法直接在jemter中引用?这就是这部分要介绍的内容,直接上示例: 1、假如我有一个java 源文件,名为:Myclass.java,代码如下: package test; public class Myclass { public int add(int a, int b) { return a + b; } } 2、Bean Shell使用代码如下: 在bean shel中通过source("代码路径")方法引入java,然后调用方法和java一样,new一个class,再调用里面的add 方法。 3、运行结果: 五、引用外部class文件: 现在知道如何引用外部文件,有时候如果我们只有class文件怎么办呢?其实在jmeter中也可以直接引用class文件,示例如下: 1、直接把上例中的java文件编译成class文件,如何编译请自行百度。 2、Bean Shell使用代码如下: 用addClassPath("D:\\")方法引入 class文件,在用import导入包及类,然后就可以像java一样调用了 3、运行结果: 六、引用外部Jar包: 上面四、五介绍了如何引用外部java和class文件,如果文件比较多时我们可以把它们打成一个jar包然后在jemter中调用,具体如何使用可以看我上一篇有介绍:Jmeter之Bean shell使用(一)。 在这里想补充一点的是jmeter中引入jar的方法: 1、上一篇中已使用过的:把jar包放到jmeter目录\apache-jmeter-2.13\lib\ext下 2、在Test Plan的右侧面板最下方直接添加需要引用的jar包,如下图: 七、其它用法: 1、在Test Plan中定义如下三个变量: 2、Bean Shell可脚本如下: a、bean shell可以接受传入参数,如下图:${u1} ${u2} ${u3} b、参数可以通过bsh.args[]按顺序提取 c、bean shell提供了一个内置变量Parameters,来保存参数的集合 3、运行结果: 下图中1输入的这两句设置: ResponseCode = 500; ResponseMessage = "This is a test"; 下图中2输入的这两句设置: log.info(Parameters); log.info(Label); 官网: http://jmeter.apache.org/usermanual/component_reference.html#BeanShell_Sampler 本文转自贺满博客园博客,原文链接:http://www.cnblogs.com/puresoul/p/4949889.html,如需转载请自行联系原作者。
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操作。 RSA是被研究得最广泛的公钥算法,从提出到现在已近二十年,经历了各种攻击的考验,逐渐为人们接受,普遍认为是目前最优秀的公钥方案之一。RSA的安全性依赖于大数的因子分解,但并没有从理论上证明破译RSA的难度与大数分解难度等价。 RSA的安全性依赖于大数分解。公钥和私钥都是两个大素数( 大于 100个十进制位)的函数。据猜测,从一个密钥和密文推断出明文的难度等同于分解两个大素数的积。 密钥对的产生。选择两个大素数,p 和q 。计算: n = p * q 然后随机选择加密密钥e(PS:最常用的e值有3,17和65537,微软就是使用的65537,采用3个中的任何一个都不存在安全问题),要求 e 和 ( p - 1 ) * ( q - 1 ) 互质。最后,利用Euclid 算法计算解密密钥d, 满足 e * d = 1 ( mod ( p - 1 ) * ( q - 1 ) ) 其中n和d也要互质。数e和n是公钥,d是私钥。两个素数p和q不再需要,应该丢弃,不要让任何人知道。 加密信息 m(二进制表示)时,首先把m分成等长数据块 m1 ,m2,..., mi ,块长s,其中 2^s <= n, s 尽可能的大。对应的密文是: ci = mi^e ( mod n ) ( a ) 解密时作如下计算: mi = ci^d ( mod n ) ( b ) .NET提供常用的加密算法类,支持RSA的类是RSACryptoServiceProvider(命名空间:System.Security.Cryptography),但只支持公钥加密,私钥解密。RSACryptoServiceProvider类包括:Modulus、Exponent、P、Q、DP、DQ、InverseQ、D等8个属性,其中Modulus和Exponent就是公钥,Modulus和D就是私钥,RSACryptoServiceProvider类提供导出公钥的方法,也提供导出私钥的方法,但导出的私钥包含上面8个属性,显然要用RSACryptoServiceProvider实现私钥加密公钥是不可行的。 从RSA的原理来看,公钥加密私钥解密和私钥加密公钥解密应该是等价的,在某些情况下,比如共享软件加密,我们需要用私钥加密注册码或注册文件,发给用户,用户用公钥解密注册码或注册文件进行合法性验证。 本人利用网上找的一个C#版的大整数类BigInteger(本人认为这是偶发现的效率最高的一个C#版大整数类)来实现私钥加密公钥加密(事实上也完全支持公租加密私钥解密),但没有使用类BigInteger的大素数生成函数,而是直接使用类RSACryptoServiceProvider来生成大素数。其中加密函数和解密函数的实现如下: /* 功能:用指定的私钥(n,d)加密指定字符串source */ private string EncryptString(string source, BigInteger d, BigInteger n) { int len = source.Length; int len1 = 0; int blockLen = 0; if ((len % 128) == 0) len1 = len / 128; else len1 = len / 128 + 1; string block = ""; string temp = ""; for (int i = 0; i < len1; i++) { if (len >= 128) blockLen = 128; else blockLen = len; block = source.Substring(i * 128, blockLen); byte[] oText = System.Text.Encoding.Default.GetBytes(block); BigInteger biText = new BigInteger(oText); BigInteger biEnText = biText.modPow(d, n); string temp1 = biEnText.ToHexString(); temp += temp1; len -= blockLen; } return temp; } /* 功能:用指定的公钥(n,e)解密指定字符串source */ private string DecryptString(string source, BigInteger e, BigInteger n) { int len = source.Length; int len1 = 0; int blockLen = 0; if ((len % 256) == 0) len1 = len / 256; else len1 = len / 256 + 1; string block = ""; string temp = ""; for (int i = 0; i < len1; i++) { if (len >= 256) blockLen = 256; else blockLen = len; block = source.Substring(i * 256, blockLen); BigInteger biText = new BigInteger(block, 16); BigInteger biEnText = biText.modPow(e, n); string temp1 = System.Text.Encoding.Default.GetString(biEnText.getBytes()); temp += temp1; len -= blockLen; } return temp; } 加密过程和解密过程代码如下所示: /* 加密过程,其中d、n是RSACryptoServiceProvider生成的D、Modulus */ private string EncryptProcess(string source, string d, string n) { byte[] N = Convert.FromBase64String(n); byte[] D = Convert.FromBase64String(d); BigInteger biN = new BigInteger(N); BigInteger biD = new BigInteger(D); return EncryptString(source, biD, biN); } /* 解密过程,其中e、n是RSACryptoServiceProvider生成的Exponent、Modulus */ private string DecryptProcess(string source, string e, string n) { byte[] N = Convert.FromBase64String(n); byte[] E = Convert.FromBase64String(e); BigInteger biN = new BigInteger(N); BigInteger biE = new BigInteger(E); return DecryptString(source, biE, biN); } 本文转自hyddd博客园博客,原文链接:http://www.cnblogs.com/hyddd/archive/2009/05/18/1459060.html,如需转载请自行联系原作者。
测试浏览器:IE 8,Firefox 由顶级域xxx.com写二级域www.xxx.com的cookie 均可以。 由二级域www.xxx.com写顶级域xxx.com的cookie 均可以。 由二级域www.xxx.com写入二级域yyy.xxx.com的cookie 均不可。 本文转自Kai的世界,道法自然博客园博客,原文链接:http://www.cnblogs.com/kaima/archive/2011/03/24/1863325.html,如需转载请自行联系原作者。
讨论原因之一: *************************** 我写的简单存储过程如下: create or replace procedure p_c(v_date in varchar2(200)) is t_count number; begin select count(*) into t_count from emp; end; 执行就包了这个错误: ”PLS-00103: 出现符号 "("在需要下列之一时: := . ) ,@% default character 符号 “:=“被替换为"("后继续。 我郁闷死了,最后找了一些资料说:存储过程定义的时候不需要指定VARCHAR2的长度!,我把v_date in varchar2(200) 改为:varchar2 就ok了。 ***************************** 原因之二: 本文转自hcy's workbench博客园博客,原文链接:http://www.cnblogs.com/alterhu/archive/2012/04/06/2434143.html,如需转载请自行联系原作者。
4,接下来主要是我们进行配置虚拟机的中的IP地址: 打开虚拟机中的“网上邻居”的属性页,如下图配置: ,如上配置完我们的虚拟机中的IP地址后,进行虚拟机和主机的ping操作检查; 5,ping我们的主机检查主机与虚拟机的通信是否正常,注意这一步操作的时候需要检查我们的虚拟机中的防火墙是否关闭,如下: @1,ping我们的虚拟机中已经设置的IP地址:(命令为:ping 192.168.128.100)(如下图所示) 如果出现以上正确的信息,表明你的windows已经可以与虚拟机正常的通信。 @2,ping我们的windows主机,在虚拟机中如下ping即可检查状态是否正常,如下: 前提:检查你的windows主机的防火墙是否关闭,如果没有关闭,那么虚拟机ping你的windows主机(命令为:ping 192.168.128.1)是ping不通的!!! 一般以上操作成功后,你的windows就已经可以与虚拟机正常的网络通信了。以上就是所有的操作步骤。 操作完以后,你就可以利用同一个网络进行一些操作了。 例如,与windows主机共享上网;与windows主机共享文件打印机等;与windows互联访问网站等等; 本文转自hcy's workbench博客园博客,原文链接:http://www.cnblogs.com/alterhu/archive/2011/11/08/2240973.html,如需转载请自行联系原作者。
1,windows 7安装中出现了一些意外的问题,最主要的要归结到windows 7设置的权限问题,(无法录制),具体的操作权限的方式,见下图所示; 2,测试中得到的预期结果和实际结果打印的时候是相同的,可是在采用if比对的时候始终都是不相同的,可能的情况就是预期的字符串没有前后的空格,而对于实际的获取到的结果可能有空格,采用trim(str)方法进行转化即可; 3,QTP测试的框架为如下: 可测试的内容,增删改查,这个比较的设计容易,QTP的核心是数据表,所有一定要学习好datatable对象,还有掌握住webtable对象的一些获取方法,因为如果是增删改查是离不开数据表的,所有掌握它是意义重大的。 采用的思路:将测试的数据采用datatable对象进行导入测试,然后对于预期值的获取方式是: 3.1,如果是像报表这样的查询操作,可以设置一个action将所有的预期值先获取到,然后存到excel,xml等; 3.2,对于实际的测试值,可以通过getROProperty方式,也可以通过数据表webtable中的getCellData(ROW,COLUMN)的方式进行获取; 4,比对以上的预期值和实际值,采用if else进行判断,一个完整的测试用例执行通过; 5,备注:以上的预期值最好存在excel中; 6,后续还有,以后再写。睡会觉。。。。。 本文转自hcy's workbench博客园博客,原文链接:http://www.cnblogs.com/alterhu/archive/2011/12/29/2305924.html,如需转载请自行联系原作者。
用途一: 定义一种类型的别名,而不只是简单的宏替换。可以用作同时声明指针型的多个对象。比如: char* pa, pb; // 这多数不符合我们的意图,它只声明了一个指向字符变量的指针, // 和一个字符变量; 以下则可行: typedef char* PCHAR; // 一般用大写 PCHAR pa, pb; // 可行,同时声明了两个指向字符变量的指针 虽然: char *pa, *pb; 也可行,但相对来说没有用typedef的形式直观,尤其在需要大量指针的地方,typedef的方式更省事。 用途二: 用在旧的C代码中(具体多旧没有查),帮助struct。以前的代码中,声明struct新对象时,必须要带上struct,即形式为: struct 结构名 对象名,如: struct tagPOINT1 { int x; int y; }; struct tagPOINT1 p1; 而在C++中,则可以直接写:结构名 对象名,即: tagPOINT1 p1; 估计某人觉得经常多写一个struct太麻烦了,于是就发明了: typedef struct tagPOINT { int x; int y; }POINT; POINT p1; // 这样就比原来的方式少写了一个struct,比较省事,尤其在大量使用的时候 或许,在C++中,typedef的这种用途二不是很大,但是理解了它,对掌握以前的旧代码还是有帮助的,毕竟我们在项目中有可能会遇到较早些年代遗留下来的代码。 用途三: 用typedef来定义与平台无关的类型。 比如定义一个叫 REAL 的浮点类型,在目标平台一上,让它表示最高精度的类型为: typedef long double REAL; 在不支持 long double 的平台二上,改为: typedef double REAL; 在连 double 都不支持的平台三上,改为: typedef float REAL; 也就是说,当跨平台时,只要改下 typedef 本身就行,不用对其他源码做任何修改。 标准库就广泛使用了这个技巧,比如size_t。 另外,因为typedef是定义了一种类型的新别名,不是简单的字符串替换,所以它比宏来得稳健(虽然用宏有时也可以完成以上的用途)。 用途四: 为复杂的声明定义一个新的简单的别名。方法是:在原来的声明里逐步用别名替换一部分复杂声明,如此循环,把带变量名的部分留到最后替换,得到的就是原声明的最简化版。举例: 1. 原声明:int *(*a[5])(int, char*); 变量名为a,直接用一个新别名pFun替换a就可以了: typedef int *(*pFun)(int, char*); 原声明的最简化版: pFun a[5]; 2. 原声明:void (*b[10]) (void (*)()); 变量名为b,先替换右边部分括号里的,pFunParam为别名一: typedef void (*pFunParam)(); 再替换左边的变量b,pFunx为别名二: typedef void (*pFunx)(pFunParam); 原声明的最简化版: pFunx b[10]; 3. 原声明:doube(*)() (*e)[9]; 变量名为e,先替换左边部分,pFuny为别名一: typedef double(*pFuny)(); 再替换右边的变量e,pFunParamy为别名二 typedef pFuny (*pFunParamy)[9]; 原声明的最简化版: pFunParamy e; 理解复杂声明可用的“右左法则”:从变量名看起,先往右,再往左,碰到一个圆括号就调转阅读的方向;括号内分析完就跳出括号,还是按先右后左的顺序,如此循环,直到整个声明分析完。举例: int (*func)(int *p); 首先找到变量名func,外面有一对圆括号,而且左边是一个*号,这说明func是一个指针;然后跳出这个圆括号,先看右边,又遇到圆括号,这说明(*func)是一个函数,所以func是一个指向这类函数的指针,即函数指针,这类函数具有int*类型的形参,返回值类型是int。 int (*func[5])(int *); func右边是一个[]运算符,说明func是具有5个元素的数组;func的左边有一个*,说明func的元素是指针(注意这里的*不是修饰func,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合)。跳出这个括号,看右边,又遇到圆括号,说明func数组的元素是函数类型的指针,它指向的函数具有int*类型的形参,返回值类型为int。 也可以记住2个模式: type (*)(....)函数指针 type (*)[]数组指针 --------------------------------- 陷阱一: 记住,typedef是定义了一种类型的新别名,不同于宏,它不是简单的字符串替换。比如: 先定义: typedef char* PSTR; 然后: int mystrcmp(const PSTR, const PSTR); const PSTR实际上相当于const char*吗?不是的,它实际上相当于char* const。 原因在于const给予了整个指针本身以常量性,也就是形成了常量指针char* const。 简单来说,记住当const和typedef一起出现时,typedef不会是简单的字符串替换就行。 陷阱二: typedef在语法上是一个存储类的关键字(如auto、extern、mutable、static、register等一样),虽然它并不真正影响对象的存储特性,如: typedef static int INT2; //不可行 编译将失败,会提示“指定了一个以上的存储类”。 ------------------------- typedef和#define的用法与区别 一、typedef的用法 在C/C++语言中,typedef常用来定义一个标识符及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间,实例像: typedef int INT; typedef int ARRAY[10]; typedef (int*) pINT; typedef可以增强程序的可读性,以及标识符的灵活性,但它也有“非直观性”等缺点。 二、#define的用法 #define为一宏定义语句,通常用它来定义常量(包括无参量与带参量),以及用来实现那些“表面似和善、背后一长串”的宏,它本身并不在编 译过程中进行,而是在这之前(预处理过程)就已经完成了,但也因此难以发现潜在的错误及其它代码维护问题,它的实例像: #define INT int #define TRUE 1 #define Add(a,b) ((a)+(b)); #define Loop_10 for (int i=0; i<10; i++) 在Scott Meyer的Effective C++一书的条款1中有关于#define语句弊端的分析,以及好的替代方法,大家可参看。 三、typedef与#define的区别 从以上的概念便也能基本清楚,typedef只是为了增加可读性而为标识符另起的新名称(仅仅只是个别名),而#define原本在C中是为了定义常量 ,到了C++,const、enum、inline的出现使它也渐渐成为了起别名的工具。有时很容易搞不清楚与typedef两者到底该用哪个好,如#define INT int这样的语句,用typedef一样可以完成,用哪个好呢?我主张用typedef,因为在早期的许多C编译器中这条语句是非法的,只是现今的 编译器又做了扩充。为了尽可能地兼容,一般都遵循#define定义“可读”的常量以及一些宏语句的任务,而typedef则常用来定义关键字、冗 长的类型的别名。 宏定义只是简单的字符串代换(原地扩展),而typedef则不是原地扩展,它的新名字具有一定的封装性,以致于新命名的标识符具有更易定义变 量的功能。请看上面第一大点代码的第三行: typedef (int*) pINT; 以及下面这行: #define pINT2 int* 效果相同?实则不同!实践中见差别:pINT a,b;的效果同int *a; int *b;表示定义了两个整型指针变量。而pINT2 a,b;的效果同int *a, b; 表示定义了一个整型指针变量a和整型变量b。 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/archive/2010/04/08/1707511.html,如需转载请自行联系原作者。
列出所有 table¶ hbase(main):> list 新增 table¶ A . 直接增加一個表 t2 hbase(main):> create 't2' B . 增加一個擁有 'f1','f2','fn' 為 column family 的表: t1 hbase(main):> create 't1','f1','f2','fn' 查詢 Table 欄位¶ hbase(main):> describe 't1' 執行結果參考 hbase(main):> describe 't1' DESCRIPTION ENABLED {NAME => 't1', FAMILIES => [{NAME => 'f1', COMPRESSION => 'NONE', VERS true IONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => ' false', BLOCKCACHE => 'true'}, {NAME => 'f2', COMPRESSION => 'NONE', V ERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY = > 'false', BLOCKCACHE => 'true'}, {NAME => 'fn', COMPRESSION => 'NONE' , VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMOR Y => 'false', BLOCKCACHE => 'true'}]} 加入cell-value¶ 需先擁有表 t1 與column-family : f1 並且加入一個 column-quantifier c1 hbase(main):> put 't1', 'r1', 'f1', 'v1' hbase(main):> put 't1', 'r1', 'f1:c1', 'v2' hbase(main):> put 't1', 'r2', 'f2', 'v3' hbase(main):> put 't1', 'r2', 'f2:c2', 'v4' Table: 't1' row-key 'f1' 'f2' 'fn' column-family * 'c1' * 'c2' * column-quantifier r1 v1 v2 r2 v3 v4 列出cell-value¶ A . 列出一列(row) hbase(main):> get 't1', 'r1' 執行結果參考 COLUMN CELL f1: timestamp=1285737082689, value=v1 f1:c1 timestamp=1285737085874, value=v2 Table: 't1' row-key 'f1' 'f2' 'fn' column-family * 'c1' * 'c2' * column-quantifier r1 v1 v2 r2 v3 v4 B . 列出一個 cell 的值 hbase(main):> get 't1', 'r1', {COLUMN => 'f1:c1'} 執行結果參考 COLUMN CELL f1:c1 timestamp=1285737085874, value=v2 Table: 't1' row-key 'f1' 'f2' 'fn' column-family * 'c1' * 'c2' * column-quantifier r1 v1 v2 r2 v3 v4 刪除 cell-value¶ hbase(main):> deleteall 't1','r1' 執行結果:會把 row-key 是 'r1' 的所有紀錄。此時資料表 't1' 會變成如下表所示。 hbase(main):> scan 't1' ROW COLUMN+CELL r2 column=f2:, timestamp=1285737091644, value=v3 r2 column=f2:c2, timestamp=1285737094157, value=v4 Table: 't1' row-key 'f1' 'f2' 'fn' column-family * 'c1' * 'c2' * column-quantifier r2 v3 v4 加入column family¶ hbase(main):> disable 't1' hbase(main):> alter 't1', {NAME => 'f3'} hbase(main):> enable 't1' 執行結果:多了一個 column-family 'f3' 可以用 describe 指令查詢,結果示意如下表: hbase(main):021:0> describe 't1' DESCRIPTION ENABLED {NAME => 't1', FAMILIES => [{NAME => 'f1', COMPRESSION => 'NONE', VERS true IONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => ' false', BLOCKCACHE => 'true'}, {NAME => 'f2', COMPRESSION => 'NONE', V ERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY = > 'false', BLOCKCACHE => 'true'}, {NAME => 'f3', VERSIONS => '3', COMP RESSION => 'NONE', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMOR Y => 'false', BLOCKCACHE => 'true'}, {NAME => 'fn', COMPRESSION => 'NO NE', VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_ME MORY => 'false', BLOCKCACHE => 'true'}]} Table: 't1' row-key 'f1' 'f2' 'f3' 'fn' column-family * 'c1' * 'c2' * * column-quantifier r2 v3 v4 刪除column family¶ hbase(main):> disable 't1' hbase(main):> alter 't1', {NAME => 'f1', METHOD => 'delete'} hbase(main):> enable 't1' 執行結果:會移除 column family 為 'f1' 的所有欄位,可用 describe 指令確認,結果如下表所示。 hbase(main):053:0> describe 't1' DESCRIPTION ENABLED {NAME => 't1', FAMILIES => [{NAME => 'f2', COMPRESSION => 'NONE', VERS true IONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY => ' false', BLOCKCACHE => 'true'}, {NAME => 'f3', COMPRESSION => 'NONE', V ERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMORY = > 'false', BLOCKCACHE => 'true'}, {NAME => 'fn', COMPRESSION => 'NONE' , VERSIONS => '3', TTL => '2147483647', BLOCKSIZE => '65536', IN_MEMOR Y => 'false', BLOCKCACHE => 'true'}]} 1 row(s) in 0.0200 seconds Table: 't1' row-key 'f2' 'f3' 'fn' column-family * 'c2' * * column-quantifier r2 v3 v4 節點狀態¶ hbase(main):> status 刪除整張table¶ hbase(main):> truncate 't1' 執行完 truncate 後,所有 't1' 的內容都會被移除。但此時,下 list 還會有 't1' 這個表格存在。 hbase(main):> disable 't1' hbase(main):> drop 't1' 要完整移除 't1' 資料表,必須使用 disable 先將 't1' 停用,再用 drop 指令把 't1' 完全刪除。 转自:http://trac.nchc.org.tw/cloud/wiki/NCHCCloudCourse100929_2_USE 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/3401078.html,如需转载请自行联系原作者。
一. 需求 最近在做数据库迁移,经常需要打包实例传输,传统scp感觉很慢。 二. 软件信息 1. 软件主页:http://tsunami-udp.sf.net/ 2. 软件安装:直接源码make && make install 三. 简单使用 以下介绍简明步骤: 在源机子开启tsunami进程:tsunamid * 在目标机子 connect ip && get 四. 测试 在几台待迁移服务器上(机子比较老)传输时发现在70Mb/s左右 五. 使用经验 如果做tar包,建议不使用压缩。 六. 注意事项 tsunami在传输的时候还是很消耗带宽的。如果对速度不要求可以不必使用。如果有,需要确认源主机上是否有其他优先级更高的业务在跑。 By 迦叶 2014-05-28 Good Luck! 转自 http://blog.itpub.net/26515977/viewspace-1208279/ 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/4111287.html,如需转载请自行联系原作者。
转自:http://www.cnblogs.com/sunada2005/archive/2013/06/06/3121098.html 最近在使用github,感觉不错。在windows下,可使用github提供的windows客户端(http://windows.github.com/)。很傻瓜,很方便。如何使用?详见:http://www.cr173.com/html/15618_1.html。(有图是王道)最近发现,在公司电脑上安装github的windows客户端时,可能由于公司网络限速和限流量限得太死,怎么也安装不成功。在家的github windows的图形客户端的同步也经常出问题。没办法,也只能通过文本界面来连接github了。如果已在windows系统中成功安装github的客户端,则除了可使用图形客户端外,还可使用github bash这个文本客户端。在我电脑上,当图形客户端同步出现问题时,文客户端还是能同步成功的。如果安装不上github的客户端,还可安装其他的git bash来连接github,如msysgit (http://msysgit.github.io/)等。因为以上软件都是以git为基础的,所以语法与linux使用的命令相同。 在linux下我仅使用了文本界面,所以安装了个文本形式的git客户来连接github。 1. 安装git 我用的是centos系统,在使用yum install git时,系统提示没有找到git包。所以,仅能通过以下方法来安装git。方法详见:http://www.cnblogs.com/Neddy/archive/2011/02/28/1967548.html。以上方法中有一个问题:方法中给出的git的下载源http://www.codemonkey.org.uk/projects/git-snapshots/git/git-latest.tar.gz 似乎无效了,于是,我在网上的这里下载了个git的最新安装包,安装到了centos上。Linux下git的官方网址为:http://git-scm.com/download ,可能因为我网慢打不开,不知道读者您那里如何。如果打不开,可以在网上其他地方找找安装包,应该可以找到的。 2. 使用git连接github 使用git连接github时,需要将linux下产生的一个ssh公钥放到github上。具体步骤详见:http://blog.sina.com.cn/s/blog_6b706e15010199p1.html。主要命令有: 1 ssh-keygen -t rsa -C"mail@mail.com" 然后系统提示输入文件保存位置等信息,连续敲三次回车即可,生成的SSH key文件保存在中~/.ssh/id_rsa.pub文件中。 用文本编辑工具打开该文件,在linux下可以用cat命令显示id_rsa.pub中的内容(cat ~/.ssh/id_rsa.pub),让后复制其内容。 接着拷贝.ssh/id_rsa.pub文件内的所以内容,将它粘帖到github帐号管理中的添加SSH key界面中。 注意,使用vim读取git_home/.ssh/id_rsa.pub中的公钥内容时,可能会有较多的空格和换行,复制到github网站上时必需删除。所以建议使用cat来读取ssh公钥。将ssh公钥成功加入github后,可使用命令ssh -T git@github.com来验证是否成功。如果出现象:hi xxx. You've successfully authenticated, but GitHub does not provide shell access.则说明连接成功。 如:Warning: Permanently added the RSA host key for IP address '*.*.*.*' to the list of known hosts. Enter passphrase for key '/home/git/.ssh/id_rsa': Hi xd502djj! You've successfully authenticated, but GitHub does not provide shell access. 如果未能连接成功。可使用命令ssh -Tv git@github.com来查找failure的原因。通过详细的debug过程,我发现象我把自己的ssh密钥信息放到了/home/admin/.ssh/下,而测试时使用的账户是root,寻找ssh密钥的路径为root/.ssh,所以permission denied的啦。su到admin下,就可以连接成功啦~~ 3. 使用git与github管理代码 3.1 新建一个repository 这里就使用github官网上的教程吧。请保证git的版本至少为1.7.10,否则可能无法成功。详细如何使用,请参见:https://help.github.com/articles/set-up-git。linux下无法新建一个repo,只能对github中已有的repo进行修改。所以,当要新建一个repo时,必须在github.com上新建,再通过linux下的git向此repo中新添内容。 3.2 修改repo中的代码 github的官网上也有修改repo代码的教程。详情请参见:https://help.github.com/articles/fork-a-repo。简要步骤如下: $git clone https://github.com/username/Spoon-Knife.git $cd Spoon-Knife $git add filename.py #添加文件到版本库 $git commit -m 'add filename.py to src' #提交,产生版本记录,注意代码依然在本地 $vim README.md #修改Spoon-Knife中的README.md文件内容 $git commit -m 'modify the README.md' #提交,产生版本记录,注意代码依然在本地 $git [remote] rm filename1.py #删除repo中的filename1.py文件 $git commit -m 'delete filename1.py' #提交,产生版本记录,注意代码依然在本地 $git push origin #将修改提交到github上<br> 3.3 常用git命令 git help #可查看git的常用命令 git config --global user.name "Your Name Here" #设置commit的署名 git config --global user.email "your_email@example.com" #设置commit的email git config [--local|--global|--system] --list/-l #查看本地的global信息 git config [--local|--global|--system] --unset[-all] user.name #删除user.name信息。如果user.name对应多个值,可用unset-all来删除 git remote add XXX https://github.com/username/repo_name.git #设置github的连接 git clone git://github.com/your_account/aimed_repo.git #复制一个repo到本地 git remote -v #查看本地设置的url连接信息 git status #查看当前工作的 branch git branch #查看本地所有的 branch git branch -a #查看远程的所有分支 git branch -d branch_name #删除本地branch_name这一分支 git push origin --delete branch_name #删除名为branch_name的远程分支 git checkout branch_name #切换到名为branch_name的分支上 git chechout -b branch_name #在本地新建一个名为branch_nam的分支 git diff test_branch_name #查看当前branch与test_branch_name中代码的区别 git mv filename newfilename #文件重命名 git push XXX branch_name #上传指定的branch到远端 git pull #将远程上的版本与本地版本进行合并,相当于get fetch + git merge git reset --hard #将刚才进行的git pull所进行的操作取消,恢复本地版本合并前的原貌 4. 如何删除github上的repository github页面上删除repo的功能比较隐蔽,得在这里表一表。比如,想删除了一个名为python的repo。则需先点击进入“python”,单击“Settings”,找到“Delete this repository”,确认删除即可。注意,github上的repo删除后就不能恢复了哦~~ 5. git clone/push时出现错误提示:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed while accessing ... 这是由于ssl认证出问题引起的错误。有两种简单的解决方法: 1. 使用命令,成功执行后,便可正常使用git clone和git push了 git config --global http.sslVerify false 2. 使用命令,但每次clone 和 push时都需要带上env的部分。 env GIT_SSL_NO_VERIFY=true git clone https://github.com/XXXX/xxxxx.git 6. git push时出现错误non-fast-forward时怎么办?(来自:http://blog.csdn.net/chain2012/article/details/7476493) 当要push代码到git时,出现提示: error:failed to push some refs to ... Dealing with “non-fast-forward” errors From time to time you may encounter this error while pushing: $ git push origin master To ../remote/ ! [rejected] master -> master (non-fast forward) error: failed to push some refs to '../remote/' To prevent you from losing history, non-fast-forward updates were rejected Merge the remote changes before pushing again. See the 'non-fast forward' section of 'git push --help' for details. This error can be a bit overwhelming at first, do not fear. Simply put, git cannot make the change on the remote without losing commits, so it refuses the push. Usually this is caused by another user pushing to the same branch. You can remedy this by fetching and merging the remote branch, or using pull to perform both at once. In other cases this error is a result of destructive changes made locally by using commands like git commit --amend or git rebase. While you can override the remote by adding --force to the push command, you should only do so if you are absolutely certain this is what you want to do. Force-pushes can cause issues for other users that have fetched the remote branch, and is considered bad practice. When in doubt, don’t force-push. 问题(Non-fast-forward)的出现原因在于:git仓库中已经有一部分代码,所以它不允许你直接把你的代码覆盖上去。于是你有2个选择方式: 1,强推,即利用强覆盖方式用你本地的代码替代git仓库内的内容 git push -f 2,先把git的东西fetch到你本地然后merge后再push $ git fetch $ git merge 这2句命令等价于 $ git pull 可是,这时候又出现了如下的问题: 上面出现的 [branch "master"]是需要明确(.git/config)如下的内容 [branch "master"] remote = origin merge = refs/heads/master 这等于告诉git2件事: 1,当你处于master branch, 默认的remote就是origin。 2,当你在master branch上使用git pull时,没有指定remote和branch,那么git就会采用默认的remote(也就是origin)来merge在master branch上所有的改变 如果不想或者不会编辑config文件的话,可以在bush上输入如下命令行: $ git config branch.master.remote origin $ git config branch.master.merge refs/heads/master 之后再重新git pull下。最后git push你的代码吧。it works now~ 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/4448491.html,如需转载请自行联系原作者。
使用安装包安装 环境: Linux, OS X, or Unix Python 2 version 2.6.5+ or Python 3 version 3.3+ 检查Python版本 $ python --version 安装步骤 1、下载安装包 $ curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip" 2、解压压缩包 $ unzip awscli-bundle.zip 3、执行安装,并生成可执行文件 $ sudo ./awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws 如果你有多个Python版本 可以选择下面的安装方式 $ sudo /usr/local/bin/python2.7 awscli-bundle/install -i /usr/local/aws -b /usr/local/bin/aws 如果没有sudo权限。可以按照下面的方式直接安装 $ curl "https://s3.amazonaws.com/aws-cli/awscli-bundle.zip" -o "awscli-bundle.zip" $ unzip awscli-bundle.zip $ ./awscli-bundle/install -b ~/bin/aws 剩下的就是在环境变量里面进行配置等了。不再累述 具体可以参考http://docs.aws.amazon.com/cli/latest/userguide/installing.html#install-bundle-other-os 最后就是配置账户等信息 配置方式有两种 1、aws configure 或者 aws configure --profile user2 2、在配置文件中直接加入 vi ~/.aws/config 具体可以参考 http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-getting-started.html#cli-using-examples 本文转自茄子_2008博客园博客,原文链接:http://www.cnblogs.com/xd502djj/p/4877791.html,如需转载请自行联系原作者。
现在手机越来越普及了,手机上能实现的功能也越来越多,很多人开始转入了手机上的应用开发,但是手机平台五花八门,如果想使开发出的程序具有较高的商业价值,就必须能够适应较多数的手机平台,要充分考虑程序的可移植性,本人接触手机应用开发已有近三年的时间,经历了许多种手机平台的开发,如基于symbian OS的S60系列、UIQ系列,基于windows CE的Pocket PC系列、SmartPhone系列,还有如MTK、ADI、Philips等,对于工程的设计深有感触,虽然经历了不少失败的教训,但收获也不小,这里把这几年的移植设计工作做一下总结,希望对于正在做移动应用开发的同业者有借鉴作用。在设计项目过程中主要要考虑如下几个要领: 1、选择易于移植的编程语言。当前在移动开发中使用的语言主流是J2ME和C语言,J2ME因为与平台无关,成为了首选的开发语言,但是用J2ME来开发,有些功能在某些手机平台上是无法实现的,有些手机平台根本就不支持J2ME的开发,所以我还是较倾向使用C语言,到目前为止,还没有碰到不支持C语言的,虽然有些平台要求用C++来开发,但C++还是对C语言兼容的,这里我们就是针对C语言来讲述如何开发易于移植的工程。 2、在程序架构设计上要针对使用异步函数的设计方法。调用某个函数,在函数退出时不能马上知道结果,必须通过获取系统返回的消息才能知道函数调用结果,这样的函数便是异步函数。所以在调用平台相关函数时要考虑到其可能是异步函数,可以设计一个事件或消息处理中心和一个超时处理方法,把有调用平台相关的函数,全部在那儿进行处理,便于简化处理流程。 3、对于基本数据类型和C语言基本标准函数要进行封装。大部份平台都会有一套不同的基本数据类型定义和函数功能一样但定义不同的C语言函数,特别是那些文件操作,基本上都不支持C语言中的函数方法定义,但实现的功能是一样的,所以可以通过宏定义或重定义进行封装。 4、最好有一套独立的内存管理程序。有些平台上的内存分配和释放函数的实现较简单,对于会产生较多内存碎片的程序可能会很快就无内存可用,有些平台上的一次能申请的最大内存可能无法满足程序的需要,这时候就需要自己设计一套内存管理程序。 5、代码设计时要考虑栈空间的大小。手机平台的程序可用栈空间一般都很小,一般不会超这8KB,函数的参数、局部变量、递归调用都是占用栈空间的,所以在手机平台中的系统函数很多都没有带参数,函数内局部变量当为数组变量时要注意数组长度,太长则容易造成栈溢出,一般不要超过128字节,要尽量少用递归函数或递归函数的递归层次要少,还有函数调用太深也是容易造成栈溢出的。 6、最好不要有全局变量。目前只知道symbian OS平台上应用程序不可以有全局变量(但可以有static const申明的全局常量),当然在symbian OS上要使用全局变量也是有方法的,不过,会有点麻烦,最好是不要有全局变量,如果确实需要全局变量,全局变量的数目应尽可能的少,并且要有一套对全局变量的统一管理方法。 7、要考虑到字节对齐问题。大部分手机是4字节对齐,所以在设计结构体数据类型时,结构体长度最好是4字节的倍数,数组的长度也最好是4字节的倍数,对于动态申请内存,最好不要申请小于4字节长度的内存,否则会浪费内存。 8、要尽量节约内存的使用。在手机平台中可用的内存一般是在几百KB左右,当然大部分智能手机(如symbian、windows CE手机)的内存能有几兆的空间,对于内存的使用要有一个很好的规划,在程序架构设计时就必须要考虑这方面的问题。 9、要考虑到字节顺序及字符集类型。大部分手机使用的字符集是UCS2字符,UCS2字符便有个高低字节顺序的问题,在处理UCS2字符时,如果发现处理后的字符乱掉了,那大部分原因是因为高低字节顺序错了,但对于UTF8字符是不用考虑字节顺序的,很多系统采用了UTF8字符便是基于这方面的考虑。 10、 循环运算次数不要太大。有些系统会对循环运算进行监视,如果循环次数太大并造成运算时间太长,系统会发生重启的现象。 11、 一次的不间断的处理过程时间不能太长。大部分低端的手机操作系统是单任务或抢占式多任务的,并且不支持多线程,如果某个不间断的处理过程时间太长,则手机会因在这个长过程中无法处理其它事件造成象死机的样子,这样子,程序的交互性便会很差,最好把一个大过程分成一个个运行时间较短的小过程,每个小过程由UI层进行控制,这样便可以及时响应和处理其它的事件。 12、文件操作不能太频繁。手机平台的系统资源有限,远不能跟PC相比,频繁地读写文件可能会造成系统应付不过来而瘫痪掉,要尽量减少特别是对文件的写入操作。 13、 与平台相关的接口设计要尽量简化。做移植主要工作量是在处理接口的设计上,接口设计得越简单,接口数目越少,移植的工作量则越少。 14、要设计好程序调试方法。在手机平台上进行程序调试是一个较麻烦的工作,有些手机平台会提供模拟器进行调试,但最后还是必须到手机上去调试,所以调试的方法很重要,必须要有一套独立的不依赖于平台的调试方法。 本文转自peterzb博客园博客,原文链接:http://www.cnblogs.com/peterzb/archive/2009/05/16/1458503.html,如需转载请自行联系原作者。
1:用Interlocked系列函数实现线程同步; 2:用CRITICAL_SECTION及其系列函数实现线程同步; 3:用RTL_SRWLOCK及其系列函数实现线程同步; 4:用事件内核对象实现线程同步; 5:用信号量内核对象实现线程同步; 1:用Interlocked系列函数实现线程同步实例如下: //旋转锁 #include <iostream> using namespace std; #include <process.h> #include <windows.h> const int threadNum=10; HANDLE hThread[threadNum]; volatile unsigned int ISOK=0; unsigned int _stdcall Interlocked(PVOID threadId) { while(InterlockedExchange(&ISOK,1)==1) ; cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; InterlockedExchange(&ISOK,0); return 0; } void InterlockedTest() { int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } cout<<"1:用Interlocked系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, Interlocked,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } } InterlockedExchange确保以原子的方式操作数据。执行速度非常快,缺点是如果要同步的部分执行的时间比较长的话,while循环会一直轮询操作,浪费CPU的时间,在单核CPU的系统中,可能会出现while一直暂用CPU导致其他线程不能修改ISOK的值,导致不能跳出while循环,出现死循环。还有就是线程的优先级问题也能导致问题。 2:用CRITICAL_SECTION及其系列函数实现线程同步实例如下: //关键段 #include <iostream> using namespace std; #include <process.h> #include <windows.h> const int threadNum=10; HANDLE hThread[threadNum]; CRITICAL_SECTION g_cs;//构造一个CRITICAL_SECTION实例 unsigned int _stdcall CriticalSection(PVOID threadId) { EnterCriticalSection(&g_cs);//进入关键段 cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; LeaveCriticalSection(&g_cs);//进入关键段 return 0; } void CriticalSectionTest() { int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } InitializeCriticalSection(&g_cs);//初始化g_cs的成员 cout<<"2:用CRITICAL_SECTION及其系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, CriticalSection,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } DeleteCriticalSection(&g_cs);//删除关键段 } CRITICAL_SECTION同样是以原子的方式操作数据,也只有以原子的方式操作数据才能实现线程的同步,所有实现线程同步的方法,最核心的部分就是以原子的方式操作数据,CRITICAL_SECTION执行的速度非常快,其内部有一个事件内核对象,当出现资源争夺的时候,才会出现初始化这个事件内核对象,由于CRITICAL_SECTION执行非常快可能不会出现资源争夺,也就没有必要创建这个事件内核对象,这个事件内核对象创建后,会将当前线程之外的线程挂起,并记录这些线程需要这个资源,其他线程就不会浪费CPU的时间,而这些被挂起的线程将由用户模式变成内核模式,当这些线程需要的资源可用时,系统会将其中一个线程唤醒。 还有一点值得注意:如果要同步的代码执行得很快,在出现争夺资源的时候,系统把其他线程挂起,而当前线程又马上执行完成了,系统又将挂起的线程唤醒,这个过程是非常浪费CPU的,也影响程序的性能,为了避免这种情况,可以结合旋转锁和CRITICAL_SECTION,先用旋转锁轮询一定次数,还不能获得资源,再将线程挂起,等待资源被释放,系统再将线程唤醒,实现这一功能的就是方法 InitializeCriticalSectionAndSpinCount( LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount//旋转锁轮询的次数 ); 除了初始化CRITICAL_SECTION用的是方法InitializeCriticalSectionAndSpinCount,而不是方法InitializeCriticalSection,其他的都是一样的。 3:用RTL_SRWLOCK及其系列函数实现线程同步实例如下: //读写锁 #include <iostream> using namespace std; #include <process.h> #include <windows.h> const int threadNum=10; HANDLE hThread[threadNum]; RTL_SRWLOCK lock;//构造一个CRITICAL_SECTION实例 unsigned int _stdcall SrwLock(PVOID threadId) { AcquireSRWLockExclusive(&lock);//进入读写锁 cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; ReleaseSRWLockExclusive(&lock);//进入读写锁 return 0; } void SrwLockTest() { int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } InitializeSRWLock(&lock);//初始化lock的成员 cout<<"3:用RTL_SRWLOCK及其系列函数实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, SrwLock,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } } SRWLock的目的和关键段是一样的,就是对资源的保护,不让其他线程访问。不同的是,它区分线程是读线程还是写线程。我们都是知道,一个资源可以同时被多个线程同时读,就是不能同时读,或是读写。也是是说写必须是独占的方式,而读可以以共享的方式访问,如果以共享的方式访问肯定就比CRITICAL_SECTION性能好。 4:用事件内核对象实现线程同步实例如下: //事件 #include <iostream> using namespace std; #include <process.h> #include <windows.h> const int threadNum=10; HANDLE hThread[threadNum]; HANDLE event1; unsigned int _stdcall Event(PVOID threadId) { WaitForSingleObject(event1,INFINITE); int* p=(int*)threadId; cout<<"线程:"<<*p<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*p<<"结束"<<endl; SetEvent(event1); return 1; } void EventTest() { int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } event1=CreateEvent(NULL,false,true,NULL); cout<<"4:用事件内核对象实现线程同步"<<endl; for(int i=0;i<threadNum;i++) { hThread[i] =(HANDLE)_beginthreadex(NULL, 0, Event ,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } CloseHandle(event1); } 用内核对象实现线程同步,一个函数是必须知道的,它就是WaitForSingleObject。 DWORD WaitForSingleObject( HANDLE hHandle,//内核对象的句柄 DWORD dwMilliseconds//等待时间 ); 该函数会一直等待,直到被指定的内核对象被触发为止,或是等待的时间结束返回。 CreateEvent( LPSECURITY_ATTRIBUTES lpEventAttributes,//安全控制 BOOL bManualReset,//true:手动重置事件,false:自动重置事件 BOOL bInitialState,//true:有信号,false:无信号 LPCWSTR lpName//事件名称 ); bManualReset为true表示事件触发了并一直处于触发状态,就像打开的门,打开之后就是一直开着,没有自动关上;false:一打开放一个进去进关了,需要用SetEvent再次触发事件。 5:用信号量内核对象实现线程同步实例如下: //信号量 #include <iostream> using namespace std; #include <process.h> #include <windows.h> const int threadNum=10; HANDLE hThread[threadNum]; HANDLE semaphore; unsigned int _stdcall Semaphore(PVOID threadId) { WaitForSingleObject(semaphore, INFINITE); cout<<"线程:"<<*(int*)threadId<<"开始"<<endl; Sleep(100); cout<<"线程:"<<*(int*)threadId<<"结束"<<endl; ReleaseSemaphore(semaphore,1,NULL); return 0; } void SemaphoreTest() { int threadId[threadNum]; for(int i=0;i<threadNum;i++) { threadId[i]=i+1; } semaphore=CreateSemaphore(NULL,1,1,NULL); cout<<"5:用信号量内核对象实现线程同步"<<endl; for(int i=0;i<10;i++){ hThread[i]=(HANDLE)_beginthreadex(NULL, 0, Semaphore,threadId+i, 0, NULL); } WaitForMultipleObjects(threadNum, hThread, TRUE, INFINITE); for(int i=0;i<threadNum;i++) { CloseHandle(hThread[i]); } CloseHandle(semaphore); } 信号量内核对象用来对资源进行计数。创建信号量内核对象的方法如下: CreateSemaphore( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,//安全控制 LONG lInitialCount,//初始资源数量 LONG lMaximumCount,//最大并发数量 LPCWSTR lpName//号量的名称 ); lMaximumCount表示最大并发数量,可以用来设置系统的最大并发数量,如果我们把他的值设为1,lInitialCount也设为1,就是只有一个资源,且每次只能一个线程访问,这样就可以实现线程同步。 在实现线程同步时,建议用方法2和方法3,如不能解决你的需求,再用方法4,方法5,用内核对象实现的线程同步性能要差一些。 多线程编程5中实现线程同步的方法介绍差多就到此了,大家可能还有一些疑问,可以看看我之前关于多线程基础知识的一些介绍: Windows线程基础 Windows内核对象简介 Windows几种线程同步方法介绍 本文转自啊汉博客园博客,原文链接:http://www.cnblogs.com/hlxs/archive/2013/03/31/2991752.html
工作中任务管理的四个原则和四个技能 这是前一阵给团队培训,提高团队工作绩效时写的。 四个原则: l 瓶颈性任务最优先解决原则 l 高不确定性的任务优先解决原则 l 前置性原则 l 复杂多变任务的处理原则 瓶颈性任务最优先解决原则 比如说,上面这个任务分解,B、C、F这条线是瓶颈线。是最优先解决的线。 高不确定性的任务优先解决原则 满足下列两条之一的任务是高不确定性任务: · 困难的、没有实现方案的; · 无法预估完成期限的; 还是以上面那张图为例子,假设A任务是高不确定性的任务,它可能无法解决,可能解决需要很长时间。它很可能比我们计划的时间要长,从而影响进度。比如说,任务图会变成这样子: 所以,这类任务要优先解决。解决步骤如下: 第一步,寻找最小实现方案,如果技术不可行,寻找替代方案;如果技术上可行,做出最小的实现,消除风险和不确定性,估计完全解决需要多长时间,将高不确定性任务转变为普通的任务; 第二步,按照普通任务的处理方式来进行优先级排程。 前置性原则 比如说,上面的图,B是C的前置任务,B应该在C之前解决。 这里有两个例外: (1)如果后置性任务属于高不确定性任务,那么需要想办法解除后置任务对前置任务的依赖,把它优先处理; 也就是说,如果C任务是高风险、不确定性的任务,那么就要想办法解除C对B的依赖,优先解决C,做出C的最小可行性方案,将它变成普通任务;然后,再按照B优先于C的原则来处理; (2)如果有多余的资源或人手,应该想办法解除后置任务对前置任务的依赖,将这个任务尽量的和前置任务并行处理; 复杂多变任务的处理原则 对于复杂的任务,需求可能发生变化的任务的处理是项目管理的难点。这种处理的原则是: 产品层面多沟通!!多沟通!!多沟通!!这种情况下,聊天比写代码重要!! 技术层面多分解!!多分解!!多分解!!分解成不同的模块,通过模块组合来实现需求,当需求发生变化时,换一种组合方式就行了,或者换一个模块就行了。切忌整个代码都是铁板一块!!这样,需求一变,会改很多很多东西!! 四个技能 l 沟通 l 解除依赖关系 l 最小实现方案 l 分解 沟通 沟通很重要,尤其是对复杂性任务,越复杂的任务越需要沟通。 这是解决复杂性任务的必备技能! 沟通也不简单,有可能三个人讨论一件事情时,最开始20分钟,三个人感觉讨论的都是一个事情,随着讨论的深入,20分钟之后,突然发现,三个人谈的表面上是一个事情,实际上心中所想的互相之间有很大区别。 多聊天,多画原型。 解除依赖关系 解除依赖关系,将不能并行的任务变成可以并行的任务,这是缩短项目时间的必备技能! 如果有多余的人手,想办法解除任务之间的依赖关系。 假设甲做A任务需要2天,乙做B任务需要3天,A任务是B任务的前置条件。如果不解除依赖关系,那么项目得5天做完。解除依赖关系后,就只需要3天。 最小实现方案 用最快的时间,实现最小实现方案,来评估高风险任务的可行性、所需人手和时间。 这是解决高风险任务的必备技能! 分解 把一个功能分解成更细的功能,这是进一步提高工作绩效的必备技能! 就像电脑一样,需求变了,换个零件、换个外壳就解决了。如果全是铁板一块,那就麻烦大了。另一点,软件代码的重用成本几乎为零,分解之后,这些就变成了代码资产了,需要A功能?需要B模块?需要C产品?直接从代码资产里拿些出来,组合组合即可。分解的要点就是尽量的解耦,尽量的不依赖于实现。 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/4427464.html,如需转载请自行联系原作者
瞎子摸象与刻舟求剑 我这几年越来越觉得,这两个成语故事是对我们世界深刻的隐喻。 瞎子摸象 从前,有四个盲人很想知道大象是什么样子,可他们看不见,只好用手摸。胖盲人先摸到了大象的牙齿。他就说:“我知道了,大象就像一个又大、又粗、又光滑的大萝卜。”高个子盲人摸到的是大象的耳朵。“不对,不对,大象明明是一把大蒲扇嘛!”他大叫起来。“你们净瞎说,大象只是根大柱子。”原来矮个子盲人摸到了大象的腿。而那位年老的盲人呢,却嘟嚷:“唉,大象哪有那么大,它只不过是一根草绳。”原来他摸到的是大象的尾巴。四个盲人争吵不休,都说自己摸到的才是大象真正的样子。 复杂的事情,前沿的事情,困难的事情,开创性的事情都是瞎子摸象。不同人说不同的话,有人话,有鬼话,有屁话,有从不同角度说的话。就像瞎子摸象,像萝卜?像扇子?像柱子?像绳子?没有上帝视角,咋办?都不对?多摸几次,到底是什么,就出来了。 最有价值的信息就是这样的信息:大象是绳子,大象是扇子,大象是柱子…… 这样的信息往往是扭曲的,残缺的,隐晦不明的。那几个瞎子很快就会知道大象是什么,开个讨论会,再摸一次就可以了。 在这个世界中,我们并不比摸大象的瞎子更高明。 刻舟求剑 有个楚国人,坐船渡河时不慎把剑掉入河中,他在船上用刀刻下记号,说:“这是我的剑掉下去的地方。”当船停下时,他沿着记号跳入河中找剑,遍寻不获。 我们的文章,我们的经验,还有书籍什么的,就好比刻舟求剑,在写(刻)下来那一刻已经落后于时间了。在看书时,看别人的文章时,一定心里要清楚,我们在看的是别人在船上做的记号。 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/4861670.html,如需转载请自行联系原作者
C# 图像编程 (1) 准备工作; 你好,空姐; 为空姐照片添加特效 很久之前,就想写一系列C#图像编程的文章,但始终没有下笔,其主要原因有二:(1)我的C#图像处理库 Geb.Image 库在大幅度变动中;(2)没有找到一个很好的演示工具。现在,对于第一个问题,Geb.Image库的基本结构已经确定了;对于第二个问题,选择了LinqPad作为C#图像编程和演示工具,轻巧简便。就从现在开始吧。 (1) 准备实验环境 假设您熟悉C#编程,且电脑中有 32 位的.Net 4.0 环境。在此基础上,我们开始搭建C# 图像编程的实验环境。 第一步:下载安装 LinqPad。 LinqPad 是一款小巧易用的C#代码段编译工具,有免费版与收费版,收费版比免费版多了自动完成功能。如果不需要自动完成功能,用免费版即可。 第二步:下载Geb.Image类库 Geb.Image 是我的C#图像处理基本库,地址:https://github.com/xiaotie/GebImage 其目录结构如上图。这里,我们只使用其中的dll目录和scripts目录。顾名思义,dll 就是一些基本的 dll,scripts 就是本系列文章所写的 C# 脚本。 第三步:设置 LinqPad 打开 LinqPad ,按 【F4】快捷键,进入 Query Properties 设置界面,在“Additional References”选项卡中,将dll目录中的dll加入进去。 然后,在“Additional Namespace Imports”里加入Geb.Image,Geb.Utils和Geb.Utils.WinForm 三个命名空间,点击“Set as Default for new queries” 保存: 这样,我们就添加了必要的 dll 引用,添加了常用的命名空间。 接着,点击LinqPad左下侧的“Set Folder ... ”链接,将 scripts 目录设置为工作目录: 工作目录中显示的每一个文件便是一个C#脚本文件。双击可加载文件。 (2) 第一个脚本:你好,空姐 在工作目录中,双击“1-1-显示图片”,可看到: 该脚本的作用是加载显示图像。在运行之前,需要将 baseDir 目录更改为 scripts/img 目录的实际路径。点击绿色三角形按钮,一副熟悉的面孔出现了: (3)像素操作演示——为照片增加夜光特效 下面,我们以空姐的照片为测试照片,来实现夜光特效算法: 夜光特效实现起来非常简单:将图像中的每个像素的Red值修改为当前值的1/2即可。程序文件为scripts\001\1-2-夜光特效.linq,这里通过四种方法来实现这一功能,来演示像素操作: String baseDir = "E:\\MyWorkspace\\DotNetWorkspace\\01_Public_Geb.Image\\scripts\\img\\"; unsafe void Main() { ImageRgb24 img = new ImageRgb24(baseDir + "cjk.jpg"); img.ShowDialog("img"); // 将图像看作连续的内存,通过偏移量来访问 ImageRgb24 img2 = img.Clone(); for(int i = 0; i < img2.Length; i++) { Rgb24 p= img2[i]; p.Red = (Byte)(p.Red/2); img2[i] = p; } img2.ShowDialog("img2"); // 将图像看作一个二维“表格”,通过行和列坐标来访问 ImageRgb24 img3 = img.Clone(); for(int row = 0; row < img3.Height; row++) 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/archive/2013/04/09/3009794.html,如需转载请自行联系原作者
把 Notepad++ 打造成一款易用的C#脚本编辑器 以前一直用Linqpad在写小程序脚本,但是Linqpad自动完成功能要收费,且不开源,这样的话就不方便扩展了。今天在 http://csscriptnpp.codeplex.com/ 发现了一款C#自动完成的插件:CS-Script for Notepad++(http://csscriptnpp.codeplex.com/),遂下载下来试用。 试用感觉很不错,不过还有点小缺陷: (1)不支持指针的自动完成(这个一般人用不上,但图像开发需要!); (2)显示自动完成列表的快捷键是 Ctrl+Space,很不爽。 于是,下载了它的源码,进行了修改,将显示自动完成列表的快捷键修改为 Ctrl+/,并且,支持指针的自动完成。 环境要求:需要.Net 4.0环境。修改后的插件文件及源码下载地址: http://files.cnblogs.com/xiaotie/CSScriptNpp-Modify.zip 下载后,将解压缩后的插件文件安装到Notpad++的plugin目录下,重启Notpad++即可。安装后的plugin 目录如下: 界面效果: F5即可执行。 可以在代码首部通过注释的方式引入dll及其它源文件,语法可参考 http://www.csscript.net/help/Directives.html ==== 最后,国际惯例:一切荣誉归 csscript,一切错误归我。 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/3274443.html,如需转载请自行联系原作者
使用Notepad++开发C#,一个复杂点的csscript脚本 使用Notepad++开发C#,一个复杂点的csscript脚本: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 //css_dir ..\..\lib; //css_ref Geb.Image.dll; //css_ref Geb.Image.ShapeAnalysis.dll; //css_ref Geb.Utils.dll; //css_ref Geb.Utils.WinForm.dll; //css_co /unsafe; using System; using Geb.Image; unsafe class Program { public static void Main() { ImageArgb32 img = new ImageArgb32(300,200); img.Fill(Argb32.RED); img.ShowDialog(); } } // css_dir 设置搜索库目录的路径; // css_ref 引用dll; // css_co 设置编译参数; 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/3298401.html,如需转载请自行联系原作者
两个平板打天下-将中国看做一个城市圈,漉战移动互联网、高铁时代 旧有两把菜刀闹革命,今有两个平板打天下。最近搞了个七寸平板手机,用了几天,很是满意,即可打电话,又可刷微博微信,又可看电子书、PDF,还可以打游戏,重度应用下也能支撑10小时。恰逢苏菲3(Surface Pro3)上市。这两平板配合,相得益彰,正可满足俺移动办公的需要,所以写了这篇文章: 4G移动互联网、高铁、云计算这些技术变革已经形成了一种合力,这种合力将对公司的运作产生深远的影响。 简述如下: · 4G 移动互联网使得随时随地办公、在线技术支持、客服成为可能;网速快,费用能承受且会越来越低; · 云时代的到来使得企业的信息资产和信息投资可以越来越多的放在云上,企业的信息资产越来越轻; · 高铁时代的到来使得实物流动得更快,电子商务会更繁荣,同时,针对全国的实物技术支持可以更为方便、更为快捷; 合理利用这些技术将会使公司进阶为一个新型的形态。 打破旧有的城市圈思维,将整个中国当作一个大的城市圈来思考,来布局,来运作,两个平板打天下(一个打电话,一个打天下)。 描述一个场景: 在郊区别墅外草地上,支起一个小桌子,兜里揣着一个7寸平板手机,开4G WIFI热点。桌子上放一个苏菲3(Surface Pro 3),写着代码。通过视频会议、在线协作工具和客户及团队其他成员沟通。如需实地沟通,5小时高铁可到达大部分大城市。在高铁上,依旧可以开着苏菲写代码、查资料、看书。需要实物的话,发快递,也很快就到了。 一些想法: · 轻、小、强、专的团队 —— 轻量、微型、强大、专业化的团队,在全国范围内具有竞争力; · 全国布局的人力资本 —— 一个很简单的例子-在北京,月薪2万也没有安全感,地铁能把人挤怀孕。而在我这个城市,月薪2万可以买4平米房子了。6K以上月薪都有安全感了。大家工作的更安心,生产效率更高; · 云端布局 —— 资产、产品、工具尽量布置在云端,减轻维护费用,增加异地接入的方便性,增加客户接入的方便性; · 快速响应 —— 因有移动互联网在,可随时随地的响应,因云端布局,大部分问题可以在线解决。需要实地解决的,高铁之即可。 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/3950954.html,如需转载请自行联系原作者
网上的视频很多都是分片的flv文件,怎么把他们合为一体呢?GUI工具就不考虑了,不适合批量执行,不适合在后台运行。有没有命令行工具或库可以实现呢? ffmpeg 提供了一个方法: (1)先把flv文件转换成mpeg; (2)将多个mpeg文件合并成1个独立的mpeg文件(二进制合并即可) (3)将独立的mpeg文件转换成独立的flv文件。 网上搜到的最多的也是这种解决办法。这种方法有两个缺点: (1)需要两遍转码,非常耗时; (2)转换后的独立的mpeg文件比原视频要短一点点。 木有办法了,只好另寻他路。有人说有一个flvmerge.exe 程序可以将多个flv合并成一个,可惜的是俺搜了很久,都没找到这个程序,最后还是在一款免费软件里把这个“flvmerge.exe”文件给揪出来了,不幸的是,这个“flvmerge.exe”得不到正确的结果。 润之同学说过,自己动手,丰衣足食。上 github 上搜“flvmerge”,发现两个项目,“flvmerge”和“flvmerger”,都是C写的。前者不依赖于第三方库,后者依赖于第三方库,那么就从第一个开始吧。 看了看它的代码,知道了flv文件合并的原理: (1) flv 文件由1个header和若干个tag组成; (2) header记录了视频的元数据; (3) tag 是有时间戳的数据; (4) flv合并的原理就是把多个文件里的tag组装起来,调整各tag的时间戳,再在文件起始处按个头部。 下面是我参照 flvmerge 项目,用linqpad写的一个C#版本的 flvmerge 代码: 1 void Main() 2 { 3 String path1 = "D:\\Videos\\Subtitle\\OutputCache\\1.flv"; 4 String path2 = "D:\\Videos\\Subtitle\\OutputCache\\2.flv"; 5 String path3 = "D:\\Videos\\Subtitle\\OutputCache\\3.flv"; 6 String output = "D:\\Videos\\Subtitle\\OutputCache\\output.flv"; 7 8 using(FileStream fs1 = new FileStream(path1, FileMode.Open)) 9 using(FileStream fs2 = new FileStream(path2, FileMode.Open)) 10 using(FileStream fs3 = new FileStream(path3, FileMode.Open)) 11 using(FileStream fsMerge = new FileStream(output, FileMode.Create)) 12 { 13 Console.WriteLine(IsFLVFile(fs1)); 14 Console.WriteLine(IsFLVFile(fs2)); 15 Console.WriteLine(IsFLVFile(fs3)); 16 17 if(IsSuitableToMerge(GetFLVFileInfo(fs1),GetFLVFileInfo(fs2)) == false 18 || IsSuitableToMerge(GetFLVFileInfo(fs1),GetFLVFileInfo(fs3)) == false) 19 { 20 Console.WriteLine("Video files not suitable to merge"); 21 } 22 23 int time = Merge(fs1,fsMerge,true,0); 24 time = Merge(fs2,fsMerge,false,time); 25 time = Merge(fs3,fsMerge,false,time); 26 Console.WriteLine("Merge finished"); 27 } 28 } 29 30 const int FLV_HEADER_SIZE = 9; 31 const int FLV_TAG_HEADER_SIZE = 11; 32 const int MAX_DATA_SIZE = 16777220; 33 34 class FLVContext 35 { 36 public byte soundFormat; 37 public byte soundRate; 38 public byte soundSize; 39 public byte soundType; 40 public byte videoCodecID; 41 } 42 43 bool IsSuitableToMerge(FLVContext flvCtx1, FLVContext flvCtx2) 44 { 45 return (flvCtx1.soundFormat == flvCtx2.soundFormat) && 46 (flvCtx1.soundRate == flvCtx2.soundRate) && 47 (flvCtx1.soundSize == flvCtx2.soundSize) && 48 (flvCtx1.soundType == flvCtx2.soundType) && 49 (flvCtx1.videoCodecID == flvCtx2.videoCodecID); 50 } 51 52 bool IsFLVFile(FileStream fs) 53 { 54 int len; 55 byte[] buf = new byte[FLV_HEADER_SIZE]; 56 fs.Position = 0; 57 if( FLV_HEADER_SIZE != fs.Read(buf,0,buf.Length)) 58 return false; 59 60 if (buf[0] != 'F' || buf[1] != 'L' || buf[2] != 'V' || buf[3] != 0x01) 61 return false; 62 else 63 return true; 64 } 65 66 FLVContext GetFLVFileInfo(FileStream fs) 67 { 68 bool hasAudioParams, hasVideoParams; 69 int skipSize, readLen; 70 int dataSize; 71 byte tagType; 72 byte[] tmp = new byte[FLV_TAG_HEADER_SIZE+1]; 73 if (fs == null) return null; 74 75 FLVContext flvCtx = new FLVContext(); 76 fs.Position = 0; 77 skipSize = 9; 78 fs.Position += skipSize; 79 hasVideoParams = hasAudioParams = false; 80 skipSize = 4; 81 while (!hasVideoParams || !hasAudioParams) 82 { 83 fs.Position += skipSize; 84 85 if (FLV_TAG_HEADER_SIZE+1 != fs.Read(tmp,0,tmp.Length)) 86 return null; 87 88 tagType = (byte)(tmp[0] & 0x1f); 89 switch (tagType) 90 { 91 case 8 : 92 flvCtx.soundFormat = (byte)((tmp[FLV_TAG_HEADER_SIZE] & 0xf0) >> 4) ; 93 flvCtx.soundRate = (byte)((tmp[FLV_TAG_HEADER_SIZE] & 0x0c) >> 2) ; 94 flvCtx.soundSize = (byte)((tmp[FLV_TAG_HEADER_SIZE] & 0x02) >> 1) ; 95 flvCtx.soundType = (byte)((tmp[FLV_TAG_HEADER_SIZE] & 0x01) >> 0) ; 96 hasAudioParams = true; 97 break; 98 case 9 : 99 flvCtx.videoCodecID = (byte)((tmp[FLV_TAG_HEADER_SIZE] & 0x0f)); 100 hasVideoParams = true; 101 break; 102 default : 103 break; 104 } 105 106 dataSize = FromInt24StringBe(tmp[1],tmp[2],tmp[3]); 107 skipSize = dataSize - 1 + 4; 108 } 109 110 return flvCtx; 111 } 112 113 int FromInt24StringBe(byte b0, byte b1, byte b2) 114 { 115 return (int)((b0<<16) | (b1<<8) | (b2)); 116 } 117 118 int GetTimestamp(byte b0, byte b1, byte b2, byte b3) 119 { 120 return ((b3<<24) | (b0<<16) | (b1<<8) | (b2)); 121 } 122 123 void SetTimestamp(byte[] data, int idx, int newTimestamp) 124 { 125 data[idx + 3] = (byte)(newTimestamp>>24); 126 data[idx + 0] = (byte)(newTimestamp>>16); 127 data[idx + 1] = (byte)(newTimestamp>>8); 128 data[idx + 2] = (byte)(newTimestamp); 129 } 130 131 int Merge(FileStream fsInput, FileStream fsMerge, bool isFirstFile, int lastTimestamp = 0) 132 { 133 int readLen; 134 int curTimestamp = 0; 135 int newTimestamp = 0; 136 int dataSize; 137 byte[] tmp = new byte[20]; 138 byte[] buf = new byte[MAX_DATA_SIZE]; 139 140 fsInput.Position = 0; 141 if (isFirstFile) 142 { 143 if(FLV_HEADER_SIZE+4 == (fsInput.Read(tmp,0,FLV_HEADER_SIZE+4))) 144 { 145 fsMerge.Position = 0; 146 fsMerge.Write(tmp,0,FLV_HEADER_SIZE+4); 147 } 148 } 149 else 150 { 151 fsInput.Position = FLV_HEADER_SIZE + 4; 152 } 153 154 while(fsInput.Read(tmp, 0, FLV_TAG_HEADER_SIZE) > 0) 155 { 156 dataSize = FromInt24StringBe(tmp[1],tmp[2],tmp[3]); 157 curTimestamp = GetTimestamp(tmp[4],tmp[5],tmp[6],tmp[7]); 158 newTimestamp = curTimestamp + lastTimestamp; 159 SetTimestamp(tmp,4, newTimestamp); 160 fsMerge.Write(tmp,0,FLV_TAG_HEADER_SIZE); 161 162 readLen = dataSize+4; 163 if (fsInput.Read(buf,0,readLen) > 0) { 164 fsMerge.Write(buf, 0, readLen); 165 } else { 166 goto failed; 167 } 168 } 169 170 return newTimestamp; 171 172 failed: 173 throw new Exception("Merge Failed"); 174 } 测试通过,合并速度很快! 不过,这个方法有一个缺点:没有将各个文件里的关键帧信息合并,这个关键帧信息,切分flv文件时很重要,合并时就没那么重要了。如果确实需要的话,可以用 yamdi 来处理。 本文转自xiaotie博客园博客,原文链接:http://www.cnblogs.com/xiaotie/p/3441030.html,如需转载请自行联系原作者
为了使我们的网站更好的被搜索引擎抓取收录,更自然的获得更高的流量,网站标签的语义化就显得尤为重要。所谓标签语义化,就是指标签的含义。 为了更好的理解标签的语义化,先看下面这个例子: 1 <table> 2 <tr> 3 <td>娱乐项目</td> 4 <td>项目支出</td> 5 </tr> 6 <tr> 7 <td>聚餐</td> 8 <td>200元</td> 9 </tr> 10 </table> 上面这一段代码就是明显的没有使用语义化标签的例子,为了让它的结构更加清晰,正确的做法如下: <table> <caption>支出统计</caption> <thead> <tr> <th>娱乐项目</th> <th>项目支出</th> </tr> </thead> <tbody> <td>聚餐</td> <td>200元</td> </tbody> </table> 其中, <caption>:表格的标题; <thead>:一表格的表头; <th>:表的某一列的列头。 是的,标签语义化的目的就是对搜索引擎友好,有了良好的结构和语义我们的网页内容便自然容易被搜索引擎抓取,这种符合搜索引擎收索规则的做法,网站的推广便可以省下不少的功夫,而且可维护性更高,因为结构清晰,十分易于阅读。这也是搜索引擎优化SEO(search engine optimization)重要的一步,当然关于SEO远远不止如此,要了解更多有关SEO的内容知识,可移步: http://baike.baidu.com/link?url=f_v0cbvzTIxhwKNaJtdd-qGjGMefJww4ko9pJaZj4rJArylR_dpUZsobKKLlMKBi http://www.seoxuetang.com/ 言归正传,所以我们要做的,就是语义化我们的HTML标签和属性,如: div 语义:Division(分隔) span 语义:Span(范围) ol 语义:Ordered List(排序列表) ul 语义:Unordered List(不排序列表) li 语义:List Item(列表项目) 1.<Hx> <h1>、<h2>、<h3>、<h4>、<h5>、<h6>,作为标题使用,并且依据重要性递减。<h1>是最高的等级。 2.<p> 段落标记,知道了<p>作为段落,你就不会再使用<br/>来换行了,而且不需要<br/><br/>来区分段落与段落。<p></p>中的文字会自动换行,而且换行的效果优于<br>。 3.<b>、<em>和<strong> <b>标签语义为“加粗” <em>标签语义为“强调” <strong>标签语义为“更强烈的强调” 而且em 默认用斜体表示,strong 用粗体表示。 当我们知道了这三个标签的语义时,做SEO时就好决定用哪个来强调重要的关键字了,强调用<em>和<strong>,纯粹加粗用<b>。 4.<ul>标签、<ol>标签、<li>标签 <ul>标签语义为定义无序列表 <ol>标签语义为定义有序列表 <li>标签语义为定义列表项目 因此当涉及到列表的项目,应该用<ul><li>或<ol><li>(或者是<dl><dt><dd>来布局),而不是用<table>或<p>甚至<span>。 5.<dl>标签、<dt>标签、<dd>标签 <dl>标签语义为定义了定义列表 <dt>标签语义为定义了定义列表中的项目(即术语部分) <dd>标签语义为定义列表中定义条目的定义部分 所以,当我们用带标题的列表时,即可采用<dl><dt><dd>自定义列表实现 6.<span>标签 <span>标签的语义为被用来组合文档中的行内元素 (另外应当区分<span>和<div>的区别,<div>是块级元素(block level),而<span>是行内元素,前者的内容会自动换行,而后者前后不会自动换行 http://www.cnblogs.com/coco1s/p/3578947.html) 7.<q>、 <blockquote>、<cite> <q>标签的语义为用来标记简短的单行引用,Web浏览器会自动识别在<q>之间的内容 <blockquote>标签的语义为用来标记那些一段或者好几段的长篇引用 <cite>标签既可以与<q> 一起用,也可以与<blockquote>一起用,用来提供引用内容的来源地址。 看一个例子 1 <p> <cite>孔子</cite>曰:<q>有朋自远方来,不亦乐乎</q>. 2 </p> 1 <blockquote cite="http://www.w3cn.org/"> 2 <p>&#8220;我们大部分人都有深刻体验,每当主流浏览器版本的升级,我们刚建立的网站就可能变得过时,我们就需要升级或者重新建造一遍网站。例如1996-1999年典型的"浏览器大战",为了兼容 Netscape 和 IE,网站不得不为这两种浏览器写不同的代码。同样的,每当新的网络技术和交互设备的出现,我们也需要制作一个新版本来支持这种新技术或新设备,例如支持手机上网的 WAP 技术。类似的问题举不胜举:网站代码臃肿、繁杂浪费了我们大量的带宽;针对某种浏览器的 DHTML 特效,屏蔽了部分潜在的客户;不易用的代码,残障人士无法浏览网站等等。这是一种恶性循环,是一种巨大的浪费。&#8221; 3 </p> 4 </blockquote> 8.<table>、<th>、<td>、<caption> <table>标签的语义的为定义 HTML 表格 <th>标签的语义为定义表格内的表头单元格 <caption>标签的语义为定义表格标题 9.<button>标签、<input>标签、<textarea>标签 <button>标签的语义为定义一个按钮 <input> 标签的语义为用于搜集用户信息,根据不同的 type 属性值,输入字段拥有很多种形式。输入字段可以是文本字段、复选框、掩码后的文本控件、单选按钮、按钮等等。 <textarea>标签的语义为定义多行的文本输入控件 button控件 与 <input type="button"> 相比,提供了更为强大的功能和更丰富的内容。<button> 与 </button> 标签之间的所有内容都是按钮的内容,其中包括任何可接受的正文内容,比如文本或多媒体内容。 10.<label> 标签 <label>标签的语义为为input元素定义标注(标记) 11.<ins>, <del> <ins>标签的语义为定义已经被插入文档中的文本。 <del>标签的语义为定义文档中已被删除的文本。 <ins>与 <del> 一同使用,来描述文档中的更新和修正。知道del,就不要再用<s>做删除线了,用del显然更具有语义化。而且del还带有cite和datetime来表明删除的原因以及删除的时间。ins是表示插入,也有这样的属性。 关于这两个标签的用法,可以参看: http://www.w3school.com.cn/tags/tag_ins.asp http://www.w3school.com.cn/tags/tag_del.asp 本文转自ChokCoco博客园博客,原文链接:http://www.cnblogs.com/coco1s/p/3583082.html
1.增加分区的SQL语法alter table table_name add partition ...2.创建一个分区表sec@ora10g> drop table t_partition_range purge;Table dropped.sec@ora10g> create table t_partition_range (id number,name varchar2(50))2 partition by range(id)(3 partition t_range_p1 values less than (10) tablespace tbs_part01,4 partition t_range_p2 values less than (20) tablespace tbs_part02,5 partition t_range_p3 values less than (30) tablespace tbs_part036 );Table created.sec@ora10g> col TABLE_NAME for a20sec@ora10g> col partition_name for a20sec@ora10g> col HIGH_VALUE for a10sec@ora10g> col TABLESPACE_NAME for a15sec@ora10g> select table_name,partition_name,high_value,tablespace_name from user_tab_partitions where table_name='T_PARTITION_RANGE' order by partition_position;TABLE_NAME PARTITION_NAME HIGH_VALUE TABLESPACE_NAME-------------------- -------------------- ---------- ---------------T_PARTITION_RANGE T_RANGE_P1 10 TBS_PART01T_PARTITION_RANGE T_RANGE_P2 20 TBS_PART02T_PARTITION_RANGE T_RANGE_P3 30 TBS_PART033.添加一个分区t_range_p4sec@ora10g> alter table t_partition_range add partition t_range_p4 values less than(40) tablespace tbs_part04;Table altered.sec@ora10g> select table_name,partition_name,high_value,tablespace_name from user_tab_partitions where table_name='T_PARTITION_RANGE' order by partition_position;TABLE_NAME PARTITION_NAME HIGH_VALUE TABLESPACE_NAME-------------------- -------------------- ---------- ---------------T_PARTITION_RANGE T_RANGE_P1 10 TBS_PART01T_PARTITION_RANGE T_RANGE_P2 20 TBS_PART02T_PARTITION_RANGE T_RANGE_P3 30 TBS_PART03T_PARTITION_RANGE T_RANGE_P4 40 TBS_PART04从这个实验结果可以看到t_range_p4分区已经创建成功4.命题:如果在创建RANGE分区表的时候指定了maxvalue,不可以添加分区(需要使用split方法来处理)5.实验证明之6.创建带有maxvalue的分区表sec@ora10g> drop table t_partition_range purge;Table dropped.sec@ora10g> create table t_partition_range (id number,name varchar2(50))2 partition by range(id)(3 partition t_range_p1 values less than (10) tablespace tbs_part01,4 partition t_range_p2 values less than (20) tablespace tbs_part02,5 partition t_range_p3 values less than (30) tablespace tbs_part03,6 partition t_range_pmax values less than (maxvalue) tablespace tbs_part04);Table created.7.此时添加分区时会报如下的错误sec@ora10g> alter table t_partition_range add partition t_range_p4 values less than(40) tablespace tbs_part04;alter table t_partition_range add partition t_range_p4 values less than(40) tablespace tbs_part04 *ERROR at line 1:ORA-14074: partition bound must collate higher than that of the last partition难道针对这样的分区表就不能修改添加分区了么?对于强大的oracle来说那是不可能的,处理方法是使用split的方法来处理之。8.展示使用split完成上面没有完成的分区任务sec@ora10g> alter table t_partition_range split partition t_range_pmax at (40) into (partition tbs_part05, partition t_range_pmax); Table altered. sec@ora10g> select table_name,partition_name,high_value,tablespace_name from user_tab_partitions where table_name='T_PARTITION_RANGE' order by partition_position;TABLE_NAME PARTITION_NAME HIGH_VALUE TABLESPACE_NAME-------------------- -------------------- ---------- ----------------T_PARTITION_RANGE T_RANGE_P1 10 TBS_PART01T_PARTITION_RANGE T_RANGE_P2 20 TBS_PART02T_PARTITION_RANGE T_RANGE_P3 30 TBS_PART03T_PARTITION_RANGE T_RANGE_P4 40 TBS_PART05T_PARTITION_RANGE T_RANGE_PMAX MAXVALUE TBS_PART04OK,搞定。 分类: OralceRac 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/07/25/2608766.html
【问题现象】在给表空间添加文件后,发现数据文件的添加的位置或名字不规范,需要规范性的更正如下述场景:sys@ora10g> col tablespace_name for a15sys@ora10g> col file_name for a50sys@ora10g> select tablespace_name,file_name from dba_data_files where tablespace_name = 'TBS_SEC_D';TABLESPACE_NAME FILE_NAME--------------- --------------------------------------TBS_SEC_D /oracle/oradata/ora10g/tbs_sec_d01dbf细心地您应该看到这个数据文件名字应该为tbs_sec_d01.dbf,这里少了一个点。(另外一种场景是错误的将数据文件添加到了不正确的路径中需要修改)这种错误也许您也会遇到。首先声明一下:如果保持这个错误名字不变,不会影响到数据库的正常运行,但为了防止在维护过程中产生不必要的干扰,还是应该将其更正的。【处理方法1】OFFLINE数据文件 --> 修改操作系统上的文件名 --> 修改数据库中的文件名 --> 对数据文件进行恢复 --> ONLINE数据文件特别强调:需要归档模式!因为需要对数据文件进行恢复1.OFFLINE数据文件sys@ora10g> alter database datafile '/oracle/oradata/ora10g/tbs_sec_d01dbf' offline;Database altered.2.修改操作系统上的文件名ora10g@testdb /oracle/oradata/ora10g$ mv tbs_sec_d01dbf tbs_sec_d01.dbf3.修改数据库中的文件名sys@ora10g> alter database rename file '/oracle/oradata/ora10g/tbs_sec_d01dbf' to '/oracle/oradata/ora10g/tbs_sec_d01.dbf';Database altered.4.对数据文件进行恢复sys@ora10g> recover datafile '/oracle/oradata/ora10g/tbs_sec_d01.dbf';Media recovery complete.5.ONLINE数据文件alter database datafile '/oracle/oradata/ora10g/tbs_sec_d01.dbf' online;6.确认修改成功sys@ora10g> select tablespace_name,file_name from dba_data_files where tablespace_name = 'TBS_SEC_D';TABLESPACE_NAME FILE_NAME--------------- ---------------------------------------TBS_SEC_D /oracle/oradata/ora10g/tbs_sec_d01.dbf【处理方法2】OFFLINE表空间 --> 修改操作系统上的文件名 --> 修改数据库中的文件名 --> ONLINE表空间1.OFFLINE表空间sys@ora10g> alter tablespace tbs_sec_d offline;Tablespace altered.2.修改操作系统上的文件名ora10g@testdb /oracle/oradata/ora10g$ mv tbs_sec_d01dbf tbs_sec_d01.dbf3.修改数据库中的文件名sys@ora10g> alter database rename file '/oracle/oradata/ora10g/tbs_sec_d01dbf' to '/oracle/oradata/ora10g/tbs_sec_d01.dbf';Database altered.4.ONLINE表空间sys@ora10g> alter tablespace tbs_sec_d online;Tablespace altered.5.确认修改成功sys@ora10g> select tablespace_name,file_name from dba_data_files where tablespace_name = 'TBS_SEC_D';TABLESPACE_NAME FILE_NAME--------------- ---------------------------------------TBS_SEC_D /oracle/oradata/ora10g/tbs_sec_d01.dbf【处理方法3】SHUTDOWN数据库 --> 修改操作系统上的文件名 --> 数据库启动到MOUNT --> 修改数据库中的文件名 --> OPEN数据库1.SHUTDOWN数据库sys@ora10g> shutdown immediate;Database closed.Database dismounted.ORACLE instance shut down.2.修改操作系统上的文件名ora10g@testdb /oracle/oradata/ora10g$ mv tbs_sec_d01dbf tbs_sec_d01.dbf3.数据库启动到MOUNTNotConnected@> startup mount;ORACLE instance started.Total System Global Area 562036736 bytesFixed Size 2022312 bytesVariable Size 171967576 bytesDatabase Buffers 381681664 bytesRedo Buffers 6365184 bytesDatabase mounted.4.修改数据库中的文件名NotConnected@> alter database rename file '/oracle/oradata/ora10g/tbs_sec_d01dbf' to '/oracle/oradata/ora10g/tbs_sec_d01.dbf';Database altered.5.OPEN数据库NotConnected@> alter database open;Database altered.6.确认修改成功sys@ora10g> select tablespace_name,file_name from dba_data_files where tablespace_name = 'TBS_SEC_D';TABLESPACE_NAME FILE_NAME--------------- ---------------------------------------TBS_SEC_D /oracle/oradata/ora10g/tbs_sec_d01.dbf【总结】以上三个实验是按照对数据库运行影响加深的顺序进行的。很显然,需要停起数据库对数据库的可用性影响是最大的,单独对特定数据文件进行修改的影响最小,对表空间offline的方法影响介于其之间。 分类: OralceRac 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/07/25/2608759.html
汇总整理一下有关重做日志文件(redo log files)管理相关的操作(增,删,改,查,切)。供参考。 1.当前日志相关信息sys@ora11g> select * from v$log; GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM---------- ---------- ---------- ---------- ---------- --- --------- ------------- --------- 1 1 10 209715200 1 YES INACTIVE 461938 09-MAR-09 2 1 11 209715200 1 NO CURRENT 485885 09-MAR-09 3 1 9 209715200 1 YES INACTIVE 432636 04-MAR-09sys@ora11g> select * from v$logfile; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ---------------------------------------- --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03.log NO2.添加重做日志组sys@ora11g>alter database add logfile group 4 ('/oracle/u02/oradata/ora11g/redo04_01.log','/oracle/u02/oradata/ora11g/redo04_02.log') size 50m;Database altered.sys@ora11g> select * from v$log; GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM---------- ---------- ---------- ---------- ---------- --- --------- ------------- --------- 1 1 10 209715200 1 YES INACTIVE 461938 09-MAR-09 2 1 11 209715200 1 NO CURRENT 485885 09-MAR-09 3 1 9 209715200 1 YES INACTIVE 432636 04-MAR-09 4 1 0 52428800 2 YES UNUSED 0sys@ora11g> select * from v$logfile; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ---------------------------------------- --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_01.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_02.log NO3.添加日志文件sys@ora11g>alter database add logfile member '/oracle/u02/oradata/ora11g/redo01_02.log' to group 1, '/oracle/u02/oradata/ora11g/redo02_02.log' to group 2, '/oracle/u02/oradata/ora11g/redo03_02.log' to group 3;Database altered.sys@ora11g> select * from v$log; GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM---------- ---------- ---------- ---------- ---------- --- --------- ------------- --------- 1 1 10 209715200 2 YES INACTIVE 461938 09-MAR-09 2 1 11 209715200 2 NO CURRENT 485885 09-MAR-09 3 1 9 209715200 2 YES INACTIVE 432636 04-MAR-09 4 1 0 52428800 2 YES UNUSED 0sys@ora11g> select * from v$logfile order by 1; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ---------------------------------------- --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01.log NO 1 INVALID ONLINE /oracle/u02/oradata/ora11g/redo01_02.log NO 2 INVALID ONLINE /oracle/u02/oradata/ora11g/redo02_02.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03.log NO 3 INVALID ONLINE /oracle/u02/oradata/ora11g/redo03_02.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_02.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_01.log NO8 rows selected.4.重命名日志成员在重命名日志组成员之前新的目标必须已经存在。Oracle的sql命令只是把控制文件中的内部指针指向新的日志文件。1)关闭数据库sys@ora11g> shutdown immediate;Database closed.Database dismounted.ORACLE instance shut down.2)使用操作系统命令重命名或移动日志文件ora11g@RHEL53 /oracle/u02/oradata/ora11g$mv redo01.log redo01_01.logora11g@RHEL53 /oracle/u02/oradata/ora11g$mv redo02.log redo02_01.logora11g@RHEL53 /oracle/u02/oradata/ora11g$mv redo03.log redo03_01.log3)启动数据库实例到mount状态,重命名控制文件中的日志文件成员。NotConnected@> select * from v$logfile order by 1,4; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ------------------------------------------ --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_01.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_02.log NO 1 ONLINE /oracle/u02/oradata/ora11g/redo01_02.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_02.log NO8 rows selected.NotConnected@>alter database rename file '/oracle/u02/oradata/ora11g/redo01.log' to '/oracle/u02/oradata/ora11g/redo01_01.log';Database altered.NotConnected@>alter database rename file '/oracle/u02/oradata/ora11g/redo02.log' to '/oracle/u02/oradata/ora11g/redo02_01.log';Database altered.NotConnected@>alter database rename file '/oracle/u02/oradata/ora11g/redo03.log' to '/oracle/u02/oradata/ora11g/redo03_01.log';Database altered.4)open数据库,验证结果NotConnected@>alter database open;Database altered.sys@ora11g> select * from v$log; GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM---------- ---------- ---------- ---------- ---------- --- -------- ------------- --------- 1 1 18 209715200 2 YES INACTIVE 486960 09-MAR-09 2 1 19 209715200 2 YES INACTIVE 486964 09-MAR-09 3 1 21 209715200 2 NO CURRENT 486973 09-MAR-09 4 1 20 52428800 2 YES INACTIVE 486968 09-MAR-09sys@ora11g> select * from v$logfile order by 1,4; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ------------------------------------------ --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01_01.log NO 1 ONLINE /oracle/u02/oradata/ora11g/redo01_02.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_01.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_02.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_01.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_02.log NO8 rows selected.5)最后,不要忘记备份控制文件sys@ora11g>alter database backup controlfile to trace;Database altered.5.删除一个非活动的重做日志组的成员sys@ora11g> select * from v$log; GROUP# THREAD# SEQUENCE# BYTES MEMBERS ARC STATUS FIRST_CHANGE# FIRST_TIM---------- ---------- ---------- ---------- ---------- --- -------- ------------- --------- 1 1 18 209715200 2 YES INACTIVE 486960 09-MAR-09 2 1 19 209715200 2 YES INACTIVE 486964 09-MAR-09 3 1 21 209715200 2 NO CURRENT 486973 09-MAR-09 4 1 20 52428800 2 YES INACTIVE 486968 09-MAR-09sys@ora11g>alter database drop logfile member '/oracle/u02/oradata/ora11g/redo04_02.log';Database altered.sys@ora11g> !ls -l /oracle/u02/oradata/ora11g/redo04_02.log-rw-r----- 1 oracle oinstall 52429312 Mar 9 16:28 /oracle/u02/oradata/ora11g/redo04_02.logsys@ora11g>!rm -f /oracle/u02/oradata/ora11g/redo04_02.logsys@ora11g> select * from v$logfile order by 1,4; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ------------------------------------------ --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01_01.log NO 1 ONLINE /oracle/u02/oradata/ora11g/redo01_02.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_01.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_02.log NO 4 ONLINE /oracle/u02/oradata/ora11g/redo04_01.log NO7 rows selected.6.删除一个非活动的重做日志组sys@ora11g>alter database drop logfile group 4;Database altered.sys@ora11g>!rm -f /oracle/u02/oradata/ora11g/redo04_01.logsys@ora11g> select * from v$logfile; GROUP# STATUS TYPE MEMBER IS_---------- ------- -------------------- ------------------------------------------ --- 1 ONLINE /oracle/u02/oradata/ora11g/redo01_01.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_01.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_01.log NO 1 ONLINE /oracle/u02/oradata/ora11g/redo01_02.log NO 2 ONLINE /oracle/u02/oradata/ora11g/redo02_02.log NO 3 ONLINE /oracle/u02/oradata/ora11g/redo03_02.log NO6 rows selected.7.强制切换日志sys@ora11g>alter system switch logfile;System altered.sys@ora11g>alter system archive log current;System altered.8.小结1)日志文件非常重要,当多路复用重做日志文件时,应该把一个组的成员保存在不同的磁盘上。2)在完成日志文件维护后一定要记得备份最新的控制文件!3)以上试验是在11g环境下完成的,在10g环境中一样适用。 Good luck.secooler 09.03.09-- The End -- 分类: OralceRac 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/07/25/2608680.html
Oracle移动重做日志的方法很简单,下面就为您详细介绍Oracle移动重做日志文件的方法,如果您对Oracle移动重做日志方面感兴趣的话,不妨一看。 $ sqlplus '/as sysdba' #关闭数据库。 SQL> shutdown immediate #cp日志文件到目标位置。 SQL> !cp /opt/oracle/oradata/redo* /opt/oracle/oratest/ #让数据库以mount模式启动。 SQL>startup mount; #修改数据库中日志文件的位置 SQL> alter database rename file '/opt/oracle/oradata/redo01.log' to '/opt/oracle/oratest/redo01.log' SQL> alter database rename file '/opt/oracle/oradata/redo02.log' to '/opt/oracle/oratest/redo02.log' SQL> alter database rename file '/opt/oracle/oradata/redo03.log' to '/opt/oracle/oratest/redo03.log' #修改数据库的状态。 SQL> alter database open; #查看修改结果。 SQL> select * from v$logfile; 分类: OralceRac 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/07/25/2608372.html
[oracle@einyboy ~]$ sqlplus / as sysdba SQL*Plus: Release 10.2.0.1.0 - Production on Wed Jul 25 12:21:02 2012 Copyright (c) 1982, 2005, Oracle. All rights reserved. Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production With the Partitioning, OLAP and Data Mining options SQL> show parameter undo NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_management string AUTO undo_retention integer 900 undo_tablespace string UNDOTBS1 SQL> alter system set undo_retention=1200 scope=both; System altered. SQL> show parameter undo NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ undo_management string AUTO undo_retention integer 1200 undo_tablespace string UNDOTBS1 SQL> 分类: OralceRac 本文转自einyboy博客园博客,原文链接:http://www.cnblogs.com/einyboy/archive/2012/07/25/2608354.html