`
wyuch
  • 浏览: 74554 次
  • 性别: 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需求。我将以回复的方式加以说明。
分享到:
评论
11 楼 lovejavaei 2009-06-06  
个人认为hibernate真正伟大之处是hql和缓层
10 楼 lovejavaei 2009-06-06  
这个问题实际是由某位大牛引发的“贫血模型”之争。在hibernate出现之前,很多公司其实已经有了自己的持久层框架,像楼主提到的方案,有不少公司在用。ufida的持久层方案介于本讨论和hibernate之间的,由dao负责对pojo进行存取,但是没有映射文件,通过反射实现映射的
9 楼 whaosoft 2009-06-06  
55555 楼主的想法不错的呢
呵呵 只不过我们那的都是分模块的 不是集中设计的 所以我们很少用继承

对  了楼主留个qq什么的吧 以便交流
8 楼 seraphim871211 2009-06-06  
很好奇关联关系是如何实现的?
LZ为什么不举个例子?
7 楼 wyuch 2009-06-06  
Bernard 写道
这是构想中的东西还是已经实现了?
我的框架里也实现了类似操作的ORM工具。
不过下面示例中的table构建比较复杂。
可以说成字段对象集,是个中间层。
可以从类似你上面的StudentSchema类转换过来。
有些操作不是很河蟹,还在重构中。


        SampleArticleTableEntry table = SampleArticleTableEntry.newInstance();
        table.getId().turnOff();
        table.setPrimeKey("id", "NEXT VALUE FOR ARTICLE_SEQ_ID ");
        table.setTitle("标题灰常党");
        table.setContent("内容灰常虚~");
        table.setEditTime(time);
        effectRowCount = zdo.contactTable(table).insert();
        assertEquals(effectRowCount, 1);



你上面提到的Zving Framework是你们自己的框架吧?是否准备开源?
我从Php进入Java快半年了,一直在为开发一套亲近Php开发人员使用的框架而努力。
这里的大牛比较多,提问很容被莫名鄙视。所以希望有机会能私下交流。
QQ:5943590 Email:SysTem128@GMail.Com


准备开源,还在整理,很快了
6 楼 Bernard 2009-06-06  
这是构想中的东西还是已经实现了?
我的框架里也实现了类似操作的ORM工具。
不过下面示例中的table构建比较复杂。
可以说成字段对象集,是个中间层。
可以从类似你上面的StudentSchema类转换过来。
有些操作不是很河蟹,还在重构中。


        SampleArticleTableEntry table = SampleArticleTableEntry.newInstance();
        table.getId().turnOff();
        table.setPrimeKey("id", "NEXT VALUE FOR ARTICLE_SEQ_ID ");
        table.setTitle("标题灰常党");
        table.setContent("内容灰常虚~");
        table.setEditTime(time);
        effectRowCount = zdo.contactTable(table).insert();
        assertEquals(effectRowCount, 1);



你上面提到的Zving Framework是你们自己的框架吧?是否准备开源?
我从Php进入Java快半年了,一直在为开发一套亲近Php开发人员使用的框架而努力。
这里的大牛比较多,提问很容被莫名鄙视。所以希望有机会能私下交流。
QQ:5943590 Email:SysTem128@GMail.Com
5 楼 wyuch 2009-06-06  
liujunsong 写道
学那个Hibernate就快把人搞死了,
现在用这个又要学新东西.
现在的技术啊,老是与时惧进,东西越来越多.

用这个东西也许能提高些效率,可是以后维护怎么办?
来的人还得从头开始学习,理解,消化...
不看好.


不用的呀,其实写在纸面上一大堆,实际上这个很简单,开发人员都不管,Schema类都是自动生成的。
我们的程序员入职花在ORM上的时间不超过一小时。
4 楼 liujunsong 2009-06-05  
学那个Hibernate就快把人搞死了,
现在用这个又要学新东西.
现在的技术啊,老是与时惧进,东西越来越多.

用这个东西也许能提高些效率,可是以后维护怎么办?
来的人还得从头开始学习,理解,消化...
不看好.
3 楼 wyuch 2009-06-05  
2.1执行SQL语句
通过使用QueryBuilder类,可以方便地对在数据库中执行SQL语句。QueryBuilder需要给定一个参数化的SQL语句,并设置它的参数,然后指定的相应的操作方法即可操作数据库,而不需要手工管理Connection、Statement、ResultSet等对象。之所以使用参数化的SQL语句,而不是直接用字符串拼接SQL,是基于以下几点原因:
1、 用字符串拼接SQL,会引入外部参数中不安全的SQL逻辑,从而受到SQL注入攻击。(请参考SQL注入相关资料)。
2、 QueryBuilder内部调用PreparedStatement处理参数化SQL,能够有效地避免SQL注入攻击。
3、 参数化SQL使得代码具有良好的可读性和可维护性。

QueryBuilder有两类构造函数:
1、 带一个String参数,即指定的SQL语句。
2、 带二或者三个参数,第一个参数为指定的参数化SQL语句,第二、第三个参数可以是int、long、String、或者Object。

通常的参数化SQL语句参数个数小于2个,所以通常使用第二类构造函数,直接指定参数。
有的SQL语句参数个数大于2个,则需要使用第一类构造函数,先指定SQL语句,然后通过add方法设置参数。
参数设置后,可以通过set方法进行修改。
QueryBuilder拥有executePagedDataTable方法,以提供分页查询的能力。QueryBuilder自动针对当前数据库类型形成分页SQL语句,使得只有当前页的数据载入内存,从而获得良好的性能。

以下是代码示例:

简单SQL查询:
	DataTable dt = new QueryBuilder("select * from user where userid=?", userid).executeDataTable();

多参数SQL查询:
	QueryBuilder qb = new QueryBuilder("select * from user where userid=? and addtime=? and lastlogintime=?");
	qb.add(userid);
	qb.add(DateUtil.parse("2006-01-01"));
	qb.add(new Date());
	DataTable dt = qb.executeDataTable();


分页查询:
	DataTable dt = new QueryBuilder("select * from user where userid=?", userid).executePagedDataTable(15,0);


删除、修改操作:
	new QueryBuilder("delete from user where userid=?",userid).executeNoQuery();


批量操作:
	QueryBuilder qb = new QueryBuilder("update user set mobile=?,email=? Where username=?");
	qb.add("0086-13988877001");
	qb.add("user1@hotmail.com");
	qb.addBatch();
	qb.add("0086-13988877001");
	qb.add("user1@hotmail.com");
	qb.addBatch();
	qb.add("0086-13988877001");
	qb.add("user1@hotmail.com");
	qb.addBatch();
	qb. executeBatch ();//批量更新3条数据,这比分别更新3条数据性能要好


返回单个值:
	int count = new QueryBuilder("select count(*) from user").executeInt();


2.1 DataTable类
通过QueryBuilder类的executeDataTable或者executePagedDataTable方法,可以得到一个DataTable实例。DataTable是对ResultSet的封装,提供了众多ResultSet不具备的功能:
1、 不需要移动当前位置,直接存取任意一行数据。
2、 直接存取任意一行的任意一列(通过列索引或列名)。
3、 直接修改任意一行的任意一列(通过列索引或列名)的值。
4、 可以对DataTable的行进行增、删、改等操作(只在内存中操作,以便于利用数据,不反馈到数据库)。
5、 可以对DataTable的列进行增、删、改等操作(只在内存中操作,以便于利用数据,不反馈到数据库)。
6、 可以合并两个DataTable,如果这两个DataTable列相同的话。
7、 可以筛选掉不符合条件的列,得到一个新的DataTable。
8、 支持按Comparable排序。
9、 可以将所有行的某一列转成数组。
10、 可以将某一行转成以字段名为key的HashMap。

以下是代码示例:

获取值:
	Object obj = dt.get(3, 4);//取第4行,第5列的值,下标从0开始
	String str = dt.getString(0, "username");//取第1行username列的值

设置值(设置的值不反馈回数据库,但可以用get方法取到,以便于数据利用):
	dt.set(0, 0, "TRUE");//将第1行第1列的值设为字符串TRUE
	dt.set(0, "username", "mike");//北朝鲜第1行username列的值设为mike

行操作:
	Object[] rowValue = new Object[] { "john", "password", "2008-01-11", "220.194.110.74" };
	dt.insertRow(rowValue);// 在DataTable最后追加一行,各列数据按rowValue中的值依次填充
	dt.insertRow(rowValue, 0);// 在DataTable最前面插入一行
	dt.deleteRow(9);// 删除第10行
	DataRow dr = dt.getDataRow(0);// 得到第1行的DataRow实例,DataRow是对一行数据的封装
	String username = dr.getString("username");// 从dr中取username的值;
dr.fill(map);//将map中的值按字段名匹配(不区分大小写)到行的字段中
	dt.getDataRow(0).toMapx();// 将第1行转成Mapx









列操作:
	dt.insertColumn("FirstName");// 增加FirstName列
	dt.insertColumn(new DataColumn("Age", DataColumn.INTEGER));// 增加Age列,类型为int
	dt.deleteColumn(4);// 删除第5列
	dt.deleteColumn("FristName");// 删除FirstName列
	Object[] columnValues = dt.getColumnValues(0);// 得到全部行的第一列的值组成的数组
	dt.getDataColumn(0).setColumnName("UserName");// 将第一列的列名修改为UserName

其他操作:
	dt.clone();// Cloneable
	dt.union(anotherDataTable);// 两个DataTable合并
	dt.getColCount();// 返回列数
	dt.getRowCount();// 返回行数
	dt.filter(new Filter() {// 过滤掉Age<18的记录
		public boolean filter(Object obj) {
			DataRow dr = (DataRow) obj;
			if (Integer.parseInt(dr.getString("Age")) < 18) {
				return false;
			}
			return true;
		}
	});
	dt.sort(new Comparator() {// 按Age列排序
		public int compare(Object obj1, Object obj2) {
			DataRow dr1 = (DataRow) obj1;
			DataRow dr2 = (DataRow) obj2;
			return Integer.parseInt(dr1.getString("Age")) - Integer.parseInt(dr2.getString("Age"));
		}
	});
2 楼 wyuch 2009-06-05  
4 事务支持
Zving Framework支持传统型事务和非阻塞事务两种事务模式。
传统型事务即JDBC本身提供的事务支持,在这种事务模式下,一开始便打开数据连接,然后执行Java业务逻辑,在Java逻辑中不时执行数据库操作,但这些操作并不立刻改变数据库中的数据,而是等最后执行commit动作时才一次性写入数据库。Zving Framework针对这种类型的事务提供了DataAccess类,代码示例如下:
		DataAccess da = new DataAccess();
		try {
			da.setAutoCommit(false); 
			da.executeNoQuery(new QueryBuilder("delete from zduser where username='test'"));
			da.insert(user);
			da.delete(alex);
			da.commit();
			da.setAutoCommit(true); 
		} catch (SQLException e) {
			try {
				da.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		} finally {
			try {
				da.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
		}

注意:使用DataAccess需要手动调用close()方法,以实现连接的关闭。

非阻塞事务是Zving Framework中提供的事务模式,在这种事务模式下,一开始并不占用连接,执行Java业务逻辑过程不时声明需要执行的操作,在最后执行commit动作时才申请连接并依次执行先前声明的操作,并且开发人员不需要手工管理连接。代码示例如下:
		Transaction tran = new Transaction();
		tran.add(new QueryBuilder("delete from zduser where username='test'"));
		tran.add(user, Transaction.INSERT);
		tran.add(alex, Transaction.DELETE);
		tran.add(set, Transaction.DELETE_AND_BACKUP);
		tran.commit();


在传统型事务中下一个数据库操作可以依赖于上一个数据库操作产生的结果,但无阻塞事务则不能。而传统型事务数据库一开始就占用连接,在两个数据库操作之间的业务逻辑处理过程中本不需要连接,但也一直被占用;而无阻塞型事务则只有最后才使用连接,连接占用的时间被压缩到了极致。如果Web应用同时在线用户数较大且业务较复杂,则无阻塞型事务比传统型事务具有相当大的性能优势。另一方面,传统型事务必须手工管理资源释放,而无阻塞型事务则不需要。
实践开发中几乎全部事务都可以改造成无阻塞事务,建议开发人员只使用无阻塞型事务。
1 楼 wyuch 2009-06-05  
直接摘抄文档吧:

3.1 Schema的使用
Schema对应着数据表中的一行完整的记录,Schema类提供了对记录进行操作的众多方法,示例如下:

取数据:
	ZDUserSchema user = new ZDUserSchema();// new一个Schema实例
	user.setUserName("alex");// 设置字段UserName的值
	user.fill();// 根据主键值从数据库中取所有字段,如果主键值未set,则报错
	user.getMobile();// 取得Mobile字段的值
	user.getEmail();// 取得Email字段的值


插入数据:
	ZDUserSchema user = new ZDUserSchema();// new一个Schema实例
	user.setUserName("test");
	user.setPassword(StringUtil.md5Hex(password));
	user.setMobile("0086-13012340000");
	user.setEmail("test@hotmail.com");
	user.setAddUser("admin");
	user.setAddTime(new Date());
	user.insert();// 插入记录到数据库;


更新数据:
	ZDUserSchema user = new ZDUserSchema();// new一个Schema实例
	user.setUserName("alex");
	user.setMobile("0086-13012340000");
	user.setEmail("test@hotmail.com");
	boolean flag = user.update();// 更新用户alex的Mobile和Email两个字段


删除数据:
	ZDUserSchema user = new ZDUserSchema();// new一个Schema实例
	user.setUserName("alex");
	boolean flag = user. delete ();// 删除用户alex


其他操作:
	user.toDataRow();//转换成DataRow
	user.toMapx();//转换成Mapx
	user.setValue(dr);//将DataRow中的数据按字段名称匹配到Schema中
	user.setValue(map);//将Mapx中的数据按字段名称匹配到Schema中
	user.clone();//Cloneable
	user.getColumnCount();//返回列数
	user.getV(0);//取第1个字段的值


3.2 Set的使用
Set对应着数据表中的多条记录,Set类提供了对记录集进行操作的方法,示例如下:

取记录集:
	ZDUserSchema user = new ZDUserSchema();
	user.setAddUser("admin");
	ZDUserSet set = user.query();// 查询所有由admin添加的用户
	for (int i = 0; i < set.size(); i++) {
		ZDUserSchema u = set.get(i);
		System.out.println(u.getUserName());
	}


添加新的Schema到Set中:
	ZDUserSchema alex = new ZDUserSchema();
	alex.setUserName("alex");
	alex.fill();// 查询出alex的所有字段
	set.add(alex);// 将alex加入到set中


记录集反馈回数据库:
	set.insert();//将记录集插入数据库
	set.update();//将记录集更新到数据库
	set.delete();//从数据库中删除记录集
	set.backup();//备份记录集到B表
	set.deleteAndBackup();//删除记录集同时备份到B表
	set.deleteAndInsert();//插入记录,插入之前先删除己有的记录,以避免可能的主键冲突


其他操作:
	set.clear();// 清空Set中的所有Schema
	set.clone();// Cloneable
	set.toDataTable();// 转换成DataTable;
	set.filter(new Filter() {// 只要Email是hotmail邮箱的用户
		public boolean filter(Object obj) {
			ZDUserSchema user = (ZDUserSchema) obj;
			if (user.getEmail().endsWith("@hotmail.com")) {
				return true;
			}
			return false;
		}
	});
	set.sort(“UserName”);//按用户名排序
	set.sort(new Comparator() {// 按添加时间排序
		public int compare(Object obj1, Object obj2) {
			ZDUserSchema user1 = (ZDUserSchema) obj1;
			ZDUserSchema user2 = (ZDUserSchema) obj2;
			return user1.getAddTime().compareTo(user2.getAddTime());
		}
	});

相关推荐

    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