`
wyuch
  • 浏览: 74565 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

反思Hibernate,可以有更简洁、更高效的ORM实现

 
阅读更多
  我思考了良久才决定发这篇文章,各位老大手下留情。

  假设有一张表Student,有几个字段ID,Name,Gender,BirthDay,实际上这么一个从数据库设计中直接生成的类就可以很好地满足我们对于ORM的要求:

public class StudentSchema extends Schema {
	private int ID;

	private String Name;

	private String Gender;

	private Date BirthDay;

	public static final TableName = "Student";

	public static final PrimaryKeys PKs = new PrimaryKeys(new String[] { "ID" });

	public Date getBirthDay() {
		return BirthDay;
	}

	public void setBirthDay(Date birthDay) {
		BirthDay = birthDay;
	}

	public String getGender() {
		return Gender;
	}

	public void setGender(String gender) {
		Gender = gender;
	}

	public int getID() {
		return ID;
	}

	public void setID(int id) {
		ID = id;
	}

	public String getName() {
		return Name;
	}

	public void setName(String name) {
		Name = name;
	}
}


  其中Schema是一个公用类,里面主要是提供了fill(),update(),delete(),backup()等功能。其中fill()就是通过主键返回一条记录,其他几个方法就不用说了吧。

  但反观Hibernate呢?我们需要一个与StudentSchema类似的POJO类,一个DAO类,一个*.hbm.xml映射文件,才能达到类似的效果,机制繁琐,性能消耗明显要高。

  我不知道为什么这么简单的高下立见的对比没有引起大家的注意,我也承认我对Hibernate浅尝辄止,并且我估计会引来大片的攻击,但我确实想像不出Hibernate有可能会比这更简洁更高效。在我们的实际应用中,StudentSchema是由工具从PowerDesigner中直接生成的,开发人员根本不管ORM,直接使用即可。StudentSchema是硬编码的类,不需要进行字节码动态生成,不需反射,不需配置文件,十分简单。

  更重要的是,我们这个ORM实现总共才几千行代码。Hibernate功能很多,但我们的ORM实现虽然代码很少,但己能覆盖实际开发中的全部ORM需求。我将以回复的方式加以说明。
分享到:
评论
51 楼 wyuch 2009-06-07  
梦秋雨 写道
看来看去,觉得楼主这个东西根本不是ORM,其目标也不是去解决ORM的问题,整个就是一个dbutils,如果比较可以去和apache里面的dbutils比较一下还差不多。

不是说把数据表里面的一个个字段,都自动化或者半自动化的转换为类里面的一个个简单属性就可以叫做ORM了。

地球人都知道ORM是用来解决对象模型和关系模型的不匹配的,于是级联、对相关联、面向对象的查询方式才是ORM的主要课题。楼主这个东西是什么?


我不知道你的ORM定义来自哪里,不认同我的观点的人很多,但觉得我的压根就不是ORM的你还是第一个。

我不介意跟什么东西做比较,作为一个技术人员出身的创业者,我关心的核心问题是学习曲线、开发效率,简而言之,是少发工资多做事。
50 楼 wyuch 2009-06-07  
fireflyc 写道

在Hibernate才是被我们玩而不是我们被它玩了。


如果一种技术使得开发人员有被它玩的风险,那么它本身确实很值得玩味了。

我用我们的框架来重写一下你的代码:
	public SiteUserSet findUserByPage(int pageno) {
		return new SiteUserSchema().query("", Constants.PAGE_SIZE , pageno);
	}

	public void saveUser(String userName) {
		SiteUserSchema su = new SiteUserSchema();
		su.setName(userName);
		su.setSiteId(UUIDGenerator.generateUUID());
		su.setPwd(MD5.crypt(su.calPwdCode()));
		su.insert();
	}

	public void updateUser(String userId, String userName) {
		SiteUserSchema su = new SiteUserSchema();
		su.setUserId(userId);
		su.fill();
		su.setName(userName);
		su.setSiteId(UUIDGenerator.generateUUID());
		su.setPwd(MD5.crypt(entity.calPwdCode()));
		su.update();
	}

	public SiteUserSchema auth(String userName, String siteId) {
		SiteUserSchema su = new SiteUserSchema();
		SiteUserSet set = su.query(new QueryBuilder("FROM SiteUser WHERE name=? AND siteId=?",userName,siteId));
		if(set.size()>0){
			return null;
		}else{
			return set.get(0);	
		}
	}


以上就是全部,没有名存实亡的siteUserDAO,没有其他类,没有配置。
49 楼 wyuch 2009-06-07  
引用
楼主的东西也是一种根据Class推导出SQL语句的。而hibernate也是这样的。所以设计思想上是相通的。而楼主的做法不如 hibernate的原因是因为,hibernate底层有不通的数据库SQL生成引擎(这个命名。。。呵呵),而且有二级缓存,关联查询,HQL查询语句等等功能。而比起楼主的做法要丰富的多。所以如果说Hibernate差那么楼主的做法比Hibernate更差。


我从未否认Hibernate的强大,从未否认它的功能丰富。正如我的标题所说,我想要的简洁,是高效,这关系到学习曲线,关系到人月,关系到成本。所以我觉得你从功能丰富的角度认为我的做法比Hibernate差我是不认同的。

我们也有SQL生成器,依照一个简单的编程规范写成的代码是可以直接在不同数据库上运行的。我们也提供数据库兼容的分页功能。

我想核心的问题是Hibernate是不是太庞大?缓存真的需要内嵌在ORM中吗?一定需要在ORM层面上实现关联吗?可不可以不用HQL?
48 楼 wyuch 2009-06-07  
kjj 写道
我看清楚了,楼主实际上并不是为了反思什么hibernate,而是为了展示自己的框架罢了, 从自己承认对hibernate 不甚了解就可以看出来端倪,这样的话,我几乎看不出来所列代码比hibernate好在哪里,你说hibernate 复杂,主要就是你没解决的hibernate 比如,关联,缓存,什么的高级特性罢了,这个所谓的 框架 貌似就是hibernate的阉割版而已,没看出推陈出新的地方!!!!!!!!!!!!!!!
最后鄙视一下,为了表现自己随意贬低别人的做法,还对人家不了解,这不是几个踏实的技术人员的态度吧!!


收获这样的砖头是在意料之中的,这个是有争议的话题。
我列出这样的一堆代码,我希望的是能够看到使用Hibernate的代码能够比我列的代码要好,因为我想像不出来它怎样做到更简洁更高效,而不是得到一个“看不出来所列代码比hibernate好在哪里”,“使用Hibernate可以完美模拟这样的需求”之类的答案。
如果Hibernate不能做得比我的框架更简洁更高效,那么我的框架的意义就有了,很明显,他的学习曲线很短。
我是没有让ORM直接管理关联,没有内嵌在ORM里的缓存,但问题是我不需要这样子,很多企业也不需要。

我不厌其乏再次重申一下这样的ORM方案的优点:
1、学习曲线,易于掌握,一个小时的学习即可。这对于一个企业来说意味着成本的降低,极有意义。
2、代码量极少,1500行左右,一个开发团队完全有能力实现一个这种类型的ORM框架,并且扩展之。
3、机制极为简单,达到了JDBC同等的性能,不需要字节码动态生成,不需要配置,直接使用。


虽然我对Hibernate了解不够深入,但还没有弄错概念,既然我用了实例去“贬低”Hibernate,那么请用实例反驳我。而且,我想JavaEye的论坛应该不禁止展示自己的框架,也不禁止表现自我。
47 楼 metadmin 2009-06-07  
<div class="quote_title">fireflyc 写道</div>
<div class="quote_div">
<p><span style="color: #ff0000; font-size: 16px;">现在Hibernate才是被我们玩而不是我们被它玩了。</span></p>
</div>
<p>很有味道!</p>
46 楼 metadmin 2009-06-07  
linginfanta 写道
metadmin 写道
我几年前就抛弃了hibernate。

抛弃原因不是因为它不强大,而是它不满足我的需求。我的很多东西都是动态的。。。另外,我不喜欢复杂的东西。。。


我也想抛弃之,老兄现在做持久化怎么做?

我是开发产品的,很多不确定动态的东东。
当时我们整个团队认为:只要知道数据库表格信息,和实体类,那么相关代码基本上不需要写了。所以就动手写了相关CURD操作引擎,没有使用任何开源产品。至于这种CURD操作,并不需要很多创新的。

基本方式是这样的:
1, 面向对象的方式,描述数据库信息和实体类信息;
2, 编写通用引擎,该引擎得到上面的参数,执行CURD方法;
3, 缓存是外挂的(这点和楼主一样)。

这是我们的快速定制查询演示:http://www.metadmin.com/download/showEmployees.html
45 楼 jejwe 2009-06-07  
楼主的ORM貌似很像.NET的subsonic
http://subsonicproject.com/active-record/
楼主可以参考下,貌似在博客园好像也见到过楼主写过一篇文章
44 楼 梦秋雨 2009-06-07  
看来看去,觉得楼主这个东西根本不是ORM,其目标也不是去解决ORM的问题,整个就是一个dbutils,如果比较可以去和apache里面的dbutils比较一下还差不多。

不是说把数据表里面的一个个字段,都自动化或者半自动化的转换为类里面的一个个简单属性就可以叫做ORM了。

地球人都知道ORM是用来解决对象模型和关系模型的不匹配的,于是级联、对相关联、面向对象的查询方式才是ORM的主要课题。楼主这个东西是什么?
43 楼 fireflyc 2009-06-07  
<p>嘿嘿,这个帖子挺热。似乎javaeye上的这种帖子都很热。。。。。都要成框架生产基地了。每天都有伟大的东西诞生,不知道是喜还是忧。<br><br>看了一下楼主的想法,无非是根据tableName和类的属性生成SQL语句。这种做的原因无非是觉得hibernate是如何如何的差。其实事情没有那么糟糕,</p>
<p> </p>
<p><span style="color: #ff0000; font-size: medium;">如果说Hibernate差,那么楼主的东西比Hibernate更差。</span></p>
<p> </p>
<p>楼主的东西也是一种根据Class推导出SQL语句的。而hibernate也是这样的。所以设计思想上是相通的。而楼主的做法不如hibernate的原因是因为,hibernate底层有不通的数据库SQL生成引擎(这个命名。。。呵呵),而且有二级缓存,关联查询,HQL查询语句等等功能。而比起楼主的做法要丰富的多。所以如果说Hibernate差那么楼主的做法比Hibernate更差。</p>
<p> </p>
<p>楼主觉得Hibernate差的原因无非是因为“<span style="color: #ff0000; font-size: medium;">我们需要一个与StudentSchema类似的POJO类,一个DAO类,一个*.hbm.xml映射文件,才能达到类似的效果,机制繁琐,性能消耗明显要高。
</span>”事实果真如此吗?不尽然,不妨分析一下:</p>
<p> </p>
<p>首先是需要一个POJO得javabean,里面到底要不要包含序列化得业务逻辑?如果包含,那么就是富领域对象了,如果不包含就是贫血对象了。而对于java开发人员来讲贫血的是更普遍的。数据承载对象由javabean的model负责,而业务逻辑有service负责。所以POJO类是一定需要的。至于DAO,完全可以省略了,我们只需要一个Service层就可以了。这里不妨引用一下我随手找大一些代码段</p>
<p> </p>
<pre name="code" class="java"> public Page&lt;SiteUser&gt; findUserByPage(int pageno) {
String hql = "FROM SiteUser siteUser";
return siteUserDao.pagedQuery(hql, pageno, Constants.PAGE_SIZE);
}

public void saveUser(String userName) {
SiteUser entity = new SiteUser();
entity.setName(userName);
entity.setSiteId(UUIDGenerator.generateUUID());
entity.setPwd(MD5.crypt(entity.calPwdCode()));
siteUserDao.save(entity);
}

public void updateUser(String userId, String userName) {
SiteUser entity = siteUserDao.get(userId);
entity.setName(userName);
entity.setSiteId(UUIDGenerator.generateUUID());
entity.setPwd(MD5.crypt(entity.calPwdCode()));
siteUserDao.save(entity);
}

public SiteUser auth(String userName, String siteId) {
String hql = "FROM SiteUser siteUser WHERE siteUser.name=? AND siteUser.siteId=?";
return siteUserDao.findOne(hql, userName, siteId);
}
</pre>
<p> </p>
<p>这里的DAO其实是</p>
<pre name="code" class="java">private HibernateDao&lt;SiteUser&gt; siteUserDao;</pre>
<p> 也就是所DAO层名存实亡了。</p>
<p> </p>
<p>那么还有一个配置文件的问题,这个基本上不是问题,使用JPA的注解。最佳实践是尽量的少写JPA的注解,尽量默认。看我的注解对象</p>
<p> </p>
<pre name="code" class="java">@Entity
public class SiteUser extends JPAModel {
@Id
private String id = UUIDGenerator.generateUUID();
@Column
private String name;
@Column
private String siteId;
@Column
private String pwd;
@Column
private Date addDate = new Date();</pre>
<p> 只需要在spring里的sessionFactory定义一下</p>
<p> </p>
<pre name="code" class="xml">&lt;property name="namingStrategy"&gt;
&lt;bean class="org.hibernate.cfg.ImprovedNamingStrategy" /&gt;
&lt;/property&gt;</pre>
<p> 就会完成名称的“约定大于配置”</p>
<p> </p>
<p>如此,这些事情也不再繁琐了。得到的好处也是显而易见的了:我们能使用hibernate的save,update,deleteById等基本操作,书写HQL语句要比书写SQL语句更短一点更容易理解一点。<span style="color: #ff0000; font-size: medium;">现在Hibernate才是被我们玩而不是我们被它玩了。</span></p>
42 楼 kjj 2009-06-07  
我看清楚了,楼主实际上并不是为了反思什么hibernate,而是为了展示自己的框架罢了, 从自己承认对hibernate 不甚了解就可以看出来端倪,这样的话,我几乎看不出来所列代码比hibernate好在哪里,你说hibernate 复杂,主要就是你没解决的hibernate 比如,关联,缓存,什么的高级特性罢了,这个所谓的 框架 貌似就是hibernate的阉割版而已,没看出推陈出新的地方!!!!!!!!!!!!!!!
最后鄙视一下,为了表现自己随意贬低别人的做法,还对人家不了解,这不是几个踏实的技术人员的态度吧!!
41 楼 linginfanta 2009-06-07  
metadmin 写道
我几年前就抛弃了hibernate。

抛弃原因不是因为它不强大,而是它不满足我的需求。我的很多东西都是动态的。。。另外,我不喜欢复杂的东西。。。


我也想抛弃之,老兄现在做持久化怎么做?
40 楼 metadmin 2009-06-07  
我几年前就抛弃了hibernate。

抛弃原因不是因为它不强大,而是它不满足我的需求。我的很多东西都是动态的。。。另外,我不喜欢复杂的东西。。。
39 楼 wyuch 2009-06-07  
我帖的代码应该算是一个简单的业务逻辑,实际上我们的整个CMS系统都是这样的逻辑构成,欢迎指点:http://demo.zving.com

有一个不能演示的例子是目前国内一半以上的保险公司所用的核心业务系统,也是由这样的逻辑构成的。保险公司属于金融业,要求是很苛刻的。

为什么我们的框架简洁,有几个原因已经被大家火眼金晴指出来了:
1、没有管理级联关系
2、没有实现Session范围内的重复读,也没有对象的同一性的概念,没有状态的变化。
3、没有缓存

缓存不说它,我们的缓存是外挂的。

.NET的DataSet应该是对级联关系有考虑的,当时用.NET做项目的时候一直当DataSet作为一个通过向DataTable的途径,没有使用过他的级联关系,当然.NET自带的数据访问机制还称不上ORM。后来遇到了几个巨型系统自己的ORM,发现也不由ORM管理级联,而且如果要把这个纳入管理的范围之内,那么复杂程序立马直线上升。所以目前还没有考虑ORM框架直接管理级联关系。

我说说实际开发中级联关系是怎么处理的。
就以定单和客户的例子:
//级联查询的例子
OrderSchema order = new OrderSchema();
order.setID(orderID);
order.fill();

CustomerSchema customer = new CustomerSchema();
customer.setID(order.getCustomerID());
customer.fill();

//级联删除的例子
CustomerSchema customer = new CustomerSchema();
customer.setID(order.getCustomerID());
customer.fill();

OrderSchema order = new OrderSchema();
order.setCutomerID(customer.getID());
OrderSet orders = order.query();

Transcation tran = new Transaction();
tran.add(customer,Transaction.DELETE);
tran.add(orders ,Transaction.DELETE);
tran.commit();

当然这谈不上ORM管理级联。级联是Hibernate的亮点之一,我看过几个例子,感觉用起来是不是有点麻烦?

第二是可重复读和对象一致性
实际上Schema是没有状态的,只是一个数据容器,与数据库中的记录没有关联,对它的值的改变不产生脏数据。
//级联更新的例子
CustomerSchema customer = new CustomerSchema();
customer.setID(order.getCustomerID());
customer.fill();

OrderSchema order = new OrderSchema();
order.setCutomerID(customer.getID());
OrderSet orders = order.query();

//中间对数据进行了很多操作,修改了Schema的值

Transcation tran = new Transaction();
tran.add(customer,Transaction.UPDATE);
tran.add(orders ,Transaction.UPDATE);
tran.commit();

如上述代码,Schema和Set一旦取出即与数据库无关,中间可以反复无限制操作,只有到最后需要写入持久层的时候,才通过Transaction一次性写入。

这样的实现与Hibernate是有很大距离,但胜在实用,够用。


还是有一些企业对Hibernate很庞大学习曲线高是有感受的,说一下我们这样的框架的红利:
1、还是学习曲线短
2、整个ORM的代码量在1500行左右。包括从PowerDesginer中生成Schema和Set的工具类代码。我想这样的代码量是很容易掌握的,扩展起来完全不成问题。

比如说大家经常会遇到的一个问题,就是业务数据在修改和删除时希望保留历史版本,这个问题不难,但很烦。
我们的ORM实现就很轻松地为Schema扩展了backup方法,以便可以保留多份历史版本的数据。
38 楼 zypro 2009-06-07  
wyuch 写道

以我对Hibernate的初步了解,它很强大,也很庞大,提供了很多的功能,远远超过我帖的这个ORM实现。但问题不是别人提供了什么,而是我们需要什么,我们实际使用中用到了什么,可以不可以做得更简洁更高效?实际使用中本文的ORM实现的过程中,还没有碰到不能实现的或者说很难实现的功能。但这种模式在简洁性上面有着巨大的优势,学习曲线极短,基本上不言自明,新手学习的时间不超过一小时。


Hibernate的学习曲线确实很长. 但作为ORM,我们需要的不仅仅是CRUD的自动生成,我们需要在业务逻辑层能够写出优雅的,OO的代码,来最贴切的反映业务需求. LZ贴的代码,只是一个前台的案例,不牵涉到什么业务逻辑. 考虑一下Order.getCustomer().getName(), Hibernate实现类似的运用,而这个正是我们需要的.
37 楼 holan 2009-06-07  
wyuch 写道
一天不来,回复良多。看了各位的回帖,颇有收获,感谢各位指教。

首先帖一段代码,是一我们框架中的典型的后台类:

package com.zving.cms.site;

import java.io.File;
import java.util.Date;

import com.zving.cms.dataservice.FullText;
import com.zving.cms.pub.SiteUtil;
import com.zving.cms.resource.ConfigImageLib;
import com.zving.framework.Config;
import com.zving.framework.Page;
import com.zving.framework.User;
import com.zving.framework.controls.DataGridAction;
import com.zving.framework.data.QueryBuilder;
import com.zving.framework.data.Transaction;
import com.zving.framework.utility.FileUtil;
import com.zving.framework.utility.HtmlUtil;
import com.zving.framework.utility.Mapx;
import com.zving.framework.utility.StringUtil;
import com.zving.platform.Application;
import com.zving.platform.pub.NoUtil;
import com.zving.schema.ZCArticleSchema;
import com.zving.schema.ZCArticleSet;
import com.zving.schema.ZCAudioSchema;
import com.zving.schema.ZCAudioSet;
import com.zving.schema.ZCCatalogSchema;
import com.zving.schema.ZCCatalogSet;
import com.zving.schema.ZCImageSchema;
import com.zving.schema.ZCImageSet;
import com.zving.schema.ZCSiteSchema;
import com.zving.schema.ZCSiteSet;
import com.zving.schema.ZCVideoSchema;
import com.zving.schema.ZCVideoSet;

public class Site extends Page {

	public static Mapx init(Mapx params) {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setID(Application.getCurrentSiteID());
		site.fill();
		return site.toMapx();
	}

	public static void dg1DataBind(DataGridAction dga) {
		String sql = "select * from ZCSite order by orderflag ";
		if (dga.getTotal() == 0) {
			String sql2 = "select count(*) from ZCSite";
			dga.setTotal(new QueryBuilder(sql2));
		}
		dga.bindData(new QueryBuilder(sql));
	}

	public void add() {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setValue(Request);
		site.setID(NoUtil.getMaxID("SiteID"));
		site.setHitCount(0);
		site.setChannelCount(0);
		site.setSpecialCount(0);
		site.setMagzineCount(0);
		site.setArticleCount(0);
		site.setImageLibCount(1);
		site.setVideoLibCount(1);
		site.setAudioLibCount(1);
		site.setAttachmentLibCount(1);
		site.setBranchCode(User.getBranchCode());
		site.setBranchInnerCode(User.getBranchInnerCode());
		site.setAddTime(new Date());
		site.setAddUser(User.getUserName());
		site.setConfigXML(ConfigImageLib.ImageLibConfigDefault);
		Transaction trans = new Transaction();
		trans.add(site, Transaction.INSERT);

		if (trans.commit()) {
			// 复制一些必要的图片
			String oldPath = Config.getContextRealPath() + "Images";
			String path =
					(Config.getContextRealPath() + Config.getValue("UploadDir") + "/" + site.getAlias() + "/Image").replaceAll("//", "/");
			File dir = new File(path);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			FileUtil.copy(oldPath + "/nocover.jpg", path + "/nocover.jpg");
			FileUtil.copy(oldPath + "/nophoto.jpg", path + "/nophoto.jpg");
			FileUtil.copy(oldPath + "/nopicture.jpg", path + "/nopicture.jpg");
			FileUtil.copy(oldPath + "/WaterMarkImage1.png", path + "/WaterMarkImage1.png");
			FileUtil.copy(oldPath + "/WaterMarkImage.png", path + "/WaterMarkImage.png");
			Response.setLogInfo(1, "新建成功");
		} else {
			Response.setLogInfo(0, "新建失败");
		}
	}

	public void save() {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setValue(Request);
		site.fill();
		site.setValue(Request);
		site.setModifyUser(User.getUserName());
		site.setModifyTime(new Date());
		if (site.update()) {
			SiteUtil.initSiteCodeMap();
			Response.setLogInfo(1, "保存成功");
			final String indexFlag = site.getAutoIndexFlag();
			final long siteID = site.getID();
			new Thread() {
				public void run() {
					FullText.dealAutoIndex(siteID, "Y".equals(indexFlag));
				}
			}.start();
		} else {
			Response.setLogInfo(0, "保存失败");
		}
	}

	public void del() {
		String ids = $V("IDs");
		if (!StringUtil.checkID(ids)) {
			Response.setStatus(0);
			Response.setMessage("传入ID时发生错误!");
			return;
		}
		Transaction trans = new Transaction();
		ZCSiteSchema site = new ZCSiteSchema();
		ZCSiteSet set = site.query(new QueryBuilder("where id in (" + ids + ")"));
		trans.add(set, Transaction.DELETE_AND_BACKUP);

		// 删除站点下的所有频道、栏目、期刊、专题
		for (int i = 0; i < set.size(); i++) {
			site = set.get(i);
			ZCCatalogSchema catalog = new ZCCatalogSchema();
			catalog.setSiteID(site.getID());
			ZCCatalogSet catalogSet = catalog.query();
			trans.add(catalogSet, Transaction.DELETE_AND_BACKUP);

			// 删除所有文章
			for (int j = 0; j < catalogSet.size(); j++) {
				catalog = catalogSet.get(j);
				ZCArticleSchema article = new ZCArticleSchema();
				article.setCatalogID(catalog.getID());
				ZCArticleSet articleSet = article.query();
				trans.add(articleSet, Transaction.DELETE_AND_BACKUP);

				ZCImageSchema image = new ZCImageSchema();
				image.setCatalogID(catalog.getID());
				ZCImageSet imageSet = image.query();
				trans.add(imageSet, Transaction.DELETE_AND_BACKUP);

				ZCAudioSchema audio = new ZCAudioSchema();
				audio.setCatalogID(catalog.getID());
				ZCAudioSet audioSet = audio.query();
				trans.add(audioSet, Transaction.DELETE_AND_BACKUP);

				ZCVideoSchema video = new ZCVideoSchema();
				video.setCatalogID(catalog.getID());
				ZCVideoSet videoSet = video.query();
				trans.add(videoSet, Transaction.DELETE_AND_BACKUP);
			}
		}
		if (trans.commit()) {
			SiteUtil.initSiteCodeMap();
			Response.setLogInfo(1, "删除成功");
		} else {
			Response.setLogInfo(0, "删除失败");
		}
	}
}


增加站点时会调用add(),修改保存时会调用update(),删除时会调用del(),向前台数据表格中展现数据时会调用dg1DataBind()。dg1DataBind()中当前页数、每页大小由前台标签通过DataGridAction传入,由框架自动处理分页。这段代码基本上已经演示了我们的后台类是怎么和数据库打交道的,怎样处理关联表的。

这种模式应该很多朋友见过有类似的,本非我独创,实际中已经使用了很多年,做过表七八百张,主要表数据几千万的巨型系统,应该说不存在明显的功能上的缺陷。

我的帖子里是承认过我对Hibernate浅尝辄止的,我的意思是我想不通过Hibernate能够以什么方式更简洁更高效的取得一样的效果。我也得诚恳地承认我标题党了一回。

以我对Hibernate的初步了解,它很强大,也很庞大,提供了很多的功能,远远超过我帖的这个ORM实现。但问题不是别人提供了什么,而是我们需要什么,我们实际使用中用到了什么,可以不可以做得更简洁更高效?实际使用中本文的ORM实现的过程中,还没有碰到不能实现的或者说很难实现的功能。但这种模式在简洁性上面有着巨大的优势,学习曲线极短,基本上不言自明,新手学习的时间不超过一小时。

事实上是你们关注的方面不一样,你实际上只是需要一个简单的sql映射,而hibernate考虑的太多了,对象统一性,session范围内的可重复读,级联,关联。
hibernate可以实现你的框架的所有功能,如果用你的框架做项目,以后如果需要上述这些东西,难道扩展你的框架?
我直接用hibernate不用它的功能可以和你的东西一样简单,额外的红利是一旦我需要之中某些高级特性的时候我不用切换框架。

36 楼 打倒小日本 2009-06-07  
斗胆问一句 楼主了解过JPA么?
(也可以理解为不用XML配置的hibernate)
35 楼 wyuch 2009-06-07  
一天不来,回复良多。看了各位的回帖,颇有收获,感谢各位指教。

首先帖一段代码,是一我们框架中的典型的后台类:

package com.zving.cms.site;

import java.io.File;
import java.util.Date;

import com.zving.cms.dataservice.FullText;
import com.zving.cms.pub.SiteUtil;
import com.zving.cms.resource.ConfigImageLib;
import com.zving.framework.Config;
import com.zving.framework.Page;
import com.zving.framework.User;
import com.zving.framework.controls.DataGridAction;
import com.zving.framework.data.QueryBuilder;
import com.zving.framework.data.Transaction;
import com.zving.framework.utility.FileUtil;
import com.zving.framework.utility.HtmlUtil;
import com.zving.framework.utility.Mapx;
import com.zving.framework.utility.StringUtil;
import com.zving.platform.Application;
import com.zving.platform.pub.NoUtil;
import com.zving.schema.ZCArticleSchema;
import com.zving.schema.ZCArticleSet;
import com.zving.schema.ZCAudioSchema;
import com.zving.schema.ZCAudioSet;
import com.zving.schema.ZCCatalogSchema;
import com.zving.schema.ZCCatalogSet;
import com.zving.schema.ZCImageSchema;
import com.zving.schema.ZCImageSet;
import com.zving.schema.ZCSiteSchema;
import com.zving.schema.ZCSiteSet;
import com.zving.schema.ZCVideoSchema;
import com.zving.schema.ZCVideoSet;

public class Site extends Page {

	public static Mapx init(Mapx params) {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setID(Application.getCurrentSiteID());
		site.fill();
		return site.toMapx();
	}

	public static void dg1DataBind(DataGridAction dga) {
		String sql = "select * from ZCSite order by orderflag ";
		if (dga.getTotal() == 0) {
			String sql2 = "select count(*) from ZCSite";
			dga.setTotal(new QueryBuilder(sql2));
		}
		dga.bindData(new QueryBuilder(sql));
	}

	public void add() {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setValue(Request);
		site.setID(NoUtil.getMaxID("SiteID"));
		site.setHitCount(0);
		site.setChannelCount(0);
		site.setSpecialCount(0);
		site.setMagzineCount(0);
		site.setArticleCount(0);
		site.setImageLibCount(1);
		site.setVideoLibCount(1);
		site.setAudioLibCount(1);
		site.setAttachmentLibCount(1);
		site.setBranchCode(User.getBranchCode());
		site.setBranchInnerCode(User.getBranchInnerCode());
		site.setAddTime(new Date());
		site.setAddUser(User.getUserName());
		site.setConfigXML(ConfigImageLib.ImageLibConfigDefault);
		Transaction trans = new Transaction();
		trans.add(site, Transaction.INSERT);

		if (trans.commit()) {
			// 复制一些必要的图片
			String oldPath = Config.getContextRealPath() + "Images";
			String path =
					(Config.getContextRealPath() + Config.getValue("UploadDir") + "/" + site.getAlias() + "/Image").replaceAll("//", "/");
			File dir = new File(path);
			if (!dir.exists()) {
				dir.mkdirs();
			}
			FileUtil.copy(oldPath + "/nocover.jpg", path + "/nocover.jpg");
			FileUtil.copy(oldPath + "/nophoto.jpg", path + "/nophoto.jpg");
			FileUtil.copy(oldPath + "/nopicture.jpg", path + "/nopicture.jpg");
			FileUtil.copy(oldPath + "/WaterMarkImage1.png", path + "/WaterMarkImage1.png");
			FileUtil.copy(oldPath + "/WaterMarkImage.png", path + "/WaterMarkImage.png");
			Response.setLogInfo(1, "新建成功");
		} else {
			Response.setLogInfo(0, "新建失败");
		}
	}

	public void save() {
		ZCSiteSchema site = new ZCSiteSchema();
		site.setValue(Request);
		site.fill();
		site.setValue(Request);
		site.setModifyUser(User.getUserName());
		site.setModifyTime(new Date());
		if (site.update()) {
			SiteUtil.initSiteCodeMap();
			Response.setLogInfo(1, "保存成功");
			final String indexFlag = site.getAutoIndexFlag();
			final long siteID = site.getID();
			new Thread() {
				public void run() {
					FullText.dealAutoIndex(siteID, "Y".equals(indexFlag));
				}
			}.start();
		} else {
			Response.setLogInfo(0, "保存失败");
		}
	}

	public void del() {
		String ids = $V("IDs");
		if (!StringUtil.checkID(ids)) {
			Response.setStatus(0);
			Response.setMessage("传入ID时发生错误!");
			return;
		}
		Transaction trans = new Transaction();
		ZCSiteSchema site = new ZCSiteSchema();
		ZCSiteSet set = site.query(new QueryBuilder("where id in (" + ids + ")"));
		trans.add(set, Transaction.DELETE_AND_BACKUP);

		// 删除站点下的所有频道、栏目、期刊、专题
		for (int i = 0; i < set.size(); i++) {
			site = set.get(i);
			ZCCatalogSchema catalog = new ZCCatalogSchema();
			catalog.setSiteID(site.getID());
			ZCCatalogSet catalogSet = catalog.query();
			trans.add(catalogSet, Transaction.DELETE_AND_BACKUP);

			// 删除所有文章
			for (int j = 0; j < catalogSet.size(); j++) {
				catalog = catalogSet.get(j);
				ZCArticleSchema article = new ZCArticleSchema();
				article.setCatalogID(catalog.getID());
				ZCArticleSet articleSet = article.query();
				trans.add(articleSet, Transaction.DELETE_AND_BACKUP);

				ZCImageSchema image = new ZCImageSchema();
				image.setCatalogID(catalog.getID());
				ZCImageSet imageSet = image.query();
				trans.add(imageSet, Transaction.DELETE_AND_BACKUP);

				ZCAudioSchema audio = new ZCAudioSchema();
				audio.setCatalogID(catalog.getID());
				ZCAudioSet audioSet = audio.query();
				trans.add(audioSet, Transaction.DELETE_AND_BACKUP);

				ZCVideoSchema video = new ZCVideoSchema();
				video.setCatalogID(catalog.getID());
				ZCVideoSet videoSet = video.query();
				trans.add(videoSet, Transaction.DELETE_AND_BACKUP);
			}
		}
		if (trans.commit()) {
			SiteUtil.initSiteCodeMap();
			Response.setLogInfo(1, "删除成功");
		} else {
			Response.setLogInfo(0, "删除失败");
		}
	}
}


增加站点时会调用add(),修改保存时会调用update(),删除时会调用del(),向前台数据表格中展现数据时会调用dg1DataBind()。dg1DataBind()中当前页数、每页大小由前台标签通过DataGridAction传入,由框架自动处理分页。这段代码基本上已经演示了我们的后台类是怎么和数据库打交道的,怎样处理关联表的。

这种模式应该很多朋友见过有类似的,本非我独创,实际中已经使用了很多年,做过表七八百张,主要表数据几千万的巨型系统,应该说不存在明显的功能上的缺陷。

我的帖子里是承认过我对Hibernate浅尝辄止的,我的意思是我想不通过Hibernate能够以什么方式更简洁更高效的取得一样的效果。我也得诚恳地承认我标题党了一回。

以我对Hibernate的初步了解,它很强大,也很庞大,提供了很多的功能,远远超过我帖的这个ORM实现。但问题不是别人提供了什么,而是我们需要什么,我们实际使用中用到了什么,可以不可以做得更简洁更高效?实际使用中本文的ORM实现的过程中,还没有碰到不能实现的或者说很难实现的功能。但这种模式在简洁性上面有着巨大的优势,学习曲线极短,基本上不言自明,新手学习的时间不超过一小时。
34 楼 YiSingQ 2009-06-07  
Hibernate真正地实现了数据层面向对象的操作方式,同时它在对象关联体现数据库表的关联思想以及缓存策略都是JAVA数据操作的一大飞跃!
33 楼 打倒小日本 2009-06-07  
zypro说的很对 楼主明明不熟悉不了解Hibernate 又何谈反思呢?
32 楼 HenryYu 2009-06-07  
这个实现没有什么,在Beetle框架中一个TableOperator操作器就搞定

相关推荐

    Hibernate框架ORM的实现原理

    ### Hibernate框架ORM的实现原理详解 #### 一、ORM概念及意义 **ORM**,即**对象关系映射**(Object Relational Mapping),是一种程序...了解Hibernate的实现原理有助于更好地运用这一框架,解决实际开发中的问题。

    Hibernate orm 实现原理

    Hibernate orm 实现原理 主要讲解了关于hibernate 的一些知识

    hibernate-orm-master.zip

    在实际开发中,理解并熟练运用这些核心概念和机制,可以帮助我们更高效地利用Hibernate ORM进行数据访问层的设计,减少数据库操作的复杂性,提高代码的可维护性。对于初学者,建议从简单的JAR包开始,逐步熟悉其API...

    HibernateORM

    Hibernate作为Java领域广泛使用的ORM框架,它极大地简化了数据库操作,将面向对象的编程思想与关系型数据库相结合,使得开发者可以更加专注于业务逻辑,而不是繁琐的SQL语句。在本书中,作者深入浅出地讲解了如何...

    hibernate-orm-3.3源码

    总结,通过分析《hibernate-orm-3.3源码》,我们可以深入理解 Hibernate 的工作机制,掌握如何高效地使用 ORM 技术,以及如何根据需求扩展和定制 Hibernate。对于任何想提升数据库操作效率和代码可维护性的 Java ...

    ORM hibernate。jar包

    标题提到的"ORM Hibernate .jar包"指的是Hibernate框架的可执行库文件,通常包含了一系列类、接口和实现,供开发者在项目中引用,以实现ORM功能。"hibernate5+jars包"表明这是Hibernate的第五个主要版本,5.2.16....

    hibernate-orm-4.3.9源码

    本文将基于从Hibernate官网下载的hibernate-orm-4.3.9源码,深入解析其内部机制,帮助开发者更好地理解和应用Hibernate。 一、Hibernate概述 Hibernate的核心功能是将Java对象与数据库表进行映射,实现了数据持久...

    Hibernate_ORM步骤详解

    Hibernate ORM 是一种强大的Java持久层框架,它实现了对象关系映射(ORM)的概念,使得开发者可以使用面向对象的方式来操作数据库,而无需关心底层SQL语句的编写。在本教程中,我们将详细介绍如何利用Hibernate 3...

    hibernate-orm-3.2.zip

    Hibernate ORM 是一个强大的Java对象关系映射(ORM)框架,它极大地简化了数据库与Java应用程序之间的数据交互...虽然现在Hibernate已经发展到了更高级的版本,但理解3.2的基础知识仍然有助于理解ORM的本质和工作原理。

    hibernate-orm-master

    hibernate-orm-master

    hibernate-search-orm-4.4.2.Final.zip

    总结来说,Hibernate Search ORM 4.4.2.Final是Java开发中实现全文检索的强大工具,而AtomicMapOperations则提供了并发映射的非阻塞原子操作,两者结合可以构建出高性能、高并发的搜索应用。对于任何处理大量数据和...

    hibernate-framework-orm-4.2.4.Final.zip

    Hibernate作为ORM工具,主要解决了Java应用与数据库之间的数据交互问题,通过将数据库表映射为Java类,实现对象与数据的自动转换。这使得开发者可以使用面向对象的方式来操作数据库,降低了数据库操作的复杂性。 2...

    自定义Orm框架的实现

    本项目旨在实现一个基于JDK5.0注解的小型ORM框架,模拟Hibernate的部分功能。 首先,我们要理解ORM的基本原理。ORM的核心思想是将数据库中的表映射为Java对象,将表中的记录映射为对象的实例,这样就可以通过操作...

    org.springframework.orm.hibernate3.LocalSessionFactoryBean

    ### 关于 "org.springframework.orm.hibernate3.LocalSessionFactoryBean" 未找到问题的知识点解析 #### 一、问题背景 在开发基于Spring与Hibernate整合的应用时,可能会遇到“`org.springframework.orm.hibernate...

    Hibernate源码(hibernate-orm-main.zip)

    Hibernate源码(hibernate-orm-main.zip)Source Code: Hibernate ORM 是一个为应用程序、库和框架提供对象/关系映射 (ORM) 支持的库。 它还提供了 JPA 规范的实现,这是 ORM 的标准 Java 规范。

    Hibernate ORM - 一对多双向关联关系

    在Hibernate中,这种关系可以通过`@OneToMany`注解实现。例如,User类可能会有如下注解: ```java @Entity public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; ...

    ORM的简单介绍及相应ORM工具Hibernate的使用规则

    对象关系映射的概念,及相应Hibernate的使用规范,同时通过实例展示到底什么是对象关系映射。

    Hibernate入门到精通

    Hibernate 是一个基于Java的ORM(Object-Relational Mapping,对象关系映射)框架,它提供了一种简洁高效的方式来访问和操作关系数据库。下面是 Hibernate 的主要知识点: Hibernate 简介 Hibernate 是一个开源的...

Global site tag (gtag.js) - Google Analytics