首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

Hibernate使用的困惑(1)

2012-10-27 
Hibernate应用的困惑(1)Hibernate级联查询应用的困惑。 比如举个简单的例子:制作一个博客系统,其中有会员,

Hibernate应用的困惑(1)
Hibernate级联查询应用的困惑。
比如举个简单的例子:制作一个博客系统,其中有会员,文章分类,对应具体类别的文章。
很明显会员与文章类别之间的映射关系是一对多,文章类别与文章之间的映射关系是一对多。
为了实现他们的查询我可以采用好几种方法:
  1:我将他们之间都设置为一对多单向映射而且是立即加载。
在会员登陆的同时我就加载所有的级联对象。这是个Action方法,里面返回一个Map类型数据,而在Map里包含了会员,文章分类以及文章的集合类型List,同时把他们
都至于Sessions中,或者Request中。
然后这个Action返回该用户的博客界面,里面我用<logic:present name="result"><logic:iterate id="order" name="result" type="com.ORM.Orders">这种Structs标签把他们的值取出并展示在界面上。同时由于全部博客信息都已经加载,那样的话我可以只用一个界面就可以满足用户对博客信息的各种查询,意思就是说我会利用JavaScript动态现实用户查询信息需要的DIV片段。那样的话代码变得很简单,而且用户体验会很不错,基本上和AJAX的效果差不多,因为所有信息随着用户第一次打开博客界面,都已经生成各个对应的Div片段啊只不过我把它们利用JavaScript和CSS技术都隐藏啦。然后更具用户的各种需求在把包含用户信息的Div片段显示出来!
当然这种情况很容易实现。但是Hibernate查询效率问题需要思考。
  2:我只是将会员与文章类别级联,然后在博客主界面先显示文章类别,至于具体文章的加载则是有用户自己决定,这样的话我就必须额外的Action类或者是其他Action类中增加对应的更具条件加载对应文章的方法。那样的话我只能在另一个页面生成用户所要的结果(文章的具体信息),因为Action类可定会生成一个返回界面的
ActionForward对象。那样的话无疑增加了复杂度。但是与前面的方法比较查询效率可定要好一些,但是需要额外增加很多JSP展示界面,代码变得更加复杂。
 3:直接利用连接池+SQL语句直接查询,这样的话查询效率更高,因为它避开了Hibernate对SQL的一些封装而且显得更加灵活,但是那些SQL语句有太麻烦,又由于本人很喜欢Hibernate所以还是觉得不舒服。
 现在真的很困惑,方法多很好,但方法的选择却很痛苦!

关于第二种方法我想更加仔细的说一下。
 按照前面的思路,用户登陆后就打开了博客主界面,上面显示了该博客里的文章分类。然后主动权就交给用户啦。他点击一个分类然后就会对应一个Action方法
,Action方法里会调用相关Service类(利用Hibernate技术与数据库打交道)假设传递的参数是类别的ID,那么在Service类里我们怎么检索对应文章
信息呢?我们可以用HQL语句查询,不过这时候就没有必要对类别与文章做一对多映射啦(采用延迟加载)。但我想充分利用Hibernate提供的集合对象的映射。那样的话我提前就为它们做了一对多的映射。我可以考虑利用具体的类别对象直接调用getTopics()返回Set然后再装换成List对象给视图。但这里就出现了一个不舒服的地方就是前面我已经加载了所有的类别对象,当然这是所有的类别对象已经处于托管状态啦!这是我还要重新加载对应ID的持久化对象但好像会出错,因为前面你已经加载过啦啊。如果我重新关联该ID对应的持久化对象似乎又不行,好像托管对象的引用并不能在这个方法中被识别。如果持久化对象是全局声明的话该多好啊,那样的话我只需要在这个Sessions中重新关联该对象,然后执行级联操作(CLASS.getTopics()),不知道这种问题怎么解决?还有持久化对象应该可以声明成全局对象吧?那样的话会不会更好?
   最近看了关于对象序列化,对象反射机制以及进程池和数据库连接池的问题,但还不是特别清楚。这里想试着用那些东西分析一下Hibbernate的大致工作机制,大家多多补充,那样的话我会受益匪浅的!
     Hibernate里面有个SessionFactory类,这个类里面包含了一些静态方法以及静态类,我们可以调用这个静态工厂获得与数据库交流的类Sessions:
public static Session currentSession() throws HibernateException {
        Session session = (Session) threadLocal.get();

        if (session == null) {
            if (sessionFactory == null) {
                try {
                    cfg.configure(CONFIG_FILE_LOCATION);
                    sessionFactory = cfg.buildSessionFactory();
                }
                catch (Exception e) {
                    System.err.println("%%%% Error Creating SessionFactory %%%%");
                    e.printStackTrace();
                }
            }
            session = sessionFactory.openSession();
            threadLocal.set(session);
        }

        return session;
    }
这个Session应该只有一个实例吧,其他的每个线程使用它的时候都会利用ThreadLocal来生成与本线程对应的Session对象的副本。
下面是一个自己简单实现的数据库连接池程序:
package Service;

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/


import java.sql.*;
import java.util.*;

public class ConnPool {
static boolean IsInit=false;
staticprivate int ConnNow=0;
staticprivate  List<Connection> connections = new ArrayList();
staticprivate String PoolName;
staticprivate String DriverName;
staticprivate String DbId;
staticprivate String UserName;
staticprivate String Password;
staticprivate int MaxConn;

/*public ConnPool(String PoolName, String DriverName, String DbId, String UserName, String Password, int MaxConn) {
this. PoolName = PoolName;
this. DriverName = DriverName;
this. DbId = DbId;
this. UserName = UserName;
this. Password = Password;
this. MaxConn = MaxConn;
        initPool();
}*/

public static synchronized void releaseConnection(Connection conn) {
connections.add(conn);
ConnNow--;
}

public static synchronized Connection getConnection() {//获取Connection对象
Connection conn = null;
if (connections.size() > 0) {
conn = (Connection) connections.get(0);

connections.remove(0);
            ConnNow++;
        }
        if(ConnNow==0&&connections.size()==0){
        connections=initPool();
        conn=getConnection();
        }
       /*  try {
            //if (conn.isClosed())
              // conn = getConnection();
         }
         catch (Exception ex) {
            ex.printStackTrace();
         }
}*/
if(ConnNow==MaxConn){
System.out.print("数据库繁忙!请稍后再试!");
}



return conn;
}


private static List initPool() {

        MaxConn=7;
    //Class.forName("com.mysql.jdbc.Driver");//Class.forName(DriverName);
if(IsInit==true) {return connections;}
else {
for(int i=0;i<MaxConn;i++){
        try {
       
//conns.add (DriverManager.getConnection(DbId,UserName, Password));
        Connection co=DriverManager.getConnection("jdbc:mysql://localhost:3306/chat?useUnicode=true&characterEncoding=gb2312","root","5769358");
     connections.add(co);
        }
        catch(SQLException ex)
{
System.out.print("数据库初始化失败!");
return null;
}
catch (Exception e) {
e.printStackTrace();
return null;
}
        }
IsInit=true;
return connections;

}
}


public static synchronized void closeConn() {

Iterator allConnections= connections.iterator();
while (allConnections.hasNext()) {
Connection conn = (Connection) allConnections.next();
try {
conn.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}
connections.clear();
}
   public static void main(String args[]) {
Connection conn=ConnPool.getConnection();
try{//Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/chat?useUnicode=true&characterEncoding=gb2312","root","5769358");
     Statement stat=conn.createStatement();
stat.execute("insert into user_info (UserName,Password) values('afei','5769358')");

System.out.print(ConnPool.connections.size());

}
catch(SQLException ex)
{
System.err.println(ex.getMessage());
}
finally{
ConnPool.releaseConnection(conn);
ConnPool.closeConn();

}







}
}
可不可以这样理解:Hibernate里的Session类其实就相当于上面程序的Connection类,只不过它对Connection做了封装,可以还封装了其他的一些功能比如事务处理等。
还有一点不同的是Hibernate是利用ThreadLocal机制实现多个线程并发访问同一个Session对象,而上面的是利用synchronized 机制来实现相同的功能。
SessionFactory里还有一个变量: private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";里面包含了所要连接的数据库信息以及其他的一些映射配置(暂且不讨论),然后Hinernate在初始化的时候会利用相关类比如DOM4J解析它,获得相应的数据库理解信息(所要连接的数据库名称,用户密码,用户姓名),再把他们赋值给Session里面的相关变量。然后Session类就会成功的建立。数据库的连接,你就可以利用他的其他封装的功能进行与数据库有关的操作。
                   
29 楼 jasstion 2009-05-24   jasstion 写道
whaosoft 写道
我不鄙视你&amp;nbsp; 但是你水平很初级 先弄点基础的 一上来就像上面说的 什么画uml 没用~&amp;nbsp;


呵呵!谢谢你手下留情!不过最重要的是给我些建议啊,写出文章就是为了让高人批的,只有这样才有收获啊,我也就是自学Struts1.x+Hibernate不到半年时间,都是业余时间看的,请教一下高手:什么东西算是基础的啊??? 30 楼 kjj 2009-05-24   别学java啦,趁还没定形学点软件工程管理,跑跑业务,比啥都强!!!! 31 楼 vlinux 2009-05-24   别在忽悠楼主,在我们公司,项目经理、业务经理都是有很强的技术背景的。特别是搞计算机这帮酸腐的文人,经常文人相轻,想要部下服你,不是看谁职位高的 32 楼 ningzai 2009-05-25   我也刚刚学完ssh ,不过我已经工作的朋友说现在没有必要学什么框架了,公司自己有自己的框架,我也不太了解,我现在也和lz一样也还没毕业呢!不过我认为ssh是最基础的东西,不会的话就说不过去了。以后有机会再学其他的。 33 楼 rrsy23 2009-05-25   需求决定 采用什么技术,什么就是的什么方式;
如果数据量很少,hibernate lazy=false没有问题

数据量大了 你直接load肯定问题;

所以,那个都可以,看你到底考虑代码简单 还是效率优先,还是折中; 34 楼 czwlucky 2009-05-25   ningzai 写道我也刚刚学完ssh ,不过我已经工作的朋友说现在没有必要学什么框架了,公司自己有自己的框架,我也不太了解,我现在也和lz一样也还没毕业呢!不过我认为ssh是最基础的东西,不会的话就说不过去了。以后有机会再学其他的。
没有什么东西是不是应该学的,只要你喜欢学就可以。可能工作中你需要SSH,甚至是其他的框架,公司不会等你学会了才开始干的,所以不能说什么框架学会了就如何如何。基础打好了,什么样的框架学起来都不是问题了。 心中有兴趣,学什么都有用的。 35 楼 giginet 2009-05-25   学习框架没什么用,只是代码工人而已,真的。可能我说的有些直白,但事实如此。学框架就是要学它是怎么实现的,明白它的精华。这个道理大家都明白,我就不废话了。

我也面过很多人,都是生套框架,有什么直接丢进框架里,一问为什么,根本不知道。很多都将基础的丢掉了,譬如,很多人用SSH,却还不知道如何写servlet,不懂tomcat,不懂数据库。。。。用了structs,却不知道为什么要这么用,只是搭好了一个模板,往里面添代码,这不是代码工人是什么?

lz能提出这个问题说明还不错,至少还从性能等方面去思考了下这个问题。hibernate我也不是很熟,以前刚毕业的时候搞过一段时间,现在发现,还是回到了sql的老路上来了。性能这个东西,放到生产环境中来接受考验,用自己真实测出的数据来说话,才是最真实的,否则别人云如何可以提高效率,自己那么做了,可是为什么,依然不懂。水平也依旧得不到提高。性能这个东西其实很复杂的,很多时候并不仅仅是从代码上考虑的,架构才是最重要的,有的时候也要经过很多试验才能说清楚。

另外,不要因hibernate而hibernate,每个框架都有其优秀之处,但譬如一对多,多对一这种,能不用的时候,就不要用。练手的时候是一个技术,但放到实际应用中,在有些情况下还是不适用的。这个时候就要果断放弃,而不是所有技术的堆积,那样,只会产生反效果。

很多新手刚开始学习的时候都恨不得把所有技术全都放到自己的作品中,我以前也是这样。但随着时间的推移,慢慢你会发现,有的时候简单才是美。现实要的并不是技术,而是好用的产品,仅此而已。 36 楼 jasstion 2009-05-25   giginet 写道
学习框架没什么用,只是代码工人而已,真的。可能我说的有些直白,但事实如此。学框架就是要学它是怎么实现的,明白它的精华。这个道理大家都明白,我就不废话了。 我也面过很多人,都是生套框架,有什么直接丢进框架里,一问为什么,根本不知道。很多都将基础的丢掉了,譬如,很多人用SSH,却还不知道如何写servlet,不懂tomcat,不懂数据库。。。。用了structs,却不知道为什么要这么用,只是搭好了一个模板,往里面添代码,这不是代码工人是什么? lz能提出这个问题说明还不错,至少还从性能等方面去思考了下这个问题。hibernate我也不是很熟,以前刚毕业的时候搞过一段时间,现在发现,还是回到了sql的老路上来了。性能这个东西,放到生产环境中来接受考验,用自己真实测出的数据来说话,才是最真实的,否则别人云如何可以提高效率,自己那么做了,可是为什么,依然不懂。水平也依旧得不到提高。性能这个东西其实很复杂的,很多时候并不仅仅是从代码上考虑的,架构才是最重要的,有的时候也要经过很多试验才能说清楚。 另外,不要因hibernate而hibernate,每个框架都有其优秀之处,但譬如一对多,多对一这种,能不用的时候,就不要用。练手的时候是一个技术,但放到实际应用中,在有些情况下还是不适用的。这个时候就要果断放弃,而不是所有技术的堆积,那样,只会产生反效果。 很多新手刚开始学习的时候都恨不得把所有技术全都放到自己的作品中,我以前也是这样。但随着时间的推移,慢慢你会发现,有的时候简单才是美。现实要的并不是技术,而是好用的产品,仅此而已。

说得很好!的确那些框架技术感觉很美!自己终是想把那些技术全部利用上,但是发现却很难!您说得关于代码工人,的确,框架再好还是别人的东西,别人的思想,如果能够深刻领悟到别人的思想,在加上自己的创新我感觉那是很高境界啊!我还是差的很远,所以一直在努力!希望能够领悟到JAVA WEB编程的思想,那样的话就会以不变应万变啦吧! 37 楼 activemq 2009-05-26   现在学习 ,电脑的人,学习 java技术的人,真多~~! 38 楼 Durian 2009-05-26   1.to download and look over a copy of servlet2.3 reference, that is so called fundation. 39 楼 xujunJ2EE 2009-05-26   hibernate3中获得session可以使用sessionFactory.getCurrentSession(),
并且在commit()之后,session就自动colse了
现在的问题是:我在DAO层定义一个load的方式获得对象,默认是lazy ture的,那么hibernate返回给我的是一个代理对象,并不是持久化对象,这样在service层调用该方法的时候,会出现异常。当然,你可以说用get()不就OK拉,但是如果是对象many-to-one关联呢,还是会有问题的
如果是web项目,并且结合了spring,那么可以使用openSessionViewFilter的方式,但是如果我现在
开发的是C/S项目呢,是不是只能lazy false或者是hibernate.initialize()方式,但这样我就没有方法获得lazy true的优势了。
各位你们怎么处理非web spring项目中的lazy问题 40 楼 lw223 2009-05-26   实际做一做就知道怎样了 41 楼 yuanke52014 2009-05-29   别来问了,自己练习吧 42 楼 icewubin 2009-05-29   jasstion 写道大家是不是误解我的意图啊?我是觉的应用Hibernate解决某个问题会有几种不同的方法,比如上面我举出的例子,但是考虑到代码与效率之间,怎么作出选择?主要是讨论一下Hibenate查询技术的运用,如何做到代码既简单同时效率有比较高。
提醒楼主一下,如果封装得好的话,手工写一个查询一对多关系的方法超级简单,为何一定要想方设法的利用映射配置呢?映射配置是死的,而且不好维护,配置修改的风险太大了,一个POJO是会被很多其他类共享使用的。

映射配置本来就是为了简化查询,但是如果查询本身已经能够做到很简单,为何还要依赖一对多的配置(尤其是在你没有很好掌握一对多配置的情况下)。不过这好像引出另外一个问题了,需要掌握高效、简洁的hql的写法。 43 楼 treblesoftware 2009-05-30   自己动手试试。软件的复杂度不是你可以预知的。 44 楼 mhx 2009-05-30       楼主,实际动手做做,不要把问题想的那么复杂。什么设计模式、UML都是根据需要来采用的,如果你仅仅写一个批处理根本不需要UML和设计模式之类的东西。
    我建议你先按照自己的思路写出一个可运行的模块。然后再增加新的功能,在这个过程中你就会慢慢发现设计模式和UML之类的东西要用在什么地方了,不要一开始就去研究这些问题。不过,之后还是要好好的读一些相关的书籍,毕竟理论领导实际,但是理论来自实际。 45 楼 jasstion 2009-05-30   mhx 写道
&nbsp;&nbsp;&nbsp; 楼主,实际动手做做,不要把问题想的那么复杂。什么设计模式、UML都是根据需要来采用的,如果你仅仅写一个批处理根本不需要UML和设计模式之类的东西。 &nbsp;&nbsp;&nbsp; 我建议你先按照自己的思路写出一个可运行的模块。然后再增加新的功能,在这个过程中你就会慢慢发现设计模式和UML之类的东西要用在什么地方了,不要一开始就去研究这些问题。不过,之后还是要好好的读一些相关的书籍,毕竟理论领导实际,但是理论来自实际。

好的,谢谢啊!我现在也是感觉初学者没有必要考虑那些问题,希望暑假能够把个中不同思路都实现一下,然后尽量用有关相关测试软件测试一下查询效率,你们公司一般都是用得什么测试软件?自己回来试着熟悉一下 46 楼 mhx 2009-06-05   我们公司的测试很不规范,基本就是人来点点,呵呵。
就我个人,作为一个开发人员我的代码都会有unittest的。 47 楼 swit1983 2009-06-09   有多少公司用自己的框架啊,还是开源的用的多。 48 楼 icewubin 2009-06-09   swit1983 写道有多少公司用自己的框架啊,还是开源的用的多。
开源的也是要决策和整合的。

热点排行