Tagged: Java RSS

  • tin 2:01 am on July 27, 2009 Permalink | Reply
    Tags: Java, ,   

    解决Mac环境下的Java Version问题 

    前一段时间遇到了一个奇怪的问题:我的Mac下面的Lotus Notes 8.5和FreeMind 0.9rc4都不能工作了,它们的共同特点就是都基于Java。我试验了在Terminal里面启动/Applications/Notes/Contents/MacOS/Notes的话是可以启动的,但是会启动以前的Basic界面(后来我才知道可能它是个Cabon应用,而不是Java版本)。所以就一直凑合着用。
    可是昨天我尝试运行/Applications/Utilities/Java Preference的时候它也无法启动了,我这才觉得这不是个简单问题,必须要彻底解决。

    我回忆了一下,我最开始的时候尝试用Java Preference的时候修改了JDK的顺序,将JDK6放在最上方,可是在Terminal里面(java -version)依然只可以访问1.5。所以当时就手动修改了系统的指向:


    /System/Library/Frameworks/JavaVM.frameworks/Versions/Current -> /System/Library/Frameworks/JavaVM.frameworks/Versions/1.6
    /System/Library/Frameworks/JavaVM.frameworks/Versions/CurrentJDK -> /System/Library/Frameworks/JavaVM.frameworks/Versions/1.6

    这样修改以后就工作了,命令行里面执行java -version显示:

    java version "1.6.0_13"
    Java(TM) SE Runtime Environment (build 1.6.0_13-b03-211)
    Java HotSpot(TM) 64-Bit Server VM (build 11.3-b02-83, mixed mode)

    但是大家千万不要这样做,这个其实是后面很多问题的一个重要原因。

    如果你修改了上面的指向,我推荐你unlink它们,然后下载Java for Mac OSX 10.5 Update 4 (http://www.apple.com/downloads/macosx/apple/application_updates/javaformacosx105update4.html)重新安装一下就可以重新生成这些link了。不过记得要unlink自己手工建立的符号链接(比如我的是Current, CurrentJDK, 1.6),否则升级包无法替换你建立的那些。

    但是我这样做了以后还是没有解决所有问题,Java Preference可以正常启动了,不过它设置的顺序依然不管用,java -version总是返回1.5。我突然想到估计是运行我们的Ant脚本曾经提醒过JAVA_HOME的问题,我手动设置过一个,忘记去掉了。所以去查我的.profile,发现了罪魁祸首:

    export JAVA_HOME='/Library/Java/Home'

    这个设置是错误的,虽然它存在,可是它不会根据Java Preference修改的结果去寻找你的Java的bin和lib,也就造成了后面的一系列错误。

    修改为(或者删掉JAVA_HOME声明也是安全的):
    export JAVA_HOME='/System/Library/Frameworks/JavaVM.framework/Current/Home'

    问题解决,教训是如果你手头有工具,应该学会使用它,如果没有耐心学习就错误的使用工具,一开始感觉能解决问题,可是后来它会造成越来越多的错误。那么决绝方案就是回到原点,恢复,学习,正确的使用工具。

     
    • blader 8:14 am on July 30, 2009 Permalink

      Lotus Notes是基于swt的吧,有可能是因为notes里的swt native binary不支持64bit的原因,我就遇到过这个问题。

      ps:snowpard里面默认没有1.5的Java了。

      PS2:好久不见,嘿嘿

    • Tin 5:49 am on July 31, 2009 Permalink

      Notes 8.5是基于Eclipse的,设置错了JAVA_HOME会让它工作不正常。info.plist里面已经设定了Java的版本是1.5和32bit了,所以不会因为版本不匹配的问题启动不了。不过赞哦发现最好还是不设置JAVA_HOME而使用空值比较好,除非遇到哪个软件不行的时候再设置。

    • blader 8:39 am on August 1, 2009 Permalink

      “发现最好还是不设置JAVA_HOME而使用空值比较好”——恩,是这样的,呵呵。

  • tin 9:06 pm on February 16, 2006 Permalink | Reply
    Tags: Java   

    Webwork 2.2的Action是否使用Spring的prototype­获取的性能对比 

    本文在060216进行了修改,因为发现了测试中的错误!注意5.5和7的内容。

    1、引子:
    其实是ajoo的这篇“Nuts和Spring 1.2.6 效率对比”和“IoC容器的prototype性能测试 ”,他们在Javaeye上详细讨论了Spring的prototype的缺陷。
    Spring的prototype指的就是singleton="false"的bean,具体可以看Spring参考手册“3.2.5. To singleton or not to singleton”介绍。

    2、Webwork 2.2的Spring结合问题:
    Webwork 2.2已经抛弃自己的IoC,默认使用Spring的IoC。
    上在OpenSymphony的官方Wiki,和jscud后来的几篇文章中没有特别提出prototype的问题。但是托他们的福,我们已经顺利的使Spring和Webwork良好的协同工作起来了。
    可是而后的一些问题却把prototype的问题搞得神秘起来……
    ajoo的测试中指出Spring的prototype性能很差,参见后面参考中的一篇文章和Javaeye的讨论。
    而后又发现robbin在Javaeye的Wiki上面的“集成webwork和spring”中的最后注到:
    “注意:目前并不推荐使用Spring来管理Webwork Action,因为对于prototype类型的bean来说,Spring创建bean和调用bean的效率是很低的!更进一步信息请看IoC容器的prototype性能测试”
    这就使我们常用的Spring+Webwork2.2的连接中使用的prototype的问题被摆出来了。
    我现在的项目中使用了prototype的方式将Webwork Action使用Spring进行显示的装配,我担心这个性能的问题会很严重,所以今天花了半天时间具体测试了一下。

    3、Prototype VS autowire的解释:
    我不知道怎么命名两种方式好,所以这里先做个解释:
    spring的配置中Action会有个id,如:

    <bean id="someAction" class="com.tin.action.SomeAction" parent="basicActionWithAuthtication" singleton="false">
    <property name="someDAO">
    <ref bean="someDAO" />
    </property>
    </bean>

    我指的prototype方式就是在xwork中这样配置:

    <action name="someAction" class="someAction">

    而autowire方式就是指在xwork中这样配置:

    <action name="someAction" class="com.tin.action.SomeAction">

    看起来相同,但其实不同(我以前发过帖子,其中说这几种方法都可,但是其实它们的机制是不同的。

    4、Portotye和autowire在XWork的SpringObjectFactory中是如何运作的:
    我们先看一下代码,就能明白两者的区别了:

    public Object buildBean(String beanName, Map extraContext) throws Exception {
    try {
    return appContext.getBean(beanName);
            }
    catch (NoSuchBeanDefinitionException e) {
                Class beanClazz 
    = getClassInstance(beanName);
    return buildBean(beanClazz, extraContext);
            }

        }


    public Object buildBean(Class clazz, Map extraContext) throws Exception {
            Object bean;

    try {
                bean 
    = autoWiringFactory.autowire(clazz, AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR, false);
            }
    catch (UnsatisfiedDependencyException e) {
    // Fall back
                bean = super.buildBean(clazz, extraContext);
            }


            bean 
    = autoWiringFactory.applyBeanPostProcessorsBeforeInitialization(bean, bean.getClass().getName());
    // We don’t need to call the init-method since one won’t be registered.
            bean = autoWiringFactory.applyBeanPostProcessorsAfterInitialization(bean, bean.getClass().getName());

    return autoWireBean(bean, autoWiringFactory);
        }


    public Object autoWireBean(Object bean) {
    return autoWireBean(bean, autoWiringFactory);
        }

    如果按照autowire配置会使用第二个buildBean方法,而prototype会使用第一个buildBean方法。

    5、我的测试,首先测试SpringObjectFactory的理论效率:

    public class testSpringObjectFactory extends TestCase {
    protected FileSystemXmlApplicationContext appContext;
    protected SpringObjectFactory sof = null;
    protected Map map = null;
    final String[] paths = {
    "WebRoot/WEB-INF/applicationContext.xml",
    "WebRoot/WEB-INF/spring-daos.xml",
    "WebRoot/WEB-INF/spring-actions.xml"
            }
    ;

    protected void setUp() throws Exception {
    super.setUp();
            appContext 
    = new FileSystemXmlApplicationContext(paths);

            sof 
    = new SpringObjectFactory();
            sof.setApplicationContext(appContext);
            sof.setAutowireStrategy(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);

            map 
    = new HashMap();
        }


    public void testSpringObjectFacotyWithAutowire() {
    long begin = System.currentTimeMillis();

    try {
    for (int i = 0; i < n style="color:#000000">100000
    ; i++{
                    sof.buildBean(
    "com.wqh.action.XinfangNewsAction", map);
                }

            }
    catch (Exception e) {
                e.printStackTrace();
            }


    long end = System.currentTimeMillis();
            System.out.println(
    "**************************Used time:" +
                (begin 
    - end));
        }


    public void testSpringObjectFacotyWithPrototype() {
    long begin = System.currentTimeMillis();

    try {
    for (int i = 0; i < 100000; i++{
                    sof.buildBean(
    "xinfangNewsAction", map);
                }

            }
    catch (Exception e) {
                e.printStackTrace();
            }


    long end = System.currentTimeMillis();
            System.out.println(
    "**************************Used time:" +
                (begin 
    - end));
        }


    public void testSpringObjectFacotyWithSpringProxyableObjectFactory() {
            sof 
    = new SpringProxyableObjectFactory();
            sof.setApplicationContext(appContext);
            sof.setAutowireStrategy(AutowireCapableBeanFactory.AUTOWIRE_BY_NAME);

    long begin = System.currentTimeMillis();

    try {
    for (int i = 0; i < 100000; i++{
                    sof.buildBean(
    "com.wqh.action.XinfangNewsAction", map);
                }

            }
    catch (Exception e) {
                e.printStackTrace();
            }


    long end = System.currentTimeMillis();
            System.out.println(
    "**************************Used time:" +
                (begin 
    - end));
        }

    }

    重要的是测试结果:
    **************************Used time:-16875
    **************************Used time:-80500
    **************************Used time:-12703(使用SpringProxyableObjectFactory()这个实现)

    prototype是autowire运行时间的4.77X倍,十分可观。

    5.5 巨大的反差,原来是我搞错了配置,发现了幕后黑手:
    第二天,我又重新运行了5里面的测试。但是结果令人吃惊,运行了十多次,结果于昨天反差巨大,prototype方式获得的bean反而性能最快!
    摘要两次测量结果
    **************************Autowire Used time:-17578
    **************************Prototype Used time:-7609
    **************************Proxy Used time:-13063
    ———————————————–
    **************************Autowire Used time:-17047
    **************************Prototype Used time:-7609
    **************************Proxy Used time:-12797

    这是为什么呢?我百思不得其解,问题出在哪里呢?后来经过跟踪svn里面的提交纪录。我发现,我在昨天测试以后,把spring配置文件中的<beans default-autowire="autodetect">变成了<beans>。也就是没有打开自动检测的autowire!
    而后就真相大白了。我有配置上default-autowire="autodetect"进行测试,结果:
    **************************Autowire Used time:-16937
    **************************Prototype Used time:-79750
    **************************Proxy Used time:-12578

    这和昨天的测试结果完全相同。也就是说我昨天写的4.77x的结果其实没有实际意义。倒是说明了Spring和Webwork集成的文章上面说的default-autowire="autodetect"是很坏的实践,即失去了name的灵活性也带来了巨大的性能损失。
    而如果使用默认的Spring autowire配置下,prototype的性能已经很好了,实际上它工作起来应该是最快的。

    6、在实际的Web项目中的性能对比:
    我使用了我的一个小项目,就是反复调用一个action获取一个页面,其中有一个DAO注入。使用了JMeter进行了一个测试:2个线程,间隔0.5秒,循环50次,对比“据和报告中的”Throughput,单位/sec。
    使用autowire方式:Avg. 148.34(吞吐量越高越好)
    使用prototype方式:Avg. 138.5

    也就是说在实际应用中两者也是有性能差距的,后者大约是前者性能的93%。
    具体代码我不放出了,因为意义不大,大家也可以自己动手试验一下。
    补充说明:
    首先注意这个测试是在default-autowire="autodetect"下进行的。
    测试的这个Action其实是一个空Action,它没有调用service和DAO,只是直接return SUCCESS,然后dispatcher到一个静态内容的jsp页面。我的本意是为了能够在获取Action占据的时间比例比较高的情况下分析性能区别。但是实际上却间接的夸大了在真正的实际应用中的性能差距。实际应用中如果加上service、DAO等逻辑的执行时间、模板View的渲染时间还有广域网上的网络传输时间,那么获取Action实例的时间差距可能就微乎其微了。

    7、后续:
    经过今天的思考,可以说完全改变了想法,重新汇总一下:
    a、在不使用default-autowire="autodetect"时,Webwork 2.2的xwork中的action class使用spring的bean id配置的理论性能最好。而且,我认为如果不是为了追求配置上的简单,严重推荐关闭spring的default-autowire。
    b、在使用default-autowire="autodetect、name、class"时,需要考虑你的需求。如果不使用Spring AOP提供的功能则在Webwork 2.2的xwork中的action class使用class全名比较好。如果使用Spring AOP的功能,则还是使用bean id。
    c、在Spring中是否使用default-autowire是个需要慎重考虑的问题。autowire如果打开,命名会受到限制(class则更不推荐,受限更大,参考相关文档),它所带来的配置简化我认为只算是小小的语法糖果,背后却是吃掉它所埋下的隐患。
    d、6中的测试还是有些说明意义的。7%的性能差距是在使用了default-autowire的方式下得出的,其中测试的那个action其实没有执行什么逻辑,而是一个直接dispatcher到success view的action,如果有商业逻辑包装,则性能差据估计会更小。因为实际上Action的执行过程、service、DAO等逻辑的执行过程和模板View的渲染过程(网络延迟)才是耗时大户。所以,关于性能应该下的结论是,prototype与否,在实际应用中性能差距是很小的,基本可以忽略不计。我们讨论的更多是编码的更好的实践。
    e、autowire不使用Spring AOP相对还是trade off,因为虽然配置简单一点,但是对于使用Spring的声明性事务等内容会带来麻烦。虽然XML不那么好,但是显示配置带来的好处还是很多的。
    f、谢谢robbin的提示。关于事务我也是无奈,放弃Action事务后难道给DAO多封装一层事务?如何没有事务依然使用HibernateDAOSurpport?Acegi的确不适合Web,使用WW的Inteceptor可以实现更舒适的解决方案。
    g、SpringProxyableObjectFactory的问题……使用上难道只能改代码?找了半天没有这个东西的介绍。看来还是需要看看代码。不过发现现在Webwork和Xwork的代码又变动了很多……
    h、我的测试是在Webwork2.2+Spring 1.2.6环境下测试的

    8、参考资源:
    Nuts和Spring 1.2.6 效率对比
    http://www.javaeye.com/pages/viewpage.action?pageId=786
    IoC容器的prototype性能测试
    http://forum.javaeye.com/viewtopic.php?t=17622&postdays=0&postorder=asc&start=0
    JavaEye的Wiki:集成webwork和spring
    http://www.javaeye.com/pages/viewpage.action?pageId=860
    WebWork – Spring官方Wiki
    http://www.opensymphony.com/webwork/wikidocs/Spring.html
    webwork2 + spring 结合的几种方法的小结
    http://forum.javaeye.com/viewtopic.php?t=9990
    WebWork2.2中结合Spring:"新的方式"
    http://www.blogjava.net/scud/archive/2005/09/21/13667.html
    我为什么不推荐对Action进行事务控制
    http://www.javaeye.com/pages/viewpage.action?pageId=1205
    我为什么不推荐使用Acegi
    http://www.javaeye.com/pages/viewpage.action?pageId=1199

     
    • 女孩 10:32 am on February 20, 2006 Permalink

      我知道2月14、15号你都在干什么,工作工作,你太努力了,你太想早些成功,来完美我们的生活。我知道,我都知道!我真的惭愧让你一个人如此的努力,而我却站在远方不能帮助你什么。我埋怨我们没有过属于我们的日子,甚至周末我们都没有腾出时间只有两个人享受的美好时光。但是我把14、15号两天都深深刻在心理,在心里我们已经在一起了,不是吗?
      不要负担太重。累了就歇歇吧。我永远站在你那边……
  • tin 11:51 pm on February 10, 2006 Permalink | Reply
    Tags: Java   

    HQL的中文问题小议 

    遇到了HQL的中文问题:
    hql的String中包括了中文以后就会出错。
    经过多次查询,转码(多字节、单字节)还是不能解决问题,说明某些环节压根就对多字节支持不正常。
    后来经过多次试验,发现是hibernate3的hql语法解释器org.hibernate.hql.ast.ASTQueryTranslatorFactory出的问题,看到有人推荐用org.hibernate.hql.classic.ClassicQueryTranslatorFactory代替。
    那当然是不可以的,否则相当于退回Hibernate2。
    解决方法是不要在hql中写中文。
    而是去使用?占位符和setParameters。
    比如在Spring HibernateTemplate里面可以:
    String hql = "select count(*) from Xinfangnews xfnews where xfnews.shifoufabu = 0 and (xfnews.title like ? or xfnews.content like ?)";
    Object[] parameters = { "%" + keyWord + "%", "%" + keyWord + "%" };
    getHibernateTemplate().find(hql, parameters);
    如此可以运行了。
    不过我走了点弯路:
    本来写成"like ‘%?%’",然后往里面插keyWord,告诉我找不到?占位符。后来才想到”中的?已经不是占位符了。
    然后就解决了:
    所以就是说不能在HQL进行语法解析之前插入中文,而需要在解析之后插入。
    还要注意,我试验了一下,在Mysql5中已经指定了使用UTF-8语言的时候,不必须在Hibernate连接的地方指明使用jdbc的encoding:
    如很多人说需要这样配置:<prop key="hibernate.connection.url">jdbc:mysql://10.206.21.171:3306/xinfangweb?useUnicode=true&amp;characterEncoding=GBK&amp;autoReconnect=true</prop>
    但实际上是用这样的配置:<prop key="hibernate.connection.url">jdbc:mysql://10.206.21.171:3306/xinfangweb</prop>
    也是可以工作的,当然还是写上比较稳妥。
     
  • tin 3:21 pm on January 30, 2006 Permalink | Reply
    Tags: Java   

    Generic Hibernate DAO试验 

    我们项目升级Weblogic 9.1,所以可以用JDK5的东西了。
    先试验一下GenericHibernateDAO,作为一个DAO的基类,实现了一些简单的方法,方便子DAO封装。

    使用方法类似:
     public class HibernateTownDAO extends GenericHibernateDAO<Town>
    implements ITownDAO{
     {
            public HibernateTownDAO() { super(Town.class); } }
     }

    这个东西基本上是从EclipseWork里面来的……

    IGenericDAO大家可以用Eclipse的抽出Interface……
    代码如下:
    package com.goldnet.dao.hibernateDAO;
    import org.apache.commons.beanutils.BeanUtils;
    import org.hibernate.Criteria;
    import org.hibernate.Session;
    import org.hibernate.criterion.Order;
    import org.hibernate.criterion.Restrictions;
    import org.springframework.orm.hibernate3.HibernateCallback;
    import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
    import com.goldnet.dao.IDAO.IGenericDAO;
    import java.io.Serializable;
    import java.util.Collection;
    import java.util.Iterator;
    /**
     * @author TIN
     * @comment
     * @param <E>
     *
     * 范型的抽象HibernateDAO,继承于Spring提供的HibernateDaoSupport,该DAO封装了大部分的Domain对象访问方法。
     * 使用范型的目的在于可以显示的规定传入/返回的类型。直接的目的在于减少使用DAO时的强行类型转换。
     *
     * TODO:getTopsByProperty(int, String)方法
     * TODO:execute(HibernateCallback callback)方法?
     * TODO:execute(HQL hql)方法?
     * TODO:execute(SQL sql)方法?
     * TODO:findByCriteria(Criterion… criterion)方法?
     * TODO:getAOfflineListCopy(List list)方法?获取一个离线list,可以在部分地方获取session无关的List,避免使用OpenSessionInView
     * TODO:String getPersistentObjectName()方法?
     * TODO:使用变长参数修改一些传入Properties和Value的地方,扩展一些方法
     * TODO:研究一下DetachedCreteria
     * 
     */
    public class GenericHibernateDAO<E> extends HibernateDaoSupport implements IGenericDAO<E> {
     private static final long serialVersionUID = 1312483055446936306L;
     private final Class clazz;
     public GenericHibernateDAO(final Class<E> clazz) {
      this.clazz = clazz;
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#saveOrUpdate(java.lang.Object,
      *      java.io.Serializable)
      * @deprecated
      *
      * @param newObject 持久化的类
      * @param id 持久化类的标识id
      *
      * 存储一个Entity,由于它的实现方式与HibernateDAO的saveOrUpdate雷同,都检测了id是否存在,但却多一个参数
      * 所以暂时部推荐,但是该实现对saveOrUpdate机理表现比较清晰,所以没有删除
      */
     public void saveOrUpdate(E newObject, Serializable id) {
      if ((id != null) && !getHibernateTemplate().contains(id)) {
       E dbObject = this.loadById(id);
       try {
        BeanUtils.copyProperties(dbObject, newObject);
       } catch (Exception e) {
        logger.error(e, e);
       }
       newObject = dbObject;
      }
      if (logger.isDebugEnabled()) {
       logger.debug("[saveOrUpdate with id Parameter] Entity<"
         + this.clazz.getName() + ">.");
       logger
         .debug("this method is deprecated! Please use saveOrUpdate(Object) instead.");
      }
      getHibernateTemplate().saveOrUpdate(newObject);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#saveOrUpdate(java.lang.Object)
      *
      * @param newObject 持久化的类
      *
      * 持久化一个Entity,一般用在不知持久化的是VO或PO时
      */
     public void saveOrUpdate(E newObject) {
      if (logger.isDebugEnabled()) {
       logger
         .debug("[saveOrUpdate] Entity<" + this.clazz.getName()
           + ">.");
      }
      getHibernateTemplate().saveOrUpdate(newObject);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#save(java.lang.Object)
      *
      * @param object 持久化的类
      *
      * 持久化一个Entity,用在持久化PO时
      */
     public void save(E object) {
      if (logger.isDebugEnabled()) {
       logger.debug("[save] Entity<" + this.clazz.getName() + ">.");
      }
      getHibernateTemplate().save(object);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#update(java.lang.Object)
      *
      * @param object 持久化的类
      *
      * 持久化一个Entity,符合jsr-220规范,用在持久化一个VO的Entity(但是它已经在库中存在)时,持久化它并返回它的PO
      */
     @SuppressWarnings("unchecked")
     public E merge(E object) {
      if (logger.isDebugEnabled()) {
       logger.debug("[merge] Entity<" + this.clazz.getName() + ">.");
      }
      return (E) getHibernateTemplate().merge(object);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#isEntityWithPropertyOfValueExist(java.lang.String,
      *      java.lang.Object)
      *
      * @param propertyName Entity属性的名称
      * @param value Entity属性的值
      * @return
      *
      * 具有propertyName的Entity是否存在?如果true则存在,如果false则不存在。
      */
     public boolean isEntityWithPropertyOfValueExist(String propertyName,
       Object value) {
      if (logger.isDebugEnabled()) {
       logger.debug("[isEntityWithPropertyOfValueExist] Entity<"
         + this.clazz.getName() + ">, propName=" + propertyName
         + ", value=" + value + ".");
      }
      if (getHibernateTemplate().find(
        "from " + this.clazz.getName() + " table where table."
          + propertyName + "=?", value).size() > 0) {
       return true;
      }
      return false;
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#isEntityIdExist(java.io.Serializable)
      *
      * @param id Entity的标识id
      * @return
      *
      * 具有该id的Entity是否存在?如果true则存在,如果false则不存在。用来检测一个VO是否已经有对应的PO存在
      */
     public boolean isEntityIdExist(Serializable id) {
      if (logger.isDebugEnabled()) {
       logger.debug("[isEntityIdExist] Entity<" + this.clazz.getName()
         + "> with id=" + id + ".");
      }
      return getHibernateTemplate().contains(id);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#delete(java.lang.Object)
      *
      * @param object Entity对象
      *
      * 删除一个Entity
      */
     public void delete(E object) {
      if (logger.isDebugEnabled()) {
       logger.debug("[delete] Entity<" + this.clazz.getName() + ">.");
      }
      getHibernateTemplate().delete(object);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#deleteById(java.io.Serializable)
      *
      * @param id Entity的标识id
      *
      * 根据Entity的标识id删除一个Entity
      */
     public void deleteById(Serializable id) {
      if (logger.isDebugEnabled()) {
       logger.debug("[deleteById] Entity<" + this.clazz.getName()
         + "> with id=" + id + ".");
      }
      getHibernateTemplate().delete(
        getHibernateTemplate().get(this.clazz, id));
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#deleteByProperty(java.lang.String,
      *      java.lang.Object)
      *
      * @param propertyName Entity属性的名称
      * @param value Entity属性的值
      *
      * 删除一组具有相同propertyName属性值(value)的Entity,用来批量删除
      */
     @SuppressWarnings("unchecked")
     public void deleteByProperty(String propertyName, Object value) {
      Iterator<E> result = listByProperty(propertyName, value).iterator();
      while (result.hasNext()) {
       delete(result.next());
      }
      if (logger.isDebugEnabled()) {
       logger.debug("[deleteByProperty] Entity<" + this.clazz.getName()
         + ">, propName=" + propertyName + ", value=" + value + ".");
      }
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#loadById(java.io.Serializable)
      *
      * @param id Entity的标识id
      * @return
      *
      * 根据Entity的标识id获取一个Entity的PO
      */
     @SuppressWarnings("unchecked")
     public E loadById(Serializable id) {
      if (logger.isDebugEnabled()) {
       logger.debug("[loadById] Entity<" + this.clazz.getName() + ">, id="
         + id + ".");
      }
      return (E) getHibernateTemplate().get(this.clazz, id);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#loadByProperty(java.lang.String,
      *      java.lang.Object)
      *
      * @param propertyName Entity属性的名称
      * @param value Entity属性的值
      * @return
      *
      * TODO:判断结果是否是unique?
      * 获取一个具有相同propertyName属性值(value)的Entity,注意改属性必须是unique的,否则改方法将没有意义
      */
     @SuppressWarnings("unchecked")
     public E loadByProperty(String propertyName, Object value) {
      Collection result = getHibernateTemplate().find(
        "from " + this.clazz.getName() + " table where table."
          + propertyName + "=?", value);
      Iterator<E> it = result.iterator();
      if (logger.isDebugEnabled()) {
       logger.debug("[loadByProperty] Entity<" + this.clazz.getName()
         + ">, propName=" + propertyName + ", value=" + value + ".");
      }
      if (it.hasNext()) {
       return it.next();
      } else {
       return null;
      }
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#loadEntitySum()
      *
      * @return
      *
      * 获取一种Entity的总数
      */
     public int loadEntitySum() {
      if (logger.isDebugEnabled()) {
       logger.debug("[loadEntitySum] Entity<" + this.clazz.getName()
         + ">.");
      }
      return ((Integer) getHibernateTemplate().find(
        "select count(*) from " + this.clazz.getName()).iterator()
        .next()).intValue();
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#loadEntitySumByProperty(java.lang.String,
      *      java.lang.Object)
      *
      * @param propertyName Entity属性的名称
      * @param value Entity属性的值
      * @return
      *
      * 获取一组具有相同propertyName属性值(value)的Entity的个数
      */
     public int loadEntitySumByProperty(String propertyName, Object value) {
      if (logger.isDebugEnabled()) {
       logger.debug("[loadEntitySum] Entity<" + this.clazz.getName()
         + ">, propName=" + propertyName + ", value=" + value + ".");
      }
      return ((Integer) getHibernateTemplate().find(
        "select count(*) from " + this.clazz.getName()
          + " table where table." + propertyName + "=?", value)
        .iterator().next()).intValue();
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#loadLastEntity()
      *
      * @param orderByPropertyName 用来排序的属性的名称
      * @return
      *
      * TODO:和获取Tops是否重复?
      * 返回最后一个Entity,用来获取如最新加入的Entity这样的方法
      * 注意改方法实际上返回的是降序排列的list中的第一个!
      */
     @SuppressWarnings("unchecked")
     public E loadLastEntity(final String orderByPropertyName) {
      if (logger.isDebugEnabled()) {
       logger.debug("[listLastEntity] Entity<" + this.clazz.getName()
         + "> and orderByPropertyName=" + orderByPropertyName
         + ", Note:it’s DESC.");
      }
      return (E) getHibernateTemplate().execute(new HibernateCallback() {
       public Object doInHibernate(Session session) {
        Criteria criteria = session.createCriteria(clazz);
        criteria.addOrder(Order.desc(orderByPropertyName));
        releaseSession(session);
        try {
         return criteria.list().iterator().next();
        } catch (Exception e) {
         logger
           .warn("[listLastEntity] faild! the entity list is empty!");
         return null;
        }
       }
      });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listAll()
      *
      * @return
      *
      * 获取所有的Entity的list
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listAll() {
      if (logger.isDebugEnabled()) {
       logger.debug("[listAll] Entity<" + this.clazz.getName() + ">.");
      }
      return getHibernateTemplate().find("from " + this.clazz.getName());
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listAllOrderBy(boolean, java.lang.String)
      *
      * @param isAsc 是否使用升序
      * @param orderByPropertyName 排序的属性
      * @return
      *
      * 获取所有的Entity的list,结果按照orderByPropertyName属性升序/降序(isAsc true则升序,否则降序)
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listAllOrderBy(final boolean isAsc,
       final String orderByPropertyName) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listAllOrderBy] Entity<" + this.clazz.getName()
         + ">, isAsc?=" + isAsc + ", orderByPropertyName="
         + orderByPropertyName + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria.addOrder(isAsc ? Order
            .asc(orderByPropertyName) : Order
            .desc(orderByPropertyName));
          releaseSession(session);
          return criteria.list();
         }
        });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByPage(int, int)
      *
      * @param pagesize 页的大小,每页最多Entity个数
      * @param pageno 页码
      * @return
      *
      * 获取一页的Entity的list,该页是所有Entity中的第pageno页,每页最多有pagesize个Entity,分页显示Entity时使用
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByPage(final int pagesize, final int pageno) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listByPage] Entity<" + this.clazz.getName()
         + ">, pagesize=" + pagesize + ", pageno=" + pageno + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria.setFirstResult(pagesize * pageno);
          criteria.setMaxResults(pagesize);
          releaseSession(session);
          return criteria.list();
         }
        });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByPageOrderBy(int, int, boolean,
      *      java.lang.String)
      *     
      * @param pagesize 页的大小,每页最多Entity个数
      * @param pageno 页码
      * @param isAsc 是否使用升序
      * @param orderByPropertyName 排序的属性
      * @return
      *
      * 获取一页的Entity的list,该页内容按照orderByPropertyName属性升序/降序(isAsc true则升序,否则降序),该页是所有Entity中的第pageno页,每页最多有pagesize个Entity
      * 分页显示排序过的Entity时使用
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByPageOrderBy(final int pagesize,
       final int pageno, final boolean isAsc,
       final String orderByPropertyName) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listByPageOrderBy] Entity<" + this.clazz.getName()
         + ">, pagesize=" + pagesize + ", isAsc?=" + isAsc
         + ", orderByPropertyName" + orderByPropertyName
         + ", pageno=" + pageno + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria
            .setFirstResult(pagesize * pageno)
            .setMaxResults(pagesize)
            .addOrder(
              isAsc ? Order.asc(orderByPropertyName)
                : Order
                  .desc(orderByPropertyName));
          releaseSession(session);
          return criteria.list();
         }
        });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByProperty(java.lang.String,
      *      java.lang.Object)
      *     
      * @param propertyName Entity属性的名称
      * @param value Entity属性的值
      * @return
      *
      * 获取一组具有相同propertyName属性值(value)的Entity的列表list,返回一组符合条件的Entity
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByProperty(String propertyName, Object value) {
      if (logger.isDebugEnabled()) {
       logger.debug("[listByProperty] Entity<" + this.clazz.getName()
         + ">, propertyName" + propertyName + ", value=" + value
         + ".");
      }
      return getHibernateTemplate().find(
        "from " + this.clazz.getName() + " table where table."
          + propertyName + "=?", value);
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByPageByProperty(java.lang.String,
      *      java.lang.Object, boolean, java.lang.String)
      *     
      * @param pagesize 页的大小,每页最多Entity个数
      * @param pageno 页码
      * @param listByPropertyName Entity属性的名称
      * @param value Entity属性的值
      * @return
      *
      * 获取一页的Entity的list,该页内容为具有相同propertyName属性值(value)的Entity,该页是所有符合条件Entity中的第pageno页,每页最多有pagesize个Entity
      * 分页显示匹配某一属性值的Entity时使用
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByPageByProperty(final int pageno,
       final int pagesize, final String listByPropertyName,
       final Object value) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listByPageByProperty] Entity<"
         + this.clazz.getName() + ">, pageno=" + pageno
         + ", pagesize=" + pagesize + ", listByPropertyName="
         + listByPropertyName + ", value" + value + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria.setFirstResult(pagesize * pageno)
            .setMaxResults(pagesize).add(
              Restrictions.eq(listByPropertyName,
                value));
          releaseSession(session);
          return criteria.list();
         }
        });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByPropertyOrderBy(java.lang.String,
      *      java.lang.Object, boolean, java.lang.String)
      *     
      * @param listByPropertyName Entity属性的名称
      * @param value Entity属性的值
      * @param isAsc 是否使用升序
      * @param orderByPropertyName 排序的属性
      * @return
      *
      * 获取所有的具有匹配propertyName属性值(value)的Entity的list,按照orderByPropertyName属性升序/降序(isAsc true则升序,否则降序)
      * 显示匹配属性值的列表且要求排序时使用
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByPropertyOrderBy(final String listByPropertyName,
       final Object value, final boolean isAsc,
       final String orderByPropertyName) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listByPropertyOrderBy] Entity<"
         + this.clazz.getName() + ">, listByPropertyName="
         + listByPropertyName + ", value" + value + ", isAsc?="
         + isAsc + ", orderByPropertyName=" + orderByPropertyName
         + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria
            .add(Restrictions.eq(listByPropertyName, value))
            .addOrder(
              isAsc ? Order.asc(orderByPropertyName)
                : Order
                  .desc(orderByPropertyName));
          releaseSession(session);
          return criteria.list();
         }
        });
     }
     /**
      * @see com.goldnet.dao.IDAO.IGenericDAO#listByPageByPropertyOrderBy(int, int,
      *      java.lang.String, java.lang.Object, boolean, java.lang.String)
      *     
      * @param pagesize 页的大小,每页最多Entity个数
      * @param pageno 页码
      * @param listByPropertyName Entity属性的名称
      * @param value Entity属性的值
      * @param isAsc 是否使用升序
      * @param orderByPropertyName 排序的属性
      * @return
      *
      * 获取一页的Entity的list,该页内容为具有相同propertyName属性值(value)的Entity,该页内容按照orderByPropertyName属性升序/降序(isAsc true则升序,否则降序),
      * 该页是所有符合条件Entity中的第pageno页,每页最多有pagesize个Entity
      * 分页显示匹配某一属性值的Entity时使用
      */
     @SuppressWarnings("unchecked")
     public Collection<E> listByPageByPropertyOrderBy(final int pagesize,
       final int pageno, final String listByPropertyName,
       final Object value, final boolean isAsc,
       final String orderByPropertyName) {
      final Class clazztemp = this.clazz;
      if (logger.isDebugEnabled()) {
       logger.debug("[listByPageByPropertyOrderBy] Entity<"
         + this.clazz.getName() + ">, pageno=" + pageno
         + ", pagesize=" + pagesize + ", listByPropertyName="
         + listByPropertyName + ", value" + value + ", isAsc?="
         + isAsc + ", orderByPropertyName=" + orderByPropertyName
         + ".");
      }
      return (Collection<E>) getHibernateTemplate().execute(
        new HibernateCallback() {
         public Object doInHibernate(Session session) {
          Criteria criteria = session.createCriteria(clazztemp);
          criteria
            .setFirstResult(pagesize * pageno)
            .setMaxResults(pagesize)
            .add(Restrictions.eq(listByPropertyName, value))
            .addOrder(
              isAsc ? Order.asc(orderByPropertyName)
                : Order
                  .desc(orderByPropertyName));
          releaseSession(session);
          return criteria.list();
         }
        });
     }
    }
     
  • tin 9:24 pm on January 19, 2006 Permalink | Reply
    Tags: Java   

    Webwork 2.2的form tag在使用jsp view时onsubmit不工作 

    起因是使用Michael Chen的JSValidation,需要手动写onsubmit,结果居然发现webwork 2.2的正式版本里面的form tag里面的onsubmit在使用jsp view的时候没法输出,苦恼于此。暂时通过修改模板修改了一下,但是如此很不爽。所以就想测试一下到底是不是我们项目的问题还是ww 2.2的问题。但一直太忙,今天才抽出功夫测。以下是测试纪录,希望知道缘由的朋友帮我指点一下。

    测试使用Webwork发行包中演示的starter项目,其中使用了ftl模板作为表现层,我按它的方式制造了newPerson.jsp。
    下面是两个页面的源文件:
    newPerson.jsp

    java代码: 
    <%@ page language="java" contentType="text/html; charset=utf-8"%>
    <%@ taglib uri="webwork" prefix="ww"%>
    <html>
    <head>
        <title>New Person</title>
        <link href="<ww:url value="/webwork/jscalendar/calendar-blue.css" />" rel="stylesheet" type="text/css" media="all"/>
    </head>

    <body>
    <ww:form action="newPerson" onsubmit="dosomething" validate="false">
        <ww:textfield label="Name" name="person.name"/>
        <ww:datepicker  name="date" id="ecoInf.turninDate" template="datepicker.ftl" language="en" format="%Y-%m-%d" label="Time
    "/>
        <ww:submit value="Create person"/>
    </ww:form>
    </body>
    </html>

    newPerson.ftl

    java代码: 
    <html>
    <head>
        <title>New Person</title>
        <link href="<@ww.url value="/webwork/jscalendar/calendar-blue.css" />" rel="stylesheet" type="text/css" media="all"/>
    </head>

    <body>
    <@ww.form action="newPerson" onsubmit="dosomething">
        <@ww.textfield label="Name" name="person.name"/>
        <@ww.datepicker  name="date" id="ecoInf.turninDate" template="datepicker.ftl" language="en" format="%Y-%m-%d" label="Time"/>
        <@ww.submit value="Create person"/>
    </@ww.form
    >
    </body>
    </html>


    程序逻辑继续使用starter项目里面的内容。
    xwork中配置如下:

    java代码: 
    <action name="newPerson" class="com.acme.CreatePerson">
                <result name="success" type="redirect">listPeople.action</result>
                <!–
                <result name="input" type="dispatcher">newPerson.jsp</result>
                –>
                <result name="input" type="freemarker">newPerson.ftl
    </result>
            </action>

    两个"success"的result轮流切换。

    试验结果如下:
    1、webwork.properties配置如下,使用vm的template,此时使用两种result的结果是相同的:

    java代码: 
    webwork.ui.theme=simple
    webwork.ui.templateDir=template/archive
    webwork.ui.templateSuffix
    =vm

    显示结果,显然onsubmit没有输出,此时datapicker标签没有输出(因为老的vm模板没有提供datapicker标签):

    java代码: 
    <form namespace="/" id="newPerson" name="newPerson" action="/starter/newPerson.action">

    2、webwork.properties配置如下,此时使用ftl的result和ftl的template:

    java代码: 
    webwork.ui.theme=simple
    webwork.ui.templateDir=template
    webwork.ui.templateSuffix
    =ftl

    显示结果,onsubmit输出正常:

    java代码: 
    <form id="newPerson" name="newPerson" onsubmit="dosomething" action="/starter/newPerson.action">


    3、webwork.properties配置如下,此时使用jsp的result和ftl的template:

    java代码: 
    webwork.ui.theme=simple
    webwork.ui.templateDir=template
    webwork.ui.templateSuffix
    =ftl


    显示结果,onsubmit没有输出:

    java代码: 
    <form namespace="/" id="newPerson" name="newPerson" action="/starter/newPerson.action">


    此时尝试使用theme="xhtml"还是没有输出。

    从上面的测试来看,似乎是个bug,可是在webwork网站却没有查到相关issue,怀疑是我这里的环境问题。以上测试在tomcat 5.5.12 or Weblogic 9.1 @ SUN JDK 1.5b6上面进行。希望哪位解决了上面问题指导一下我,谢谢。

     
  • tin 9:22 pm on January 19, 2006 Permalink | Reply
    Tags: Java   

    Spring+Hibernate中使用Mysql存储过程初步 

    Hibernate中使用Mysql存储过程
    1、我使用了mysql-connector-java-5.0.0-beta-bin.jar(其实用老的mysql-connector-java-3.1.8-bin.jar也可以调用存储过程的)这个最新的mysql驱动。
    2、数据库我使用了mysql-5.0.18-win32,安装后建立了一个简单的数据表。
    sql如下:

    java代码: 
    create database testprocedure;
    use testprocedure;
    create table testtable (id int(11) AUTO_INCREMENT, content varchar(255), readcount int(11) DEFAULT 0,primary key (id));
    desc testtable;(查看是否建立正确)


    3、建立一个专用的用户(可选,建立时请使用具有grant权限的用户如root):

    java代码: 
    grant select,delete,update,create,alter,execute on testtable.* to testprocedure@"localhost" identified by "test";

    用户名为testprocedure,密码test。注意权限中的execute,它就是执行call procedure的权限。在你的Hibernate配置中使用该帐户。
    4、建立一个存储过程:
    sql如下:

    java代码: 
    delimiter //
    (注意//是新的命令结束符,方便我们建立procedure)
    create procedure readcountplusone (inputid int)
    begin
    update testtable set readcount = readcount + 1 where id = inputid;
    end//

    (建立存储过程完毕)
    delimiter ;
    (恢复命令结束符为;)

    5、测试一下存储过程:

    java代码: 
    insert into testtable values (null,‘test’,0);
    select * from testtable;
    call readcountplusone(1)
    ;
    select * from testtable;

    应该看到原先readcount为0,call以后变成1,而且每次call都加1。
    如果执行有错,可以删除procedure重新建立。
    删除的命令为drop procedure readcountplusone;
    6、开始在我们的Hibernate+Spring support项目中使用procedure:
    HBM映射我们不说了,这里没有使用named query。Hibernate+Spring的配置这里也不多说了,应该可以搜寻到很多文章。
    我的DAO是extends HibernateDAO,具体的使用方法可以参照其他很多讲Spring hibernate support的文章。
    我们建立一个方法,比较丑陋(只是测试,大家有好方法可以提),假设对应testtable的pojo为TestPojo,它的getId()返回id对应的值:

    java代码: 
    public void readCountPlusOne(final TestPojo pojo) {
            getHibernateTemplate().execute(new HibernateCallback() {
    public Object doInHibernate(Session session) {
    try {
    Connection conn = session.connection();

    String sql = "{call readcountplusone(?)}";
    CallableStatement stmt = conn.prepareCall(sql);
                            stmt.setLong(1, pojo.getId().longValue());
                            stmt.execute();
    } catch (Exception e) {
    if(log.isDebugEnable){
                                    log.debug("call DAO
    ’s readCountPlusOne() faild, with Exception:");
                                    e.printStackTrace();
                            }
                        }

                        return null;
                    }
                });
        }

    7、然后我们在我们的bussiness中调用readCountPlusOne方法既可实现通过Hibernate调用一个简单的Mysql存储过程。

    有点走马观花,主要是把口舌都放在mysql部分,hibernate部分则用的比较简单,我想把调用方法改为Named Query,这样不会这么丑陋。
    抛砖引玉,谢谢。

     
    • shmily52322 9:27 pm on January 19, 2006 Permalink

      是搞软件的?/
      看的我眼花缭乱!
      厉害!

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
esc
cancel