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所以还是觉得不舒服。
 现在真的很困惑,方法多很好,但方法的选择却很痛苦!

[align=center][size=large][color=red]关于第二种方法我想更加仔细的说一下。[/color][/size][/align]
 按照前面的思路,用户登陆后就打开了博客主界面,上面显示了该博客里的文章分类。然后主动权就交给用户啦。他点击一个分类然后就会对应一个Action方法
,Action方法里会调用相关Service类(利用Hibernate技术与数据库打交道)假设传递的参数是类别的ID,那么在Service类里我们怎么检索对应文章
信息呢?我们可以用HQL语句查询,不过这时候就没有必要对类别与文章做一对多映射啦(采用延迟加载)。但我想充分利用Hibernate提供的集合对象的映射。那样的话我提前就为它们做了一对多的映射。我可以考虑利用具体的类别对象直接调用getTopics()返回Set然后再装换成List对象给视图。但这里就出现了一个不舒服的地方就是前面我已经加载了所有的类别对象,当然这是所有的类别对象已经处于托管状态啦!这是我还要重新加载对应ID的持久化对象但好像会出错,因为前面你已经加载过啦啊。如果我重新关联该ID对应的持久化对象似乎又不行,好像托管对象的引用并不能在这个方法中被识别。如果持久化对象是全局声明的话该多好啊,那样的话我只需要在这个Sessions中重新关联该对象,然后执行级联操作(CLASS.getTopics()),不知道这种问题怎么解决?还有持久化对象应该可以声明成全局对象吧?那样的话会不会更好?
[size=xx-large] 最近看了关于对象序列化[/size],对象反射机制以及进程池和数据库连接池的问题,但还不是特别清楚。这里想试着用那些东西分析一下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;
static private int ConnNow=0;
static private List<Connection> connections = new ArrayList();
static private String PoolName;
static private String DriverName;
static private String DbId;
static private String UserName;
static private String Password;
static private 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类就会成功的建立。数据库的连接,你就可以利用他的其他封装的功能进行与数据库有关的操作。
发布了17 篇原创文章 · 获赞 4 · 访问量 5690

猜你喜欢

转载自blog.csdn.net/jasstion/article/details/83398243