• 今天晚上改一个程序,发现了一个很奇怪的问题,hibernate所说的POJO并不像其宣称的那样,可以当做普通的java对象使用,至少有时不注意的时候会出问题,在写程序的时候,千万要注意这种情况。

    晚上遇到的问题是这样子的,有一个对象Document,用Spring的HibernateTemplate load之后,我设置了这个对象的一个属性,例如一个叫做md5的属性,代码如下:

    ...开始事务
    Document doc = hTemplate.load(new Interger(documenId),Document.class);
    String content = doc.getContent();
    String md5 = MD5.get(content);//计算文档内容的md5值
    doc.setMd5(md5);

    /*
    getDocumentByMd5 的定义 :select doc.id from Document doc where doc.md5=:md5
    在查询之前,数据库里的md5是惟一的,没有md5码相同的Document

    */

    List list = hTemplate.getHibernateTemplate().findByNamedQueryAndNamedParam("getDocumentByMd5",
    "md5", md5);

    ....结束事务


    返回的list结果的里按照我的思维应该是空的,但是结果是返回的list的第一个元素的值就是doc的对象id。
    按理讲程序的事务还没有提交,doc也没有被update,怎么就会查出结果了呢?太奇怪了。

    研究了一下Hibernate2.17c的SessionImpl源代码,发现下面的注释,在作查询前,Hibernate要先检测在查询语句中出现的表涉及的对象是否被修改过,如果被修改过,那么先提交这些修改,之后再查询。这也解释了为什么刚修改过的对象,还没有提交修改,就在查询结果出查出来了。

    /**
    * detect in-memory changes, determine if the changes are to tables
    * named in the query and, if so, complete execution the flush
    */
    private boolean autoFlushIfRequired(Set querySpaces)

    我就在想,这样的POJO是真正的POJO吗?而这些细节一般很难被注意到,反正我以后是不敢再这样子用了,在用Hibernate的时候,从它那儿得到的POJO对象小心使用,它可不是“真正的POJO”。

    今天刚发现Groovy有vim的插件,很好用,语法加亮显示,下午在公司把它装上后,工作效率明显提高,不在满屏白字了,呵呵,从这里可以下载到这个插件http://www.vim.org/scripts/script.php?script_id=945,安装很方便。

    Groovy目前竟然不支持java标准的for (int i=0;i<10;i++) 循环,别的样式的for循环倒是有好几种,郁闷中。


    注:上面说到的Hibernate的问题可以通过session.setFlushMode(FlushMode.COMMIT)设置提交来解决,abside的指点很正确,非常感谢。

    Hibernate有四种FlushMode:NEVER,COMMIT,AUTO,ALWAYS,默认是AUTO,工作还需要再细心些。

    (2006.06.07)

  • 最近的总结

    2006-01-24

    又是一个多月没有写日志了,总是在瞎忙,今天就把最近的情况总结一下。

    1.Linux

    取得Shell运行时所在的目录

    功能:主要取得了当前运行脚本的绝对目录和参数,这个脚本是晚上帮朋友写的,以前也想写一个类似的脚本,一直没有动手,效果还不错。
    #! /bin/sh
    name=$0
    args=$*
    name=`echo $name|sed 's/^\.\{1,2\}\/\{1,\}//'`
    if [ ! $(echo $name | grep  '^/' - ) ]; then
        if [ `pwd` == '/' ]; then
            name=/$name
        else
            name=`pwd`/$name
        fi
    fi
    script=`/bin/ls -l $name | awk '{ print $NF; }'`
    while test -h "$script"
    do
      script=`/bin/ls -l $script | awk '{ print $NF; }'`
    done
    bindir=`dirname $script`
    echo "BaseDir:$bindir Args:$args"

    在两台机子之间拷贝文件

    cat <file0> | ssh  <host> "cat > /destfilepath"

    这个脚本需要在两台机子之间配置ssh,有可能需要输入密码,很是方便。

    2.Tagpstry

    换了新的工作,对一些j2ee的框架接触的少了许多,最近在用tapestry(tacos)+spring+hibernate做一个东西,另外用了jdk5.0,用了其中的泛型和annotation的功能,最喜欢String.fromat这个功能了,强。

    有时用tapestry进行一些特殊功能的实现,不是太灵活,特别是在基于tacos时,例如当提交form的时候,想要为用户提供一个确认的窗口,直接使用tacos的时候,是很难办到的,我找了它的好些component也没有找到类似的功能,用了一个比较别扭的办法:

    <form jwcid="pageForm">
        <div> 
            <label>
            <span key="title">标题:</span>     </label>
            <input name="title" type="text"  size="60" value="ognl:document.pageTitle" jwcid="title@TextField"/>
           </div>
          <div>
    <a jwcid="@tacos:AjaxDirectLink" name="dp" id="dp" listener="ognl:listeners.deletePageData" parameters="ognl:{pageDataId}" updateComponents="ognl:{'auditResult'}"/>

    <!--在这个a tag中触发jwcid dp的click事件-->

    <a href="javaScript:var ok = window.confirm('confirm?');if(ok){did.style.display='none';document.all.dp.click()}"><span key="deletePageData">删除此记录</span></a>
        </div>
      </form>

    使用Tapestry最大的感触是刚开始的时候有些不大适应,用的习惯后就对它强大的功能很是佩服,而且在DW中设计页面正如它所声明的一样,基本上不影响整体页面的效果。

    3.Java

    说起来实在是不好意思,最近才明白了String.replace和String.replaceAll之间的区别,前者不使用正则表达式,而后者使用正则表达式来执行替换操作。

    Jrockit是一个很强大的jvm,利用它提供的工具,可以动态的监视jvm中内存使用的状态,从Bea的文档上知道了Jrockit5.0有内存泄漏检测的工具,令人郁闷的是一直也没有成功的使用这个功能,不知道是否是由于License的限制。Jrockit的性能通过调整jvm的参数可以有很大的提升,公司有一台服务器,双CPU,把Jrockit的垃圾收集改为parallele,同时把-Xmx设为1000M,系统的响应速度得到了很大的提升,呵呵。

    Hibernate删除的时候,可以通过它来删除Object,但如果对象的个数多于一个,还是用sql来删除的好,不要猜测数据的多少,因为我们不好预测到所有可能发生的情况,在sql server使用Hibernate的delete方法的时候,按照hibernate的做法,它会先找到所有要删除的对象,之后才删除,我在测试一个程序的时候,发现sql server的后台进程阻塞了好几个,全是由于事先认为数据量不大,使用Hibernate删除不会有太多的影响,就懒得用jdbc来直接删除,其实通过spring的JdbcTemplate非常方便。

    4.Python

    前些日子用Python写了个程序,先在windows上写,后传到Linux上运行,发现总是不对,在网上搜索了一下,有高人说可能是由于windows和Linux之间换行符的不同赞成的,可以用dos2unix命令解决,不过这个命令不是在所有的Linux发行版上都有的。

    5.其它

    最近GCT考试结果出来了,还好被录取了,又要上学了,呵呵。今天上午把亲爱的GF送上火车了,心里的一块石头总算落下来了,不过又要给自己找火票了,晚上有同学打过电话来说,回大同的票已经没有了,郁闷,该怎么回家呢?明天再说吧。

  • 昨天下载了一个新版MyEclipse3.8.1,感觉挺爽,校验JSP,根据数据表生成Java文件和Hibernate的配置文件,图形化的Struts开发,挺不错!
  • 刚做完了一个小东西,用了久未用的Hibernate,顺便看了看Hibernate最新的发展-Hibernate3,其中的许多新特性让我兴奋不已,尤其是对存储过程的支持,更是值得期待,我想以后Hibernate可以成为o/r映射的标准了:)

     

  • Hibernate自带的连接池有比较严重的问题,如果没有使用事务,或者使用了事务但是没有提交(回滚),那么它会经常得不到新增加的数据,建议使用DBCP或其它的连接池.

    例如,下面的代码,如果在新增加了数据或修改后,它不会马上得到新的数据,惟一的方法就是把注释去掉,在多数据情况下它会得到新的数据。

    HibernateBase hb = new HibernateBase();
      try {
       //hb.begin();
       List list = hb.listQuery("select company from Company company",null);
       Iterator ir = list.iterator();
       while(ir.hasNext()){
        Company c = (Company)ir.next();
        System.out.println("compnay name:"+c.getName());
        
       }
       //hb.commit();或//hb.rollback();
      }
      catch (PersistentException e) {   
       e.printStackTrace();
       throw e;
      }
      finally{
       hb.release();
      }

    这个问题可能是由于Hibernate自带连接池的实现问题,具体情况有待于以后证实。其实这个连接池在实际项目中使用的并不多,但是在开发、测试的时候有较多的使用,所以如果在测试时发现这种问题,更换连接池试试:)

     

     

     

  • 在建立父类与子类映射关系时,要同时建立子类和父类的双重关系即在父类中有子类的set,同时子类有父类的引用。如果仅仅建立子类对父类的引用则在删除父类对象后,不能正确读取子类对象。
  • Hibernate中文档

    2004-02-02

    刚才发现了一个好东东,Hibernate的中文文档,虽然没有译完,但真是不错了。

    http://www.redsaga.com/hibernate-ref/html-seprated/