2009年4月9日
#
http://www.iteye.com/topic/930648
RBAC(Role-Based Access Control,基于角色的訪問(wèn)控制),就是用戶通過(guò)角色與權(quán)限進(jìn)行關(guān)聯(lián)。簡(jiǎn)單地說(shuō),一個(gè)用戶擁有若干角色,每一個(gè)角色擁有若干權(quán)限。這樣,就構(gòu)造成“用戶-角色-權(quán)限”的授權(quán)模型。在這種模型中,用戶與角色之間,角色與權(quán)限之間,一般者是多對(duì)多的關(guān)系。(如下圖)

角色是什么?可以理解為一定數(shù)量的權(quán)限的集合,權(quán)限的載體。例如:一個(gè)論壇系統(tǒng),“超級(jí)管理員”、“版主”都是角色。版主可管理版內(nèi)的帖子、可管理版內(nèi)的用戶等,這些是權(quán)限。要給某個(gè)用戶授予這些權(quán)限,不需要直接將權(quán)限授予用戶,可將“版主”這個(gè)角色賦予該用戶。
當(dāng)用戶的數(shù)量非常大時(shí),要給系統(tǒng)每個(gè)用戶逐一授權(quán)(授角色),是件非常煩瑣的事情。這時(shí),就需要給用戶分組,每個(gè)用戶組內(nèi)有多個(gè)用戶。除了可給用戶授權(quán)外,還可以給用戶組授權(quán)。這樣一來(lái),用戶擁有的所有權(quán)限,就是用戶個(gè)人擁有的權(quán)限與該用戶所在用戶組擁有的權(quán)限之和。(下圖為用戶組、用戶與角色三者的關(guān)聯(lián)關(guān)系)

在應(yīng)用系統(tǒng)中,權(quán)限表現(xiàn)成什么?對(duì)功能模塊的操作,對(duì)上傳文件的刪改,菜單的訪問(wèn),甚至頁(yè)面上某個(gè)按鈕、某個(gè)圖片的可見(jiàn)性控制,都可屬于權(quán)限的范疇。有些權(quán)限設(shè)計(jì),會(huì)把功能操作作為一類(lèi),而把文件、菜單、頁(yè)面元素等作為另一類(lèi),這樣構(gòu)成“用戶-角色-權(quán)限-資源”的授權(quán)模型。而在做數(shù)據(jù)表建模時(shí),可把功能操作和資源統(tǒng)一管理,也就是都直接與權(quán)限表進(jìn)行關(guān)聯(lián),這樣可能更具便捷性和易擴(kuò)展性。(見(jiàn)下圖)

請(qǐng)留意權(quán)限表中有一列“權(quán)限類(lèi)型”,我們根據(jù)它的取值來(lái)區(qū)分是哪一類(lèi)權(quán)限,如“MENU”表示菜單的訪問(wèn)權(quán)限、“OPERATION”表示功能模塊的操作權(quán)限、“FILE”表示文件的修改權(quán)限、“ELEMENT”表示頁(yè)面元素的可見(jiàn)性控制等。
這樣設(shè)計(jì)的好處有二。其一,不需要區(qū)分哪些是權(quán)限操作,哪些是資源,(實(shí)際上,有時(shí)候也不好區(qū)分,如菜單,把它理解為資源呢還是功能模塊權(quán)限呢?)。其二,方便擴(kuò)展,當(dāng)系統(tǒng)要對(duì)新的東西進(jìn)行權(quán)限控制時(shí),我只需要建立一個(gè)新的關(guān)聯(lián)表“權(quán)限XX關(guān)聯(lián)表”,并確定這類(lèi)權(quán)限的權(quán)限類(lèi)型字符串。
這里要注意的是,權(quán)限表與權(quán)限菜單關(guān)聯(lián)表、權(quán)限菜單關(guān)聯(lián)表與菜單表都是一對(duì)一的關(guān)系。(文件、頁(yè)面權(quán)限點(diǎn)、功能操作等同理)。也就是每添加一個(gè)菜單,就得同時(shí)往這三個(gè)表中各插入一條記錄。這樣,可以不需要權(quán)限菜單關(guān)聯(lián)表,讓權(quán)限表與菜單表直接關(guān)聯(lián),此時(shí),須在權(quán)限表中新增一列用來(lái)保存菜單的ID,權(quán)限表通過(guò)“權(quán)限類(lèi)型”和這個(gè)ID來(lái)區(qū)分是種類(lèi)型下的哪條記錄。
到這里,RBAC權(quán)限模型的擴(kuò)展模型的完整設(shè)計(jì)圖如下:

隨著系統(tǒng)的日益龐大,為了方便管理,可引入角色組對(duì)角色進(jìn)行分類(lèi)管理,跟用戶組不同,角色組不參與授權(quán)。例如:某電網(wǎng)系統(tǒng)的權(quán)限管理模塊中,角色就是掛在區(qū)局下,而區(qū)局在這里可當(dāng)作角色組,它不參于權(quán)限分配。另外,為方便上面各主表自身的管理與查找,可采用樹(shù)型結(jié)構(gòu),如菜單樹(shù)、功能樹(shù)等,當(dāng)然這些可不需要參于權(quán)限分配。
http://developer.51cto.com/art/200907/136668.htmspring 中已經(jīng)提供了很好的實(shí)現(xiàn),所以這又省去了很多的功夫,接下來(lái)看看
iBATIS是如何支持
Clob和blob的。
iBATIS提供了TypeHandler接口,用于處理數(shù)據(jù)類(lèi)型,基本的實(shí)現(xiàn)類(lèi)為BaseTypeHandler
在spring 中,提供了AbstractLobTypeHandler作為基礎(chǔ)類(lèi),并且提供了相應(yīng)的模版方法,所有的工作由LobHandler處理。
BlobByteArrayTypeHandler 主要用于處理blob類(lèi)型數(shù)據(jù),使用byte[]來(lái)映射相應(yīng)的Blob
ClobStringTypeHandler 用于處理Clob類(lèi)型數(shù)據(jù),使用字符串來(lái)映射Clob
有一點(diǎn)需要注意的是,AbstractLobTypeHandler中實(shí)現(xiàn)了事務(wù)支持,需要用來(lái)釋放相應(yīng)的資源,所以一定需要在事務(wù)環(huán)境中進(jìn)行。
下面是一個(gè)簡(jiǎn)單的例子:
- public class Food {
- private String content;
-
- private String id;
-
- private byte[] image;
-
- private String name;
- ...
- }
xml如下:說(shuō)明一下,在resultMap中可以通過(guò)typeHandler來(lái)指定具體的handler.在inline變量中,可以通過(guò)handler來(lái)定義相應(yīng)的typeHandler
- ﹤sqlMap namespace="Food"﹥
-
- ﹤typeAlias alias="Food" type="org.esoft.hdb.bo.Food"/﹥
- ﹤resultMap id="foodResult" class="Food"﹥
- ﹤result property="id" column="C_ID"/﹥
- ﹤result property="name" column="C_NAME"/﹥
- ﹤result property="content" column="C_content"
- typeHandler="org.springframework.orm.ibatis.support.ClobStringTypeHandler"/﹥
- ﹤result property="image" column="C_image"
- typeHandler="org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler"/﹥
- ﹤/resultMap﹥
- ﹤sql id="foodFragment"﹥select C_ID,C_NAME,C_CONTENT,C_IMAGE from T_FOOD﹤/sql﹥
- ﹤select id="getAll" resultMap="foodResult"﹥
- ﹤include refid="foodFragment"/﹥
- ﹤/select﹥
- ﹤select id="selectById" parameterClass="string" resultMap="foodResult"﹥
- ﹤include refid="foodFragment"/﹥ where C_ID=#id#﹤/select﹥
-
- ﹤insert id="insert" parameterClass="Food"﹥ insert into T_FOOD ( C_ID,
- C_NAME,C_CONTENT, C_IMAGE) values ( #id#,
- #name#,#content,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#,
- #image,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#)
- ﹤/insert﹥
-
- ﹤update id="update" parameterClass="Food"﹥ update T_FOOD set C_NAME = #name#,
- C_CONTENT =
- #content,handler=org.springframework.orm.ibatis.support.ClobStringTypeHandler#,
- C_IMAGE =
- #image,handler=org.springframework.orm.ibatis.support.BlobByteArrayTypeHandler#
- where C_ID = #id# ﹤/update﹥
-
- ﹤delete id="deleteById" parameterClass="string"﹥ delete from T_FOOD where C_ID = #id#
- ﹤/delete﹥
-
- ﹤/sqlMap﹥
-
-
- public interface FoodService {
-
-
- void save(Food food);
- Food get(String id);
- /**
- * @param food
- */
- void update(Food food);
- }
-
- public class FoodServiceImpl implements FoodService {
- private FoodDAO foodDAO;
-
- private DaoCreator creator;
-
- public void setCreator(DaoCreator creator) {
- this.creator = creator;
- }
-
- protected FoodDAO getFoodDAO() {
- if (foodDAO == null) {
- foodDAO = (FoodDAO) creator.createDao(FoodDAO.class, Food.class);
- }
- return foodDAO;
- }
-
- public Food get(String id) {
- return getFoodDAO().get(id);
- }
- public void save(Food food) {
- getFoodDAO().save(food);
- }
- public void update(Food food) {
- getFoodDAO().update(food);
- }
-
- }
-
- spring xml 配置:
-
- 。。。
- ﹤bean id="lobHandler"
- class="org.springframework.jdbc.support.lob.DefaultLobHandler"/﹥
-
- ﹤bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager"﹥
- ﹤property name="dataSource" ref="dataSource"/﹥
- ﹤/bean﹥
-
- ﹤bean id="sqlMapClient"
- class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"﹥
- ﹤property name="dataSource" ref="dataSource"/﹥
- ﹤property name="configLocation"﹥
- ﹤value﹥SqlMapConfig.xml﹤/value﹥
- ﹤/property﹥
- ﹤property name="lobHandler" ref="lobHandler"/﹥
- ﹤/bean﹥
-
- ﹤bean id="daoCreate" class="org.esoft.hdb.ibatis.IbatisDaoCreator"﹥
- ﹤property name="sqlMapClient" ref="sqlMapClient"/﹥
- ﹤/bean﹥
-
- ﹤bean id="foodService" class="org.esoft.hdb.service.FoodServiceImpl"﹥
- ﹤property name="creator" ref="daoCreate"/﹥
- ﹤/bean﹥
-
-
- ﹤aop:config﹥
- ﹤aop:pointcut id="foodServiceMethods"
- expression="execution(* org.esoft.hdb.service.FoodService.*(..))"/﹥
- ﹤aop:advisor advice-ref="txAdvice" pointcut-ref="foodServiceMethods"/﹥
- ﹤/aop:config﹥
- ﹤tx:advice id="txAdvice" transaction-manager="transactionManager"﹥
- ﹤tx:attributes﹥
- ﹤tx:method name="*" propagation="REQUIRED"/﹥
- ﹤/tx:attributes﹥
- ﹤/tx:advice﹥
簡(jiǎn)單的測(cè)試:
- save :
- Food food = new Food();
- food.setPk("1");
- food.setName("food1");
- BufferedInputStream in = new BufferedInputStream(getClass()
- .getResourceAsStream("/1.gif"));
- byte[] b = FileCopyUtils.copyToByteArray(in);
- food.setImage(b);
- in = new BufferedInputStream(getClass().getResourceAsStream(
- "/hibernate.cfg.xml"));
- b = FileCopyUtils.copyToByteArray(in);
- food.setContent(new String(b));
- foodService.save(food);
- update:
- Food food = foodService.get("1");
- BufferedInputStream in = new BufferedInputStream(getClass()
- .getResourceAsStream("/jdbc.properties"));
- byte[] b = FileCopyUtils.copyToByteArray(in);
- food.setContent(new String(b));
- foodService.update(food);
- food = foodService.get("1");
- assertNotNull(food.getImage());
select sess.sid,
sess.serial#,
lo.oracle_username,
lo.os_user_name,
ao.object_name,
lo.locked_mode
from v$locked_object lo,
dba_objects ao,
v$session sess
where ao.object_id = lo.object_id and lo.session_id = sess.SID;獲得未提交的事物的列表和基礎(chǔ)信息
然后根據(jù) sessionID和serial#號(hào)強(qiáng)制關(guān)閉事物:
ALTER SYSTEM KILL SESSION '9,108';
--'9,108'為sessionID和serial#號(hào),逗號(hào)分開(kāi)
http://www.javaeye.com/topic/37302
類(lèi)與類(lèi)之間的關(guān)系對(duì)于理解面向?qū)ο缶哂泻苤匾淖饔茫郧霸诿嬖嚨臅r(shí)候也經(jīng)常被問(wèn)到這個(gè)問(wèn)題,在這里我就介紹一下。
類(lèi)與類(lèi)之間存在以下關(guān)系:
(1)泛化(Generalization)
(2)關(guān)聯(lián)(Association)
(3)依賴(lài)(Dependency)
(4)聚合(Aggregation)
UML圖與應(yīng)用代碼例子:
1.泛化(Generalization)
[泛化]
表示類(lèi)與類(lèi)之間的繼承關(guān)系,接口與接口之間的繼承關(guān)系,或類(lèi)對(duì)接口的實(shí)現(xiàn)關(guān)系。一般化的關(guān)系是從子類(lèi)指向父類(lèi)的,與繼承或?qū)崿F(xiàn)的方法相反。
[具體表現(xiàn)]
父類(lèi) 父類(lèi)實(shí)例=new 子類(lèi)()
[UML圖](圖1.1)


圖1.1 Animal類(lèi)與Tiger類(lèi),Dog類(lèi)的泛化關(guān)系
[代碼表現(xiàn)]
- class Animal{}
- class Tiger extends Animal{}
- public class Test
- {
- public void test()
- {
- Animal a=new Tiger();
- }
- }
2.依賴(lài)(Dependency)
[依賴(lài)]
對(duì)于兩個(gè)相對(duì)獨(dú)立的對(duì)象,當(dāng)一個(gè)對(duì)象負(fù)責(zé)構(gòu)造另一個(gè)對(duì)象的實(shí)例,或者依賴(lài)另一個(gè)對(duì)象的服務(wù)時(shí),這兩個(gè)對(duì)象之間主要體現(xiàn)為依賴(lài)關(guān)系。
[具體表現(xiàn)]
依賴(lài)關(guān)系表現(xiàn)在局部變量,方法的參數(shù),以及對(duì)靜態(tài)方法的調(diào)用
[現(xiàn)實(shí)例子]
比如說(shuō)你要去擰螺絲,你是不是要借助(也就是依賴(lài))螺絲刀(Screwdriver)來(lái)幫助你完成擰螺絲(screw)的工作
[UML表現(xiàn)](圖1.2)

圖1.2 Person類(lèi)與Screwdriver類(lèi)的依賴(lài)關(guān)系
[代碼表現(xiàn)]
- public class Person{
-
- public void screw(Screwdriver screwdriver){
- screwdriver.screw();
- }
- }
3.關(guān)聯(lián)(Association)
[關(guān)聯(lián)]
對(duì)于兩個(gè)相對(duì)獨(dú)立的對(duì)象,當(dāng)一個(gè)對(duì)象的實(shí)例與另一個(gè)對(duì)象的一些特定實(shí)例存在固定的對(duì)應(yīng)關(guān)系時(shí),這兩個(gè)對(duì)象之間為關(guān)聯(lián)關(guān)系。
[具體表現(xiàn)]
關(guān)聯(lián)關(guān)系是使用實(shí)例變量來(lái)實(shí)現(xiàn)
[現(xiàn)實(shí)例子]
比如客戶和訂單,每個(gè)訂單對(duì)應(yīng)特定的客戶,每個(gè)客戶對(duì)應(yīng)一些特定的訂單;再例如公司和員工,每個(gè)公司對(duì)應(yīng)一些特定的員工,每個(gè)員工對(duì)應(yīng)一特定的公司
[UML圖] (圖1.3)

圖1.3 公司和員工的關(guān)聯(lián)關(guān)系
[代碼表現(xiàn)]
- public class Company{
- private Employee employee;
- public Employee getEmployee(){
- return employee;
- }
- public void setEmployee(Employee employee){
- this.employee=employee;
- }
-
- public void run(){
- employee.startWorking();
- }
- }
(4)聚合(Aggregation)
[聚合]
當(dāng)對(duì)象A被加入到對(duì)象B中,成為對(duì)象B的組成部分時(shí),對(duì)象B和對(duì)象A之間為聚集關(guān)系。聚合是關(guān)聯(lián)關(guān)系的一種,是較強(qiáng)的關(guān)聯(lián)關(guān)系,強(qiáng)調(diào)的是整體與部分之間的關(guān)系。
[具體表現(xiàn)]
與關(guān)聯(lián)關(guān)系一樣,聚合關(guān)系也是通過(guò)實(shí)例變量來(lái)實(shí)現(xiàn)這樣關(guān)系的。關(guān)聯(lián)關(guān)系和聚合關(guān)系來(lái)語(yǔ)法上是沒(méi)辦法區(qū)分的,從語(yǔ)義上才能更好的區(qū)分兩者的區(qū)別。
[關(guān)聯(lián)與聚合的區(qū)別]
(1)關(guān)聯(lián)關(guān)系所涉及的兩個(gè)對(duì)象是處在同一個(gè)層次上的。比如人和自行車(chē)就是一種關(guān)聯(lián)關(guān)系,而不是聚合關(guān)系,因?yàn)槿瞬皇怯勺孕熊?chē)組成的。
聚合關(guān)系涉及的兩個(gè)對(duì)象處于不平等的層次上,一個(gè)代表整體,一個(gè)代表部分。比如電腦和它的顯示器、鍵盤(pán)、主板以及內(nèi)存就是聚集關(guān)系,因?yàn)橹靼迨请娔X的組成部分。
(2)對(duì)于具有聚集關(guān)系(尤其是強(qiáng)聚集關(guān)系)的兩個(gè)對(duì)象,整體對(duì)象會(huì)制約它的組成對(duì)象的生命周期。部分類(lèi)的對(duì)象不能單獨(dú)存在,它的生命周期依賴(lài)于整體類(lèi)的對(duì)象的生命周期,當(dāng)整體消失,部分也就隨之消失。比如張三的電腦被偷了,那么電腦的所有組件也不存在了,除非張三事先把一些電腦的組件(比如硬盤(pán)和內(nèi)存)拆了下來(lái)。
[UML圖](圖1.4)

圖1.3 電腦和組件的聚合關(guān)系
[代碼表現(xiàn)]
- public class Computer{
- private CPU cpu;
- public CPU getCPU(){
- return cpu;
- }
- public void setCPU(CPU cpu){
- this.cpu=cpu;
- }
-
- public void start(){
-
- cpu.run();
- }
- }
在快捷方式屬性-目標(biāo)里加入 -vm "%JAVA_HOME%/jre/bin/javaw.exe"
Oracle 10g Express Edition是Oracle專(zhuān)門(mén)為小型用戶提供的免費(fèi)版本。Oracle XE十分小巧,安裝簡(jiǎn)單,可供第三方軟件開(kāi)發(fā)商部署較小的應(yīng)用。
不過(guò)Oracle XE目前的beta2缺省安裝的字符集是WE8MSWIN1252,不是中文字符集,并且不能通過(guò)直接運(yùn)行 alter database character set ZHS16GBK ; 來(lái)修改,因?yàn)閆HS16GBK不是缺省字符集的超集。過(guò)去流傳很廣的直接修改sys用戶下的PROPS$表的方法,也會(huì)給字符集的變更留下很多潛在的問(wèn)題.
不過(guò)在安裝完Oracle XE后,可以在sqlplus(即Oracle XE的run SQL command line)中, 進(jìn)行如下的操作來(lái)修改字符集:
connect system/oracle9i as sysdba
shutdown immediate
startup mount
alter system enable restricted session ;
alter system set JOB_QUEUE_PROCESSES=0;
alter system set AQ_TM_PROCESSES=0;
alter database open ;
alter database character set internal_use ZHS16GBK ;
shutdown immediate
startup
這樣字符集的修改就完成了
摘自紅色黑客聯(lián)盟(www.7747.net) 原文:http://www.7747.net/px/200902/34068.html
在數(shù)據(jù)庫(kù)服務(wù)器上運(yùn)行 sqlplus system/password@xe (其中 system 是數(shù)據(jù)庫(kù)用戶無(wú)需改變;password 是數(shù)據(jù)庫(kù)密碼應(yīng)指定為實(shí)際密碼;xe 是數(shù)據(jù)庫(kù)實(shí)例名稱(chēng)) ,然后執(zhí)行:
alter system set session_cached_cursors=200 scope=spfile;
alter system set session_max_open_files=200 scope=spfile;
alter system set sessions=20 scope=spfile;
alter system set license_max_sessions=200 scope=spfile;
alter system set license_sessions_warning=200 scope=spfile;
alter system set processes=200 scope=spfile;
執(zhí)行后,重啟 Oracle XE 數(shù)據(jù)庫(kù)實(shí)例即可。要重啟 Oracle XE 數(shù)據(jù)庫(kù)實(shí)例:
1. 如安裝于 Windows 上,先運(yùn)行 net stop oracleservicexe,再運(yùn)行 net start oracleservicexe 即可。也可通過(guò)“服務(wù)”管理控制臺(tái)重啟 OracleServiceXE 服務(wù)。
2. 如安裝于 Linux 上,先運(yùn)行 /etc/init.d/oracle-xe start,再運(yùn)行 /etc/init.d/oracle-xe stop 即可。
此時(shí),可以支持 179 個(gè)額外的連接會(huì)話。
選擇“運(yùn)行SQL命令”,進(jìn)入如下提示符
SQL>
首先連接到服務(wù)器
connect 用戶名/密碼
登陸后輸入如下命令:
sql 代碼
1.call dbms_xdb.cfg_update(updateXML(dbms_xdb.cfg_get(),'/xdbconfig/sysconfig/protocolconfig/httpconfig/http-port/text()',8081));
其中8081是修改后的端口,可以任意。
這樣你就不會(huì)與Tomcat的默認(rèn)端口沖突了,方便開(kāi)發(fā)。
ftp服務(wù)占用2100端口,更改命令是:
sql 代碼
1.call dbms_xdb.cfg_update(updateXML(dbms_xdb.cfg_get() , '/xdbconfig/sysconfig/protocolconfig/ftpconfig/ftp-port/text()', 2111));
1. 把插件文件直接覆蓋到eclipse目錄里
2. 使用link文件,就是把插件存放到任一的地方(例如/eclipse/MyPuls),然后 在eclipse的文件夾里新建一個(gè)links的文件,在里面添加一些后追名為.link的文件(例如emfPlugins.link)結(jié)構(gòu)是這樣的:
/eclipse/
links/
emfPlugins.link
webtools.link
updateManager.link
...
...
link文件的里包含這樣一條 “path=D:\\JavaDev\\plugins\\vssplugin”這個(gè)路徑就是插件的存放路徑。
3. 使用eclipse自帶的圖形界面的插件安裝方法:選擇Help > Software Updates > Manager Configuration
在選擇Add > Extension Location 找到你要安裝插件的目錄就可以了。強(qiáng)烈推薦這種方法,優(yōu)點(diǎn)很多比如可以方便的添加刪除,也不用自己寫(xiě)link文件!
備注:Eclipse插件的目錄結(jié)構(gòu)
/eclipse-plugins/
eclipse/
.eclipseextension
features/
plugins/
第2、3種方法所指向的目錄都指的是"eclipse"目錄,
如果用第3種方法,在eclipse這個(gè)目錄下必須有文件.eclipseextension,如果你下的插件沒(méi)有這個(gè)文件,那就隨便eclipse安裝目錄下的那個(gè)文件靠過(guò)去就行了!只有有這么個(gè)文件就可以了,內(nèi)容沒(méi)什么用,主要是一些版本信息!例如:
id=org.eclipse.platform name=Eclipse Platformversion=3.3.1
創(chuàng)建XMLHtttRequest對(duì)象(針對(duì)mozilla,IE8,FF,IE5,IE5.5,IE6,IE7)
//2、創(chuàng)建XMLHttpRequest對(duì)象
//這其實(shí)是XMLHttpReqest對(duì)象使用最復(fù)雜的一步
//針對(duì)IE和其他類(lèi)型瀏覽器建立這個(gè)對(duì)象的不同方式寫(xiě)不同的代碼
if(window.XMLHttpRequest){
//針對(duì)firefox,mozillaz,opera,IE7,IE8
xmlhttp = new XMLHttpRequest();
//用于修復(fù)某些Mozillaz瀏覽器bug
if(xmlhttp.overrideMimeType)
{
xmlhttp.overrideMimeType("text/xml");
}
}
else if(window.ActiveXObject){
//針對(duì)IE6,IE5.5,IE5
//兩個(gè)都可以創(chuàng)建XMLHttpRequest對(duì)象,保存在js數(shù)組中
var activeName=["MSXML2.XMLHTTP","Microsoft.XMLHTTP"];
//var activeName= ['MSXML2.XMLHTTP.6.0','MSXML2.XMLHTTP.5.0', //'MSXML2.XMLHTTP.4.0','MSXML2.XMLHTTP.3.0', //'MSXML2.XMLHTTP','Microsoft.XMLHTTP'];
for(var i =0;i<activeName.length;i++)
{//取出一個(gè)控件名來(lái)創(chuàng)建XMLHttpRequest對(duì)象,創(chuàng)建成功就終止循環(huán),如果創(chuàng)建失敗可以繼續(xù)創(chuàng)建
//可以拋出異常,繼續(xù)創(chuàng)建
try{
xmlhttp= new ActiveXObject(activeName[i]);
break;
}catch(e){
}
}
}
//確認(rèn)XMLHttpRequest對(duì)象已經(jīng)創(chuàng)建成功
if(!xmlhttp)
{
alert("XmlHttpRequest創(chuàng)建失敗");
return;
}
//3、注冊(cè)回調(diào)函數(shù),函數(shù)名后面不要加括號(hào)
//如果加了括號(hào),就變成了調(diào)用函數(shù),會(huì)把函數(shù)的返回值發(fā)揮給xmlhttp,沒(méi)有達(dá)到我們的目的
xmlhttp.onreadystatechange=callback;
//4、設(shè)置連接信息
//第一個(gè)參數(shù)設(shè)置http請(qǐng)求方式,主要是get和post兩種方式
//第二個(gè)參數(shù)是uri地址
//第三個(gè)參數(shù)表示異步交互還是同步交互方式,true表示異步,false表示同步
xmlhttp.open("GET","/JQuery/servlet/AjaxServlet?name="+username,true);
//5、發(fā)送數(shù)據(jù)開(kāi)始和服務(wù)器端交互
//同步方式下,send這句話會(huì)在服務(wù)器端的數(shù)據(jù)回來(lái)后,才執(zhí)行完
//異步方式下,send會(huì)立即執(zhí)行完
xmlhttp.send(null);
}
//5、寫(xiě)回調(diào)函數(shù)
//回調(diào)函數(shù)
function callback(){
//接收相應(yīng)的相應(yīng)數(shù)據(jù)
//判斷交互狀態(tài)已經(jīng)完成
if(xmlhttp.readyState ==4)
{
//判斷http的交互狀態(tài)
if(xmlhttp.status == 200)
{
//獲取服務(wù)器端返回的數(shù)據(jù)
//獲取服務(wù)器端純文本數(shù)據(jù)
var responseText = xmlhttp.responseText;
//將數(shù)據(jù)顯示在頁(yè)面上
//通過(guò)dom獲取div元素節(jié)點(diǎn)
var divNode =document.getElementById("result");
//設(shè)置元素節(jié)點(diǎn)的html內(nèi)容
divNode.innerHTML=responseText;
}
}
1,<meta name="Robots" contect="all|none|index|noindex|follow|nofollow"> 默認(rèn)是all
其中的屬性說(shuō)明如下:
設(shè)定為all:文件將被檢索,且頁(yè)面上的鏈接可以被查詢(xún);
設(shè)定為none:文件將不被檢索,且頁(yè)面上的鏈接不可以被查詢(xún);
設(shè)定為index:文件將被檢索;
設(shè)定為follow:頁(yè)面上的鏈接可以被查詢(xún);
設(shè)定為noindex:文件將不被檢索,但頁(yè)面上的鏈接可以被查詢(xún);
設(shè)定為nofollow:文件將不被檢索,頁(yè)面上的鏈接可以被查詢(xún)。
2,revisit-after (重訪)
<META name="revisit-after" CONTENT="7 days" >
通知搜索引擎多少天訪問(wèn)一次
其他的:
<META NAME="GENERATOR" CONTENT="Macromedia Dreamweaver MX">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<Meta http-equiv="Content-Language" Content="zh-CN">
<Meta http-equiv="Refresh" Content="5; Url=http://hi.baidu.com/pihi">
<Meta http-equiv="Expires" Content="Wed, 26 Feb 1997 08:21:57 GMT">
<meta http-equiv="cache-control" content="no-cache">
<META name="keywords" content="關(guān)鍵字">
<meta name="description" content="描述">
<meta name="author" content="作者">
<meta name="build" content="日期">
<meta name="coprright" content="版權(quán)">
<meta name="reply-to" content="email">
<meta name="robots" content="all">
<meta http-equiv="Page-Enter" content="RevealTrans (Duration=3, Transition=23)">
<meta http-equiv="Page-Exit" content="RevealTrans (Duration=3, Transition=23)">
<link rel="shortcut icon" href="favicon.ico">
------------------------------------------------------------------------------------------------------------
meta標(biāo)簽分兩大部分:HTTP標(biāo)題信息(HTTP-EQUIV)和頁(yè)面描述信息(NAME)。
1、Content-Type和Content-Language (顯示字符集的設(shè)定)
說(shuō)明:設(shè)定頁(yè)面使用的字符集,用以說(shuō)明主頁(yè)制作所使用的文字已經(jīng)語(yǔ)言,瀏覽器會(huì)根據(jù)此來(lái)調(diào)用相應(yīng)的字符集顯示page內(nèi)容。
注意: 該meta標(biāo)簽定義了HTML頁(yè)面所使用的字符集為GB2132,就是國(guó)標(biāo)漢字碼。如果將其中的“charset=GB2312”替換成“BIG5”,則該頁(yè)面所用的字符集就是繁體中文Big5碼。當(dāng)你瀏覽一些國(guó)外的站點(diǎn)時(shí),IE瀏覽器會(huì)提示你要正確顯示該頁(yè)面需要下載xx語(yǔ)支持。這個(gè)功能就是通過(guò)讀取HTML頁(yè)面Meta標(biāo)簽的Content-Type屬性而得知需要使用哪種字符集顯示該頁(yè)面的。如果系統(tǒng)里沒(méi)有裝相應(yīng)的字符集,則IE就提示下載。其他的語(yǔ)言也對(duì)應(yīng)不同的charset,比如日文的字符集是“iso-2022-jp ”,韓文的是“ks_c_5601”。
Charset選項(xiàng):ISO-8859-1(英文)、BIG5、UTF-8、SHIFT-Jis、Euc、Koi8-2、us-ascii, x-mac-roman, iso-8859-2, x-mac-ce, iso-2022-jp, x-sjis, x-euc-jp,euc-kr, iso-2022-kr, gb2312, gb_2312-80, x-euc-tw, x-cns11643-1,x-cns11643-2等字符集;Content-Language的Content還可以是:EN、FR等語(yǔ)言代碼。
2、Refresh (刷新)
3、Expires (期限)
說(shuō)明:指定網(wǎng)頁(yè)在緩存中的過(guò)期時(shí)間,一旦網(wǎng)頁(yè)過(guò)期,必須到服務(wù)器上重新調(diào)閱。
注意:必須使用GMT的時(shí)間格式,或直接設(shè)為0(數(shù)字表示多少時(shí)間后過(guò)期)。
4、Pragma (cach模式)
說(shuō)明:禁止瀏覽器從本地機(jī)的緩存中調(diào)閱頁(yè)面內(nèi)容。
注意:網(wǎng)頁(yè)不保存在緩存中,每次訪問(wèn)都刷新頁(yè)面。這樣設(shè)定,訪問(wèn)者將無(wú)法脫機(jī)瀏覽。
5、Set-Cookie (cookie設(shè)定)
說(shuō)明:瀏覽器訪問(wèn)某個(gè)頁(yè)面時(shí)會(huì)將它存在緩存中,下次再次訪問(wèn)時(shí)就可從緩存中讀取,以提高速度。當(dāng)你希望訪問(wèn)者每次都刷新你廣告的圖標(biāo),或每次都刷新你的計(jì)數(shù)器,就要禁用緩存了。通常HTML文件沒(méi)有必要禁用緩存,對(duì)于ASP等頁(yè)面,就可以使用禁用緩存,因?yàn)槊看慰吹降捻?yè)面都是在服務(wù)器動(dòng)態(tài)生成的,緩存就失去意義。如果網(wǎng)頁(yè)過(guò)期,那么存盤(pán)的cookie將被刪除。
用法:<Meta http-equiv="Set-Cookie" Content="cookievalue=xxx; expires=Wednesday,
21-Oct-98 16:14:21 GMT; path=/">
注意:必須使用GMT的時(shí)間格式。
6、Window-target (顯示窗口的設(shè)定)
說(shuō)明:強(qiáng)制頁(yè)面在當(dāng)前窗口以獨(dú)立頁(yè)面顯示。
用法:<Meta http-equiv="Widow-target" Content="_top">
注意:這個(gè)屬性是用來(lái)防止別人在框架里調(diào)用你的頁(yè)面。Content選項(xiàng):_blank、_top、_self、_parent。
7、Pics-label (網(wǎng)頁(yè)RSAC等級(jí)評(píng)定)
說(shuō)明:在IE的Internet選項(xiàng)中有一項(xiàng)內(nèi)容設(shè)置,可以防止瀏覽一些受限制的網(wǎng)站,而網(wǎng)站的限制級(jí)
別就是通過(guò)該參數(shù)來(lái)設(shè)置的。
用法:<META http-equiv="Pics-label" Contect=
"(PICS-1.1'http://www.rsac.org/ratingsv01.html'
I gen comment 'RSACi North America Sever' by 'inet@microsoft.com'
for 'http://www.microsoft.com' on '1997.06.30T14:21-0500' r(n0 s0 v0 l0))">
注意:不要將級(jí)別設(shè)置的太高。RSAC的評(píng)估系統(tǒng)提供了一種用來(lái)評(píng)價(jià)Web站點(diǎn)內(nèi)容的標(biāo)準(zhǔn)。用戶可以設(shè)置Microsoft Internet Explorer(IE3.0以上)來(lái)排除包含有色情和暴力內(nèi)容的站點(diǎn)。上面這個(gè)例子中的HTML取自Microsoft的主頁(yè)。代碼中的(n 0 s 0 v 0 l 0)表示該站點(diǎn)不包含不健康內(nèi)容。級(jí)別的評(píng)定是由RSAC,即美國(guó)娛樂(lè)委員會(huì)的評(píng)級(jí)機(jī)構(gòu)評(píng)定的,如果你想進(jìn)一步了解RSAC評(píng)估系統(tǒng)的等級(jí)內(nèi)容,或者你需要評(píng)價(jià)自己的網(wǎng)站,可以訪問(wèn)RSAC的站點(diǎn):http://www.rsac.org/。
8、Page-Enter、Page-Exit (進(jìn)入與退出)
說(shuō)明:這個(gè)是頁(yè)面被載入和調(diào)出時(shí)的一些特效。
用法:<Meta http-equiv="Page-Enter" Content="blendTrans(Duration=0.5)">
<Meta http-equiv="Page-Exit" Content="blendTrans(Duration=0.5)">
注意:blendTrans是動(dòng)態(tài)濾鏡的一種,產(chǎn)生漸隱效果。另一種動(dòng)態(tài)濾鏡RevealTrans也可以用于頁(yè)面進(jìn)入與退出效果:
<Meta http-equiv="Page-Enter" Content="revealTrans(duration=x, transition=y)">
<Meta http-equiv="Page-Exit" Content="revealTrans(duration=x, transition=y)">
Duration 表示濾鏡特效的持續(xù)時(shí)間(單位:秒)
Transition 濾鏡類(lèi)型。表示使用哪種特效,取值為0-23。
0 矩形縮小
1 矩形擴(kuò)大
2 圓形縮小
3 圓形擴(kuò)大
4 下到上刷新
5 上到下刷新
6 左到右刷新
7 右到左刷新
8 豎百葉窗
9 橫百葉窗
10 錯(cuò)位橫百葉窗
11 錯(cuò)位豎百葉窗
12 點(diǎn)擴(kuò)散
13 左右到中間刷新
14 中間到左右刷新
15 中間到上下
16 上下到中間
17 右下到左上
18 右上到左下
19 左上到右下
20 左下到右上
21 橫條
22 豎條
23 以上22種隨機(jī)選擇一種
9、MSThemeCompatible (XP主題)
說(shuō)明:是否在IE中關(guān)閉 xp 的主題
用法:<Meta http-equiv="MSThemeCompatible" Content="Yes">
注意:關(guān)閉 xp 的藍(lán)色立體按鈕系統(tǒng)顯示樣式,從而和win2k 很象。
10、IE6 (頁(yè)面生成器)
說(shuō)明:頁(yè)面生成器generator,是ie6
用法:<Meta http-equiv="IE6" Content="Generator">
注意:用什么東西做的,類(lèi)似商品出廠廠商。
11、Content-Script-Type (腳本相關(guān))
說(shuō)明:這是近來(lái)W3C的規(guī)范,指明頁(yè)面中腳本的類(lèi)型。
用法:<Meta http-equiv="Content-Script-Type" Content="text/javascript">
★NAME變量
name是描述網(wǎng)頁(yè)的,對(duì)應(yīng)于Content(網(wǎng)頁(yè)內(nèi)容),以便于搜索引擎機(jī)器人查找、分類(lèi)(目前幾乎所有的搜索引擎都使用網(wǎng)上機(jī)器人自動(dòng)查找meta值來(lái)給網(wǎng)頁(yè)分類(lèi))。
name的value值(name="")指定所提供信息的類(lèi)型。有些值是已經(jīng)定義好的。例如description(說(shuō)明)、keyword(關(guān)鍵字)、refresh(刷新)等。還可以指定其他任意值,如:creationdate(創(chuàng)建日期) 、
document ID(文檔編號(hào))和level(等級(jí))等。
name的content指定實(shí)際內(nèi)容。如:如果指定level(等級(jí))為value(值),則Content可能是beginner(初級(jí))、intermediate(中級(jí))、advanced(高級(jí))。
1、Keywords (關(guān)鍵字)
說(shuō)明:為搜索引擎提供的關(guān)鍵字列表
用法:<Meta name="Keywords" Content="關(guān)鍵詞1,關(guān)鍵詞2,關(guān)鍵詞3,關(guān)鍵詞4,……">
注意:各關(guān)鍵詞間用英文逗號(hào)“,”隔開(kāi)。META的通常用處是指定搜索引擎用來(lái)提高搜索質(zhì)量的關(guān)鍵詞。當(dāng)數(shù)個(gè)META元素提供文檔語(yǔ)言從屬信息時(shí),搜索引擎會(huì)使用lang特性來(lái)過(guò)濾并通過(guò)用戶的語(yǔ)言?xún)?yōu)先參照來(lái)顯示搜索結(jié)果。例如:
<Meta name="Kyewords" Lang="EN" Content="vacation,greece,sunshine">
<Meta name="Kyewords" Lang="FR" Content="vacances,grè:ce,soleil">
2、Description (簡(jiǎn)介)
說(shuō)明:Description用來(lái)告訴搜索引擎你的網(wǎng)站主要內(nèi)容。
用法:<Meta name="Description" Content="你網(wǎng)頁(yè)的簡(jiǎn)述">
注意:
3、Robots (機(jī)器人向?qū)?
說(shuō)明:Robots用來(lái)告訴搜索機(jī)器人哪些頁(yè)面需要索引,哪些頁(yè)面不需要索引。Content的參數(shù)有all、none、index、noindex、follow、nofollow。默認(rèn)是all。
用法:<Meta name="Robots" Content="All|None|Index|Noindex|Follow|Nofollow">
注意:許多搜索引擎都通過(guò)放出robot/spider搜索來(lái)登錄網(wǎng)站,這些robot/spider就要用到meta元素的一些特性來(lái)決定怎樣登錄。
all:文件將被檢索,且頁(yè)面上的鏈接可以被查詢(xún);
none:文件將不被檢索,且頁(yè)面上的鏈接不可以被查詢(xún);(和 "noindex, no follow" 起相同作用)
index:文件將被檢索;(讓robot/spider登錄)
follow:頁(yè)面上的鏈接可以被查詢(xún);
noindex:文件將不被檢索,但頁(yè)面上的鏈接可以被查詢(xún);(不讓robot/spider登錄)
nofollow:文件將不被檢索,頁(yè)面上的鏈接可以被查詢(xún)。(不讓robot/spider順著此頁(yè)的連接往下探找)
4、Author (作者)
說(shuō)明:標(biāo)注網(wǎng)頁(yè)的作者或制作組
用法:<Meta name="Author" Content="張三,abc@sina.com">
注意:Content可以是:你或你的制作組的名字,或Email
5、Copyright (版權(quán))
說(shuō)明:標(biāo)注版權(quán)
用法:<Meta name="Copyright" Content="本頁(yè)版權(quán)歸Zerospace所有。All Rights Reserved">
注意:
6、Generator (編輯器)
說(shuō)明:編輯器的說(shuō)明
用法:<Meta name="Generator" Content="PCDATA|FrontPage|">
注意:Content="你所用編輯器"
7、revisit-after (重訪)
說(shuō)明:
用法:<META name="revisit-after" CONTENT="7 days" >
PostgreSQL支持管理員直接手動(dòng)安裝數(shù)據(jù)庫(kù),給用戶提供了更大的方便。
1. 在PostgreSQL官方網(wǎng)站上下載免安裝二進(jìn)制的包,名字類(lèi)似于postgresql-*.*.*.*-binaries-no-installer.tar.gz之類(lèi)的。
下載到本地,解壓到某路徑PATH下。
2. 在PATH目錄中創(chuàng)建data文件夾,用于存放數(shù)據(jù)。
3. 開(kāi)始-->運(yùn)行-->cmd 進(jìn)入命令行。并cd到PATH\bin目錄下執(zhí)行下面的命令用來(lái)初始化數(shù)據(jù)庫(kù):
PATH\bin> initdb.exe -D PATH\data -E UTF8 --locale=C
4. 將pgsql注冊(cè)為windows服務(wù),便于操作和控制:
PATH\bin> pg_ctl.exe register -D PATH\data -N pgsql
其中-N參數(shù)用來(lái)設(shè)置pgsql作為windows服務(wù)的名稱(chēng)。
5. 啟動(dòng)和關(guān)閉數(shù)據(jù)庫(kù),在命令行下:
> net start pgsql (開(kāi)啟數(shù)據(jù)庫(kù))
> net stop pgsql (關(guān)閉數(shù)據(jù)庫(kù))
注:為避免以后可能發(fā)生的亞州大字符集的亂碼問(wèn)題,統(tǒng)一使用UTF8編碼。
需要一個(gè)非管理員帳號(hào)來(lái)運(yùn)行PostgreSQL?
當(dāng)一個(gè)駭客通過(guò)軟件的缺陷獲得了侵入一臺(tái)計(jì)算機(jī)的入口時(shí),她獲得的是這個(gè)程序運(yùn)行所用用戶帳號(hào)的對(duì)應(yīng)權(quán)限。由于我們無(wú)法預(yù)知PostgreSQL中是否還存在這樣的bug,所以我們強(qiáng)制使用一個(gè)非管理員的服務(wù)帳號(hào)來(lái)最小化潛在的駭客利用此類(lèi)漏洞對(duì)系統(tǒng)進(jìn)行破壞的風(fēng)險(xiǎn)。這樣的設(shè)置已是Unix界的慣例做法,同時(shí)在Windows世界中,Microsoft以及其他供應(yīng)商也開(kāi)始采用這樣的做法來(lái)改進(jìn)他們系統(tǒng)的安全性。補(bǔ)充: 自PostgreSQL 8.2發(fā)行后,從管理帳號(hào)啟動(dòng)變得可行。PostgreSQL 8.2及后續(xù)版本會(huì)在啟動(dòng)后不可撤銷(xiāo)地放棄管理權(quán)限,從而保證了當(dāng)極端不可能事件,當(dāng)PostgreSQL受到入侵時(shí),系統(tǒng)的安全性。
<script type="text/javascript">
//** iframe自動(dòng)適應(yīng)頁(yè)面 **//
//輸入你希望根據(jù)頁(yè)面高度自動(dòng)調(diào)整高度的iframe的名稱(chēng)的列表
//用逗號(hào)把每個(gè)iframe的ID分隔. 例如: ["myframe1", "myframe2"],可以只有一個(gè)窗體,則不用逗號(hào)。
//定義iframe的ID
var iframeids=["test"]
//如果用戶的瀏覽器不支持iframe是否將iframe隱藏 yes 表示隱藏,no表示不隱藏
var iframehide="yes"
function dyniframesize()
{
var dyniframe=new Array()
for (i=0; i<iframeids.length; i++)
{
if (document.getElementById)
{
//自動(dòng)調(diào)整iframe高度
dyniframe[dyniframe.length] = document.getElementById(iframeids[i]);
if (dyniframe[i] && !window.opera)
{
dyniframe[i].style.display="block"
if (dyniframe[i].contentDocument && dyniframe[i].contentDocument.body.offsetHeight) //如果用戶的瀏覽器是NetScape
dyniframe[i].height = dyniframe[i].contentDocument.body.offsetHeight;
else if (dyniframe[i].Document && dyniframe[i].Document.body.scrollHeight) //如果用戶的瀏覽器是IE
dyniframe[i].height = dyniframe[i].Document.body.scrollHeight;
}
}
//根據(jù)設(shè)定的參數(shù)來(lái)處理不支持iframe的瀏覽器的顯示問(wèn)題
if ((document.all || document.getElementById) && iframehide=="no")
{
var tempobj=document.all? document.all[iframeids[i]] : document.getElementById(iframeids[i])
tempobj.style.display="block"
}
}
}
if (window.addEventListener)
window.addEventListener("load", dyniframesize, false)
else if (window.attachEvent)
window.attachEvent("onload", dyniframesize)
else
window.onload=dyniframesize
</script>
使用的時(shí)候只要貼在<head></head>里面就可以
歡迎各位大俠加入IT精英俱樂(lè)部(QQ群:11672321)
一、使用mod_jk.so方式
1.無(wú)集群方式
1)下載、安裝Apache2.2.11,Tomcat6.0.20略
2)下載mod_jk-1.2.28-httpd-2.2.3.so改名為mod_jk.so放到%APACHE_HOME%\modules下(不改名會(huì)出錯(cuò),不知道為什么)
3)打開(kāi)%APACHE_HOME%\conf\httpd.conf,找到最末一個(gè)Include節(jié)點(diǎn),加入mod-jk_nocluster.conf
4)在%APACHE_HOME%\conf\新建mod-jk_nocluster.conf,加入以下內(nèi)容:
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers_nocluster.properties
JkLogFile logs/mod_jk_nocluster.log
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /* ajp13
#關(guān)掉主機(jī)Lookup,如果為on,很影響性能,可以有10多秒鐘的延遲。
HostnameLookups Off
5)在%APACHE_HOME%\conf\新建workers_nocluster.properties,加入以下內(nèi)容:
worker.list=ajp13
worker.maintain=60
worker.ajp13.port=8009
worker.ajp13.host=localhost
worker.ajp13.type=ajp13
worker.ajp13.lbfactor=1
6)啟動(dòng)Apache,tomcat,在地址欄輸入http://localhost看到tomcat畫(huà)面成功了
2.使用集群(以?xún)蓚€(gè)tomcat為例)
1)、2)同上
3)打開(kāi)%APACHE_HOME%\conf\httpd.conf,找到最末一個(gè)Include節(jié)點(diǎn),更改mod-jk_nocluster.conf為mod-jk_cluster.conf
4)在%APACHE_HOME%\conf\新建mod-jk_cluster.conf,加入以下內(nèi)容:
LoadModule jk_module modules/mod_jk.so
JkWorkersFile conf/workers_cluster.properties
JkLogFile logs/mod_jk_cluster.log
JkLogLevel info
JkLogStampFormat "[%a %b %d %H:%M:%S %Y] "
JkOptions +ForwardKeySize +ForwardURICompat -ForwardDirectories
JkRequestLogFormat "%w %V %T"
JkMount /* controller
HostnameLookups Off
5)在%APACHE_HOME%\conf\新建workers_cluster.properties,加入以下內(nèi)容:
worker.list = controller,tomcat1,tomcat2 #server 列表
#========tomcat1========
worker.tomcat1.port=18109 #ajp13 端口號(hào),在tomcat下server.xml配置,默認(rèn)8009
worker.tomcat1.host=localhost #tomcat的主機(jī)地址,如不為本機(jī),請(qǐng)?zhí)顚?xiě)ip地址
worker.tomcat1.type=ajp13
worker.tomcat1.lbfactor = 1 #server的加權(quán)比重,值越高,分得的請(qǐng)求越多
#worker.tomcat1.redirect=tomcat2 #是在cluster環(huán)境之下,當(dāng)tomcat1掛點(diǎn)或無(wú)回應(yīng),jk會(huì)將request導(dǎo)向這個(gè)指令指定的其他worker作處理。
#========tomcat2========
worker.tomcat2.port=18209 #ajp13 端口號(hào),在tomcat下server.xml配置,默認(rèn)8009
worker.tomcat2.host=localhost #tomcat的主機(jī)地址,如不為本機(jī),請(qǐng)?zhí)顚?xiě)ip地址
worker.tomcat2.type=ajp13
worker.tomcat2.lbfactor = 1 #server的加權(quán)比重,值越高,分得的請(qǐng)求越多
#worker.tomcat2.activation=disabled #
#========controller,負(fù)載均衡控制器========
worker.controller.type=lb
worker.controller.balanced_workers=tomcat1,tomcat2 #指定分擔(dān)請(qǐng)求的tomcat
worker.controller.sticky_session=1
6)修改tomcat1配置文件server.xml,tomcat2配置修改地方同tomcat1,僅需注意相關(guān)端口號(hào),在同一臺(tái)服務(wù)器上時(shí)不能重復(fù)
以下列出需修改節(jié)點(diǎn)地方:
#默認(rèn)為8005
<Server port="8105" shutdown="SHUTDOWN">
#默認(rèn)8080,此處可根據(jù)需求修改線程并發(fā)等
<Connector port="8180" ...>
#默認(rèn)8009,
<Connector port="8109" protocol="AJP/1.3" redirectPort="8443" />
#name可為Standalone
<Engine name="Catalina" defaultHost="localhost" jvmRoute="tomcat1">
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"
channelSendOptions="6">
<Manager
className="org.apache.catalina.ha.session.BackupManager"
expireSessionsOnShutdown="false" notifyListenersOnReplication="true"
mapSendOptions="6" />
<!--
<Manager className="org.apache.catalina.ha.session.DeltaManager"
expireSessionsOnShutdown="false"
notifyListenersOnReplication="true"/>
-->
<Channel
className="org.apache.catalina.tribes.group.GroupChannel">
<Membership
className="org.apache.catalina.tribes.membership.McastService"
mcastBindAddress="127.0.0.1" #安裝了VPN、svn等,會(huì)導(dǎo)致綁定失敗需加上此句
address="228.0.0.4" port="45564"
frequency="500" dropTime="3000" />
<Receiver
className="org.apache.catalina.tribes.transport.nio.NioReceiver"
address="auto" port="4001" selectorTimeout="100" maxThreads="6" />
<Sender
className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
<Transport
className="org.apache.catalina.tribes.transport.nio.PooledParallelSender" />
</Sender>
<Interceptor
className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector" />
<Interceptor
className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor" />
<Interceptor
className="org.apache.catalina.tribes.group.interceptors.ThroughputInterceptor" />
</Channel>
<Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" />
<ClusterListener
className="org.apache.catalina.ha.session.ClusterSessionListener" />
</Cluster>
在<Host>節(jié)點(diǎn)加入
<Deployer className="org.apache.catalina.ha.deploy.FarmWarDeployer"
tempDir="/tmp/war-temp/xxx/"
deployDir="/tmp/war-deploy/xxx/"
watchDir="/tmp/war-listen/xxx/"
watchEnabled="false"/>
7)將Web應(yīng)用打成war包放到每一個(gè)webapps下,確保web.xml中加了
<display-name>xxx<display-name>
<distributable />
或者直接放到tomcat的web.xml中
至此mod-jk.so方式全配好了,啟動(dòng)服務(wù)就OK了!
待續(xù)Apache新增的配置方式。。。。。。
1.安裝Apache-httpd-2.2.11
2.下載svn-win32-1.6.3.zip for Apache-httpd-2.2.11,解壓到某個(gè)目錄
3.添加環(huán)境變量%SVN_HOME%,修改%PATH%,增加%SVN_HOME%\bin
4.新建空目錄x:\Respository\test\
5.進(jìn)入命令行:svnadmin create --fs-type fsfs x:\Respository\test\
6.進(jìn)入x:\Respository\test\conf\svnserve.conf
去掉注釋
auth-access = write
password-db = passwd
在本目錄passwd文件中新建用戶 xxx = xxx
7.新增服務(wù)
sc create svnservice binPath= "%SVN_HOME%\bin\svnserve.exe --service -r x:\Respository" displayname= "SVNService" depend= Tcpip start= auto
刪除服務(wù)運(yùn)行"sc delete svnservice"
8.復(fù)制%SVN_HOME%\bin中的文件mod_dav_svn.so和mod_authz_svn.so到%APACHE_HOME%\modules目錄,
復(fù)制%SVN_HOME%\bin\libdb44.dll、libeay32.dll、 ssleay32.dll到%APACHE_HOME%\bin
9.%APACHE_HOME%\conf\httd.conf做如下修改:
去掉以下行的注釋?zhuān)▽㈤_(kāi)頭的#刪除):
#LoadModule dav_fs_module modules/mod_dav_fs.so
#LoadModule dav_module modules/mod_dav.so
在LoadModule節(jié)的最后添加以下兩行:
LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so
在文件末尾加入:
<Location /svn>
DAV svn
SVNParentPath x:\Respository
AuthType Basic
AuthName "Subversion repositories"
AuthUserFile x:\Respository\conf\passwd
#AuthzSVNAccessFile x:\Respository\conf\authz
Require valid-user
</Location>
可是現(xiàn)在啟動(dòng)不了Apache ,那位大俠能幫幫我,網(wǎng)上找了好多都試過(guò)了還是不行
<script language="javascript">
var oPopup=null; //彈出菜單
var popWidth=110; //彈出菜單的寬度
var popHeight=140; //彈出菜單的高度
var curRow=null; //記錄彈出菜單最后指向的行
function init(){
oPopup = window.createPopup();
var oPopBody = oPopup.document.body;
//設(shè)置菜單樣式
oPopBody.style.backgroundColor = "scrollbar";
oPopBody.style.border = "2px solid";
oPopBody.style.borderColor = "buttonhighlight buttonshadow buttonshadow buttonhighlight"
var strHTML=""
strHTML+='<table oncontextmenu="return false;" onselectstart="return false;" id="tbMenu" ';
strHTML+=' style="cursor:default; width:100%; height:100%;font-size:12px;" border=0 cellpadding=0 cellspacing=2>';
//在這里擴(kuò)展菜單的選項(xiàng)start
strHTML+='<tr operation="edit"><td> 編輯</td></tr>';
strHTML+='<tr operation="refresh"><td> 刷新</td></tr>';
strHTML+='<tr operation="addrowup"><td> 添加新行(上)</td></tr>';
strHTML+='<tr operation="addrowdown"><td> 添加新行(下)</td></tr>';
strHTML+='<tr operation="delrow"><td> 刪除該行</td></tr>';
strHTML+='<tr operation="moveup"><td> 向上移動(dòng)一行</td></tr>';
strHTML+='<tr operation="movedown"><td> 向下移動(dòng)一行</td></tr>';
//在這里擴(kuò)展菜單的選項(xiàng)end
strHTML+='</table>';
oPopBody.innerHTML=strHTML;
var tb = oPopup.document.getElementById("tbMenu");
var rs=tb.rows;
for(var i=0;i<rs.length;i++){
var row=rs[i];
addEvent(row);
}
}
function showMenu(){
var e=window.event;
var src=e.srcElement;
oPopup.show(window.event.clientX, window.event.clientY, popWidth, popHeight, document.body);
window.event.returnValue=false;
}
function addEvent(row){
row.attachEvent("onmouseover",function(){selRow(row)});
row.attachEvent("onclick",function(){onEvent(row)});
}
function selRow(src){
if(curRow!=null){ curRow.style.backgroundColor="scrollbar"; curRow.style.color="black";}
curRow=src; curRow.style.backgroundColor="midnightblue"; curRow.style.color="white";
}
function onEvent(src){
oPopup.hide();
switch(src.operation){
//在這里為菜單項(xiàng)的點(diǎn)擊事件添加處理方法
//本示例的方法只供參考,沒(méi)有實(shí)現(xiàn)
case "edit": example(src.operation); break;
case "refresh": example(src.operation); break;
case "addrowup": example(src.operation); break;
case "addrowdown": example(src.operation); break;
case "delrow": example(src.operation); break;
case "moveup": example(src.operation); break;
case "movedown": example(src.operation); break;
default: return;
}
src.style.backgroundColor="scrollbar";
src.style.color="black";
curRow=null;
}
function example(str){
alert("您選擇了"+str+"操作!");
}
</script>
<body onload="init();showMenu()">
</body>
我們?cè)跀?shù)據(jù)庫(kù)插入一條數(shù)據(jù)的時(shí)候,經(jīng)常是需要返回插入這條數(shù)據(jù)的主鍵。但是數(shù)據(jù)庫(kù)供應(yīng)商之間生成主鍵的方式都不一樣。
有些是預(yù)先生成(pre-generate)主鍵的,如Oracle和PostgreSQL;有些是事后生成(post-generate)主鍵的,如MySQL和SQL Server。但是不管是哪種方式,我們都可以用iBATIS的節(jié)點(diǎn)來(lái)獲取語(yǔ)句所產(chǎn)生的主鍵。
例子如下:
xml 代碼
<insert id="insertProduct-ORACLE" parameterClass="product">
<selectKey resultClass="int" type="pre" keyProperty="Id" >
SELECT YOURPKSEQUENCE.NEXTVAL AS VALUE FROM DUAL
<selectKey>
insert into PRODUCT (PRD_ID,PRD_DESCRIPTION) values (#id#,#description#)
<insert>
<insert id="insertProduct-MS-SQL" parameterClass="product">
insert into PRODUCT (PRD_DESCRIPTION) values (#description#)
<selectKey resultClass="int" type="post" keyProperty="id" >
select @@IDENTITY as value
<selectKey>
<insert>
<insert id="insertProduct-MYSQL" parameterClass="product">
insert into PRODUCT (PRD_DESCRIPTION) values (#description#)
<selectKey resultClass="int" type="post" keyProperty="id" >
select LAST_INSERT_ID() as value
<selectKey>
<insert>
alter database datafile 'D:\DevTools\Oracle\oradata\ora92\USERS01.DBF' offline drop;
alter database open;
在Oracle9i中執(zhí)行下面的SQL重建exu81rls視圖即可。
CREATE OR REPLACE view exu81rls
(objown,objnam,policy,polown,polsch,polfun,stmts,chkopt,enabled,spolicy)
AS select u.name, o.name, r.pname, r.pfschma, r.ppname, r.pfname,
decode(bitand(r.stmt_type,1), 0,'', 'SELECT,')
|| decode(bitand(r.stmt_type,2), 0,'', 'INSERT,')
|| decode(bitand(r.stmt_type,4), 0,'', 'UPDATE,')
|| decode(bitand(r.stmt_type,8), 0,'', 'DELETE,'),
r.check_opt, r.enable_flag,
DECODE(BITAND(r.stmt_type, 16), 0, 0, 1)
from user$ u, obj$ o, rls$ r
where u.user# = o.owner#
and r.obj# = o.obj#
and (uid = 0 or
uid = o.owner# or
exists ( select * from session_roles where role='SELECT_CATALOG_ROLE')
)
/
grant select on sys.exu81rls to public;
/
-- Change the HTTP/WEBDAV port from 8080 to 8081
SQL> call dbms_xdb.cfg_update(updateXML( dbms_xdb.cfg_get() ,
'/xdbconfig/sysconfig/protocolconfig/httpconfig/http-port/text()'
8081))
/
-- Change the FTP port from 2100 to 2111
SQL> call dbms_xdb.cfg_update(updateXML( dbms_xdb.cfg_get() ,
'/xdbconfig/sysconfig/protocolconfig/ftpconfig/ftp-port/text()' , 2111))
SQL> COMMIT;
SQL> EXEC dbms_xdb.cfg_refresh
@echo off
if '%1=='## goto ENVSET
rem 要啟動(dòng)的類(lèi)名
SET CLSNAME=com.main
rem 設(shè)定CLSPATH
SET CLSPATH=.
FOR %%c IN (.\lib\*.jar) DO CALL %0 ## %%c
rem 運(yùn)行
GOTO RUN
:RUN
java -cp %CLSPATH% %CLSNAME%
goto END
:ENVSET
set CLSPATH=%CLSPATH%;%2
goto END
:END
在query的時(shí)候加上binary,select * from usertest where username like binary '%夏%'
一、同步問(wèn)題提出
線程的同步是為了防止多個(gè)線程訪問(wèn)一個(gè)數(shù)據(jù)對(duì)象時(shí),對(duì)數(shù)據(jù)造成的破壞。
例如:兩個(gè)線程ThreadA、ThreadB都操作同一個(gè)對(duì)象Foo對(duì)象,并修改Foo對(duì)象上的數(shù)據(jù)。
public class Foo {
private int x = 100;
public int getX() {
return x;
}
public int fix(int y) {
x = x - y;
return x;
}
}
public class MyRunnable implements Runnable {
private Foo foo = new Foo();
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
Thread ta = new Thread(r, "Thread-A");
Thread tb = new Thread(r, "Thread-B");
ta.start();
tb.start();
}
public void run() {
for (int i = 0; i < 3; i++) {
this.fix(30);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " : 當(dāng)前foo對(duì)象的x值= " + foo.getX());
}
}
public int fix(int y) {
return foo.fix(y);
}
}
運(yùn)行結(jié)果:
Thread-A : 當(dāng)前foo對(duì)象的x值= 40
Thread-B : 當(dāng)前foo對(duì)象的x值= 40
Thread-B : 當(dāng)前foo對(duì)象的x值= -20
Thread-A : 當(dāng)前foo對(duì)象的x值= -50
Thread-A : 當(dāng)前foo對(duì)象的x值= -80
Thread-B : 當(dāng)前foo對(duì)象的x值= -80
Process finished with exit code 0
從結(jié)果發(fā)現(xiàn),這樣的輸出值明顯是不合理的。原因是兩個(gè)線程不加控制的訪問(wèn)Foo對(duì)象并修改其數(shù)據(jù)所致。
如果要保持結(jié)果的合理性,只需要達(dá)到一個(gè)目的,就是將對(duì)Foo的訪問(wèn)加以限制,每次只能有一個(gè)線程在訪問(wèn)。這樣就能保證Foo對(duì)象中數(shù)據(jù)的合理性了。
在具體的Java代碼中需要完成一下兩個(gè)操作:
把競(jìng)爭(zhēng)訪問(wèn)的資源類(lèi)Foo變量x標(biāo)識(shí)為private;
同步哪些修改變量的代碼,使用synchronized關(guān)鍵字同步方法或代碼。
二、同步和鎖定
1、鎖的原理
Java中每個(gè)對(duì)象都有一個(gè)內(nèi)置鎖
當(dāng)程序運(yùn)行到非靜態(tài)的synchronized同步方法上時(shí),自動(dòng)獲得與正在執(zhí)行代碼類(lèi)的當(dāng)前實(shí)例(this實(shí)例)有關(guān)的鎖。獲得一個(gè)對(duì)象的鎖也稱(chēng)為獲取鎖、鎖定對(duì)象、在對(duì)象上鎖定或在對(duì)象上同步。
當(dāng)程序運(yùn)行到synchronized同步方法或代碼塊時(shí)才該對(duì)象鎖才起作用。
一個(gè)對(duì)象只有一個(gè)鎖。所以,如果一個(gè)線程獲得該鎖,就沒(méi)有其他線程可以獲得鎖,直到第一個(gè)線程釋放(或返回)鎖。這也意味著任何其他線程都不能進(jìn)入該對(duì)象上的synchronized方法或代碼塊,直到該鎖被釋放。
釋放鎖是指持鎖線程退出了synchronized同步方法或代碼塊。
關(guān)于鎖和同步,有一下幾個(gè)要點(diǎn):
1)、只能同步方法,而不能同步變量和類(lèi);
2)、每個(gè)對(duì)象只有一個(gè)鎖;當(dāng)提到同步時(shí),應(yīng)該清楚在什么上同步?也就是說(shuō),在哪個(gè)對(duì)象上同步?
3)、不必同步類(lèi)中所有的方法,類(lèi)可以同時(shí)擁有同步和非同步方法。
4)、如果兩個(gè)線程要執(zhí)行一個(gè)類(lèi)中的synchronized方法,并且兩個(gè)線程使用相同的實(shí)例來(lái)調(diào)用方法,那么一次只能有一個(gè)線程能夠執(zhí)行方法,另一個(gè)需要等待,直到鎖被釋放。也就是說(shuō):如果一個(gè)線程在對(duì)象上獲得一個(gè)鎖,就沒(méi)有任何其他線程可以進(jìn)入(該對(duì)象的)類(lèi)中的任何一個(gè)同步方法。
5)、如果線程擁有同步和非同步方法,則非同步方法可以被多個(gè)線程自由訪問(wèn)而不受鎖的限制。
6)、線程睡眠時(shí),它所持的任何鎖都不會(huì)釋放。
7)、線程可以獲得多個(gè)鎖。比如,在一個(gè)對(duì)象的同步方法里面調(diào)用另外一個(gè)對(duì)象的同步方法,則獲取了兩個(gè)對(duì)象的同步鎖。
8)、同步損害并發(fā)性,應(yīng)該盡可能縮小同步范圍。同步不但可以同步整個(gè)方法,還可以同步方法中一部分代碼塊。
9)、在使用同步代碼塊時(shí)候,應(yīng)該指定在哪個(gè)對(duì)象上同步,也就是說(shuō)要獲取哪個(gè)對(duì)象的鎖。例如:
public int fix(int y) {
synchronized (this) {
x = x - y;
}
return x;
}
當(dāng)然,同步方法也可以改寫(xiě)為非同步方法,但功能完全一樣的,例如:
public synchronized int getX() {
return x++;
}
與
public int getX() {
synchronized (this) {
return x;
}
}
效果是完全一樣的。
三、靜態(tài)方法同步
要同步靜態(tài)方法,需要一個(gè)用于整個(gè)類(lèi)對(duì)象的鎖,這個(gè)對(duì)象是就是這個(gè)類(lèi)(XXX.class)。
例如:
public static synchronized int setName(String name){
Xxx.name = name;
}
等價(jià)于
public static int setName(String name){
synchronized(Xxx.class){
Xxx.name = name;
}
}
四、如果線程不能不能獲得鎖會(huì)怎么樣
如果線程試圖進(jìn)入同步方法,而其鎖已經(jīng)被占用,則線程在該對(duì)象上被阻塞。實(shí)質(zhì)上,線程進(jìn)入該對(duì)象的的一種池中,必須在哪里等待,直到其鎖被釋放,該線程再次變?yōu)榭蛇\(yùn)行或運(yùn)行為止。
當(dāng)考慮阻塞時(shí),一定要注意哪個(gè)對(duì)象正被用于鎖定:
1、調(diào)用同一個(gè)對(duì)象中非靜態(tài)同步方法的線程將彼此阻塞。如果是不同對(duì)象,則每個(gè)線程有自己的對(duì)象的鎖,線程間彼此互不干預(yù)。
2、調(diào)用同一個(gè)類(lèi)中的靜態(tài)同步方法的線程將彼此阻塞,它們都是鎖定在相同的Class對(duì)象上。
3、靜態(tài)同步方法和非靜態(tài)同步方法將永遠(yuǎn)不會(huì)彼此阻塞,因?yàn)殪o態(tài)方法鎖定在Class對(duì)象上,非靜態(tài)方法鎖定在該類(lèi)的對(duì)象上。
4、對(duì)于同步代碼塊,要看清楚什么對(duì)象已經(jīng)用于鎖定(synchronized后面括號(hào)的內(nèi)容)。在同一個(gè)對(duì)象上進(jìn)行同步的線程將彼此阻塞,在不同對(duì)象上鎖定的線程將永遠(yuǎn)不會(huì)彼此阻塞。
五、何時(shí)需要同步
在多個(gè)線程同時(shí)訪問(wèn)互斥(可交換)數(shù)據(jù)時(shí),應(yīng)該同步以保護(hù)數(shù)據(jù),確保兩個(gè)線程不會(huì)同時(shí)修改更改它。
對(duì)于非靜態(tài)字段中可更改的數(shù)據(jù),通常使用非靜態(tài)方法訪問(wèn)。
對(duì)于靜態(tài)字段中可更改的數(shù)據(jù),通常使用靜態(tài)方法訪問(wèn)。
如果需要在非靜態(tài)方法中使用靜態(tài)字段,或者在靜態(tài)字段中調(diào)用非靜態(tài)方法,問(wèn)題將變得非常復(fù)雜。已經(jīng)超出SJCP考試范圍了。
六、線程安全類(lèi)
當(dāng)一個(gè)類(lèi)已經(jīng)很好的同步以保護(hù)它的數(shù)據(jù)時(shí),這個(gè)類(lèi)就稱(chēng)為“線程安全的”。
即使是線程安全類(lèi),也應(yīng)該特別小心,因?yàn)椴僮鞯木€程是間仍然不一定安全。
舉個(gè)形象的例子,比如一個(gè)集合是線程安全的,有兩個(gè)線程在操作同一個(gè)集合對(duì)象,當(dāng)?shù)谝粋€(gè)線程查詢(xún)集合非空后,刪除集合中所有元素的時(shí)候。第二個(gè)線程也來(lái)執(zhí)行與第一個(gè)線程相同的操作,也許在第一個(gè)線程查詢(xún)后,第二個(gè)線程也查詢(xún)出集合非空,但是當(dāng)?shù)谝粋€(gè)執(zhí)行清除后,第二個(gè)再執(zhí)行刪除顯然是不對(duì)的,因?yàn)榇藭r(shí)集合已經(jīng)為空了。
看個(gè)代碼:
public class NameList {
private List nameList = Collections.synchronizedList(new LinkedList());
public void add(String name) {
nameList.add(name);
}
public String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
public class Test {
public static void main(String[] args) {
final NameList nl = new NameList();
nl.add("aaa");
class NameDropper extends Thread{
public void run(){
String name = nl.removeFirst();
System.out.println(name);
}
}
Thread t1 = new NameDropper();
Thread t2 = new NameDropper();
t1.start();
t2.start();
}
}
雖然集合對(duì)象
private List nameList = Collections.synchronizedList(new LinkedList());
是同步的,但是程序還不是線程安全的。
出現(xiàn)這種事件的原因是,上例中一個(gè)線程操作列表過(guò)程中無(wú)法阻止另外一個(gè)線程對(duì)列表的其他操作。
解決上面問(wèn)題的辦法是,在操作集合對(duì)象的NameList上面做一個(gè)同步。改寫(xiě)后的代碼如下:
public class NameList {
private List nameList = Collections.synchronizedList(new LinkedList());
public synchronized void add(String name) {
nameList.add(name);
}
public synchronized String removeFirst() {
if (nameList.size() > 0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
這樣,當(dāng)一個(gè)線程訪問(wèn)其中一個(gè)同步方法時(shí),其他線程只有等待。
七、線程死鎖
死鎖對(duì)Java程序來(lái)說(shuō),是很復(fù)雜的,也很難發(fā)現(xiàn)問(wèn)題。當(dāng)兩個(gè)線程被阻塞,每個(gè)線程在等待另一個(gè)線程時(shí)就發(fā)生死鎖。
還是看一個(gè)比較直觀的死鎖例子:
public class DeadlockRisk {
private static class Resource {
public int value;
}
private Resource resourceA = new Resource();
private Resource resourceB = new Resource();
public int read() {
synchronized (resourceA) {
synchronized (resourceB) {
return resourceB.value + resourceA.value;
}
}
}
public void write(int a, int b) {
synchronized (resourceB) {
synchronized (resourceA) {
resourceA.value = a;
resourceB.value = b;
}
}
}
}
假設(shè)read()方法由一個(gè)線程啟動(dòng),write()方法由另外一個(gè)線程啟動(dòng)。讀線程將擁有resourceA鎖,寫(xiě)線程將擁有resourceB鎖,兩者都堅(jiān)持等待的話就出現(xiàn)死鎖。
實(shí)際上,上面這個(gè)例子發(fā)生死鎖的概率很小。因?yàn)樵诖a內(nèi)的某個(gè)點(diǎn),CPU必須從讀線程切換到寫(xiě)線程,所以,死鎖基本上不能發(fā)生。
但是,無(wú)論代碼中發(fā)生死鎖的概率有多小,一旦發(fā)生死鎖,程序就死掉。有一些設(shè)計(jì)方法能幫助避免死鎖,包括始終按照預(yù)定義的順序獲取鎖這一策略。已經(jīng)超出SCJP的考試范圍。
八、線程同步小結(jié)
1、線程同步的目的是為了保護(hù)多個(gè)線程反問(wèn)一個(gè)資源時(shí)對(duì)資源的破壞。
2、線程同步方法是通過(guò)鎖來(lái)實(shí)現(xiàn),每個(gè)對(duì)象都有切僅有一個(gè)鎖,這個(gè)鎖與一個(gè)特定的對(duì)象關(guān)聯(lián),線程一旦獲取了對(duì)象鎖,其他訪問(wèn)該對(duì)象的線程就無(wú)法再訪問(wèn)該對(duì)象的其他非同步方法。
3、對(duì)于靜態(tài)同步方法,鎖是針對(duì)這個(gè)類(lèi)的,鎖對(duì)象是該類(lèi)的Class對(duì)象。靜態(tài)和非靜態(tài)方法的鎖互不干預(yù)。一個(gè)線程獲得鎖,當(dāng)在一個(gè)同步方法中訪問(wèn)另外對(duì)象上的同步方法時(shí),會(huì)獲取這兩個(gè)對(duì)象鎖。
4、對(duì)于同步,要時(shí)刻清醒在哪個(gè)對(duì)象上同步,這是關(guān)鍵。
5、編寫(xiě)線程安全的類(lèi),需要時(shí)刻注意對(duì)多個(gè)線程競(jìng)爭(zhēng)訪問(wèn)資源的邏輯和安全做出正確的判斷,對(duì)“原子”操作做出分析,并保證原子操作期間別的線程無(wú)法訪問(wèn)競(jìng)爭(zhēng)資源。
6、當(dāng)多個(gè)線程等待一個(gè)對(duì)象鎖時(shí),沒(méi)有獲取到鎖的線程將發(fā)生阻塞。
7、死鎖是線程間相互等待鎖鎖造成的,在實(shí)際中發(fā)生的概率非常的小。真讓你寫(xiě)個(gè)死鎖程序,不一定好使,呵呵。但是,一旦程序發(fā)生死鎖,程序?qū)⑺赖簟?/p>
測(cè)試通過(guò)的版本如下:
Eclipse:3.3.2
jdk:1.6
junit:3.8
ant:1.7(1.7之前的版本好像還不提供mail功能。。。)
<!-- JUnit build script using ant 1.7 -->
<project name="JunitTestProject" default="mail" basedir=".">
<property name="app.name" value="JunitTestProject" />
<property name="build.dir" value="bin" />
<!-- ====================" path define " ================================ -->
<path id="cobertura.classpath">
<fileset dir="lib/coberture">
<include name="cobertura.jar" />
<include name="*.jar" />
</fileset>
</path>
<!-- ====================" cobertura task define " Target ================================ -->
<taskdef classpathref="cobertura.classpath" resource="tasks.properties" />
<!-- ==================== "clean " Target ================================ -->
<target name="clean">
<available property="junit.present" classname="junit.framework.TestCase" />
<delete dir="${build.dir}" quiet="true" />
<delete file="report" quiet="true" />
</target>
<!-- ==================== "copy xml resource " Target ================================ -->
<target name="copyxml" depends="clean">
<copy todir="${build.dir}/testcases">
<fileset dir="WEB-INF" />
</copy>
</target>
<!-- ==================== "compile src" Target ================================ -->
<target name="compile" depends="copyxml">
<mkdir dir="${build.dir}" />
<javac srcdir="src" destdir="${build.dir}" debug="yes">
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="**/*.java" />
</javac>
<javac srcdir="WEB-INF" destdir="${build.dir}">
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="*.jsp" />
</javac>
</target>
<!-- ==================== jar" Target ================================ -->
<target name="jar" depends="compile">
<mkdir dir="dist/lib" />
<jar jarfile="dist/lib/${app.name}.jar" basedir="${build.dir}" includes="com/**" />
</target>
<!-- ==================== compile test src" Target ================================ -->
<target name="compiletests" depends="jar">
<mkdir dir="${build.dir}/testcases" />
<javac srcdir="test" destdir="${build.dir}/testcases" >
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
<fileset dir="dist/lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
</classpath>
<include name="**/*.java" />
</javac>
</target>
<!-- ==================== instrumented" Target ================================ -->
<target name="instrumented" depends="compiletests">
<cobertura-instrument todir="bin/instrumented-classes">
<ignore regex="org.apache.log4j.*" />
<fileset dir="bin">
<include name="com/**/*.class" />
</fileset>
</cobertura-instrument>
</target>
<!-- ==================== junit-test" Target ================================ -->
<target name="runtests" depends="instrumented">
<mkdir dir="report" />
<property name="tests" value="*Test" />
<junit printsummary="yes" haltonerror="yes" haltonfailure="yes" fork="yes">
<formatter type="plain" usefile="false" />
<formatter type="xml" />
<batchtest todir="report">
<fileset dir="test">
<include name="**/${tests}.java" />
<exclude name="**/ConfigTest.java" />
</fileset>
</batchtest>
<!--
Note the classpath order: instrumented classes are before the
original (uninstrumented) classes. This is important.
-->
<classpath location="bin/instrumented-classes" />
<!--
src classpath
-->
<classpath location="bin" />
<!--
The instrumented classes reference classes used by the
Cobertura runtime, so Cobertura and its dependencies
must be on your classpath.
-->
<classpath refid="cobertura.classpath" />
<!--
test case class path define
-->
<classpath>
<fileset dir="lib" casesensitive="yes">
<include name="**/*.jar" />
</fileset>
<pathelement location="bin/testcases" />
</classpath>
</junit>
</target>
<!-- ==================== junit-report" Target ================================ -->
<target name="report" depends="runtests">
<mkdir dir="report/html" />
<junitreport todir="report">
<fileset dir="report">
<include name="TEST-*.xml" />
</fileset>
<report todir="report/html" />
</junitreport>
</target>
<!-- ==================== "coverage-report" Target ================================ -->
<target name="coverage-report" depends="report">
<cobertura-report format="html" destdir="cobertura" >
<fileset dir="src">
<include name="**/*.java" />
</fileset>
</cobertura-report>
<echo>The execution of coverage-report is complete. Coverage Reports are available in /${coverage-report}</echo>
</target>
<!-- ==================== "make file to zip" Target ================================ -->
<target name="make_data_zip" depends="coverage-report">
<tstamp>
<format property="date" pattern="yyyy-MM-dd HH-mm" />
</tstamp>
<jar jarfile="dist/lib/cobertura${date}.zip" basedir="cobertura" />
<jar jarfile="dist/lib/report${date}.zip" basedir="report" excludes="*.xml"/>
</target>
<!-- ==================== "mail" Target ================================ -->
<target name="mail" depends="make_data_zip">
<!-- <taskdef name="mail" classname="org.apache.tools.ant.taskdefs.optional.mail.MimeMail"/> -->
<tstamp/>
<mail messageMimeType="text/html"
messageFile="message.txt"
tolist="bpcjy@hotmail.com"
mailhost="mailsvr or mail IPAddress"
subject="JUnit Test Results: ${TODAY}"
from="bpcjy@hotmail.com">
<fileset dir=".">
<include name="dist/lib/*.zip"/>
</fileset>
</mail>
</target>
</project>