??xml version="1.0" encoding="utf-8" standalone="yes"?>亚洲理论电影在线观看,亚洲Av熟妇高潮30p,亚洲成a人片在线观看老师http://m.tkk7.com/NeonWay/category/7515.htmlspring、hibernate、webwork框架实践与探索?/description>zh-cnThu, 01 Mar 2007 23:02:49 GMTThu, 01 Mar 2007 23:02:49 GMT60在java中严格校验日期正?/title><link>http://m.tkk7.com/NeonWay/archive/2007/01/25/95855.html</link><dc:creator>王R锋的技术实?/dc:creator><author>王R锋的技术实?/author><pubDate>Thu, 25 Jan 2007 02:09:00 GMT</pubDate><guid>http://m.tkk7.com/NeonWay/archive/2007/01/25/95855.html</guid><wfw:comment>http://m.tkk7.com/NeonWay/comments/95855.html</wfw:comment><comments>http://m.tkk7.com/NeonWay/archive/2007/01/25/95855.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://m.tkk7.com/NeonWay/comments/commentRss/95855.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/NeonWay/services/trackbacks/95855.html</trackback:ping><description><![CDATA[ <p>   /**<br />     * 验输入是否ؓ正确的日期格?不含U的M情况),严格要求日期正确?格式:yyyy-MM-dd HH:mm<br />     * @param sourceDate<br />     * @return<br />     */<br />    public static boolean checkDate(String sourceDate){<br />        if(sourceDate==null){<br />            return false;<br />        }<br />        try {<br />               SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");<br />               dateFormat.setLenient(false);<br />               dateFormat.parse(sourceDate);<br />               return true;<br />        } catch (Exception e) {<br />        }<br />         return false;<br />    }<br />    <br />    /**<br />     * Ҏ日期获得日期(不含U的M情况),严格要求日期正确?格式:yyyy-MM-dd HH:mm<br />     * @param sourceDate<br />     * @return<br />     */<br />    public static Date getDate(String sourceDate) throws DataFormatException{<br />           if(sourceDate==null){<br />               throw new DataFormatException("源数据ؓnull");<br />           }<br />           try {<br />                     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm");<br />                     dateFormat.setLenient(false);<br />                      return dateFormat.parse(sourceDate);<br />           } catch (Exception e) {<br />                     throw new DataFormatException("源数据格式错?);<br />           }<br />    }<br /><br /><br />//日期格式可以自定?<br />    public static void main(String[] args) throws IOException {<br />             String s="2006-01-30 12:26";<br />             System.out.println(s+"是否为日?"+Test.checkDate(s));<br /><br />             s="2006-1-30 12:26";<br />             System.out.println(s+"是否为日?"+Test.checkDate(s));<br />        <br />            s="2006-01-32 12:26";<br />            System.out.println(s+"是否为日?"+Test.checkDate(s));<br />    }</p> <img src ="http://m.tkk7.com/NeonWay/aggbug/95855.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/NeonWay/" target="_blank">王R锋的技术实?/a> 2007-01-25 10:09 <a href="http://m.tkk7.com/NeonWay/archive/2007/01/25/95855.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java里抽象类和接口的区别 http://m.tkk7.com/NeonWay/archive/2007/01/22/95243.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Mon, 22 Jan 2007 03:22:00 GMThttp://m.tkk7.com/NeonWay/archive/2007/01/22/95243.htmlhttp://m.tkk7.com/NeonWay/comments/95243.htmlhttp://m.tkk7.com/NeonWay/archive/2007/01/22/95243.html#Feedback1http://m.tkk7.com/NeonWay/comments/commentRss/95243.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/95243.html
abstract class和interface是Java语言中对于抽象类定义q行支持的两U机Ӟ正是׃q两U机制的存在Q才赋予了Java强大的面向对象能力。abstract class和interface之间在对于抽象类定义的支持方面具有很大的怼性,甚至可以怺替换Q因此很多开发者在q行抽象cd义时对于abstract class和interface的选择昑־比较随意。其实,两者之间还是有很大的区别的Q对于它们的选择甚至反映出对于问题领域本质的理解、对于设计意囄理解是否正确、合理。本文将对它们之间的区别q行一番剖析,试图l开发者提供一个在二者之间进行选择的依据。?

理解抽象c?

abstract class和interface在Java语言中都是用来进行抽象类Q本文中的抽象类q从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法,误者注意区分)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?

在面向对象的概念中,我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这Lcd是抽象类。抽象类往往用来表征我们在对问题领域q行分析、设计中得出的抽象概念,是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:如果我们q行一个图形编辑Y件的开发,׃发现问题领域存在着圆、三角Şq样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它是一个抽象概c正是因为抽象的概念在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的。?

在面向对象领域,抽象cM要用来进行类型隐藏。我们可以构造出一个固定的一l行为的抽象描述Q但是这l行为却能够有Q意个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一个抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟悉OCP的读者一定知道,Z能够实现面向对象设计的一个最核心的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在。?


从语法定义层面看abstract class和interface 

在语法层面,Java语言对于abstract class和interfacel出了不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同。?

使用abstract class的方式定义Demo抽象cȝ方式如下Q?

abstract class Demo {?
 abstract void method1(); 
 abstract void method2(); 
 …?
}?

使用interface的方式定义Demo抽象cȝ方式如下Q?

interface Demo { 
 void method1(); 
 void method2(); 
 …?


在abstract class方式中,Demo可以有自q数据成员Q也可以有非abstarct的成员方法,而在interface方式的实CQDemo只能够有静态的不能被修改的数据成员Q也是必须是static final的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ都是abstract的。从某种意义上说Qinterface是一U特DŞ式的abstract class。?

      从编E的角度来看Qabstract class和interface都可以用来实?design by contract"的思想。但是在具体的用上面还是有一些区别的。?

首先Qabstract class在Java语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧。?

其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ。但是在interface的定义中Q方法却不能拥有默认行ؓQؓ了绕q这个限Ӟ必须使用委托Q但是这会 增加一些复杂性,有时会造成很大的麻烦。?

在抽象类中不能定义默认行存在另一个比较严重的问题Q那是可能会造成l护上的ȝ。因为如果后来想修改cȝ界面Q一般通过abstract class或者interface来表C)以适应新的情况Q比如,d新的Ҏ或者给已用的方法中d新的参数Q时Q就会非常的ȝQ可能要p很多的时_对于zcd多的情况Q尤为如此)。但是如果界面是通过abstract class来实现的Q那么可能就只需要修改定义在abstract class中的默认行ؓ可以了。?

同样Q如果不能在抽象cM定义默认行ؓQ就会导致同LҎ实现出现在该抽象cȝ每一个派生类中,q反?one ruleQone place"原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小心。?


从设计理念层面看abstract class和interface 

上面主要从语法定义和~程的角度论qCabstract class和interface的区别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:abstract class和interface所反映出的设计理念Q来分析一下二者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在。?

前面已经提到q,abstarct class在Java语言中体C一U承关p,要想使得l承关系合理Q父cdzcM间必d?is a"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?is a"关系的大幅深入的论qͼ有兴的读者可以参考)。对于interface 来说则不Ӟq不要求interface的实现者和interface定义在概忉|质上是一致的Q仅仅是实现了interface定义的契U而已。ؓ了便于理解Q下面将通过一个简单的实例q行说明。?

考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C: 

使用abstract class方式定义DoorQ?

abstract class Door { 
 abstract void open(); 
 abstract void close()Q?


  
使用interface方式定义DoorQ?


interface Door { 
 void open(); 
 void close(); 


  
其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别。?

如果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中,主要是ؓ了展Cabstract class和interface反映在设计理念上的区别,其他斚w无关的问题都做了化或者忽略)Q下面将|列出可能的解决ҎQƈ从设计理念层面对q些不同的方案进行分析。?

解决Ҏ一Q?

单的在Door的定义中增加一个alarmҎQ如下: 

abstract class Door { 
 abstract void open(); 
 abstract void close()Q?
 abstract void alarm(); 


  
或者?

interface Door { 
 void open(); 
 void close(); 
 void alarm(); 


  
那么h报警功能的AlarmDoor的定义方式如下: 

class AlarmDoor extends Door { 
 void open() { … } 
 void close() { … } 
 void alarm() { … } 


  
或者?

class AlarmDoor implements Door {?
 void open() { … } 
 void close() { … } 
 void alarm() { … } 
}?

q种Ҏq反了面向对象设计中的一个核心原则ISPQInterface Segregation PricipleQ,在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方法؜在了一赗这样引L一个问题是那些仅仅依赖于Doorq个概念的模块会因ؓ"报警?q个概念的改变(比如Q修改alarmҎ的参敎ͼ而改变,反之依然。?

解决Ҏ二: 

既然open、close和alarm属于两个不同的概念,ҎISP原则应该把它们分别定义在代表q两个概늚抽象cM。定义方式有Q这两个概念都用abstract class方式定义Q两个概念都使用interface方式定义Q一个概念用abstract class方式定义Q另一个概念用interface方式定义。?

昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明。?

如果两个概念都用interface方式来定义,那么反映出两个问题Q?、我们可能没有理解清楚问题领域,AlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:我们通过对于问题领域的分析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均用interface方式定义Q反映不Zq含义。?

如果我们对于问题领域的理解是QAlarmDoor在概忉|质上是DoorQ同时它有具有报警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关pd本质上是"is a"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,说明它又能够完成报警概念中定义的行ؓQ所以报警概念可以通过interface方式定义。如下所C: 

abstract class Door { 
 abstract void open(); 
 abstract void close()Q?

interface Alarm { 
 void alarm(); 

class AlarmDoor extends Door implements Alarm { 
 void open() { … } 
 void close() { … } 
    void alarm() { … } 


  
q种实现方式基本上能够明的反映出我们对于问题领域的理解Q正的揭示我们的设计意图。其实abstract class表示的是"is a"关系Qinterface表示的是"like a"关系Q大家在选择时可以作Z个依据,当然q是建立在对问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来了。 ?/font> 

]]>
spring事务探烦 http://m.tkk7.com/NeonWay/archive/2007/01/15/93872.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Mon, 15 Jan 2007 02:10:00 GMThttp://m.tkk7.com/NeonWay/archive/2007/01/15/93872.htmlhttp://m.tkk7.com/NeonWay/comments/93872.htmlhttp://m.tkk7.com/NeonWay/archive/2007/01/15/93872.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/93872.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/93872.htmlhttp://www.javaeye.com/topic/11190?page=1

spring自徏事务理模块。而且q个事务理是一个抽象设计,可以应用到很多场合,包括普通的DataSourceQjtaQjms和hibernate上?/p>

要正用spring的事务,首先需要了解spring在事务设计上的一些概?
l观spring事务Q围l着两个核心PlatformTransactionManager和TransactionStatus

PlatformTransactionManager直译q来是q_相关事务Q这里的q_指的是“事务源”,包括刚才我说的DataSourceQjta{等。这些无一不是一个事务源。广义的_凡是可以完成事务性操作的对象Q都可以设计出相对应的PlatformTransactionManagerQ只要这个事务源支持commitQrollback和getTransaction语意?/p>

查看spring代码Q可以发现这些manager实现事务Q就是调用事务源的事务操作方?/p>

比如

HibernateTransactionManager

代码
  1. protected void doCommit(DefaultTransactionStatus status) {   
  2.         HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();   
  3.         if (status.isDebug()) {   
  4.             logger.debug("Committing Hibernate transaction on session [" +   
  5.                     txObject.getSessionHolder().getSession() + "]");   
  6.         }   
  7.         try {   
  8.             txObject.getSessionHolder().getTransaction().commit();   
  9.         }   
  10. ...   
  11.   
  12.     }  

jdbc 的DataSourceTransactionManager

代码
  1. protected void doCommit(DefaultTransactionStatus status) {   
  2.         DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();   
  3.         Connection con = txObject.getConnectionHolder().getConnection();   
  4.         if (status.isDebug()) {   
  5.             logger.debug("Committing JDBC transaction on connection [" + con + "]");   
  6.         }   
  7.         try {   
  8.             con.commit();   
  9.         }   
  10.         ...   
  11.     }  

那么PlatformTransactionManager以什么依据处理事务呢Q?
是TransactionStatus
查看api发现q个接口有三个方?
isNewTransaction() QisRollbackOnly()QsetRollbackOnly()
PlatformTransactionManager是Ҏ前两个方法决定是否要创徏一个新事务Q是要递交q是回滚。至于第三个Ҏ是改变事务当前状态的Q很多地斚w要用刎ͼ偏偏PlatformTransactionManager自n好像不怎么用,毕竟事务状态的改变是由E序员代码决定的Q不需要一个manager多管闲事?/p>

ȝ上面所说的Qspring的事务由PlatformTransactionManager理Qmanager最后调用事务源的方法来实现一个事务过E。而manager通过TransactionStatus 来决定如何实现?
接下去说spring事务中的TransactionTemplate和TransactionInterceptor

TransactionTemplate其实和spring中其他的template的作用类|起到化简代码的作用,不要被它那么长的名字吓倒了Q事实上q个templateq不是什么非常核心的对象。如果比较学I派的,可以ȝ看template设计模式Q在此就不再Ҏ赘述了?
Z么要有TransactionTemplateQ先来看看如果没有TransactionTemplateQ我们的代码该怎么?/p>

先来看看spring reference中的一D代?

代码
  1. DefaultTransactionDefinition def = new DefaultTransactionDefinition()   
  2. def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);   
  3.   
  4. TransactionStatus status = transactionManager.getTransaction(def);   
  5.   
  6. try {   
  7.     // execute your business logic here   
  8. catch (MyException ex) {   
  9.     transactionManager.rollback(status);   
  10.     throw ex;   
  11. }   
  12. transactionManager.commit(status);  

q是直接使用transactionManager的例子,可以看到真正执行business logic 的地Ҏ在try当中那段Q前后的代码都是Z完成事务理的。如果每个business logic都要写上那么一D,我肯定是疯了。我们翻出TransactionTemplate的代码看看他怎么化简了我们的代码

代码
  1. public Object execute(TransactionCallback action) throws TransactionException {   
  2.         TransactionStatus status = this.transactionManager.getTransaction(this);   
  3.         Object result = null;   
  4.         try {   
  5.             result = action.doInTransaction(status);   
  6.         }   
  7.         catch (RuntimeException ex) {   
  8.             // transactional code threw application exception -> rollback   
  9.             rollbackOnException(status, ex);   
  10.             throw ex;   
  11.         }   
  12.         catch (Error err) {   
  13.             // transactional code threw error -> rollback   
  14.             rollbackOnException(status, err);   
  15.             throw err;   
  16.         }   
  17.         this.transactionManager.commit(status);   
  18.         return result;   
  19.     }  

同上面的代码如出一辙,前后是事务处理代码,当中那段result = action.doInTransaction(status);是我们的应用代码。至于action是什么,全看各位的需要了。但是有一点要主要Q如果利用TransactionTemplateQ那么他不管你扔Z么异帔R会回滚事务,但是回滚的是哪个事务呢?l箋挖代?

代码
  1. private void rollbackOnException(TransactionStatus status, Throwable ex) throws TransactionException {   
  2.         if (logger.isDebugEnabled()) {   
  3.             logger.debug("Initiating transaction rollback on application exception", ex);   
  4.         }   
  5.         try {   
  6.             this.transactionManager.rollback(status);   
  7.         }   
  8.         catch (RuntimeException ex2) {   
  9.             logger.error("Application exception overridden by rollback exception", ex);   
  10.             throw ex2;   
  11.         }   
  12.         catch (Error err) {   
  13.             logger.error("Application exception overridden by rollback error", ex);   
  14.             throw err;   
  15.         }   
  16.     }  

真相大白Q是对template所持有的某个transactionManagerq行回滚。所以如果你的应用代码用的是事务源a的一些资源,比如到服务器a的一个datasourceQ但是你的transactionManager理的是另一些资源,比如服务器b的一个datasourceQ代码铁定不会正常运?

特别是在一些多事务源的E序里,q点千万不能搞错。如果多个事务源之间要完成全局事务Q还是老老实实用分布式事务管理服务吧QjtaQ?/p>

那么TransactionInterceptor是干什么的Q这个是spring 的声明式事务的支持方式。因为用TransactionTemplate要硬~码Q而且调整事务{略很麻烦(不是说不能调。D个例子原来程序抛出异常A需要回滚,现在不需要要Q我可以把a catch吃掉。这时候template׃会回滚了。但是每ơ调整都要重写编码。)而用TransactionInterceptor可以将q些调整写在配置中。我们再来挖TransactionInterceptor的代?/p>

代码
  1. public Object invoke(MethodInvocation invocation) throws Throwable {   
  2.         // Work out the target class: may be null.   
  3.         // The TransactionAttributeSource should be passed the target class   
  4.         // as well as the method, which may be from an interface   
  5.         Class targetClass = (invocation.getThis() != null) ? invocation.getThis().getClass() : null;   
  6.            
  7.         // Create transaction if necessary   
  8.         TransactionInfo txInfo = createTransactionIfNecessary(invocation.getMethod(), targetClass);   
  9.   
  10.         Object retVal = null;   
  11.         try {   
  12.             // This is an around advice.   
  13.             // Invoke the next interceptor in the chain.   
  14.             // This will normally result in a target object being invoked.   
  15.             retVal = invocation.proceed();   
  16.         }   
  17.         catch (Throwable ex) {   
  18.             // target invocation exception   
  19.             doCloseTransactionAfterThrowing(txInfo, ex);   
  20.             throw ex;   
  21.         }   
  22.         finally {   
  23.             doFinally(txInfo);   
  24.         }   
  25.         doCommitTransactionAfterReturning(txInfo);   
  26.   
  27.         return retVal;   
  28.     }  

万变不离其宗?

所以用spring的事务管理需要作q些?
1Q设|好事务源,比如DataSourceQhibernate的session。如果有多个事务源要考虑他们之间是否有全局事务Q如果有Q老老实实用jtaQ否则就需要自己写一个manager?
2Q设|managerQ根据你的事务源选择对应的PlatformTransactionManager
3Q选择实现事物的方式,用templateq是interceptor。用template代码直观点,但是template所辖的manager和你应用代码所用的事务源要一致。如果用interceptor千万注意Q一定要调用interceptor那个beanQ而不是原始的那个target。在坛子上我已经看到臛_有两个朋友说spring事物不v作用Q从配置和代码上看都正确Q这时要好好查查Q调用的bean是哪一个?
4Q这个是设计问题了,推荐事务处于一个较高层ơ,比如service上的某个函数Q而底层的dao可以不考虑事务Q否则可能会出现事务嵌套Q增加程序复杂度?/p>

]]>
理解 java中Stringhttp://m.tkk7.com/NeonWay/archive/2007/01/15/93859.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Mon, 15 Jan 2007 01:56:00 GMThttp://m.tkk7.com/NeonWay/archive/2007/01/15/93859.htmlhttp://m.tkk7.com/NeonWay/comments/93859.htmlhttp://m.tkk7.com/NeonWay/archive/2007/01/15/93859.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/93859.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/93859.htmlhttp://www.javaeye.com/post/199106

 要理?java中String的运作方式,必须明确一点:String是一个非可变c(immutableQ。什么是非可变类呢?单说来,非可变类的实例是不能被修改的Q每个实例中包含的信息都必须在该实例创徏的时候就提供出来Qƈ且在对象的整个生存周期内固定不变。javaZ么要把String设计为非可变cdQ你可以问问 james Gosling Q)。但是非可变cȝ实有着自n的优势,如状态单一Q对象简单,便于l护。其ơ,该类对象对象本质上是U程安全的,不要求同步。此外用户可以共享非可变对象Q甚臛_以共享它们的内部信息。(详见 《Effective java》item 13Q。Stringcdjava中被大量q用Q甚臛_class文g中都有其w媄Q因此将其设计ؓ单轻便的非可变类是比较合适的?

一、创建?br />    好了Q知道String是非可变cM后,我们可以q一步了解String的构造方式了。创Z个Stirng对象Q主要就有以下两U方式:

java 代码
  1. String str1 = new String("abc");    
  2. Stirng str2 = "abc";  

     虽然两个语句都是q回一个String对象的引用,但是jvm对两者的处理方式是不一L。对于第一U,jvm会马上在heap中创Z个String对象Q然后将该对象的引用q回l用戗对于第二种Qjvm首先会在内部l护的strings pool中通过String?equels Ҏ查找是对象池中是否存放有该String对象Q如果有Q则q回已有的String对象l用P而不会在heap中重新创Z个新的String对象Q如果对象池中没有该String对象Qjvm则在heap中创建新的String对象Q将其引用返回给用户Q同时将该引用添加至strings pool中。注意:使用W一U方法创建对象时Qjvm是不会主动把该对象放到strings pool里面的,除非E序调用 String的internҎ。看下面的例子:

java 代码
  1. String str1 = new String("abc"); //jvm 在堆上创Z个String对象   
  2.   
  3.  //jvm 在strings pool中找不到gؓ“abc”的字符Ԍ因此   
  4.  //在堆上创Z个String对象Qƈ该对象的引用加入至strings pool?  
  5.  //此时堆上有两个String对象   
  6. Stirng str2 = "abc";   
  7.   
  8.  if(str1 == str2){   
  9.          System.out.println("str1 == str2");   
  10.  }else{   
  11.          System.out.println("str1 != str2");   
  12.  }   
  13.   //打印l果是 str1 != str2,因ؓ它们是堆上两个不同的对象   
  14.   
  15.   String str3 = "abc";   
  16.  //此时Qjvm发现strings pool中已有“abc”对象了Q因为“abc”equels “abc?  
  17.  //因此直接q回str2指向的对象给str3Q也是说str2和str3是指向同一个对象的引用   
  18.   if(str2 == str3){   
  19.          System.out.println("str2 == str3");   
  20.   }else{   
  21.          System.out.println("str2 != str3");   
  22.   }   
  23.  //打印l果为 str2 == str3  

   再看下面的例子:

java 代码
  1. String str1 = new String("abc"); //jvm 在堆上创Z个String对象   
  2.   
  3. str1 = str1.intern();   
  4. //E序昑ּstr1攑ֈstrings pool中,internq行q程是这LQ首先查看strings pool   
  5. //有没“abc”对象的引用Q没有,则在堆中新徏一个对象,然后新对象的引用加入至   
  6. //strings pool中。执行完该语句后Qstr1原来指向的String对象已经成ؓ垃圾对象了,随时?  
  7. //被GC攉?  
  8.   
  9. //此时Qjvm发现strings pool中已有“abc”对象了Q因为“abc”equels “abc?  
  10. //因此直接q回str1指向的对象给str2Q也是说str2和str1引用着同一个对象,   
  11. //此时Q堆上的有效对象只有一个?  
  12. Stirng str2 = "abc";   
  13.   
  14.  if(str1 == str2){   
  15.          System.out.println("str1 == str2");   
  16.  }else{   
  17.          System.out.println("str1 != str2");   
  18.  }   
  19.   //打印l果是 str1 == str2   
  20.   


    Z么jvm可以q样处理String对象呢?是因ؓString的非可变性。既然所引用的对象一旦创建就怸更改Q那么多个引用共用一个对象时互不影响?/p>


二、串接(ConcatenationQ?br />     javaE序员应该都知道滥用String的串接操作符是会影响E序的性能的。性能问题从何而来呢?归根l底是Stringcȝ非可变性。既然String对象都是非可变的Q也是对象一旦创Z׃能够改变其内在状态了Q但是串接操作明显是要增长字W串的,也就是要改变String的内部状态,两者出C矛盾。怎么办呢Q要l护String的非可变性,只好在串接完成后新徏一个String 对象来表C新产生的字W串了。也是_每一ơ执行串接操作都会导致新对象的生,如果串接操作执行很频J,׃D大量对象的创建,性能问题也就随之而来了?br />    Z解决q个问题Qjdk为StringcL供了一个可变的配套c,StringBuffer。用StringBuffer对象Q由于该cL可变的,串接时仅仅时改变了内部数据结构,而不会创建新的对象,因此性能上有很大的提高。针对单U程Qjdk 5.0q提供了StringBuilderc,在单U程环境下,׃不用考虑同步问题Q用该cM性能得到q一步的提高?/p>

三、String的长?br />   我们可以使用串接操作W得C个长度更长的字符Ԍ那么QString对象最多能容纳多少字符呢?查看String的源代码我们可以得知cString中是使用?count 来记录对象字W的数量Q而count 的类型ؓ intQ因此,我们可以推测最长的长度?2^32Q也是4G?br />    不过Q我们在~写源代码的时候,如果使用 Sting str = "aaaa";的Ş式定义一个字W串Q那么双引号里面的ASCII字符最多只能有 65534 个。ؓ什么呢Q因为在class文g的规范中Q?CONSTANT_Utf8_info表中使用一?6位的无符h数来记录字符串的长度的,最多能表示 65536个字节,而java class 文g是用一U变体UTF-8格式来存攑֭W的Qnullg用两个字节来表示Q因此只剩下 65536Q?2 Q?65534个字节。也正是变体UTF-8的原因,如果字符串中含有中文{非ASCII字符Q那么双引号中字W的数量会更(一个中文字W占用三个字节)。如果超个数量,在编译的时候编译器会报错?/p>

]]>
关于|页采集http://m.tkk7.com/NeonWay/archive/2006/11/15/81328.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Wed, 15 Nov 2006 09:24:00 GMThttp://m.tkk7.com/NeonWay/archive/2006/11/15/81328.htmlhttp://m.tkk7.com/NeonWay/comments/81328.htmlhttp://m.tkk7.com/NeonWay/archive/2006/11/15/81328.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/81328.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/81328.htmlhttp://m.tkk7.com/ekinglong/archive/2006/11/12/80704.html

http://m.tkk7.com/ekinglong/archive/2006/10/27/77688.html

]]>
Hibernate中对Session理http://m.tkk7.com/NeonWay/archive/2006/09/09/68662.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Sat, 09 Sep 2006 02:04:00 GMThttp://m.tkk7.com/NeonWay/archive/2006/09/09/68662.htmlhttp://m.tkk7.com/NeonWay/comments/68662.htmlhttp://m.tkk7.com/NeonWay/archive/2006/09/09/68662.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/68662.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/68662.html Hibernate中对Session理

在各USession 理Ҏ中, ThreadLocal 模式得到了大量用。ThreadLocal 是Java中一U较为特D的U程l定机制。通过ThreadLocal存取的数据,L与当前线E相养I也就是说QJVM 为每个运行的U程Q绑定了U有的本地实例存取空_从而ؓ多线E环境常出现的ƈ发访问问题提供了一U隔L制。首先,我们需要知道,SessionFactory负责创徏SessionQSessionFactory是线E?br />安全的,多个q发U程可以同时讉K一个SessionFactory q从中获取Session 实例。?br />SessionqU程安全Q也是_如果多个U程同时使用一个Session实例q行数据存取Q?br />则将会导致Session 数据存取逻辑混ؕ。下面是一个典型的ServletQ我们试N过一个类
变量session实现Session的重用,以避免每ơ操作都要重新创建:
public class TestServlet extends HttpServlet {
private Session session;
public void doGet( HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
session = getSession();
doSomething();
session.flush();
}
public void doSomething(){
......//Zsession的存取操?br />}
}
代码看上L无误,甚至在我们单机测试的时候可能也不会发生什么问题,但这L?br />Hibernate Developer's Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
码一旦编译部|到实际q行环境中,接踵而来的莫名其妙的错误很可能会使得我们怸扑֤脑?br />问题出在哪里Q?br />首先QServlet q行是多U程的,而应用服务器q不会ؓ每个U程都创Z个Servlet
实例Q也是_TestServlet在应用服务器中只有一个实例(在Tomcat中是q样Q其他的
应用服务器可能有不同的实玎ͼQ而这个实例会被许多个U程q发调用QdoGet Ҏ也将被不
同的U程反复调用Q可惌知Q每ơ调用doGet ҎQ这个唯一的TestServlet 实例?br />session 变量都会被重|,U程A 的运行过E中Q其他的U程如果也被执行Q那么session
的引用将发生改变Q之后线EA 再调用sessionQ可能此时的session 与其之前所用的
session׃再一_昄Q错误也׃期而至?br />ThreadLocal的出玎ͼ使得q个问题q刃而解?br />我们对上面的例子q行一些小的修改Q?br />public class TestServlet extends HttpServlet {
private ThreadLocal localSession = new ThreadLocal();
public void doGet( HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
localSession.set(getSession());
doSomething();
session.flush();
}
public void doSomething(){
Session session = (Session)localSession.get();
......//Zsession的存取操?br />}
}
可以看到QlocalSession 是一个ThreadLocal cd的对象,在doGet Ҏ中,我们
通过其set Ҏ获取的session 实例保存Q而在doSomething Ҏ中,通过get Ҏ?br />出session实例?br />q也是ThreadLocal的独特之处,它会为每个线E维护一个私有的变量I间。实际上Q?br />其实现原理是在JVM 中维护一个MapQ这个Map的key 是当前的线E对象,而value则是
U程通过ThreadLocal.setҎ保存的对象实例。当U程调用ThreadLocal.getҎӞ
ThreadLocal会根据当前线E对象的引用Q取出Map中对应的对象q回?br />q样QThreadLocal通过以各个线E对象的引用作ؓ区分Q从而将不同U程的变量隔d
来?
Hibernate官方开发手册的CZ中,提供了一个通过ThreadLocall护Session的好
榜样Q?

public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory
sessionFactory = new
Configuration().configure().buildSessionFactory();
} catch (HibernateException ex) {
throw new RuntimeException(
"Configuration problem: " + ex.getMessage(),
ex
);
}
}
public static final ThreadLocal session = new ThreadLocal();
public static Session currentSession() throws HibernateException
{
Session s = (Session) session.get();
// Open a new Session, if this Thread has none yet
if (s == null) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
在代码中Q只要借助上面q个工具c获取Session 实例Q我们就可以实现U程范围内的
Session ׃nQ从而避免了在线E中频繁的创建和销毁Session 实例。不q注意在U程l束
时关闭Session?br />
同时值得一提的是,新版本的Hibernate在处理Session的时候已l内|了延迟加蝲?br />Ӟ只有在真正发生数据库操作的时候,才会从数据库q接池获取数据库q接Q我们不必过于担
心Session的共享会D整个U程生命周期内数据库q接被持l占用?br />


对于WebE序
而言Q我们可以借助Servlet2.3规范中新引入的Filter机制Q轻村֮现线E生命周期内?br />Session理Q关于Filter的具体描qͼ请参考Servlet2.3规范Q?br />Filter的生命周期诏I了其所覆盖的ServletQJSP也可以看作是一U特D的ServletQ?br />及其底层对象。Filter在Servlet被调用之前执行,在Servlet调用l束之后l束。因此,
在Filter 中管理Session 对于Web E序而言显得水到渠成。下面是一个通过Filter q?br />行Session理的典型案例:
public class PersistenceFilter implements Filter
{
protected static ThreadLocal hibernateHolder = new ThreadLocal();
public void doFilter(ServletRequest request, ServletResponse
response, FilterChain chain)
throws IOException, ServletException
{
hibernateHolder.set(getSession());
try
{
......
chain.doFilter(request, response);
......
}
finally
{
Session sess = (Session)hibernateHolder.get();
if (sess != null)
{
hibernateHolder.set(null);
try
{
sess.close();
}
catch (HibernateException ex) {
throw new ServletException(ex);
}
}
}
}
......
Hibernate Developer's Guide Version 1.0
September 2, 2004 So many open source projects. Why not Open your Documents?
}
通过在doFilter中获取和关闭SessionQƈ在周期内q行的所有对象(Filter链中?br />余的FilterQ及其覆盖的Servlet 和其他对象)ҎSession 实例q行重用Q保证了一?br />Http Request处理q程中只占用一个SessionQ提高了整体性能表现?br />在实际设计中QSession的重用做到线E别一般已l够,企图通过HttpSession?br />现用L的Session重用反而可能导致其他的问题。凡事不能过火,Session重用也一栗?br />

 转自:http://bbs.tech.ccidnet.com/read.php?tid=147661


]]>
hibernate集合映射inverse和cascade详解 Q{载)http://m.tkk7.com/NeonWay/archive/2006/09/09/68659.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Sat, 09 Sep 2006 02:00:00 GMThttp://m.tkk7.com/NeonWay/archive/2006/09/09/68659.htmlhttp://m.tkk7.com/NeonWay/comments/68659.htmlhttp://m.tkk7.com/NeonWay/archive/2006/09/09/68659.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/68659.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/68659.html?. hibernate如何Ҏpojo来更新数据库

4.0 在commit/flush之前Qhibernate不会对pojo对象作神U的处理?br />4.0.1 在select查询出pojoӞhibernateҎ“字D?-属性”的对应关系Q用字段的值填充pojo的属性;
然后Ҏ“关pL记”生成sql语句从relationTable中查询出满条g的relationPojoQƈ把这些relatinPojo
攑ֈ“关pd性”中。这个过E是机械的?br />
4.0.2 在pojo对象被查出来后,到commit(或flush)之前Q它是一个普通的java对象Qhibernate不会做额外的手脚?br />比如Q不会限制你讄一个属性的gؓnull或其它Q何?br />在集合类Set的add(object)操作Ӟ 不会改变object的|不会查参数object是否是一个pojo对象
讄mainPojo的一个“桥属性”的|不会自动讄relationPojo的对应的“桥属性”的倹{?br />执行session.delete(pojo)Ӟpojo本n没有变化Q他的属性g没有变化?br />执行session.save(pojo)Ӟ如果pojo的id不是hibernate或数据库生成,则它的值没有变化?br />如果pojo的id是hibernate或数据库生成Q则hibernate会把idlpojo设上厅R?br />
extend: 对lazy=true的setQhibernate在进行set的操?调用java.util.Set中声明的Ҏ)?br />会先inializeq个setQ仅此而已。而inialize仅仅是从数据库中捞出set的数据?
如果一个set已经被inialize了,那么对它q行的操作就是java.util.Set接口中定义的语义?br />
另外Q如果id由hibernate来生成,那么在save(pojo)Ӟhibernate会改变该pojoQ会讄它的idQ这
可能改变该pojo的hashCodeQ详l地讨论见帖《?br />
mapping文g中标记的某些属性及pojo对象的操作会Ҏ据库操作产生影响Q这些媄响都是在commit时才会v作用?br />而在commit前pojo的状态不受它们的影响?br />
不过Q待commit之时Q将由hibernate完全掌控Q它好像知道pojo对象从创建到commitq中间的所有变化?br />

4.01. 兌更新
"关系标记"对应的属性是一个pojo或一个pojo的集合,修改“关pd性”的D会导致更新mainTable表,也可能会更新relationTable表?br />
q种更新暂叫“关联更新”?br />

4.1.inverse属性的作用Q假定没有设|cascade属性)
4.1.1 “只有集合标讎ͼset/map/list/array/bagQ才有inverse属性”?br />————不妨以标记setZQ具体ؓ“一个地区(Address表)的学校(School表)?-- address.schoolSet?br />
4.1.2 “set的inverse属性决定是否把对set的改动反映到数据库中厅R?br />inverse=false————反映;inverse=true————不反映?br />inverse属性默认ؓfalse

?lt;one-to-many>?lt;many-to-many>子标讎ͼq两条都适用?br />不管是对set做什么操作,4.1.2都适用?br />
4.1.3当inverse=falseӞhibernate如何对set的改动反映到数据库中Q?br />
对set的操作主要有Q(1Q新增元?address.getSchoolSet().add(oneSchool);
Q?Q删除元?address.getSchoolSet().remove(oneSchool);
Q?Q删除set address.setSchoolSet(null);
Q?Q设新set address.setSchoolSet( newSchoolSet);
Q?Q{Uset otherSchoolSet = otherAddress.getSchoolSet();
otherAddress.setSchoolSet(null);
address.setSchoolSet(otherSchoolSet);
Q?Q改变set中元素的属性的?如果是改变key属性,q会D异常
如果改变的是普通的属性,则hibernate认ؓset没有变化Q在后面可以看出~由Q?br />所以这U情形不予考虑?br />
改变set后,hibernateҎ据库的操作根据是<one-to-many>关系q是<many-to-many>关系而有不同?br />
对one-to-manyQ对school set的改动,会改变表SCHOOL中的数据:
#SCHOOL_ID是school表的主键QSCHOOL_ADDRESS是school表中的地址栏位
#表School的外键ؓSCHOOL_ADDRESSQ它对应表Address的主键ADDRESS_ID
Q?1Qinsert oneSchool———?sqlInsertRowString:
update SCHOOL set SCHOOL_ADDRESS=? where SCHOOL_ID=?
(仅仅update foreign-key的倹{?
Q?2Qdelete oneSchool———?sqlDeleteRowString:
update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ID=?
Q很奇怪,把foreign-key讄为null不知道有什么实际意义?Q?br />Q?3Qdelete 属于某一address的所有school ————sqlDeleteStringQ?br />update SCHOOL set SCHOOL_ADDRESS=null where SCHOOL_ADDRESS=?
Q?4Qupdate ————sqlUpdateRowStringQ?"Q?no need

对many-to-manyQ对school set的改动,会改变关p表ADDRESS_SCHOOL中的数据:
#“地区————学校”的关系为多对多的关pL点牵强,只是Z方便与上面的one-to-many作比?br />#假设有一个关p表ADDRESS_SCHOOLQ有两个字段ADDRESS_ID, SCHOOL_IDQ?br />#q两个字D分别对应ADDRESS和SCHOOL两表的key
Q?1Qinsert的SQL语句为: insert into ADDRESS_SCHOOL(ADDRESS_ID, SCHOOL_ID)
values(?,?)
Q?2Qdelete的SQL语句为: delete from ADDRESS_SCHOOL
where ADDRESS_ID=? AND SCHOOL_ID=?
Q?3Qdelete all的SQL语句为: delete from ADDRESS_SCHOOL
where ADDRESS_ID=?
Q?4Qupdate的sql语句?————sqlUpdateRowStringQ?br />update ADDRESS_SCHOOL set ADDRESS_ID=?
where ADDRESS_ID=? AND SCHOOL_ID=?

对set的操?1),hibernate会执?11)sqlInsertRowString
对set的操?2),hibernate会执?22)sqlDeleteRowString
对set的操?3),hibernate会执?33)sqlDeleteString
对set的操?4),老的schoolSet因ؓ没有所属的address,所以被全部delete掉,卛_执行(33)sqlDeleteString
然后新增新的schoolSet,卛_执行sqlInsertRowString
对set的操?5)Q实际上是set从一个pojo转移到另一pojoQ?br />首先Q执行sqlDeleteStringQ删除掉otherAddress所属的school
然后Q执行sqlDeleteStringQ删除掉address原先的school
最后,执行sqlInsertRowStringQ将otherSchoolSet新增laddress

ȝQ(1Q对one-to-many而言Q改变setQ会让hibernate执行一pd的update语句Q?不会delete/insert数据
Q?Q对many-to-many而言Q改变set,只修改关p表的数据,不会影响many-to-many的另一斏V?br />Q?Q虽然one-to-many和many-to-many的数据库操作不一P但目的都是一个:l护数据的一致性。执行的sql?br />只涉及到“桥字段”,不会考虑或改变其他的字段Q所以对set的操?6)是没有效果地?br />extend:对list,可能q会l护index字段?br />
4.1.4 “inverse与cascade没有什么关p,互无牉|。?br />commit后,q两个属性发挥作用的时机不同Qhibernate会根据对pojo对象的改动,及cascade属性的讄Q?br />生成一pd的ActionQ比如UpdateAction,DeleteAction,InsertAction{,每个Action都有executeҎ以执行对应的sql语句?br />待所有这些Action都生成好了后Qhibernate再一h行它们,在执行sql前,inverse属性v作用Q?br />当inverse=trueӞ不执行sqlQ当inverse=falseӞ执行sql?br />
4.1.5 inverse的默认gؓfalseQ所以inverse属性默认会q行“关联更新”?br />
4.1.6 Q只对set + many-to-many讄inverse=falseQ其他的标记不考虑inverse属性?br />  p糕的是Q不讄inverse属性时Qinverse默认为false?br />
4.2. U联QcascadeQ属性的作用Q?
4.2.1 只有“关pL记”才有cascade属性:many-to-oneQone-to-one Qany,
set(map, bag, idbag, list, array) + one-to-many(many-to-many)

4.2.2 U联指的是当LҎ行操作时Q关联对象(被动方)是否同步执行同一操作?br />pojo和它的关pd性的关系是“主控方 -- 被动方”的关系Q如果关pd性是一个setQ那么被动方是set中的一个一个元素,?br />比如Q学校(SchoolQ有三个属性:地区(Address),校长QTheMasterQ和学生(SetQ?元素为Student)
执行session.delete(school)ӞU联军_是否执行session.delete(Address),session.delete(theMaster)Q?br />是否Ҏ个aStudent执行session.delete(aStudent)?br />
extend:q点和inverse属性是有区别的。见4.3.

4.2.3 一个操作因U联cascade可能触发多个兌操作。前一个操作叫“主控操作”,后一个操作叫“关联操作”?br />cascade属性的可选|
all : 所有情况下均进行关联操作?br />noneQ所有情况下均不q行兌操作。这是默认倹{?br />save-update:在执行save/update/saveOrUpdate时进行关联操作?br />deleteQ在执行delete时进行关联操作?

具体执行什么“关联操作”是Ҏ“主控操作”来的:
“主控操作?      “关联操作?br />session.saveOrUpdate --> session.saveOrUpdate (执行saveOrUpdate实际上会执行save或者update)
session.save ----> session.saveOrUpdate
session.udpate --> session.saveOrUpdate
session.delete --> session.delete

4.2.4 L操作和关联操作的先后序是“先保存oneQ再保存manyQ先删除manyQ再删除oneQ先updateL方,再update被动方?br />对于one-to-oneQ当其属性constrained="false"Q默认|Ӟ它可看作one-to-many关系Q?br />  当其属性constrained="true"Ӟ它可看作many-to-one关系Q?br />对many-to-manyQ它可看作one-to-many?br />
比如Q学校(SchoolQ有三个属性:地区(Address),校长QTheMasterQ其constrained="false"Q和学生(SetQ?元素为Student)
当执行session.save(school)Ӟ
实际的执行顺序ؓQsession.save(Address);
session.save(school);
session.save(theMaster);
for( Ҏ一个student ){
session.save(aStudent);
}

当执行session.delete(school)Ӟ
实际的执行顺序ؓQsession.delete(theMaster);
for( Ҏ一个student ){
session.delete(aStudent);
}
session.delete(school);
session.delete(Address);

当执行session.update(school)Ӟ
实际的执行顺序ؓQsession.update(school);
session.saveOrUpdate(Address);
session.saveOrUpdate(theMaster);
for( Ҏ一个student ){
session.saveOrUpdate(aStudent);
}
注意Qupdate操作因联引发的兌操作为saveOrUpdate操作Q而不是update操作?br />saveOrUpdate与update的区别是Q前者根据操作对象是保存了还是没有保存,而决定执行updateq是save

extends: 实际中,删除学校不会删除地区Q即地区的cascade一般设为false
另外Qmany-to-many关系很少讄cascade=trueQ而是讄inverse=false。这个反映了cascade和inverse的区别。见4.3

4.2.6 cascade的默认gؓfalseQ所以inverse属性默认会q行“关联更新”?br />
4.2.7 ȝQ联(cascadeQ就是操作一个对象时Q对它的属性(其cascade=trueQ也q行q个操作?br />

4.3 inverse和cascade的比?br />q两个属性本w互不媄响,但v的作用有些类|都能引发对关p表的更新?br />
4.3.1 inverse只对set+one-to-many(或many-to-many)有效Q对many-to-one, one-to-one无效?br />cascade对关pL记都有效?br />
4.3.2 inverse寚w合对象整体v作用Qcascade寚w合对象中的一个一个元素v作用Q如果集合ؓI,那么cascade不会引发兌操作?br />比如集合对象置为nullQ?school.setStudentSet(null)
inverseDhibernate执行:udpate STUDENT set SCHOOL_ID=null where SCHOOL_ID=?
cascade则不会执行对STUDENT表的兌更新Q?因ؓ集合中没有元素?br />
再比新增一个school, session.save(school)
inverseDhibernate执行Q?br />for( ?school的每一个student ){
udpate STUDENT set SCHOOL_ID=? where STUDENT_ID=? //学生的school_id改ؓ新的school的id
}
cascadeDhibernate执行Q?br />for( 对school的每一个student ){
session.save(aStudent); //对学生执行save操作
}

extends:如果改变集合中的部分元素Q比如新增一个元素)Q?br />inverse: hibernate先判断哪些元素改变了Q对改变的元素执行相应的sql
cascade: 它L寚w合中的每个元素执行关联操作?br />Q在兌操作中,hibernate会判断操作的对象是否改变Q?br />
4.3.2 两个起作用的时机不同Q?br />cascadeQ在对主控方操作ӞU联发生?br />inverse: 在flushӞcommit会自动执行flush)Q对session中的所有setQhibernate判断每个set是否有变化,
Ҏ变化的set执行相应的sqlQ执行之前,会有个判断:if( inverse == true ) return;

可以看出cascade在先Qinverse在后?br />
4.3.3 inverse 对set + one-to-many ?set + many-to-many L作用不同。hibernate生成的sql不同?br />对one-to-manyQhibernate对many方的数据库表执行update语句?br />对many-to-many, hibernate对关p表执行insert/update/delte语句Q注意不是对many方的数据库表而是关系表?br />
cascase 对set都是一致的Q不one-to-manyq是many-to-many。都单地把操作传递到set中的每个元素。所以它L更新many
方的数据库表?br />
4.3.4 Q只对set + many-to-many讄inverse=falseQ其他的标记不考虑inverse属性,都设为inverse=true?br /> 
  对cascadeQ一般对many-to-oneQmany-to-manyQconstrained=true的one-to-one 不设|联删除?br />
引自Q?a >http://bbs.tech.ccidnet.com/simple/index.php?t144447.html


王R锋的技术实?/a> 2006-09-09 10:00 发表评论
]]>
quartz学习ȝQ?/title><link>http://m.tkk7.com/NeonWay/archive/2006/08/09/62627.html</link><dc:creator>王R锋的技术实?/dc:creator><author>王R锋的技术实?/author><pubDate>Wed, 09 Aug 2006 10:52:00 GMT</pubDate><guid>http://m.tkk7.com/NeonWay/archive/2006/08/09/62627.html</guid><wfw:comment>http://m.tkk7.com/NeonWay/comments/62627.html</wfw:comment><comments>http://m.tkk7.com/NeonWay/archive/2006/08/09/62627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/NeonWay/comments/commentRss/62627.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/NeonWay/services/trackbacks/62627.html</trackback:ping><description><![CDATA[ <p> <font size="1">quartz学习ȝQ?br />一、关于job:<br />   用Quartz的行话讲Q作业是一个执行Q务的单JavacRQ务可以是MJava代码。只需你实现org.quartz.Job接口q且在出C重错误情况下抛出JobExecutionException异常卛_。Job接口包含唯一的一个方法execute()Q作业从q里开始执行。一旦实CJob接口和execute()ҎQ当Quartz定该是作业q行的时候,它将调用你的作业。Execute()Ҏ内就完全是你要做的事情。要注意Q自己实现job时必L一个public 的无参数的构造方?对于jobQ大多数情况下都要依赖于某些具体的条Ӟq时Q就要用到JobDataMap了。JobDataMap是Map的一个子c,获取时很单,直接用getҎok了,Z参数Q我们就可以定制不同的jobd了。下面是一个简单的jobQ用来列丑և所有的参数q且获得参数名ؓname的?</font> </p> <p> <font size="1">   public class HelloJob implements Job {</font> </p> <p> <font size="1"> private static Log _log = LogFactory.getLog(HelloJob.class);</font> </p> <p> <font size="1"> public HelloJob() {<br /> }</font> </p> <p> <font size="1"> public void execute(JobExecutionContext context)<br />   throws JobExecutionException {</font> </p> <p> <font size="1">  JobDataMap jobDataMap =  context.getJobDetail().getJobDataMap();</font> </p> <p> <font size="1">  _log.info("要执行的参数如下:");<br />  Iterator i = jobDataMap.entrySet().iterator();  <br />  while(i.hasNext()) {<br />  Map.Entry me = (Map.Entry)i.next();<br />  _log.info(me.getKey() + ": "+me.getValue());<br />  }  <br />  _log.info("U Are Welcome:"+jobDataMap.get("name"));<br /> }</font> </p> <p> <font size="1">     }</font> </p> <p> <br /> <font size="1">二、关于jobdetail:<br />    Quartzq不存储一个真正的Job实例Q相反的Q它通过jobdetail来定义job,q指定job的name和group,在一个调度器QSchedulerQ中,name和group是唯一被定义的Q一个触发器(trigger)只能指定一个job,但多个触发器可以指定同一个job.</font> </p> <p> <br /> <font size="1">三、关于Scheduler</font> </p> <p> <font size="1">    Scheduler的作用就是调用Q务,在指定的旉执行指定的Q务。主要方法如?</font> </p> <p> <font size="1">    scheduleJobҎ:</font> </p> <p> <font size="1">    scheduleJob(JobDetail jobDetail, Trigger trigger):把jobDetaild到调度器中,q指定触发器trigger.在这里要注意Q在同一个调度器中,jobDetail的name和group是唯一?Trigger的name和group也必L唯一的。如果在trigger中指定job的name,则该name必须和jobDetail的name保持一_否则会抛出异常?br />    scheduleJob(Trigger trigger):指定的trigger中必d含jobdetai的name.以便于让quartz知道要执行的dQ如果指定的jobdetail的name不在调度器中的Q务列表中Q则会抛出JobPersistenceException异常?/font> </p> <p> <font size="1">    deleteJob(String jobName,String groupName)Ҏ:<br />    删除指定的job,q且删除所有相兌的触发器。(Delete the identified Job from the Scheduler - and any associated Triggers.Q?/font> </p> <p> <font size="1">四、关于作业存?br />    Quartz提供两种基本作业存储cd?br />    <br />    W一U类型叫做RAMJobStoreQ它利用通常的内存来持久化调度程序信息。这U作业存储类型最Ҏ配置、构造和q行。对许多应用来说Q这U作业存储已l够了。然而,因ؓ调度E序信息是存储在被分配给JVM的内存里面,所以,当应用程序停止运行时Q所有调度信息将被丢失?br />    <br />    W二U类型称为JDBC作业存储。Quartz提供两种不同的实玎ͼ但两U实C般都需要JDBC驱动E序和后台数据库来持久化调度E序信息。这两种cd的不同在于你是否惌控制数据库事务或q释放控制给应用服务器例如BEA's WebLogic或Jboss。(q类gJ2EE领域中,Bean理的事务和和容器管理事务之间的区别Q这两种JDBC作业存储是: </font> </p> <p> <font size="1">    · JobStoreTXQ当你想要控制事务或工作在非应用服务器环境中是?Q注Q自己控制事务)?/font> </p> <p> <font size="1">    · JobStoreCMTQ当你工作在应用服务器环境中和想要容器控制事务时使用 (web服务器控制事??/font> </p> <p> <font size="1">五、关于触发器</font> </p> <p> <font size="1">      Quartz中的触发器用来告诉调度程序作业什么时候触发。框架提供了一把触发器cdQ但两个最常用的是SimpleTrigger和CronTrigger。SimpleTrigger为需要简单打火调度而设计?</font> </p> <p> <font size="1">      典型圎ͼ如果你需要在l定的时间和重复ơ数或者两ơ打火之间等待的U数打火一个作业,那么SimpleTrigger适合你?br />      <br />      另一斚wQ如果你有许多复杂的作业调度Q那么或讔R要CronTrigger?<br />     <br />      CronTrigger很强大,使用复杂的时间判断来使用Q效果很好?/font> </p> <p> <font size="1">六、关于Quartz中的几个表:<br />    QRTZ_TRIGGERS                   存放Trigger(包括SIMPLE_TRIGGERS和CRON_TRIGGERS)和jobDetail的对应关p?br />    QRTZ_TRIGGER_LISTENERS<br />    QRTZ_SIMPLE_TRIGGERS            存储单触发器  <br />    QRTZ_SCHEDULER_STATE<br />    QRTZ_PAUSED_TRIGGER_GRPS<br />    QRTZ_LOCKS<br />    QRTZ_JOB_LISTENERS<br />    QRTZ_JOB_DETAILS                 存储jobDetail<br />    QRTZ_FIRED_TRIGGERS<br />    QRTZ_CRON_TRIGGERS               存储复杂触发器CRON_TRIGGERS<br />    QRTZ_CALENDARS<br />    QRTZ_BLOB_TRIGGERS ?/font> </p> <p> <font size="1">    注:q几个表|上q没有相兌明,{研I一D后补充()?/font> </p> <p> <br /> <font size="1">七、把quartz集成到web应用?br />    1、根据quartz中提供的文档Q徏立数据库.<br />    2、把如下quartz.properties文g攄到classes目录?文g内容如下:<br />    <br /> #============================================================================<br /> # Configure Main Scheduler Properties  <br /> #============================================================================<br />        <br /> #调度器名Q无关紧?名字L?br /> org.quartz.scheduler.instanceName = ZXScheduler<br /> org.quartz.scheduler.instanceId = AUTO</font> </p> <p> <font size="1"> #============================================================================<br /> # Configure ThreadPool   配置数据库连接池<br /> #============================================================================</font> </p> <p> <font size="1"> org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool<br /> org.quartz.threadPool.threadCount = 12<br /> org.quartz.threadPool.threadPriority = 5</font> </p> <p> <font size="1"> #============================================================================<br /> # Configure JobStore  配置做业存储方式<br /> #============================================================================<br />        <br /> #相当于扫描频率,如果pȝZUQ应Ҏ?000,quartz默认为分U(60000Q?br /> org.quartz.jobStore.misfireThreshold = 1000</font> </p> <p> <font size="1"> #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore<br />        <br /> #在这里自己控制事?br /> org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX</font> </p> <p> <font size="1"> org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate<br /> org.quartz.jobStore.useProperties = false</font> </p> <p> <font size="1"> #配置dataSource?br /> org.quartz.jobStore.dataSource = myDS<br /> #表前~<br /> org.quartz.jobStore.tablePrefix = QRTZ_<br /> org.quartz.jobStore.isClustered = false</font> </p> <p> <font size="1"> #============================================================================<br /> # Configure Datasources  配置数据库的q接Q不用解?br /> #============================================================================</font> </p> <p> <font size="1"> org.quartz.dataSource.myDS.driver = com.microsoft.jdbc.sqlserver.SQLServerDriver<br /> org.quartz.dataSource.myDS.URL = jdbc:microsoft:sqlserver://127.0.0.1:1433;DatabaseName=quartzTest<br /> org.quartz.dataSource.myDS.user = sa<br /> org.quartz.dataSource.myDS.password = sa<br /> org.quartz.dataSource.myDS.maxConnections = 5</font> </p> <p> <font size="1">    3、配|web.xml,启动quartz的初试化c?d初始化servlet</font> </p> <p> <font size="1">   <servlet> <br />    <servlet-name>QuartzInitializer</servlet-name> <br />    <servlet-class>org.quartz.ee.servlet.QuartzInitializerServlet</servlet-class> <br />    <init-param><br />      <param-name>shutdown-on-unload</param-name><br />      <param-value>true</param-value><br />    </init-param><br />    <init-param><br />     <param-name>config-file</param-name><br />     <param-value>quartz.properties</param-value> <br />    </init-param><br />    <load-on-startup>2</load-on-startup><br />  </servlet>    <br />  <br />     4、系l配|完毕?/font> </p> <p> <font size="1">八、构造cron触发?个h译Q英文不好,莫见W?</font> </p> <p> <font size="1">    cron 触发器规?</font> </p> <p> <font size="1">    Seconds Minutes Hours Day-of-month Month Day-of-Week Year<br />    U     ?分    ?时   ?天         ?月  ?周        ?qb?<br />    </font> </p> <p> <font size="1">    Seconds            0-59    , - * / <br />    Minutes            0-59    , - * / <br />    Hours              0-23    , - * / <br />    Day-of-month       1-31    , - * ? / L C <br />    Month              1-12 or JAN-DEC    , - * / <br />    Day-of-Week        1-7 or SUN-SAT    , - * ? / L C # <br />    Year (Optional)    empty, 1970-2099    , - * / </font> </p> <p> <font size="1">    关于字符串的讄(在cron expression中所有字W不区分大小?:</font> </p> <p> <br /> <font size="1">    The '*' character is used to specify all values. For example, "*" in the minute field means "every minute".<br />    "*"字符被用来指定所有的|例如Q?*"在分钟字D|表示每一分钟</font> </p> <p> <font size="1">    The '?' character is allowed for the day-of-month and day-of-week fields. It is used to specify 'no specific value'. This is useful when you need to specify something in one of the two fileds, but not the other. See the examples below for clarification.<br />    "?"字符在天和周字段中用。表C没有指定|天和周字D|定一个,但不能两个都指定?Q?</font> </p> <p> <font size="1">    The '-' character is used to specify ranges For example "10-12" in the hour field means "the hours 10, 11 and 12".<br />    '-'字符被用来设|范_比如"10-12"在小时字D늚意义?10?11点,12?</font> </p> <p> <font size="1">    The ',' character is used to specify additional values. For example "MON,WED,FRI" in the day-of-week field means "the days Monday, Wednesday, and Friday".</font> </p> <p> <font size="1">    ','字符被用来设|添加的|例如在周字段讄"MON,WED,FRI"的意义即?在周一、周三、周五激z?/font> </p> <p> <font size="1">    The '/' character is used to specify increments. For example "0/15" in the seconds field means "the seconds 0, 15, 30, and 45". And "5/15" in the seconds field means "the seconds 5, 20, 35, and 50". You can also specify '/' after the '*' character - in this case '*' is equivalent to having '0' before the '/'.</font> </p> <p> <font size="1">    '/'字符被用来设|增量。例如秒字段讄"0/15"的意思ؓ?开始,?5U触发,卛_0?5?0?5U触发,U字D设|?5/15"的意思ؓQ从5开始,W?5U触发,卛_5?0?5?0U触?你还可以?*'后面使用'/'字符Q在q种情况?*'与字W?0'意义相同?/font> </p> <p> <br /> <font size="1">    The 'L' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "last", but it has different meaning in each of the two fields. For example, the value "L" in the day-of-month field means "the last day of the month" - day 31 for January, day 28 for February on non-leap years. If used in the day-of-week field by itself, it simply means "7" or "SAT". <br />    <br />    But if used in the day-of-week field after another value, it means "the last xxx day of the month" - for example "6L" means "the last friday of the month". When using the 'L' option, it is important not to specify lists, or ranges of values, as you'll get confusing results.<br />    'L'在天字段和周字段中用?L'字符?last'的羃写,但在两个字段中,它有不同的意义。例如,'L'在天字段的意思ؓ月的最后一天,在一月ؓ31Q非闰月2月ؓ28。如果在'L'用在周字D中Q意思ؓ'7'(周六),卛_?一周最后一天。但如果在周字段的另一个值后面,他意味着最后一个星期几在指定月。例?6L'意味着月的最后一个周?在?L'选项Ӟ指定列表或者范围是非常重要的,不然Ҏ被结果搞乱?/font> </p> <p> <font size="1">    The '#' character is allowed for the day-of-week field. This character is used to specify "the nth" XXX day of the month. For example, the value of "6#3" in the day-of-week field means the third Friday of the month (day 6 = Friday and "#3" = the 3rd one in the month). Other examples: "2#1" = the first Monday of the month and "4#5" = the fifth Wednesday of the month. Note that if you specify "#5" and there is not 5 of the given day-of-week in the month, then no firing will occur that month.<br />    '#'被用在周字段。它用来指定W几个周几中ȀzR如:"6#3"-->月的W三个周五;"2#1"-->月的W一个周一;"4#5"-->月的W五个周三。要注意Q如果要使用#后面?,但当月ƈ没有W五周相应的周天Q那么job不被执行(Ȁz)Q?/font> </p> <p> <font size="1">    The 'C' character is allowed for the day-of-month and day-of-week fields. This character is short-hand for "calendar". This means values are calculated against the associated calendar, if any. If no calendar is associated, then it is equivalent to having an all-inclusive calendar. A value of "5C" in the day-of-month field means "the first day included by the calendar on or after the 5th". A value of "1C" in the day-of-week field means "the first day included by the calendar on or after sunday".</font> </p> <p> <font size="1">    Support for the features described for the 'C' character is not complete<br />    'C'被用在天和周字段中,'C'?calendar'的羃?(不太明白Q关于日历的支持q不完善)</font> </p> <p> <font size="1">    Support for specifying both a day-of-week and a day-of-month value is not complete (you'll need to use the '?' character in on of these fields).<br />    同时在周、天中??'q不完善Q目前只在两者中使用一个?/font> </p> <p> <font size="1">    Pay attention to the effects of '?' and '*' in the day-of-week and day-of-month fields!<br />    要注??'?*'在周和天字段带来的媄响?br />    注意以下例子:</font> </p> <p> <font size="1">    1?0 15 10 * * 6L 2002-2005"   ?002?005q的每月每天?0Q?5触发?br />    2?0 15 10 ? * 6L 2002-2005"   ?002?005q的每月的最后一个周五触发?br />    1?表示每天Q覆盖了6L(最后一个周?</font> </p> <p> <font size="1"> </font> </p> <p> <font size="1"> </font> </p> <p> <font size="1"> </font> </p> <p> <font size="1"> </font> </p> <p> <font size="1">    </font> </p> <img src ="http://m.tkk7.com/NeonWay/aggbug/62627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/NeonWay/" target="_blank">王R锋的技术实?/a> 2006-08-09 18:52 <a href="http://m.tkk7.com/NeonWay/archive/2006/08/09/62627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>把java本地E序配置在windows服务来运?/title><link>http://m.tkk7.com/NeonWay/archive/2006/07/26/60112.html</link><dc:creator>王R锋的技术实?/dc:creator><author>王R锋的技术实?/author><pubDate>Wed, 26 Jul 2006 01:51:00 GMT</pubDate><guid>http://m.tkk7.com/NeonWay/archive/2006/07/26/60112.html</guid><wfw:comment>http://m.tkk7.com/NeonWay/comments/60112.html</wfw:comment><comments>http://m.tkk7.com/NeonWay/archive/2006/07/26/60112.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://m.tkk7.com/NeonWay/comments/commentRss/60112.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/NeonWay/services/trackbacks/60112.html</trackback:ping><description><![CDATA[ <font size="2">   步骤如下Q?br />       0、把javaE序转换为exe文gQ下载exe4j来{换:q程比较单,选择regular mode,excutable tyep 选择GUI Application,选择其他会有问题Q不能成功做成服务,按步骤生成yourApp.exe文g?br />       1、下载instsrv.exe和srvany.exeE序Q这是win2000自带的程序,在winxp中因为安全原因被去除Q可以在|上下蝲到?br />       2、把两个文g攄在与java的bin目录下,q行 x:\bin\instsrv.exe yourApp x:\bin\srvany.exe ,yourApp是要建立的服务名?br />       3、yourApp服务已经建立h了,打开注册表,展开"HKEY_LOCAL_MACHINE\SYSTEM\currentcontrolset\services",扑ֈyourApp ,在该下面新Z个名?Parameters"的项目,接着在“Parameters”项下新Z个类型ؓ字符串值的“application”子键,该键gؓ要执行的exe文g的磁盘全路径?br />       4、运行中输入"Services.msc"q回车,在列表中扑ֈ我们刚添加的yourApp 服务,把它讄动运行,q启动之?br />       5、配|完?</font><img src ="http://m.tkk7.com/NeonWay/aggbug/60112.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/NeonWay/" target="_blank">王R锋的技术实?/a> 2006-07-26 09:51 <a href="http://m.tkk7.com/NeonWay/archive/2006/07/26/60112.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使javaE序只运行一?/title><link>http://m.tkk7.com/NeonWay/archive/2006/07/12/57877.html</link><dc:creator>王R锋的技术实?/dc:creator><author>王R锋的技术实?/author><pubDate>Wed, 12 Jul 2006 14:23:00 GMT</pubDate><guid>http://m.tkk7.com/NeonWay/archive/2006/07/12/57877.html</guid><wfw:comment>http://m.tkk7.com/NeonWay/comments/57877.html</wfw:comment><comments>http://m.tkk7.com/NeonWay/archive/2006/07/12/57877.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/NeonWay/comments/commentRss/57877.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/NeonWay/services/trackbacks/57877.html</trackback:ping><description><![CDATA[ <p> <font size="2">使javaE序只运行一ơ,既只允许一个实例保留在内存?br /><br />主要是利用fileLockcL实现Ҏ件加锁,实现上述目的(多说无益Q代码如?:<br /><br />package com.neonway.oneinstance;</font> </p> <p> <font size="2">import java.io.*;</font> </p> <p> <font size="2">import java.nio.channels.*;</font> </p> <p> <br /> <font size="2">public class OneInstance {<br />    /**<br />     * @param args<br />     */<br />    public static void main(String[] args) {<br />     try {</font> </p> <p> <font size="2">            System.out.println("progran start ...");</font> </p> <p> <font size="2">            String filename = new String("test.txt");</font> </p> <p> <font size="2">            File testFile = new File(filename);<br />            RandomAccessFile raf;<br />            FileChannel fc;<br />            FileLock fl;</font> </p> <p> <font size="2">            testFile.createNewFile();</font> </p> <p> <font size="2">            if (testFile.canWrite()) {<br />                raf = new RandomAccessFile(testFile, "rw");<br />                fc = raf.getChannel();<br />                fl = fc.tryLock();</font> </p> <p> <font size="2">                if ((fl == null) || (fl.isValid() == false)) {<br />                    System.out.println("this is useing by another program!");<br />                } else {<br />                 System.out.println("program running...");<br />                    Thread.sleep(30 * 1000);<br />                    fl.release();<br />                }</font> </p> <p> <font size="2">                raf.close();<br />            }<br />           System.out.println("program end ...");<br />  } catch (Exception e) {<br />   e.printStackTrace();<br />  }<br />    }<br />}<br /></font> </p> <img src ="http://m.tkk7.com/NeonWay/aggbug/57877.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/NeonWay/" target="_blank">王R锋的技术实?/a> 2006-07-12 22:23 <a href="http://m.tkk7.com/NeonWay/archive/2006/07/12/57877.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>log4j配置详解http://m.tkk7.com/NeonWay/archive/2006/05/29/48717.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Mon, 29 May 2006 04:15:00 GMThttp://m.tkk7.com/NeonWay/archive/2006/05/29/48717.htmlhttp://m.tkk7.com/NeonWay/comments/48717.htmlhttp://m.tkk7.com/NeonWay/archive/2006/05/29/48717.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/48717.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/48717.html  Log4j日志理pȝ单用说?br />
    通常Q我们都提供一个名? log4j.properties的文Ӟ在第一ơ调用到Log4JӞLog4J会在c\径(../web-inf/class/当然也可以放到其它Q 何目录,只要该目录被包含到类路径中即可)中定位这个文Ӟq读入这个文件完成的配置。这个配|文件告 诉Log4J以什么样的格式、把什么样的信息、输出到什么地斏V?br />   Log4j有三个主要的lgQLoggers(记录?QAppenders (输出?和Layouts(布局)Q这里可单理解ؓ日志cdQ日志要输出的地方和日志以何UŞ式输出。综合用这三个lg可以L的记录信息的cd? U别Qƈ可以在运行时控制日志输出的样式和位置。下面对三个lg分别q行说明Q?br />   
  1?Loggers
   Loggerslg在此pȝ中被分ؓ五个U别QDEBUG、INFO、WARN、ERROR和FATAL。这五个U别是有序的,DEBUG < INFO < WARN < ERROR < FATALQ分别用来指定这条日志信息的重要E度,明白q一点很重要Q这里Log4j有一个规则:假设LoggersU别为PQ如果在Loggers中发 生了一个别Q比P高,则可以启动,否则屏蔽掉?br /> 假设你定义的U别是infoQ那么error和warn的日志可以显C比他低的debug信息׃昄了?br />   
  JavaE序举例来说Q?br />   
  //建立Logger的一个实例,命名为“com.foo?br />    Logger logger = Logger.getLogger("com.foo"); //"com.foo"是实例进行命名,也可以Q?br />   //讄logger的别。通常不在E序中设|logger的别。一般在配置文g中设|?br />   logger.setLevel(Level.INFO);
  Logger barlogger = Logger.getLogger("com.foo.Bar");
  //下面q个h可用Q因为WARN >= INFO
  logger.warn("Low fuel level.");
  //下面q个h不可用,因ؓDEBUG < INFO
  logger.debug("Starting search for nearest gas station.");
  //命名为“com.foo.bar”的实例barlogger会承实例“com.foo”的U别。因此,下面q个h可用Q因为INFO >= INFO
  barlogger.info("Located nearest gas station.");
  //下面q个h不可用,因ؓDEBUG < INFO
  barlogger.debug("Exiting gas station search");
  q里“是否可用”的意思是能否输出Logger信息?br />     在对Logger实例q行命名Ӟ没有限制Q可以取L自己感兴的名字。一般情况下以类的所在位|来命名Logger实例Q这是目前来讲比较有效的Logger命名方式。这样可以得每个类建立自己的日志信息,便于理。比如:
  
  static Logger logger = Logger.getLogger(ClientWithLog4j.class.getName());
  
  2、Appenders
  用与用日志请求只是Log4j其中的一个小的地方QLog4j日志pȝ允许把日志输出到不同的地方,如控制台QConsoleQ、文ӞFilesQ、根据天数或者文件大生新的文件、以的形式发送到其它地方{等?br />   
  其语法表CZؓQ?br />   
  org.apache.log4j.ConsoleAppenderQ控制台Q?br />   org.apache.log4j.FileAppenderQ文Ӟ
  org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ
    org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ
  org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)
  
  配置时用方式ؓQ?br />   log4j.appender.appenderName = fully.qualified.name.of.appender.class
  log4j.appender.appenderName.option1 = value1
  ?br />     log4j.appender.appenderName.option = valueN
  q样׃ؓ日志的输出提供了相当大的便利?br />   
  3、Layouts
   有时用户希望Ҏ自己的喜好格式化自己的日志输出。Log4j可以在Appenders的后面附加Layouts来完成这个功能。Layouts提供? 四种日志输出样式Q如ҎHTML样式、自由指定样式、包含日志别与信息的样式和包含日志旉、线E、类别等信息的样式等{?br />   
  其语法表CZؓQ?br />   
  org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
  org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
  org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
  org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)
  
  配置时用方式ؓQ?br />   
  log4j.appender.appenderName.layout =fully.qualified.name.of.layout.class
  log4j.appender.appenderName.layout.option1 = value1
  ?br />   log4j.appender.appenderName.layout.option = valueN

 Log4j的配|?
  
  以上是从原理斚w说明Log4j的用方法,在具体Java~程使用Log4j可以参照以下CZQ?br />   
  1?建立Logger实例Q?br />   语法表示Qpublic static Logger getLogger( String name)
  实际使用Qstatic Logger logger = Logger.getLogger(ServerWithLog4j.class.getName ()) ;
  
  2?d配置文gQ?br />   获得了Logger的实例之后,接下来将配置Log4j使用环境Q?br />   语法表示Q?br />   BasicConfigurator.configure()Q自动快速地使用~省Log4j环境?br />   PropertyConfigurator.configure(String configFilename)Q读取用Java的特性文件编写的配置文g?br />   DOMConfigurator.configure(String filename)Q读取XML形式的配|文件?br />   实际使用Q?br />     PropertyConfigurator.configure("ServerWithLog4j.properties");
  
  3?插入日志信息
  完成了以上连个步骤以后,下面可以按日志的不同别插入到你要记录日志的Q何地方了?br />   语法表示Q?br />   Logger.debug(Object message);//调试信息
  Logger.info(Object message);//一般信?br />   Logger.warn(Object message);//警告信息
  Logger.error(Object message);//错误信息
  Logger.fatal(Object message);//致命错误信息

  实际使用Qlogger.info("ServerSocket before accept: " + server);
  
  配置q程

 在实际编E时Q要使Log4j真正在系l中q行事先q要寚w|文件进行定义。定义步骤就是对Logger、Appender及Layout的分别用?br />     Log4j支持两种配置文g格式Q一U是XML格式的文Ӟ一U是java propertiesQkey=valueQ【JavaҎ文Ӟ?|】。下面我们介l用JavaҎ文件做为配|文件的Ҏ
   具体如下Q?br />   
  1、配|根LoggerQ?/strong>其语法ؓQ?br />   log4j.rootLogger = [ level ] , appenderName1, appenderName2, ?br />          level : 是日志记录的优先U,分ؓOFF、FATAL、ERROR、WARN、INFO、DEBUG、ALL或者您定义的别。Log4j只用四个别,? 先从高C分别是ERROR、WARN、INFO、DEBUG。通过在这里定义的U别Q您可以控制到应用程序中相应U别的日志信息的开兟뀂比如在q里? 义了INFOU别Q则应用E序中所有DEBUGU别的日志信息将不被打印出来?br />        appenderName:是指定日志信息输出到哪个地斏V您可以同时指定多个输出目的地?br />    例如Qlog4j.rootLoggerQinfo,A1,B2,C3
  
  2、配|日志信息输出目的地Q其语法为:
  log4j.appender.appenderName = fully.qualified.name.of.appender.class  //
    "fully.qualified.name.of.appender.class" 可以指定下面五个目的C的一个:
          1.org.apache.log4j.ConsoleAppenderQ控制台Q?br />           2.org.apache.log4j.FileAppenderQ文Ӟ
          3.org.apache.log4j.DailyRollingFileAppenderQ每天生一个日志文Ӟ
          4.org.apache.log4j.RollingFileAppenderQ文件大到达指定尺寸的时候生一个新的文Ӟ
          5.org.apache.log4j.WriterAppenderQ将日志信息以流格式发送到L指定的地方)
             1.ConsoleAppender选项
                    Threshold=WARN:指定日志消息的输出最低层ơ?br />                     ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />                     Target=System.errQ默认情况下是:System.out,指定输出控制?br />               2.FileAppender 选项
                    Threshold=WARN:指定日志消息的输出最低层ơ?br />                     ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />                     File=mylog.txt:指定消息输出到mylog.txt文g?br />                     Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />             3.DailyRollingFileAppender 选项
                    Threshold=WARN:指定日志消息的输出最低层ơ?br />                     ImmediateFlush=true:默认值是true,意谓着所有的消息都会被立卌出?br />                      File=mylog.txt:指定消息输出? mylog.txt文g?br />                     Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />                     DatePattern='.'yyyy-ww:每周滚动一ơ文Ӟx周生一个新的文件。当然也可以指定按月、周、天、时和分。即对应的格式如下:
                    1)'.'yyyy-MM: 每月
                    2)'.'yyyy-ww: 每周 
                    3)'.'yyyy-MM-dd: 每天
                    4)'.'yyyy-MM-dd-a: 每天两次
                    5)'.'yyyy-MM-dd-HH: 每小?br />                     6)'.'yyyy-MM-dd-HH-mm: 每分?br />             4.RollingFileAppender 选项
                     Threshold=WARN:指定日志消息的输出最低层ơ?br />                      ImmediateFlush=true:默认值是true,? 谓着所有的消息都会被立卌出?br />                     File=mylog.txt:指定消息输出到mylog.txt文g?br />                     Append=false:默认值是true,卛_消息增加到指定文件中Qfalse指将消息覆盖指定的文件内宏V?br />                     MaxFileSize=100KB: 后缀可以是KB, MB 或者是 GB. 在日志文件到达该大小Ӟ会自动滚动Q即原来的内容Udmylog.log.1文g?br />                     MaxBackupIndex=2:指定可以产生的滚动文件的最大数?/font>

实际应用Q?br />   log4j.appender.A1=org.apache.log4j.ConsoleAppender //q里指定了日志输出的W一个位|A1是控制台ConsoleAppender
  
  3、配|日志信息的格式Q其语法为:
  A.log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
              "fully.qualified.name.of.layout.class" 可以指定下面4个格式中的一个:
               1.org.apache.log4j.HTMLLayoutQ以HTML表格形式布局Q,
         2.org.apache.log4j.PatternLayoutQ可以灵zd指定布局模式Q,
         3.org.apache.log4j.SimpleLayoutQ包含日志信息的U别和信息字W串Q,
         4.org.apache.log4j.TTCCLayoutQ包含日志生的旉、线E、类别等{信息)
                   1.HTMLLayout 选项
                      LocationInfo=true:默认值是false,输出java文g名称和行?br />                       Title=my app file: 默认值是 Log4J Log Messages.
                   2.PatternLayout 选项
                      ConversionPattern=%m%n :指定怎样格式化指定的消息?br />                    3.XMLLayout  选项
                      LocationInfo=true:默认值是false,输出java文g和行?br />    实际应用Q?br />      log4j.appender.A1.layout=org.apache.log4j.PatternLayout

       B. log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
           q里需要说明的是日志信息格式中几个符h代表的含义:
           QX? X信息输出时左寚wQ?br />                    %p: 输出日志信息优先U,即DEBUGQINFOQWARNQERRORQFATAL,
                   %d: 输出日志旉点的日期或时_默认格式为ISO8601Q也可以在其后指定格式,比如Q?d{yyy MMM dd HH:mm:ss,SSS}Q输出类|2002q?0?8?22Q?0Q?8Q?21
                   %r: 输出自应用启动到输出该log信息耗费的毫U数
                   %c: 输出日志信息所属的cȝQ通常是所在类的全?br />                    %t: 输出产生该日志事件的U程?br />                    %l: 输出日志事g的发生位|,相当?C.%M(%F:%L)的组?包括cȝ名、发生的U程Q以及在代码中的行数。D例:Testlog4.main (TestLog4.java:10)
                   %x: 输出和当前线E相兌的NDC(嵌套诊断环境),其用到像java servletsq样的多客户多线E的应用中?br />                    %%: 输出一?%"字符
                   %F: 输出日志消息产生时所在的文g名称
                   %L: 输出代码中的行号
                   %m: 输出代码中指定的消息,产生的日志具体信?br />                    %n: 输出一个回车换行符QWindowsq_?\r\n"QUnixq_?\n"输出日志信息换行
            可以?与模式字W之间加上修饰符来控制其最宽度、最大宽度、和文本的对齐方式。如Q?br />                      1)%20cQ指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q默认的情况下右寚w?br />                      2)%-20c:指定输出category的名Uͼ最的宽度?0Q如果category的名U小?0的话Q?-"h定左寚w?br />                      3)%.30c:指定输出category的名Uͼ最大的宽度?0Q如果category的名U大?0的话Q就会将左边多出的字W截掉,但小?0? 话也不会有空根{?br />                      4)%20.30c:如果category的名U小?0pI格Qƈ且右寚wQ如果其名称长于30字符Q就从左边交q销出的字符截掉?/font>

  q里上面三个步骤是对前面Log4jlg说明的一个简化;下面l出一个具体配|例子,在程序中可以参照执行Q?br />   log4j.rootLogger=INFO,A1QB2
  log4j.appender.A1=org.apache.log4j.ConsoleAppender
  log4j.appender.A1.layout=org.apache.log4j.PatternLayout
  log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %d{yyyy-MM-dd HH:mm:ssS} %c %m%n
   Ҏ上面的日志格式,某一个程序的输出l果如下Q?br />   0  INFO 2003-06-13 13:23:46968 ClientWithLog4j Client socket: Socket[addr=localhost/127.0.0.1,port=8002,localport=2014]
         16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server says: 'Java server with log4j, Fri Jun 13 13:23:46 CST 2003'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j GOOD
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Command 'HELLO' not understood.'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j HELP
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j Server responds: 'Vocabulary: HELP QUIT'
  16  DEBUG 2003-06-13 13:23:46984 ClientWithLog4j QUIT
 
      4. # 当输Z息于回滚文g?/strong>

          log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender   //指定以文件的方式输出日志
           log4j.appender.ROLLING_FILE.Threshold=ERROR 
           log4j.appender.ROLLING_FILE.File=rolling.log  //文g位置,也可以用变量${java.home}、rolling.log
           log4j.appender.ROLLING_FILE.Append=true 
           log4j.appender.ROLLING_FILE.MaxFileSize=10KB  //文g最大尺?br />            log4j.appender.ROLLING_FILE.MaxBackupIndex=1  //备䆾?br />            log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout 
           log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n    

××××××××××××××××××××××××××××××××××××××××××××××××
 
 Log4j比较全面的配|?

 LOG4J的配|之单它遍及于来多的应用中了:Log4J配置文g实现了输出到控制台、文件、回滚文件、发送日志邮件、输出到数据库日志表、自定义标签{全套功能。择其一二用就够用了,

 log4j.rootLogger=DEBUG,CONSOLE,A1,im
 log4j.addivity.org.apache=true

 # 应用于控制台

 log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
 log4j.appender.Threshold=DEBUG
 log4j.appender.CONSOLE.Target=System.out
 log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
 log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
 #log4j.appender.CONSOLE.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD] n%c[CATEGORY]%n%m[MESSAGE]%n%n

 #应用于文?

 log4j.appender.FILE=org.apache.log4j.FileAppender
 log4j.appender.FILE.File=file.log
 log4j.appender.FILE.Append=false
 log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
 log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n
 # Use this layout for LogFactor 5 analysis

 # 应用于文件回?

 log4j.appender.ROLLING_FILE=org.apache.log4j.RollingFileAppender
 log4j.appender.ROLLING_FILE.Threshold=ERROR
 log4j.appender.ROLLING_FILE.File=rolling.log  //文g位置,也可以用变量${java.home}、rolling.log
 log4j.appender.ROLLING_FILE.Append=true       //true:d  false:覆盖
 log4j.appender.ROLLING_FILE.MaxFileSize=10KB   //文g最大尺?br />  log4j.appender.ROLLING_FILE.MaxBackupIndex=1  //备䆾?br />  log4j.appender.ROLLING_FILE.layout=org.apache.log4j.PatternLayout
 log4j.appender.ROLLING_FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


 #应用于socket
 log4j.appender.SOCKET=org.apache.log4j.RollingFileAppender
 log4j.appender.SOCKET.RemoteHost=localhost
 log4j.appender.SOCKET.Port=5001
 log4j.appender.SOCKET.LocationInfo=true
 # Set up for Log Facter 5
 log4j.appender.SOCKET.layout=org.apache.log4j.PatternLayout
 log4j.appender.SOCET.layout.ConversionPattern=[start]%d{DATE}[DATE]%n%p[PRIORITY]%n%x[NDC]%n%t[THREAD]%n%c[CATEGORY]%n%m[MESSAGE]%n%n


 # Log Factor 5 Appender
 log4j.appender.LF5_APPENDER=org.apache.log4j.lf5.LF5Appender
 log4j.appender.LF5_APPENDER.MaxNumberOfRecords=2000

 # 发送日志给邮g

 log4j.appender.MAIL=org.apache.log4j.net.SMTPAppender
 log4j.appender.MAIL.Threshold=FATAL
 log4j.appender.MAIL.BufferSize=10
 log4j.appender.MAIL.From=web@www.wuset.com
 log4j.appender.MAIL.SMTPHost=www.wusetu.com
 log4j.appender.MAIL.Subject=Log4J Message
 log4j.appender.MAIL.To=web@www.wusetu.com
 log4j.appender.MAIL.layout=org.apache.log4j.PatternLayout
 log4j.appender.MAIL.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

 # 用于数据?
 log4j.appender.DATABASE=org.apache.log4j.jdbc.JDBCAppender
 log4j.appender.DATABASE.URL=jdbc:mysql://localhost:3306/test
 log4j.appender.DATABASE.driver=com.mysql.jdbc.Driver
 log4j.appender.DATABASE.user=root
 log4j.appender.DATABASE.password=
 log4j.appender.DATABASE.sql=INSERT INTO LOG4J (Message) VALUES ('[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n')
 log4j.appender.DATABASE.layout=org.apache.log4j.PatternLayout
 log4j.appender.DATABASE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n


 log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
 log4j.appender.A1.File=SampleMessages.log4j
 log4j.appender.A1.DatePattern=yyyyMMdd-HH'.log4j'
 log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout

 #自定义Appender

 log4j.appender.im = net.cybercorlin.util.logger.appender.IMAppender

 log4j.appender.im.host = mail.cybercorlin.net
 log4j.appender.im.username = username
 log4j.appender.im.password = password
 log4j.appender.im.recipient = corlin@cybercorlin.net

 log4j.appender.im.layout=org.apache.log4j.PatternLayout
 log4j.appender.im.layout.ConversionPattern =[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

摘自:http://blog.csdn.net/eako/archive/2005/09/23/488099.aspx



]]>
CVSNT在win2000下的权限分配?/title><link>http://m.tkk7.com/NeonWay/archive/2006/05/26/48316.html</link><dc:creator>王R锋的技术实?/dc:creator><author>王R锋的技术实?/author><pubDate>Fri, 26 May 2006 05:53:00 GMT</pubDate><guid>http://m.tkk7.com/NeonWay/archive/2006/05/26/48316.html</guid><wfw:comment>http://m.tkk7.com/NeonWay/comments/48316.html</wfw:comment><comments>http://m.tkk7.com/NeonWay/archive/2006/05/26/48316.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://m.tkk7.com/NeonWay/comments/commentRss/48316.html</wfw:commentRss><trackback:ping>http://m.tkk7.com/NeonWay/services/trackbacks/48316.html</trackback:ping><description><![CDATA[ <p> <a href="/images/blogjava_net/neonway/11542/o_cvs.jpg"> <img height="64" alt="t_cvs.jpg" src="http://m.tkk7.com/images/blogjava_net/neonway/11542/t_cvs.jpg" width="120" border="0" /> </a> <br /> </p> <img src ="http://m.tkk7.com/NeonWay/aggbug/48316.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://m.tkk7.com/NeonWay/" target="_blank">王R锋的技术实?/a> 2006-05-26 13:53 <a href="http://m.tkk7.com/NeonWay/archive/2006/05/26/48316.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用.bat文g在Windows下运行JavaE序时怎样避免DOSH口 http://m.tkk7.com/NeonWay/archive/2006/04/24/42817.html王R锋的技术实?/dc:creator>王R锋的技术实?/author>Mon, 24 Apr 2006 04:51:00 GMThttp://m.tkk7.com/NeonWay/archive/2006/04/24/42817.htmlhttp://m.tkk7.com/NeonWay/comments/42817.htmlhttp://m.tkk7.com/NeonWay/archive/2006/04/24/42817.html#Feedback0http://m.tkk7.com/NeonWay/comments/commentRss/42817.htmlhttp://m.tkk7.com/NeonWay/services/trackbacks/42817.html我们在启动脚本中一般用类似如下的命o执行一个JavaE序Q?br />    java xxx.xxx.MailClass.class
或:
    java -jar xxx.jar
q样在JavaE序启动Ӟ加蝲的DOSH口一直出玎ͼ直到你关闭了JavaE序才一起关闭?br />
很多朋友询问怎样才能避免q个DOSH口Q你只需要把.bat中的启动命名修改为:
    start javaw xxx.xxx.MailClass.class
?
    start javaw -jar xxx.jar
卛_?br />

注:DOSH口q是会一闪而过Q因为javaw是一个需要dos加蝲的命令?

转自Q?a >http://affair.gzgo.gov.cn/java/display/8119.htm

]]>
վ֩ģ壺 ޹Ʒһ߹ۿ| Ļ˾Ʒ| ޾Ʒav| պѾƷƵ| ͬgayƬ| պƷAƬ| ޾ƷƵ| ƷѾƷ| 99ȾƷѹۿ| þ䰮| պƷһ | 3Dһ| ޾Ʒ| 97Ƶ˰| ɫwwwۺ| պƷרվ | һӰ߿Ƭ| һѹۿ| Ļ| AVһAV| ŷëƬAƵ޷| һëƬƵ| ƷѴƬһ| ۺŷۺվ| һƷ޶߲ | ۺһ| һƷ˾þ| Ƭѿڵ| ˬaëƬ| ŷŮƬѲƵ| һëƬ߹| ޹AV| ڵƷƵ| hƬѹۿ| ƷѹۿƵ| վ߲Ƶѹۿ| ŷձ| ޾Ʒר| AVҹ丣㽶149| ҹѸ| žƷƵ|