欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

可爱的javaee:让对象持久化变平 JavaEEHibernateSQL框架ORM 

程序员文章站 2024-02-04 15:30:28
...

JDBC java 对象持久化提供了有效的支持,但仍然繁琐,以至于现在甚至没人再愿意提他。ORM 框架使java 对象持久化更聪明更简单,却并不一定轻松。hibernate 实现了“完全对象映射”的质量等级,为了解决长长的问题列表,他的开发团队付出了令人尊敬的努力。但是用好hibernate ,你需要掌握更多的知识而不是更少。由于应用软件和关系数据库面对的问题域的不同,设计差异、复杂对象、不恰当的映射配置、自动生成语句都可能给系统带来隐患。最糟糕的是,这种自动生成的sql 难于调试。

iBatis 是另一个选择,平面映射使事情变得简单,不过,数据持久层和sql 语句总是息息相关,sql 语句配置在外部文件的方式使得无论是开发还是维护,我们都要配置代码两头看。而且对于简单的CRUD 语句,SQL 是一个相当通用的标准,所以完全不自动生成sql 的做法也显得有点傻。

即使有了很多ORM 框架可供选择,但是重复发明*的事还是不断出现,比如,笔者将为你介绍一个小而简单的ORM 框架(真头疼,又是框架!)。与大多数ORM 框架相比,他能做的更少而不是更多,甚至能否跻身ORM 框架之列也是个问号。一个不太聪明的框架也许会使你扫兴,但笔者要说的是:如果能用更少的技术,做更多的事情,岂不是很好?

      假设我们有这样的类:

public class Foo {
	private String fooId;
	private User modifyMan;
	//getter and setter
}

      使用hibernate ,你可以这样得到这个对象:

// hibernate code
Foo foo = new Foo(“123”);
session.get(foo);

      这样,你得到了包括User的完整对象。换一种方式,如果这样做我们会有什么损失吗?

public class Foo {
	private String fooId;
	private String modifyManId;
	private User modifyMan;
	//getter and setter
}

// simple ORM framework code
Foo foo = new Foo(“123”);
if(broker.readBean(foo)){
	User modifyMan = new User(foo.getModifyManId());
	foo.setModifyMan(broker.readBean(modifyMan));
}

      多写了几行代码。当然,如果你的对象很复杂,需要的代码就更多,这是不够聪明的做法,但是这样做避免了复杂的自动对象映射。如果你不需要modifyMan的详细信息,你就可以不载入他,不加入这个属性。而为了CUD操作的方便,modifyManId属性总是应该加入,你可以象下面这样更新一条记录:

Foo foo = new Foo(“123”);
if(broker.readBean(foo)){
	foo.setModifyManId(“1”);
	broker.updateBean(foo);
}

      如果你要得到一个聚合,做法也是类似的:

public class Foo {
	private String fooId;
	private String modifyManId;
	private List childs;
	//getter and setter
}

SQLBuilder sql = new SQLBuilder();
sql.segment(“foo = ”);
sql.value(foo.getFooId());
foo.setChilds(broker.readBeanList(Foo.class,sql));

      SQLBuilder是一个sql语句的构建工具,他使你可以用类似StringBuilder的方式构建sql语句,而不必关心底层的处理方式。笔者介绍的ORM框架内部可以使用Statement,也可以使用PreparedStatement。至于为什么不始终使用PreparedStatement,是因为各种DBMS的JDBC驱动对这两种声明的支持程度不同,比如MySql用Statement速度更快,而Oracle用PreparedStatement可以提升整体性能。当然MySql和Oracle都有自己的JDBC扩展,效率更高,但是由于他们没有采用JDBC标准的接口,所以ORM框架也不能对其提供支持。
      好吧,必须再告诉你一个真相,即笔者介绍的ORM框架还是需要配置的,不过不是在配置文件里,而且需要JDK5以上的支持。没错,你猜对了,就是使用元数据。不过笔者并没有使用JPA的标准元数据,由于作用范围有限,所以这些元数据非常简单。使用了元数据,你的类就象是下面这个样子:

 

public class Foo {
	@Key
	@Column(name = “foo_id”)
	private String fooId;
	@Column(name = “modify_man_id”)
	private String modifyManId;
	@Column(type = ColumnType.OUT)	
	private String modifyManName;
	private List childs;
	//getter and setter
}

 

      元数据只能标注基本类型,包装类型和日期时间类型的属性。其中@Key标注主键,默认为用户指定类型,另外还有自增类型和序列类型;@Column标注列,如果属性名和列名相同就不必指明name属性;@Column(type=ColumnType.READ)标注只读的列,可以用来标注如更新时间这样的只读不写的字段,@Column(type=ColumnType.OUT),如果你只需要外表的某些属性用来显示,你就可以这样做:

SQLBuilder sql = new SQLBuilder();
sql.segment(“select t.*, t2.user_name as modifyManName from foo t, user t2
                                         where t.modify_man_id = t2.user_id and t.foo_id = ”);
sql.value(“123”);
Foo foo = new Foo();
broker.queryBean(foo, sql);

      你会得到你需要的数据。是的,本ORM框架也不生成关联查询语句,因为那样做会面临太多问题。除以上功能外,broker还可以为你查出数据行、列表和分页。当然这就不属于ORM的范畴了。如果broker不能满足你的需求,比如处理大对象,你还可以得到你想要的:

Connection connection = broker.getConnection();

      之后你就可以为所欲为了。
      说了半天,其实这个ORM框架并没有名字。这个没有名字的目标有限的框架只有简单功能并且没有发明新的概念。他遵循80/20原则,把棘手的问题都抛给了应用层。这些问题包括:对象组装、大对象、批处理、存储过程和缓存。现在总结一下他的特点:

 

  • 平面映射
  • 支持继承
  • 通用的sql 构建方法
  • 可直接运行的sql 输出
  • 支持多数据源

 

      普元说,让世界变平。这个平字寓意深刻,见仁见智。hibernate可以为你做很多事,也有适用范围的性能优化策略和技术,但在有一定规模和复杂度的场景中,使用hibernate会增加而不是减少架构设计和质量保证的难度。如果你的项目特点是读多写少,项目环境比较单一,并且你的团队技术和管理水平都跟得上,那么hibernate是个很好的选择。不过,相信也有很多场景,使用简单通用的ORM框架,加上灵活的按需而动的架构策略,还对象持久化一个直观透明的面貌会是更明智的选择。

 

      后记:这篇文章忽略了hibernate的优秀的懒加载机制,这的确是个大大的错误,另外笔者发现,在实际应用中,为了规避hibernate的复杂性,也有人拿hibernate完全当平面映射框架来用的,hibernate很多有用的特性都被闲置了,不过也确实简单易用了,这真是有些尴尬啊。

 

2013年2月19日更新说明:修正非字符型参数空值报空指针错误

2014年3月28日更新说明:加入了读取Oracle Clob字段的支持