Sparkle’s Workshop

Ibatis with MapBean

Posted on January 29, 2008 - Filed Under Java |

用了两年的Hibernate之后,对ORM深有感触。一方面,ORM可以令到我们从OO角度来思考数据,屏蔽了数据库的差异(其实Hibernate被吹的最厉害就是那个分页,其实分页没什么技术含量,而且ROR都把分页从核心抽离了)。另一方面,性能问题,例如必须select才能update,必须select全部,必须update全部,cache带来的后遗症,javabean关联问题(一对多,多对一,多对多等),lazyload问题。当然,小型项目是很有优势的

Hibernate一直说,他生成的sql比一般程序员的要好,可以减少很多问题。但是,我倒是认为用Hibernate反而因为对程序员的要求更高导致更多问题。而且我现在认为,SQL才是王道,至少目前是。

于是在新项目中启用Ibatis,这一年来的使用感觉很不错,全程使用细粒度的SQL语句,虽然多写了很多SQL语句,但是感觉到项目在自己的控制中

我只用了Ibatis 40%不到的功能,可能大家会觉得不可思议。我没有用cache,没有用关联,没有用resultMap,甚至,连JavaBean也没有用

在大家都在讨论PO,VO,DTO的时候,我的系统里面一个JavaBean都没有

首先我问问,JavaBean是用来做什么的,存储数据,每一个PO,其实就约等于一个表里面的一行数据

我举一个真实一点的例子,一个user表

public class User {
  private int id;
  private String name;
 
  // 省略getter/setter一大段
}

不知道大家有没有用eclipse生成JavaBean getter/setter的痛苦,至少非常枯燥。整个JavaBean实现了什么功能?完全没有

好了我开谜底了,我用的是HashMap

什么,HashMap?是不是听错了

没听错,请问有什么事情是上面那个那么普通的JavaBean能做到的,而HashMap不能做到的呢

用HashMap没有具体属性的类型啊,那不是变成动态语言一样了,而且我要在JavaBean里面加逻辑怎么办

好吧,这是我想到的两个问题(如果你也有别的问题可以留意提出来)

首先,现在不同以前了,动态语言的优势慢慢提高了,像动态语言有什么不好,我从ROR里面学了很多不错的思想

其次是要加逻辑怎么办,这个问题,之前在Javaeye讨论充血模型还是贫血模型不可开交,最后还是没什么结论,目前还是一片贫血的情况,你可以翻一下你的项目里面的JavaBean,至少大多数的Bean都是没有意义的getter/setter。BO跟PO混杂在一起也很多人不建议的。至于逻辑,大可以写在util包里面,我都把整个model包去掉了,强化一下util不成么,呵呵

再次,数据库的列,跟JavaBean的属性两者,本来就是冗余的,如果我们修改数据库结构,就还要修改相应的JavaBean,或者影射文件。当然我这种做法更依赖数据库。另外,ROR的名字转换功能可以令到代码中的调用名字更好看一些,我觉得也不是非常有必要的实现

直接使用HashMap不太方便,尤其是类型转换上,于是我实现了一个MapBean的类,其实这个类很简单,关键是用HashMap代替JavaBean的思想

public class MapBean extends HashMap<String, Object> {
	public MapBean() {
	}
 
	public MapBean(Object... args) {
		put(args);
	}
 
	public int getInt(Object key) {
		return getInt(key, 0);
	}
 
	public int getInt(Object key, int defaultInt) {
		Integer i = (Integer) get(key);
		return i == null ? defaultInt : i;
	}
 
	public String getString(Object key) {
		return (String) get(key);
	}
 
	public String getString(Object key, String defaultValue) {
		String value = (String) get(key);
		return value == null ? defaultValue : value;
	}
 
	public Timestamp getTimestamp(Object key) {
		return (Timestamp) get(key);
	}
 
	public void put(Object... args) {
		for (int i = 1; i < args.length; i += 2) {
			put(String.valueOf(args[i - 1]), args[i]);
		}
	}
 
	public JSONObject toJson() {
		return JSONObject.fromObject(this);
	}
 
	public JSONObject toJson(String... keys) {
		xxx
	}
 
	public String toJsonString() {
		return toJson().toString();
	}
}

这个类主要是方便做类型转换,加入了getInt,getString等方法,另外因为我的系统里面大量使用了JSON,也有一些HashMap向JSON转换的辅助方法,还有一个特别处理过的put方法和构造器,有什么用呢,看下面的例子

MapBean params = new MapBean("id",userId,"name",username,"sex",0,"online",true);

如果你直接用HashMap实现以上功能,要写五行代码,就这个差别而已,呵呵

当然如果你用JavaBean的话,你也可以写一个对应的构造函数

接下来,我们在sql-map-config.xml中加入

<typeAlias alias="mapbean" type="xxxxxxx.MapBean" />

就可以用mapbean的别称来引用这个类了

例如具体的SQL xml是这样的

<select id="getWorkManagerSystemRole" resultClass="mapbean"
	parameterClass="mapbean">
	select * from work_manager_system_role where
	system_id=#system_id# and user_id=#user_id#
</select>

其实我已经把Ibatis当成SQL wrapper来用了,我曾经评估过Spring的JDBC Template,不过功能始终差少少,或许以后我把JDBC Template再强化一下来代替Ibatis吧

Most Commented Posts

Comments

7 Responses to “Ibatis with MapBean”

  1. cyfdecyfNo Gravatar on January 29th, 2008 6:05 pm

    Hibernate 也可以在 load 对象只 select 必要的属性,不过需要在 JavaBean 里面添加对应的构造函数。update 我没有注意过。另外 Hibernate 也能把数据库里面的值 load 成一个 HashMap 对象,不过我没有用过。

    我在用 Hibernate 的时候是直接写 JavaBean,用 annotation 而不是配置文件来指定映射关系。之后再通过 JavaBean 自动生成数据库 schema。这样就避免了修改 JavaBean 还得同时修改配置文件和数据库的麻烦。我觉得用 annotation 就是把配置文件和代码写在一起,好在 JavaBean 原来就简单,annotation 加多了也不会很难看。不过自动生成的数据库 schema 还是会有一些不满足要求的地方,有时还用脚本做些修改。而自动生成的外键名字毫无规律,需要再通过 annotation 来指定外键名字。

    确实觉得用 Hibernate 时自己不能随心所欲的控制,一对多,多对一之类的关系指定起来非常麻烦。有时与其花时间去找 Hibernate 文档来完成某项功能还不如自己写 SQL 语句来得快,而用 Hibernate 的话也总是会要写自己的查询语句,HQL 跟 SQL 也长的很像。不过 Hibernate Search 倒是很吸引人,用它结合 Lucene 做搜索很方便。

    以后有机会的话还是要尝试下 Ibatis 了。

  2. SparkleNo Gravatar on January 30th, 2008 9:50 am

    我贴到Javaeye上面了

    http://www.javaeye.com/topic/160162

  3. SparkleNo Gravatar on January 30th, 2008 9:59 am

    另一方面,性能问题,例如必须select才能update,必须select全部,必须update全部,cache带来的后遗症,javabean关联问题(一对多,多对一,多对多等), lazyload问题

    有些朋友对我这句话质疑,我不是不懂hibernate,这篇文章不是说hibernate的不是,所以我稍微带过了

    select也可以字段lazyload,不过需要先强化javabean
    update有两种部分update的方法,一个是配置文件打开动态update
    另一个是直接用hibernate3引入的update语法

    但是,这些能算有实用价值吗
    lazyload可以独立来批判
    动态update也是hibernate所不建议的,至少不具有通用性
    update语法会引发first level cache问题

    关于hibernate的问题,迟点我专门写一篇文章来跟大家讨论

  4. SparkleNo Gravatar on January 30th, 2008 10:00 am

    说实在话,hibernate的缓冲也是比较鸡肋性质的
    只有read-only cache是最有效的
    而read-write cache是基本废掉的
    nostrict-read-write效果比较好,但是不知道expire的点在哪里

    也有可能因为我不会用,又或者后来hibernate改进了很多,会用的朋友出来指点一下

    我认为,对entity的cache意义不大,因为多数entity都是易变的,expire问题会成为一个大问题

    但是我使用hibernate的时候,也是手工用ehcache在mvc那里cache service gen出来的数据

    现在用ibatis,也是原用这种方案

    呵呵,缓冲问题,也是可以独立讨论的

  5. SparkleNo Gravatar on January 30th, 2008 10:00 am

    hibernate不是不好,只是当你的项目做到一定程度的时候,就会碰上这样或那样的问题,而当你去解决这些问题的时候,你就会觉得, hibernate的实现已经渐渐被你废掉了。当然hibernate在一些范围里面很有用,尤其是你们的team有个hibernate的熟手,我的意思不仅仅是说很会用hibernate,而是曾经在项目中遇过hibernate的不足

    例如,我在招聘的时候,如果看见简历上面写着熟悉hibernate,我就会问他,hibernate有什么缺点(而不是优点),能够说出一个framework的缺点,才是真正了解它

  6. SparkleNo Gravatar on January 30th, 2008 10:01 am

    我没有使用JDBC Template的其中一个原因,就是要在sql里面写大量的问号
    当然spring有提供NamedParameterJdbcTemplate

    但是,JdbcTemplate、NamedParameterJdbcTemplate、SimpleJdbcTemplate之间完全不通用,也没有继承关系,后两者的实现远远没有前者完整,这令我非常烦躁

  7. 屹砾No Gravatar on March 19th, 2008 4:40 pm

    用HashMap做JavaBean很有特点,
    感谢你让我有了新的见识

Leave a Reply