posts - 35,  comments - 7,  trackbacks - 0

随着Hibernate在Java开发中的广泛应用,我们在使用Hibernate进行对象持久化操作中也遇到了各种各样的问题。这些问题往往都是我们对Hibernate缺乏了解所致,这里我讲个我从前遇到的问题及一些想法,希望能给大家一点借鉴。
 
       这是在一次事务提交时遇到的异常。
       an assertion failure occured (this may indicate a bug in Hibernate, but is more likely due to unsafe use of the session)
net.sf.hibernate.AssertionFailure: possible nonthreadsafe access to session
注:非possible non-threadsafe access to the session (那是另外的错误,类似但不一样)
 
       这个异常应该很多的朋友都遇到过,原因可能各不相同。但所有的异常都应该是在flush或者事务提交的过程中发生的。这一般由我们在事务开始至事务提交的过程中进行了不正确的操作导致,也会在多线程同时操作一个Session时发生,这里我们仅仅讨论单线程的情况,多线程除了线程同步外基本与此相同。
 
       至于具体是什么样的错误操作那?我给大家看一个例子(假设Hibernate配置正确,为保持代码简洁,不引入包及处理任何异常)
  

SessionFactory sf = new Configuration().configure().buildSessionFactory() ;
Session s = sf.openSession();
Cat cat = new Cat();

Transaction tran = s.beginTransaction(); (1)
s.save(cat); (2)(此处同样可以为update delete)
s.evict(cat); (3)
tran.commit(); (4)
s.close();(5)


       这就是引起此异常的典型错误。我当时就遇到了这个异常,检查代码时根本没感觉到这段代码出了问题,想当然的认为在Session上开始一个事务,通过Session将对象存入数据库,再将这个对象从Session上拆离,提交事务,这是一个很正常的流程。如果这里正常的话,那问题一定在别处。
 
        问题恰恰就在这里,我的想法也许没有错,但是一个错误的论据所引出的观点永远都不可能是正确的。因为我一直以为直接在对数据库进行操作,忘记了在我与数据库之间隔了一个Hibernate,Hibernate在为我们提供持久化服务的同时,也改变了我们对数据库的操作方式,这种方式与我们直接的数据库操作有着很多的不同,正因为我们对这种方式没有一个大致的了解造成了我们的应用并未得到预先设想的结果。
 
那Hibernate的持久化机制到底有什么不同那?简单的说,Hibernate在数据库层之上实现了一个缓存区,当应用save或者update一个对象时,Hibernate并未将这个对象实际的写入数据库中,而仅仅是在缓存中根据应用的行为做了登记,在真正需要将缓存中的数据flush入数据库时才执行先前登记的所有行为。
 
在实际执行的过程中,每个Session是通过几个映射和集合来维护所有与该Session建立了关联的对象以及应用对这些对象所进行的操作的,与我们这次讨论有关的有entityEntries(与Session相关联的对象的映射)、insertions(所有的插入操作集合)、deletions(删除操作集合)、updates(更新操作集合)。下面我就开始解释在最开始的例子中,Hibernate到底是怎样运作的。
(1)生成一个事务的对象,并标记当前的Session处于事务状态(注:此时并未启动数据库级事务)。
(2)应用使用s.save保存cat对象,这个时候Session将cat这个对象放入entityEntries,用来标记cat已经和当前的会话建立了关联,由于应用对cat做了保存的操作,Session还要在insertions中登记应用的这个插入行为(行为包括:对象引用、对象id、Session、持久化处理类)。
(3)s.evict(cat)将cat对象从s会话中拆离,这时s会从entityEntries中将cat这个对象移出。
(4)事务提交,需要将所有缓存flush入数据库,Session启动一个事务,并按照insert,update,……,delete的顺序提交所有之前登记的操作(注意:所有insert执行完毕后才会执行update,这里的特殊处理也可能会将你的程序搞得一团糟,如需要控制操作的执行顺序,要善于使用flush),现在cat不在entityEntries中,但在执行insert的行为时只需要访问insertions就足够了,所以此时不会有任何的异常。异常出现在插入后通知Session该对象已经插入完毕这个步骤上,这个步骤中需要将entityEntries中cat的existsInDatabase标志置为true,由于cat并不存在于entityEntries中,此时Hibernate就认为insertions和entityEntries可能因为线程安全的问题产生了不同步(也不知道Hibernate的开发者是否考虑到例子中的处理方式,如果没有的话,这也许算是一个bug吧),于是一个net.sf.hibernate.AssertionFailure就被抛出,程序终止。
 
我想现在大家应该明白例子中的程序到底哪里有问题了吧,我们的错误的认为s.save会立即的执行,而将cat对象过早的与Session拆离,造成了Session的insertions和entityEntries中内容的不同步。所以我们在做此类操作时一定要清楚Hibernate什么时候会将数据flush入数据库,在未flush之前不要将已进行操作的对象从Session上拆离。
 
对于这个错误的解决方法是,我们可以在(2)和(3)之间插入一个s.flush()强制Session将缓存中的数据flush入数据库(此时Hibernate会提前启动事务,将(2)中的save登记的insert语句登记在数据库事务中,并将所有操作集合清空),这样在(4)事务提交时insertions集合就已经是空的了,即使我们拆离了cat也不会有任何的异常了。
前面简单的介绍了一下Hibernate的flush机制和对我们程序可能带来的影响以及相应的解决方法,Hibernate的缓存机制还会在其他的方面给我们的程序带来一些意想不到的影响。看下面的例子:
  

(name为cat表的主键)
Cat cat = new Cat();
cat.setName(“tom”);
s.save(cat);

cat.setName(“mary”);
s.update(cat);(6)

Cat littleCat = new Cat();
littleCat.setName(“tom”);
s.save(littleCat);

s.flush();


这个例子看起来有什么问题?估计不了解Hibernate缓存机制的人多半会说没有问题,但它也一样不能按照我们的思路正常运行,在flush过程中会产生主键冲突,可能你想问:“在save(littleCat)之前不是已经更改cat.name并已经更新了么?为什么还会发生主键冲突那?”这里的原因就是我在解释第一个例子时所提到的缓存flush顺序的问题,Hibernate按照insert,update,……,delete的顺序提交所有登记的操作,所以你的s.update(cat)虽然在程序中出现在s.save(littleCat)之前,但是在flush的过程中,所有的save都将在update之前执行,这就造成了主键冲突的发生。
 
这个例子中的更改方法一样是在(6)之后加入s.flush()强制Session在保存littleCat之前更新cat的name。这样在第二次flush时就只会执行s.save(littleCat)这次登记的动作,这样就不会出现主键冲突的状况。
 
再看一个例子(很奇怪的例子,但是能够说明问题)

Cat cat = new Cat();
cat.setName(“tom”);
s.save(cat); (7)
s.delete(cat);(8)

cat.id=null;(9)
s.save(cat);(10)
s.flush();

 
这个例子在运行时会产生异常net.sf.hibernate.HibernateException: identifier of an instance of Cat altered from 8b818e920a86f038010a86f03a9d0001 to null
 
这里例子也是有关于缓存的问题,但是原因稍有不同:
(7)和(2)的处理相同。
(8)Session会在deletions中登记这个删除动作,同时更新entityEntries中该对象的登记状态为DELETED。
(9)Cat类的标识符字段为id,将其置为null便于重新分配id并保存进数据库。
(10)此时Session会首先在entityEntries查找cat对象是否曾经与Session做过关联,因为cat只改变了属性值,引用并未改变,所以会取得状态为DELETED的那个登记对象。由于第二次保存的对象已经在当前Session中删除,save会强制Session将缓存flush才会继续,flush的过程中首先要执行最开始的save动作,在这个save中检查了cat这个对象的id是否与原来执行动作时的id相同。不幸的是,此时cat的id被赋为null,异常被抛出,程序终止(此处要注意,我们在以后的开发过程尽量不要在flush之前改变已经进行了操作的对象的id)。
 
这个例子中的错误也是由于缓存的延时更新造成的(当然,与不正规的使用Hibernate也有关系),处理方法有两种:
1、在(8)之后flush,这样就可以保证(10)处save将cat作为一个全新的对象进行保存。
2、删除(9),这样第二次save所引起的强制flush可以正常的执行,在数据库中插入cat对象后将其删除,然后继续第二次save重新插入cat对象,此时cat的id仍与从前一致。
 
这两种方法可以根据不同的需要来使用,呵呵,总觉得好像是很不正规的方式来解决问题,但是问题本身也不够正规,只希望能够在应用开发中给大家一些帮助,不对的地方也希望各位给与指正。
 
  总的来说,由于Hibernate的flush处理机制,我们在一些复杂的对象更新和保存的过程中就要考虑数据库操作顺序的改变以及延时flush是否对程序的结果有影响。如果确实存在着影响,那就可以在需要保持这种操作顺序的位置加入flush强制Hibernate将缓存中记录的操作flush入数据库,这样看起来也许不太美观,但很有效。
posted @ 2006-05-24 13:47 java小记 阅读(319) | 评论 (0)编辑 收藏

     public   static   void  main(String[] args)  throws  Exception 
        System.out.println(isWrapClass(Long.
class )); 
        System.out.println(isWrapClass(String.
class )); 
    }
 

    
public   static   boolean  isWrapClass(Class clz) 
        
try  
            
return  ((Class) clz.getField( " TYPE " ).get( null )).isPrimitive(); 
        }
  catch  (Exception e) 
            
return   false
        }
 
    }
 
posted @ 2006-05-22 16:44 java小记 阅读(887) | 评论 (0)编辑 收藏
<script language="javascript">
  g_blnCheckUnload = true;
  function RunOnBeforeUnload() {
     if (g_blnCheckUnload) {window.event.returnValue = 'You will lose any unsaved content';  
     } 
  }
</script>
<body  onbeforeunload="RunOnBeforeUnload()">
</body>
posted @ 2006-05-15 09:27 java小记 阅读(251) | 评论 (0)编辑 收藏

 

import  java.io.FileOutputStream;
import  java.util.List;

import  org.jdom.Attribute;
import  org.jdom.Document;
import  org.jdom.Element;
import  org.jdom.input.SAXBuilder;
import  org.jdom.output.Format;
import  org.jdom.output.XMLOutputter;

public   class  XML  {
    
public   static   void  main(String[] args)  throws  Exception  {

        SAXBuilder builder 
=   new  SAXBuilder();
        Document doc 
=  builder.build( " d:\\destination.xml " );
        Element root 
=  doc.getRootElement();
        root.removeChild(
" Target " );
        Element items 
=  root.getChild( " Items " );
        List item 
=  items.getChildren( " item " );
        
for  ( int  i  =   0 ; i  <  item.size(); i ++ {
            Element elem 
=  (Element) item.get(i);
            Attribute attr 
=  elem.getAttribute( " displayName " );            
            attr.setValue(attr.getValue() 
+   " 中国 " );            
        }

        
//  保存
        Format format  =  Format.getCompactFormat();
        format.setEncoding(
" gb2312 " );
        format.setIndent(
"    " );
        XMLOutputter XMLOut 
=   new  XMLOutputter(format);
        XMLOut.output(doc, 
new  FileOutputStream( " d:\\destination_tmp.xml " ));

    }

}

posted @ 2006-05-13 09:22 java小记 阅读(219) | 评论 (0)编辑 收藏
STUN (Simple Traversal of UDP through NATs (Network Address Translation)) is a protocol for assisting devices behind a NAT firewall or router with their packet routing.
  • STUN enables a device to find out its public IP address and the type of NAT service its sitting behind.
  • STUN operates on TCP and UDP port 3478.
  • STUN is not widely supported by VOIP devices yet.
  • STUN may use DNS SRV records to find STUN servers attached to a domain. The service name is _stun._udp or _stun._tcp

Definitions (from the RFC)

  • STUN Client: A STUN client (also just referred to as a client) is an entity that generates STUN requests. A STUN client can execute on an end system, such as a user's PC, or can run in a network element, such as a conferencing server.
  • STUN Server: A STUN Server (also just referred to as a server) is an entity that receives STUN requests, and sends STUN responses. STUN servers are generally attached to the public Internet.

Various types of NAT (still according to the RFC)
  • Full Cone: A full cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Furthermore, any external host can send a packet to the internal host, by sending a packet to the mapped external address.
  • Restricted Cone: A restricted cone NAT is one where all requests from the same internal IP address and port are mapped to the same external IP address and port. Unlike a full cone NAT, an external host (with IP address X) can send a packet to the internal host only if the internal host had previously sent a packet to IP address X.
  • Port Restricted Cone: A port restricted cone NAT is like a restricted cone NAT, but the restriction includes port numbers. Specifically, an external host can send a packet, with source IP address X and source port P, to the internal host only if the internal host had previously sent a packet to IP address X and port P.
  • Symmetric: A symmetric NAT is one where all requests from the same internal IP address and port, to a specific destination IP address and port, are mapped to the same external IP address and port. If the same host sends a packet with the same source address and port, but to a different destination, a different mapping is used. Furthermore, only the external host that receives a packet can send a UDP packet back to the internal host.
posted @ 2006-05-12 16:19 java小记 阅读(315) | 评论 (0)编辑 收藏
1、密码由6-32位字母、数字或下划线构成;
2、至少需要一位小写字母;
3、至少需要一位大写字母;
4、至少需要一位数字。

String password = "password";
        System.out.println(password 
!= null && password.length() >= 6
                
&& password.length() <= 32
                
&& Pattern.compile("[a-z]+").matcher(password).find()
                
&& Pattern.compile("[A-Z]+").matcher(password).find()
                
&& Pattern.compile("[\\d]+").matcher(password).find());
posted @ 2006-05-10 09:10 java小记 阅读(403) | 评论 (0)编辑 收藏

  
JList组件有一个单独的显示模式ListModel来表示JList的显示数据.  
JList创建以后,JList数据元素的值及数据元素的数量可以动态地改变.  
JList在它的数据模式ListModel中观察数据的改变.因此,一个ListModel 的正确实现应当在每次数据发生改变时,通知事件的监听者.  
当使用构造函数JList(Object[])创建一个JList的实例时,系统将自动 创建一个DefaultListModel的实例来存储JList的显示数据, 可以调用 DefaultListModel中定义的简便方法来动态地修改JList的数据,如 removeElementAt(index),addElement(Object)等. DefaultListModel 在修改数据的同时,将通知JList关于数据的改变.  

 

posted @ 2006-04-28 08:28 java小记 阅读(468) | 评论 (0)编辑 收藏

 

import  java.awt. * ;
import  java.awt.event. * ;
public   class  MyFrame  extends  Frame {
{
public  MyFrame() {
  setSize(
500 , 400 );
  setResizable( 
false  ); 
  
this .addWindowStateListener( new  WindowStateListener() { // 状态监听器
     public   void  windowStateChanged(WindowEvent e) {
      
if (getState() == 1 ) { // 最小化状态
        setState( 0 ); // 切换成正常状态
      }

    }

  }
);
}


public   static   void  main(String[] args) {
    
new  MyFrame().setVisible( true );
}


}
posted @ 2006-04-28 08:28 java小记 阅读(2699) | 评论 (0)编辑 收藏
简而言之:
Big endian machine: It thinks the first byte it reads is the biggest.
Little endian machine: It thinks the first byte it reads is the littlest.
举个例子,从内存地址0x0000开始有以下数据
 0x0000     0x12
 0x0001     0x34
 0x0002     0xab
 0x0003     0xcd
如果我们去读取一个地址为0x0000的四个字节变量,若字节序为big-endian,则读出
结果为0x1234abcd;若字节序位little-endian,则读出结果为0xcdab3412.
如果我们将0x1234abcd写入到以0x0000开始的内存中,则结果为
                big-endian     little-endian
0x0000     0x12              0xcd
0x0001     0x23              0xab
0x0002     0xab              0x34
0x0003     0xcd              0x12
x86系列CPU都是little-endian的字节序.
posted @ 2006-04-25 15:21 java小记 阅读(320) | 评论 (0)编辑 收藏
 VoIP applications like Skype, GoogleTalk and Others

Internet Voice, also known as Voice over Internet Protocol (VoIP), is a technology that allows you to make telephone calls using a broadband Internet connection instead of a regular (or analog) phone line. Some services using VoIP may only allow you to call other people using the same service, but others may allow you to call anyone who has a telephone number - including local, long distance, mobile, and international numbers. Also, while some services only work over your computer or a special VoIP phone, other services allow you to use a traditional phone through an adaptor.
posted @ 2006-04-05 09:59 java小记 阅读(260) | 评论 (1)编辑 收藏
import  java.security.MessageDigest;
import  java.security.NoSuchAlgorithmException;
public   class  PasswordManager  {
    
    
// ***************************************************************
    
//  Public Interface
    
// ***************************************************************

    
/**
     * Creates a one-way has of the specified password.  This allows passwords to be
     * safely stored in the database without any way to retrieve the original value.
     * 
     * 
@param  password the string to encrypt.
     * 
     * 
@return  the encrypted password, or null if encryption failed.
     
*/

    
public   static  String encryptPassword( String password )  {
        
        
try   {
            MessageDigest md 
=  MessageDigest.getInstance( " SHA " );
        
            
// Create the encrypted Byte[]
            md.update( password.getBytes() );
            
byte [] hash  =  md.digest();
            
            
// Convert the byte array into a String
            
            StringBuffer hashStringBuf 
=   new  StringBuffer();
            String byteString;
            
int  byteLength;
            
            
for int  index  =   0 ; index  <  hash.length; index ++  )  {
                
                byteString 
=  String.valueOf( hash[index ]  +   128  );
                
                
// Pad string to 3.  Otherwise hash may not be unique.
                byteLength  =  byteString.length();
                
switch ( byteLength )  {
                
case   1 :
                    byteString 
=   " 00 "   +  byteString;
                    
break ;
                
case   2 :
                    byteString 
=   " 0 "   +  byteString;
                    
break ;
                }

                hashStringBuf.append( byteString );
            }

            
            
return  hashStringBuf.toString();
        }

        
catch ( NoSuchAlgorithmException nsae )  {
            System.out.println( 
" Error getting password hash -  "   +  nsae.getMessage() );
            
return   null ;
        }

    }

}
posted @ 2006-03-28 15:45 java小记 阅读(273) | 评论 (0)编辑 收藏
偶尔eclipse3.1的web项目有时候不能自动编译/WEB-INF/src,即使选择工程的自动编译开关也不好使,不知道是不是Bug
我这样解决的:
1. project->properties->java build path->source->.../WEB-INF/src的output folder不要默认,编辑让它指向../WEB-INF/classes
然后重新点击build工程即可自动编译。

2. 再就是最重要的要看工程下面是否缺少了work目录,由于CVS控制时不把work加如版本,所以checkout后没有这个目录,要手工加上有的工程就能自动编译了
posted @ 2006-03-21 10:50 java小记 阅读(1318) | 评论 (0)编辑 收藏
XP系统一般情况下在装完系统后会有一个计算机管理员权限的用户,以后登陆时就显示这个用户
进入系统后在控制面板中的用户帐号下看不到Administrator用户,就好象丢失了一样,如何看到呢?
里面有另外一个问题涉及XP自动登陆                                      
单击"开始/运行",输入"rundll32 netplwiz.dll,UsersRunDll",按回车键后弹出“用户帐户”窗口,
这和“控制面板”中打开的“用户账户”窗口不同!
然后取消选定"要使用本机,用户必须输入用户名和密码"选项,单击确定.
在弹出的对话框中输入你想让电脑每次自动登录的账户(默认Administrator)和密码即可。
下一次开机自动用Administrator登陆到系统,再看控制面板就有了Administrator。
Xp默认把Administrator隐藏,虽然都是计算机管理员Administrator和有计算机管理员权限的用户还是有
细微差别的。但是一般情况下使用系统用计算机管理员权限的用户就足够了
posted @ 2006-02-13 21:40 java小记 阅读(5285) | 评论 (3)编辑 收藏


安全域是Tomcat的内置功能,主要有以下几种安全域:
JDBCRealm
DataSourceRealm
JNDIRealm
MemoryRealm
JAASRealm

在conf/server.xml中配置应用的<Context......>下面的<Realm className="org.apache.catalina.realm.MemoryRealm" />
从一个XML文件中读取用户信息,默认的就是tomcat-users.xml

tomcat-users.xml中的角色定义
<?xml version='1.0' encoding='utf-8'?>
<tomcat-users> 
    <role rolename="tomcat"/> 
    <role rolename="role1"/> 
    <role rolename="guest"/>
    <user username="lee" password="lee" roles="guest"/>
    <user username="suoxin" password="suoxin" roles="tomcat,role1"/>
</tomcat-users>

在应用下的web.xml中加入<security-constraint>元素
<security-constraint>  
    <web-resource-collection>
         <url-pattern>/*</url-pattern>   
    </web-resource-collection>   
    <auth-constraint>    
         <role-name>admin</role-name>   
         <role-name>guest</role-name>  
    </auth-constraint>
</security-constraint>

在应用下的web.xml中加入<login-config>元素
<login-config>     
   <auth-method>FORM</auth-method>
   <!--这里FORM是基于表单的验证,会跳转到mylogin.jsp,如果出错就到myerror.jsp,
   还有基于对话筐的是BASIC关键字,但是不安全在网络传输中。摘要验证DIGEST会采
   用MD5(Message Digest Algorithm)加密传输-->
   <form-login-config>       
      <form-login-page>/mylogin.jsp</form-login-page>       
      <form-error-page>/myerror.jsp</form-error-page>     
   </form-login-config>
</login-config>

mylogin.jsp的action和name必须严格规范写
<form name="form1" id="form1" method="post" action="j_security_check"> 
   <input type="text" name="j_username"/> 
   <input type="text" name="j_password"/>
   <input type="submit" name="Submit" value="提交" />
</form>

 

posted @ 2006-02-11 09:11 java小记 阅读(217) | 评论 (0)编辑 收藏
 
  1,下载OSCache, oscache-2.2-full.zip
  2,解压缩oscache-2.2-full.zip后把oscache-2.2.jar拷贝到应用的WEB-INF/lib下 ,
     并把etc目下下的oscache.properties拷贝到应用的WEB-INF/classes下.
  3, 在应用的web.xml中加入缓存过滤器    
    
       <filter>
           
<filter-name>CacheFilter</filter-name>
           
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
           
<init-param>
               
<param-name>time</param-name>
               
<param-value>600</param-value>
           
</init-param>
           
<init-param>
               
<param-name>scope</param-name>
               
<param-value>application</param-value>
           
</init-param>
       
</filter>
       
       
<filter-mapping>
           
<filter-name>CacheFilter</filter-name>
           
<url-pattern>/servlets/UserAllProducts</url-pattern>
       
</filter-mapping>

  以上的/servlets/UserAllProducts访问需要操作数据库,并且这些内容一段时间内很少改变,这样在内存缓存这个URL很有必要
  它可以降低数据库访问量。
 
  经过以上配置后,当第一次访问/servlets/UserAllProducts时,从数据库中查出所有产品列表并缓存到application中600秒。
  在600秒内的任何访问/servlets/UserAllProducts都不会真正执行这个servlet,而直接从application中取出缓存的内容。这样
  就减少了数据库的访问量。
posted @ 2006-02-09 18:58 java小记 阅读(287) | 评论 (0)编辑 收藏

今天遇到了这样的问题,就是浮点运算后数据比较出现错误,郁闷了半天,网上查了资料才发现浮点数直接用双目运算符连接会出现结果不准确问题。解决方法如下:
1。所有浮点运算都在数据库内做好,也就是都用sql实现了
2。用BigDecimal实现,方法如下(仅仅是个例子):

import java.math.BigDecimal;

public class tt {

 
/**
  * 
@param args
  
*/

 
public static void main(String[] args) {
  
float a = 1.1f;
  
float b = 2.2f;
  tt t 
= new tt();
  System.out.println(t.add(a,b));
  System.out.println(t.sub(a,b));
  System.out.println(t.mul(a,b));
  System.out.println(t.div(a,b));
  System.out.println(t.round(a));

 }

 
public float add(float v1,float v2){//加法
   BigDecimal b1 = new BigDecimal(Float.toString(v1));
   BigDecimal b2 
= new BigDecimal(Float.toString(v2));
   
return b1.add(b2).floatValue();
  }


  
public float sub(float v1,float v2){//减法
   BigDecimal b1 = new BigDecimal(Float.toString(v1));
   BigDecimal b2 
= new BigDecimal(Float.toString(v2));
   
return b1.subtract(b2).floatValue();
  }


  
public float mul(float v1,float v2){//乘法
   BigDecimal b1 = new BigDecimal(Float.toString(v1));
   BigDecimal b2 
= new BigDecimal(Float.toString(v2));
   
return b1.multiply(b2).floatValue();
  }


  
public float div(float v1,float v2){//除法
   BigDecimal b1 = new BigDecimal(Float.toString(v1));
   BigDecimal b2 
= new BigDecimal(Float.toString(v2));
   
return b1.divide(b2,3,BigDecimal.ROUND_HALF_UP).floatValue();
  }


  
public float round(float v){//截取3位
   BigDecimal b = new BigDecimal(Float.toString(v));
   BigDecimal one 
= new BigDecimal("1");
   
return b.divide(one,3,BigDecimal.ROUND_HALF_UP).floatValue();
  }

}

posted @ 2006-02-08 16:43 java小记 阅读(275) | 评论 (0)编辑 收藏

spring配置中bean的循环引用问题及解决方法

问题:Spring+Hibernate的应用中,定义了两个业务Service,这里分别称它们为serivceA,ServiceB。
它们的关系简单点来说是这样的:
serviceA需要引用serviceB,在serviceB中定义了一个接口列表,serverA必须在serviceB初始化时设置进列表。
在纯bean的情况下,也就是这两个类不需要设置其他bean的情况下,循环引用是正常的,可以通过的。例如下面配置所表示:

    <bean id="serviceA" class="A"  autowire="byName"  lazy-init="true">
     <property name="serviceB"><ref local="serviceB"/></property>
    </bean>
 <bean id="serviceB" class="B"  autowire="byName"  lazy-init="true">
     <property name="serviceA"><ref bean="serviceA"/></property>
 </bean>
但是作为一个业务接口,它应该是不需要关心事务,回滚这些无关的东西,
但现实又有这样的需求,所以我们必须保证透明的实现这个功能,于是引
入了AOP方式解决该问题,利用的是Spring自带的org.springframework.t
ransaction.interceptor.TransactionProxyFactoryBean.
重新声明文件如下:
   <bean id="baseTxProxy" lazy-init="true"
      class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="proxyTargetClass"><value>true</value></property>
        <property name="transactionAttributes">
            <props>
  <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>
    </bean>
     
    <bean id="serviceA" parent="baseTxProxy">
     <property name="target"><ref local="serviceAImpl"/></property>
    </bean>
   
   <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
     <property name="serviceB">
         <ref bean="serviceB"/>
     </property>
   </bean>
   
    <bean id="serviceB" parent="baseTxProxy" lazy-init="true">
     <property name="target"><ref local="serviceBImpl"/></property>
    </bean>
  
   <bean id="serviceBImpl" class="D" lazy-init="true">
     <property name="serviceA">
         <ref bean="serviceA"/>
     </property>
   </bean>
于是问题就出现了,Spring报了FactoryBeanCircularReferenceException,无法继续完成设置工作。
查看TransactionProxyFactoryBean源码,其实现了FactoryBean和InitializingBean接口,应该是
做了代理之后,两个代理Bean需要等待所有Bean设置完成后才会标识状态为初始化完毕,于是造成了
冲突。

    由于两个业务服务互相调用的路径是不相交的,所以采用了一种变通的方法,在声明serviceA时,
直接定义serviceB:
  <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
     <property name="serviceB">
         <bean class="B"  autowire="byName"/>
     </property>
 </bean>
相当于serviceB和serviceA中使用的serviceB不是同一个实例。
 
 但是如果确实调用重合时怎么办?
 
 解决方法是这样的:
 
 <bean id="serviceAImpl" class="serviceA"  autowire="byName"  lazy-init="true">
     <property name="serviceB">
         <ref bean="serviceBImpl"/>
     </property>
 </bean>
 
  非常简单,serviceAImpl调用时,可能已经在事务环境中了,不需再使用serviceB代理的事务支持,
  于是直接引用serviceB实例。这个方法是我写这篇文章时想到的,-_-!!!,看来知识果真还是好好
  整理呀。

 

posted @ 2006-02-08 16:32 java小记 阅读(896) | 评论 (0)编辑 收藏
关于网站开发中连接的可移植性总结

网络主机地址http://localhost:
8080/

1. 相对于根目录的连接,形如: "/another.jsp"
 
 /DIR/目录下的
 <a href
="/another.jsp">Link</a>
 <html:link href
="/another.jsp">Link</html:link>
 <html:link page
="/another.jsp">Link</html:link> 
 在默认ROOT应用中
,分别连接到地址:
 http://localhost:
8080/another.jsp
 http://localhost:
8080/another.jsp
 http://localhost:
8080/another.jsp 
 在应用test中
,分别连接到地址:
 http://localhost:
8080/another.jsp
 http://localhost:
8080/another.jsp
 http://localhost:
8080/test/another.jsp 
 
2. 相对于当前目录的连接,形如: "./another.jsp" 或 "another.jsp"
 
 /DIR/目录下的
 <a href
="./another.jsp">Link</a> 
 <html:link href
="./another.jsp">Link</html:link>
 <html:link page
="./another.jsp">Link</html:link> 
 在默认ROOT应用中
,都分别连接到地址:
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp  
 在应用test中
,分别连接到地址:
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080/test./another.jsp   错误连接(而且与DIR无关,都连接到此地址)
  
 /DIR/目录下的
 <a href
="another.jsp">Link</a> 
 <html:link href
="another.jsp">Link</html:link> 
 <html:link page
="another.jsp">Link</html:link> 
 在默认ROOT应用中
,都分别连接到地址:
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp   
 在应用test中
,分别连接到地址:
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080//DIR/another.jsp
 http://localhost:
8080/testanother.jsp       错误连接(而且与DIR无关,都连接到此地址)
 
3总结
 由于在网站开发时经常不使用默认的WEB应用,而可能把一个模块开发成一个WEb应用(可能多人合作),
 但是在发布的时候要把所有模块发布为一个WEB应用,并通常是默认的WEB应用,为了使URL不依赖于Web应用
 和是否是默认WEB应用,建议如下
  a.对于相对于WEB应用根目录的连接
,形如: "/another.jsp"
    使用<html:link page
="/..">Link </html:link>
  b.对于相对于当前目录的连接,形如: 
"./another.jsp" 或 "another.jsp"
    使用<html:link href
="./another.jsp">Link </html:link>
        <a href
="./another.jsp">Link </a>或        
        <html:link href
="another.jsp">Link </html:link>
        <a href
="another.jsp">Link </a>
    不要使用<html:link page
="./another.jsp">Link </html:link>
            <html:link page
="another.jsp">Link </html:link> 此二者不可移植
  c.建议使用struts的html标签库<html:link..标签,因为当用户关闭Cookie时会自动重写URL,所以概括
    两句话:相对应用根目录用<html:link page
="/.."  
            相对当前的目录用<html:link href
="./XXXXX.jsp"   或 <html:link href="XXXXX.jsp"  
 
 
4.补充
  还有一个标签<html:link forward
="forwardname"> Link </html:link> 上面没有提到,现做以说明。
  
  forward属性和struts配置文件<global-forwards>中的一个<forward>元素匹配,不能和<action>中<forward>匹配。
  
  例子:<global-forwards>
         <forward name
="forwardname" path="//another.jsp"/>
       </global-forwards>
       
       <html:link forward
="forwardname"> Link </html:link>
       相当于<html:link page
="//another.jsp"> Link </html:link>
  需要注意的是:<global-forwards>中<forward>的path要使用相对于WEB应用的根目录路径,包括<action>中也是。
  
  在struts1.1多应用模块时<html:link forwad. 有时不好使,不知道为什么????(好像是模块切换状态
  不对)所以最好不用。
  替代方法;
  网页中用连接
    <html:link page
="/forwardaction.do">forward</html:link>
  在action-mapping配置如下action
     <action  path
="/forwardaction"  forward="/index.jsp" />
  
posted @ 2006-02-06 20:58 java小记 阅读(207) | 评论 (0)编辑 收藏
package aa;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

//for test6
import static java.lang.Math.*;

public class Test {

    
public static void main(String[] args) {
        
// 1
        Double d = 123.45;
        d 
+= 20.601;
        System.out.println(d);
        
double dd = d + 45.123;
        System.out.println(dd);

        
// 2,3
        List<List<String>> list = new ArrayList<List<String>>();

        List
<String> line1 = new ArrayList<String>();
        line1.add(
"hello");
        line1.add(
",");
        line1.add(
"world");
        
// line1.add(new Integer(123));//complie error
        list.add(line1);

        List
<String> line2 = new ArrayList<String>();
        line2.add(
"hello2");
        line2.add(
",");
        line2.add(
"world2");
        list.add(line2);

        
for (List<String> g : list) {
            
for (String str : g) {
                System.out.print(str);
            }

            System.out.println();
        }


        
// 4
        Color bg = Color.Red;
        System.out.println(bg);

        
for (Color c : Color.values()) {
            System.out.println(c);
        }


        
// 5
        print("hello"",""World"new Date(), 123456);
        
        
//6
        double i=2*PI;
        print(i);

    }


    
public static void print(Object objects) {
        
for (Object obj : objects) {
            System.out.println(obj);
        }

    }


}


enum Color {
    Red, Green, Blue
}

posted @ 2006-02-05 10:55 java小记 阅读(230) | 评论 (0)编辑 收藏
eclipse2不支持jdk1.5支持1.4
eclipse3.0好象也不支持jdk1.5
eclipse3.1支持jdk1.5

jbuilder9不支持jdk1.5支持1.4
jbuilder2006好象集成的就是jdk1.5,没用过
posted @ 2006-02-05 10:52 java小记 阅读(236) | 评论 (0)编辑 收藏

<2006年2月>
2930311234
567891011
12131415161718
19202122232425
2627281234
567891011

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

  •  

最新评论

阅读排行榜

评论排行榜