`

选用ibatis和hibernate的区别

 
阅读更多
.

Hibernate简介
Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。 
一、基本功能
Hibernate作为数据持久化的中间件,足以让数据库在业务逻辑层开发中去冬眠。它通过可扩展标记语言(XML)实现了类和数据表之间的映射,使程序员在业务逻辑的开发中面向数据库而改为面向对象开发。使整个项目开发分工更加明确,提高了程序开发的效率。 
configuration对象: 
Configuration 类负责管理Hibernate 的配置信息。Hibernate 运行时需要
获取一些底层实现的基本信息,其中几个关键属性包括:
1. 数据库URL
2. 数据库用户
3. 数据库用户密码
4. 数据库JDBC驱动类
5. 数据库dialect,用于对特定数据库提供支持,其中包含了针对特定数据库特性的实现,如Hibernate数据类型到特定数据库数据类型的映射等。 
以上信息一般情况下由hibernate.cfg.xml或者hibernate.properties文件来配置,实现与不同数据库的连接。 
Session对象: 
Session是持久层操作的基础,相当于JDBC中的Connection:
实例通过SessionFactory实例构建:
Configuration config = new Configuration().configure();
SessionFactory sessionFactory = config.buildSessionFactory();
Session session = sessionFactory.openSession();
之后我们就可以调用Session所提供的save、find、flush等方法完成持久层操作。因此Session对象也封装了所有对数据库的操作来实现Hibernate对数据库的操纵功能,如: 
Save()方法实现增加和保存; 
Delete()方法实现数据的删除; 
Update()方法实现数据更新和修改; 
Find()方法实现数据的检索; 
Hibernate会根据不同的操作自动生成相应的SQL语句,从而实现了程序员对PO对象的操作转化为对数据库关系表的操作。 
二、使用步骤
1.编写Hibernate配置文件 
       Hibernate配置文件有两种,分别是hibernate.cfg.xml文件和hibernate.properties,推荐使用hibernate.cfg.xml。 
2.PO和映射文件 
使用middlegen和hibernate-extensions从数据库导出PO的映射文件,并在hibernate.cfg.xml当中声明。 
3.编写DAO 
       对每一张关系表编写一个DAO,提供一组增、删、改、查方法供业务逻辑对数据库操作使用。 
更多的细节请大家参阅hibernate的网站获取详细的信息。并在各自的实践和开发中加深体会。
Ibatis简介
相对Hibernate和Apache OJB 等"一站式"ORM解决方案而言,ibatis 是一种"半自动化"的ORM实现。所谓"半自动",可能理解上有点生涩。纵观目前主流的ORM,无论Hibernate 还是Apache OJB,都对数据库结构提供了较为完整的封装,提供了从POJO 到数据库表的全套映射机制。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate或者OJB 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握,Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。 
Ibatis最直接的好处就是不但为程序员提供了对象与关系数据库之间的映射,同时提供操作方法与SQL间的直接影射,设计者可以直接为一个方法指定一条SQL语句,从而取得更加准确的数据,同时为优化查询、连接查询提供了方便。 
一、基本功能
作为又一个轻量级的ORM中间件,ibatis除了提供了对数据库基本的增、删、改、查外还提供了连接管理,缓存支持,线程支持,(分布式)事物管理等一套教为完整的数据库管理功能。 
SqlMapClient对象是ibatis持久层操作的基础,相当于hibernate中的session,提供对SQL映射的方法。 
insert()方法实现对插入SQL语句的映射; 
delete()方法实现对删除SQL语句的映射; 
update()方法实现对更新SQL语句的影射; 
queryForList()、queryForMap()、queryForObject()、queryForPaginatedList()等方法提供了一组查询SQL语句的影射;
二、使用步骤
1.ibatis SQL Map 配置文件 
       文件中对所用数据库的连接做了基本配置,包括数据库驱动类型、用户名、密码,以及连接池的相关管理数据。 
2.PO和映射文件 
       和hibernate一样,PO作为数据库关系表的影射,也需要响应的映射配置文件,可以手写,也可以借助hibernate的相关工具生成PO,不会影响PO在ibatis中的使用。与hibernate不同的是,ibatis的映射文件中没有对PO中每个属性做响应的描述,而是指定了一系列与PO有关的SQL相关操作,也体现了ibatis良好的灵活性与可扩展性。 
3.编写DAO 
       在DAO中,可以使用SqlMapClient提供的方法来对应的指定对PO操作的SQL语句,从而使业务逻辑层的开发仍然是面向对象的操作。

选择Hibernate还是iBATIS都有它的道理:
Hibernate的特点:
Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。以数据库字段一一对应映射得到的PO和Hibernte这种对象化映射得到的PO是截然不同的,本质区别在于这种PO是扁平化的,不像Hibernate映射的PO是可以表达立体的对象继承,聚合等等关系的,这将会直接影响到你的整个软件系统的设计思路。Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/R Mapping实现了POJO 和数据库表之间的映射,以及SQL 的自动生成和执行。程序员往往只需定义好了POJO 到数据库表的映射关系,即可通过Hibernate 提供的方法完成持久层操作。程序员甚至不需要对SQL 的熟练掌握, Hibernate/OJB 会根据制定的存储逻辑,自动生成对应的SQL 并调用JDBC 接口加以执行。Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行,但是Hibernate现在已经是主流O/R Mapping框架,从文档的丰富性,产品的完善性,版本的开发速度都要强于iBATIS。
iBATIS的特点:
iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。当系统属于二次开发,无法对数据库结构做到控制和修改,那iBATIS的灵活性将比Hibernate更适合。系统数据处理量巨大,性能要求极为苛刻,这往往意味着我们必须通过经过高度优化的SQL语句(或存储过程)才能达到系统性能设计指标。在这种情况下iBATIS会有更好的可控性和表现。
对于实际的开发进行的比较:
1. iBATIS需要手写sql语句,也可以生成一部分,Hibernate则基本上可以自动生成,偶尔会写一些Hql。同样的需求,iBATIS的工作量比Hibernate要大很多。类似的,如果涉及到数据库字段的修改,Hibernate修改的地方很少,而iBATIS要把那些sql mapping的地方一一修改。
2. iBatis 可以进行细粒度的优化
比如说我有一个表,这个表有几个或者几十个字段,我需要更新其中的一个字段,iBatis 很简单,执行一个sql UPDATE TABLE_A SET column_1=#column_1# WHERE id=#id# 但是用 Hibernate 的话就比较麻烦了,缺省的情况下 hibernate 会更新所有字段。 当然我记得 hibernate 有一个选项可以控制只保存修改过的字段,但是我不太确定这个功能的负面效果。 
例如:我需要列出一个表的部分内容,用 iBatis 的时候,这里面的好处是可以少从数据库读很多数据,节省流量SELECT ID, NAME FROM TABLE_WITH_A_LOT_OF_COLUMN WHERE ...一般情况下Hibernate 会把所有的字段都选出来。比如说有一个上面表有8个字段,其中有一两个比较大的字段,varchar(255)/text。上面的场景中我为什么要把他们也选出来呢?用hibernate 的话,你又不能把这两个不需要的字段设置为lazy load,因为还有很多地方需要一次把整个 domain object 加载出来。这个时候就能显现出ibatis 的好处了。如果我需要更新一条记录(一个对象),如果使用 hibernate,需要现把对象 select 出来,然后再做 update。这对数据库来说就是两条sql。而iBatis只需要一条update的sql就可以了。减少一次与数据库的交互,对于性能的提升是非常重要。
3. 开发方面:
开发效率上,我觉得两者应该差不多。可维护性方面,我觉得 iBatis 更好一些。因为 iBatis 的 sql 都保存到单独的文件中。而 Hibernate 在有些情况下可能会在 java 代码中保sql/hql。相对Hibernate“O/R”而言,iBATIS 是一种“Sql Mapping”的ORM实现。 而iBATIS 的着力点,则在于POJO 与SQL之间的映射关系。也就是说,iBATIS并不会为程序员在运行期自动生成SQL 执行。具体的SQL 需要程序员编写,然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。使用iBATIS 提供的ORM机制,对业务逻辑实现人员而言,面对的是纯粹的Java对象,这一层与通过Hibernate 实现ORM 而言基本一致,而对于具体的数据操作,Hibernate会自动生成SQL 语句,而iBATIS 则要求开发者编写具体的SQL 语句。相对Hibernate而言,iBATIS 以SQL开发的工作量和数据库移植性上的让步,为系统设计提供了更大的自由空间。
4. 运行效率 
在不考虑 cache 的情况下,iBatis 应该会比hibernate 快一些或者很多。
将Hibernate和iBatis两Orm框架整合,取长补短

由于Hibernate比较适合对数据进行增,删,改的操作,而iBatis适合进行数据 查询,批量操作,而且方便利用DB底层的功能,因此我尝试着持久层同时使用Hibernate和iBatis。 
以下是我BaseDaoImpl的代码: 
[code:1] 
package mypack.dao; 

import org.hibernate.SessionFactory; 
import org.springframework.orm.hibernate3.HibernateCallback; 
import org.springframework.orm.hibernate3.HibernateTemplate; 
import org.springframework.orm.ibatis.SqlMapClientTemplate; 

import com.ibatis.sqlmap.client.SqlMapClient; 

public abstract class BaseDaoImpl implements BaseDAO 

//iBatis的Template 
private SqlMapClientTemplate sqlMapClientTemplate ; 
//Hibernate的Template 
private HibernateTemplate hibernateTemplate ; 
 
//设置Hibernate 
public final void setSessionFactory(SessionFactory sessionFactory) { 
if(this.hibernateTemplate == null){ 
this.hibernateTemplate = new HibernateTemplate(sessionFactory); 
}else{ 
this.hibernateTemplate.setSessionFactory(sessionFactory); 


//设置ibatis 
public final void setSqlMapClient(SqlMapClient sqlMapClient) { 
if(this.sqlMapClientTemplate == null){ 
this.sqlMapClientTemplate = new SqlMapClientTemplate(); 

this.sqlMapClientTemplate.setSqlMapClient(sqlMapClient); 

 
//获取Hibernate的模板 
protected HibernateTemplate getHibernateTemplate(){ 
return hibernateTemplate 

//获取iBatis的模板 
protected SqlMapClientTemplate getSqlMapClientTemplate() { 
return sqlMapClientTemplate; 


//一些Hibernate 的通用方法, 
//当然也可不必声明,子类通过hibernateTemplate来操作 

protected void save(Object object) { 
hibernateTemplate.save(object); 

protected void saveOrUpdate(Object object) { 
hibernateTemplate.saveOrUpdate(object); 


protected void update(Object object) { 
hibernateTemplate.update(object); 

protected void delete(Object object){ 
hibernateTemplate.delete(object); 

protected Object getObject(Class clazz, Serializable id){ 
return hibernateTemplate.get(clazz, id); 

 
//子类通过iBatis 的sqlMapClientTemplate来操作 


[/code:1] 
即以组合方式,将HibernateTemplate和sqlMapClientTemplate集成起来,完成类似SqlMapClientDaoSupport和HibernateDaoSupport的工作,由于Java无法多类继承,所以只得以组合方式来做。不过Spring的两个Support代码不多,自己做满好,满好--记得这是梁家辉在《棋王》上最爱说说的:) 
在Spring中的主要配置是这样的: 
首先配置Hibernate的SessionFactory: 
[code:1] 
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
<!-- 引用上述定义的数据源 --> 
<property name="dataSource"> 
<ref local="dataSource"/> 
</property> 

<!-- 定义Hibernate映射文件(资源) --> 
<property name="mappingDirectoryLocations"> 
<list> 
<value>classpath:/mypack</value> 
</list> 
</property> 

<!-- 定义Hibernate配置属性 --> 
<property name="hibernateProperties"> 
<props> 
<prop key="hibernate.dialect">${hibernate.dialect}</prop> 
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop> 
<prop key="hibernate.cglib.use_reflection_optimizer">${hibernate.cglib.use_reflection_optimizer}</prop> 
</props> 
</property> 
<property name="useTransactionAwareDataSource" value="true"></property> 
</bean> 
[/code:1] 
再是iBatis的sqlMapClient 
[code:1] 
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean"> 
<property name="configLocation" value="sql-map-config.xml"/> 
<property name="dataSource" ref="dataSource"/> 
<property name="useTransactionAwareDataSource" value="true"></property> 
</bean> 
[/code:1] 
两者是useTransactionAwareDataSource属性都设置为ture,看Spring的Javadoc,说这可以在多Orm框架中保持事务的一致性,即通过DataSource关联,果真如此否?我还没有确定出来。 
事务管理器,用Hibernate的 
[code:1] 
<!-- 事务处理的AOP配置 --> 
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
<property name="sessionFactory"> 
<ref local="sessionFactory"/> 
</property> 
</bean > 

<bean id="txProxyTemplate" abstract="true" 
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
<!-- 指定事务管理器 --> 
<property name="transactionManager" > 
<ref local="transactionManager"/> 
</property> 
 
<!-- 指定业务策略 --> 
<property name="transactionAttributes"> 
<props> 
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop> 
<prop key="add*">PROPAGATION_REQUIRED</prop> 
<prop key="update*">PROPAGATION_REQUIRED</prop> 
<prop key="delete*">PROPAGATION_REQUIRED</prop> 
</props> 
</property> 
</bean> 
[/code:1] 
然后做两个Dao,一个是CustomerDao,这个走Hibernate,直接看其实现: 
[code:1] 
package mypack.dao; 

import mypack.Customer; 

public class CustomerDaoImpl extends BaseDaoImpl implements CustomerDao { 

public void update(Customer customer) { 
super.save(customer); 


[/code:1] 
再看OrderDao的实现,这个走iBatis(先分道扬镳,再殊途同归): 
[code:1] 
package mypack.dao; 

import java.sql.SQLException; 

import org.springframework.orm.ibatis.SqlMapClientCallback; 

public class OrderDaoImpl extends BaseDaoImpl implements OrderDao { 
/** 
* update ibatis 
*/ 
public void updateOrderPrice(float rate) 

getSqlMapClientTemplate().update("updateOrderPrice",null); 


[/code:1] 
再在一个Service中同时用这两上Dao完成一个事务: 
[code:1] 
package mypack.service; 

import mypack.Customer; 
import mypack.dao.CustomerDao; 
import mypack.dao.OrderDao; 

public class CustomerServiceImpl implements CustomerService { 

private CustomerDao customerDao; 
private OrderDao orderDao; 
public void updateCustomerAndOrder(Customer customer, float rate) { 
customerDao.update(customer); 
orderDao.updateOrderPrice(rate); 

public CustomerDao getCustomerDao() { 
return customerDao; 

public void setCustomerDao(CustomerDao customerDao) { 
this.customerDao = customerDao; 

public OrderDao getOrderDao() { 
return orderDao; 

public void setOrderDao(OrderDao orderDao) { 
this.orderDao = orderDao; 


[/code:1] 
插入一条Customer记录,再Update所有Order(纯粹研究,没有实际意义) 
走: 
[code:1] 
package test.service; 

import org.apache.log4j.PropertyConfigurator; 
import org.springframework.context.ApplicationContext; 
import org.springframework.context.support.ClassPathXmlApplicationContext; 

public class SysInit 

public static ApplicationContext factory = null; 
private static String[] filepath = {"applicationContext_service.xml"}; 
public static void init() 

PropertyConfigurator.configure("D:\\personalWork\\proGroup\\hiTestPro\\src\\log4j.properties"); 
if (factory == null) 

try 

factory = new ClassPathXmlApplicationContext(filepath); 
 

} catch (Exception e) 

e.printStackTrace(); 



try 

} catch (Exception e) 

e.printStackTrace(); 



public static Object getBean(String name) 

if (factory == null) 

init(); 

return factory.getBean(name); 


public static void main(String[] args) 

SysInit.init(); 





package test.service; 

import junit.framework.TestCase; 
import mypack.Customer; 
import mypack.service.CustomerService; 

public class CustomerServiceTest extends TestCase { 

protected void setUp() throws Exception { 
super.setUp(); 
SysInit.init(); 


protected void tearDown() throws Exception { 
super.tearDown(); 


public void testupdateCustomerAndOrder() 

CustomerService customerService = (CustomerService)SysInit.getBean("customerService"); 
Customer customer = new Customer(); 
customer.setId(3L); 
customer.setFirstname("xiong"); 
customer.setLastname("hua"); 
customer.setSex('F'); 
customerService.updateCustomerAndOrder(customer, 2); 


[/code:1] 
我测试了一下,如果iBatis的操作有问题,Customer也是没有办法插入了,所以基本上判断,这两个框架是可以做事务的。
配置一个上层的 service, 

<bean id="userService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager"><ref local="transactionManager"/></property>
<property name="target">
<bean class="*********youPackage******.UserServiceImpl">
<property name="userDAO" ref="userDAO"></property>
<property name="userBackupDAO" ref="userBacupDAO"></property>
</bean>
</property>
 
 
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="query">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="update">PROPAGATION_REQUIRED</prop>
<prop key="execute">PROPAGATION_REQUIRED</prop> 
</props>
</property>
</bean>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics