这是我的一个综合评分,总共分为12个单项,每个单项最高5分,最低0分。注意,评价只包含这些软件提供的标准功能,不包含第三方提供的功能,如代码生成等。
开发效率
hibernate 能获取数据库metadata,因此简单的sql操作,如插入,更新,删除,翻页等,都可以自动完成。但因为概念复杂,经常会导致开发人员会写sql,能写java,但不会写hibernate情况出现(关系配置或者hql),导致开发效率反而降低。
session.save(user);
String hql= "from bank.Person person where person.id.country = 'AU' "
Query query = sessin.createQuery(hql);
mybatis 必须手工写sql,效率较低,有第三方工具能自动生成才勉强提高了开发效率
beetlsq l 同样具有hibernate 的功能,但不要求配置或者annotation。所以认为开发效率比hibernate高,是因为beetlsql 本身使用不容易出错,不像hibernate那样概念复杂,容易使用错误,导致实际开发速度降低. 在写sql文件的时候,基于MD+beetl的也比myabtis 的xml 要快很多.
sqlManager.save(user);
List<User> list = sqlManager.select("user.queryMaxAgeUser",User.class,paras);
//or UserDao是一个开发者定义的接口,通过代理实现DAO
UserDao dao = sqlManager.getMapper(UserDao.class);
List<User> list dao.queryMaxAgeUser(paras)
跨多种数据库
hibernate 支持几乎所有数据库,通过自动生成的sql(插入,删除,翻页等),hql,来完成跨数据库操作,但对于数据库之间确实不同地方,hibernate无力处理,所以只有4分
mybatis 几乎没有考虑过跨数据库功能,配置文件里可以通过if标签来做判断,但这种技术鸡肋的很。
beetlsql ,目前支持Oracle,Mysql,Postgres,SQLServer,SQLLite,H2。同样提供了自动生成sql完成插入,删除,翻页等跨数据库的功能,beetl脚本来完成一些跨数据库操作。另外,beetlsql独立管理sql文件,sql放在根目录下,特定数据库sql放在以数据库命名的子目录下。如果数据库sql确实有一样地方,可以用特定数据库sql覆盖默认的sql。
维护性
hibernate : hibernate本生复杂性导致了维护比较难。对于一些简单的重构,hibernate代码不需要改动。对于复杂的sql(hql)改动,hibernate比较费劲
mybatis :可以适应复杂的sql改动,但表重构等,必须修改mapper 配置文件里的sql。
beetlsql : 同时具备hibernate 和 myabtis 在维护性方面的优点。支持重构,支持代码外维护sql。 beetlsql的md格式使得维护sql像读文档一样。同myabtis一样,支持将sql文件的sql语句自动映射成dao方法。
系统启动耗时
hibernate :启动需要加载数据库的metadata,加载pojo,加载配置文件,然后校验等操作,启动很耗时
mybatis : 需要做一个基本的配置文件加载,以及各个mapper文件加载,系统第一次访问的时候会慢
beetlsql :只简单的加载了数据库的metadata,不做任何校验,启动几乎不消耗时间
错误提示
hibernate 由于本生ORMapping的复杂性.所以提示也很复杂。另外无论是xml配置还是annotation配置,如果有出错提示,也很难明白错误提示意思。HQL 也是这样,错误提示也并不理想
mybatis : myabtis 错误提示最难搞懂,因为他基于xml解析和ognl 表达式都不是他自己的,所以我们会看到各种莫名其妙的提示。
如下,本来应该是resultType,但写成resultMap
<select id="getGrantCount" resultMap="Integer" parameterType="Map">
错误提示尽管可以理解,但非常不直观,没有告诉你哪行错了,你只能配置文件所有地方才能排查这个手误
Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for cn.xxx.IGiftStatisticCacheService.Integer
beetlsql : 基于beetl模板语言,哪个配置文件哪行错了,错误原因是什么,提示的非常清楚,而且是中文的
如下一个sql配置,if语句多了一个d
select * from User where 1 =1
@if(isNotEmpty(age)d){
and age = #age#
@}
错误提示如下
>>11:14:10:缺少符号(PARSER_MISS_ERROR):d 位于2行 资源:user.queryUser_page
多余输入 'd' 期望 RIGHT_PAR
1|select * from User where 1 =1
2|@if(isNotEmpty(age)d){
3|and age = #age#
4|@}
模型支持
hibernate ,只支持pojo,而且由于有关系约束,导致开发不够快捷
mybatis :pojo和map都支持,map支持可以快速支持一些小的功能开发
beetlsql :pojo和map都支持,另外混合模型,使用较少的pojo完成大量的查询操作而无需为模型添额外的属性,因此模型支持比myabtis要好。
List<User> list = sqlManager.select("user.queryXXX",User.class,paras);
List<Map> list = sqlManager.select("user.queryXXX",Map.class,paras);
//如果user继承了Tail接口,支持混合模型.如下例子可以通过user.get("roleName ") 访问角色名,这对于web项目来说,很好用
List<User> list = sqlManager.excute("select u.*,r.name roleName from user u,role r ... ",User.class,paras);
学习曲线
hibernate 毫无疑问最难掌握的是hibernate,这是公认的,他的别扭之处是明明就是个sql 操作,非要让开发人员先转成对象,然后再转成sql(实际上,sql语言已经屏蔽了操作数据库的复杂性了),看看hibernate有多少书和文档就知道他的复杂性
myabtis : 很简单,除了写mapper文件,可能需要学一下怎么写,但大概也就3-5天时间。myabtis作者当时的出发点也是写一个“不要一本书来说明的dao工具”,他做到了,但做的还不够好。
beetlsql : API仅仅在SQLManager里,一看就明白。sql文件采用md格式,去除了xml那种繁琐,并且使用beetl作为模板语言,非常简单,1天就能完全掌握。 对于数据库这种访问技术来说,本不应该出现所谓的“砖家”,但hibernate有,这是不正常的。所以,hiberante评分最低,beetlsql最高。
对DBA友好
hibernate : 此工具是仇视DBA的,自然DBA也不喜欢hibernate。在这就不谈了。
myabtis :sql文件单独管理,采用xml方式,相对友好,但xml方式过于繁琐了,像常见的"<" 符号,myabtis不得不专门处理
beetlsql : sql 既可以出现在代码里,也可以在sql文件里,由于采用md+beetl 格式,比myabtis更好,DBA看beetlsql的sql文件,就像阅读文档一样
与其他工具友好
hibernate :由于是采用容器管理bean,因此在容器里使用第三方工具,和容器外使用第三方工具,效果不一样,比如hibenate独有的Open Session In View 问题,还有 Session Has Closed ...
myabtis :无容器管理,所以怎么用都顺手
beetlsql :同myabtis,对其他工具很友善
性能
没有具体比较过,但考虑三者工具都涉及到sql模板解析,MetaData 获取和分析,ResutlSet 的Mapping操作,java反射等,因此,性能差不多。我将在以后给出具体性能对比。再考虑到数据库操作,dao基本上可以忽略不计,所以性能都给予5分
数据库主从支持
hibernate : 不支持,需要借助第三方路由中间件
myabtis : 支持,但需要做一些简单的编码,以切换数据源
beetlsql :支持数据库主从配置,无需开发人员编码。beetlsql默认根据sql是查询还是更新决定去主从库,也可以根据事务决定数据库主从,如只读事务就去从库。beetlsql 既能适合一个初创项目,也适合项目飞速发展的巨大用户量情况。当然,超大用户量,这就超出了beetlsql的功能了。
OR Mapping
hibernate : 实体,关系都通过配置完成OR Mapping,包含了一对多,多对多,继承等各种关系的实现。但正如我在一篇文章里吐槽过OR Mapping那样,尽管hibernate此项做的非常好,但没什么用。
myabtis : 实体,关系也通过配置来完成,但因为这是后期加的功能,所以用的并不好
beetlsql :支持实体映射,不支持关系映射,但支持关系映射查询,支持一对一,一对多,多对多的查询和懒加载
BeetlSQL一分钟介绍
由于beetlsql 是个新工具,所以简单用一个例子说明beetlsql
//初始化部分,通过跟框架结合,如通过spring ioc直接注入SqlManager
MySqlStyle style = new MySqlStyle();
MySqlConnectoinSource cs = new MySqlConnectoinSource();
SQLLoader loader = new ClasspathLoader("/org/beetl/sql/test");
SQLManager sql = new SQLManager(style,loader,cs,new DefaultNameConversion(), new Interceptor[]{new DebugInterceptor()});
//直接使用sqlmanager 的api操作
User user = ....;
sql.insert(user);
User query = new User();
query.setStatus(1);
List<User> list = sql.template(User.class,query);
// 查询user.sql 文件的mySelect sql模板
List<User> list = sql.select("user.mySelect",User.class,query) ;
beetlsql 也封装了SqlManager,提供了dao 接口
public interface UserDao extends BaseMapper<User> {
public User findById(@Param("id") Integer id);
public int getCount();
public void setUserStatus(User user);
public Integer setAge(@Param("id") Integer id,@Param("age") Integer age);
}
然后,在业务逻辑里可以这么使用,使得dao更容易维护
UserDao dao = sql.getMapper(UserDao.class);
dao.insert(user); //使用BaseMapper 内置的方法
dao.setAge(12, 18); // 调用user.sql文件里的 setAge sql模板
user.sql 是一个md格式文件
setAge
===
* 更改用户年纪
update user set age = #age# where id=#id#