论坛首页 Java企业应用论坛

将Hibernate和iBatis两Orm框架整合,取长补短

浏览 31182 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2006-08-18  
由于Hibernate比较适合对数据进行增,删,改的操作,而iBatis适合进行数据 查询,批量操作,而且方便利用DB底层的功能,因此我尝试着持久层同时使用Hibernate和iBatis。
   以下是我BaseDaoImpl的代码:
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来操作
}


     即以组合方式,将HibernateTemplate和sqlMapClientTemplate集成起来,完成类似SqlMapClientDaoSupport和HibernateDaoSupport的工作,由于Java无法多类继承,所以只得以组合方式来做。不过Spring的两个Support代码不多,自己做满好,满好--记得这是梁家辉在《棋王》上最爱说说的:)
     在Spring中的主要配置是这样的:
   首先配置Hibernate的SessionFactory:
 	<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>

    再是iBatis的sqlMapClient
    <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>

     两者是useTransactionAwareDataSource属性都设置为ture,看Spring的Javadoc,说这可以在多Orm框架中保持事务的一致性,即通过DataSource关联,果真如此否?我还没有确定出来。
    事务管理器,用Hibernate的
     	<!-- 事务处理的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>	

    然后做两个Dao,一个是CustomerDao,这个走Hibernate,直接看其实现:
   package mypack.dao;

import mypack.Customer;

public class CustomerDaoImpl extends BaseDaoImpl implements CustomerDao {

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

     再看OrderDao的实现,这个走iBatis(先分道扬镳,再殊途同归):
     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);;
  }
}

    再在一个Service中同时用这两上Dao完成一个事务:
    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;
	}
}

     插入一条Customer记录,再Update所有Order(纯粹研究,没有实际意义)
   走:
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);;	
	}
}

       我测试了一下,如果iBatis的操作有问题,Customer也是没有办法插入了,所以基本上判断,这两个框架是可以做事务的。
     各位看客以为如何?引玉中....
   发表时间:2006-08-18  
hibernate缓存。。。怎么办?
0 请登录后投票
   发表时间:2006-08-18  
Hibernate的缓存确实是一个问题,不过可以通过合理分配两者的工作来解决,比如Hibernate负责增删改,而ibatis只负责查询。
   目前我的应用就是简要列表查询的数据由iBatis负责获取,从简要列表进入后的操作由Hibernate负责。
   不过,如果这样限定后,也就没有必须管事务的事了。整合的目的只是为了提高Dao的内聚性并屏蔽掉具体实现。
0 请登录后投票
   发表时间:2006-08-18  
在一个工具出来的时候,要能在最大的限度上杜绝工具的使用者
去理解工具发明者的一些潜规则

你这样定义了一些使用的潜规则,但是一般的程序员不一定能理解你的思想,就会滥用,肯定有bug的时候。所以这个思路我认为不好的。

其实阿,ibaits和hibernate难道没有别的方法取长补短吗?放开思维就可以了
0 请登录后投票
   发表时间:2006-08-18  
不是已经有帖子证明过这个事情是可行的嘛?除了要自己处理缓存。

另外,你为什么要自己写?extends HibernateDaoSupport,然后在你的DAO里面去创建一个SqlMapClient对象不就好了?
0 请登录后投票
   发表时间:2006-08-18  
downpour 写道
不是已经有帖子证明过这个事情是可行的嘛?除了要自己处理缓存。

另外,你为什么要自己写?extends HibernateDaoSupport,然后在你的DAO里面去创建一个SqlMapClient对象不就好了?

   不错,象你说的这样确实可以减少代码,只是这样一来,Hibernate和iBatis就处于不同地位了,这个Dao is a hernate Support and  has a iBatis Support,我不想让两者的地位不一致。
0 请登录后投票
   发表时间:2006-08-18  
两者本来就不处于同一个地位,你一定要让他们在一起使用,难道还要顾及你意念上的什么is-a或者has-a的所谓划分?这不是重复发明轮子嘛?

还有就是事务类型,你不妨试试在分布式环境下做这个事情。因为我记得Spring文档提到过Mix ORM工具的前提是你访问同一个数据库。
0 请登录后投票
   发表时间:2006-08-18  
downpour 写道
两者本来就不处于同一个地位,你一定要让他们在一起使用,难道还要顾及你意念上的什么is-a或者has-a的所谓划分?这不是重复发明轮子嘛?

还有就是事务类型,你不妨试试在分布式环境下做这个事情。因为我记得Spring文档提到过Mix ORM工具的前提是你访问同一个数据库。

    我也有点觉得将两个ORM放到一个Dao中有点别扭?另一方案是将Hibernate的 走Hibernate的Dao,iBatis的 走iBatis的Dao,各自为政,但在系统级上做集成,两者不位于同一个事务中。这种方案如何?
   另:Spring走ORM,不一定是访问同一个数据库,只要TransactionManager配置成Jta的TransactionManager就可以了,下面是具体的配置。
  
<bean id="dataSource11" class="org.springframework.jndi.JndiObjectFactoryBean" singleton="true" lazy-init="default" autowire="default" dependency-check="default">
    <property name="jndiName">
      <value>jdbc/test11</value>
    </property>
  </bean>
  <bean id="dataSource249" class="org.springframework.jndi.JndiObjectFactoryBean" singleton="true" lazy-init="default" autowire="default" dependency-check="default">
    <property name="jndiName">
      <value>jdbc/test249</value>
    </property>
  </bean>
...
 <bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager" singleton="true" lazy-init="default" autowire="default" dependency-check="default">
  </bean>
0 请登录后投票
   发表时间:2006-08-18  
为什么你们要用ibaits呢?难道ibaits的优势就不能用hibernate取代吗?
就拼个sql嘛!!
0 请登录后投票
   发表时间:2006-08-18  
welllove53 写道
为什么你们要用ibaits呢?难道ibaits的优势就不能用hibernate取代吗?
就拼个sql嘛!!

     iBatis主要是可以将Sql和代码解耦,使Java代码更纯一些,而Hibernate有在查询数据时有一个不好的地方是,结果集中的记录要对应Domain Class,这就限制了结果集字段的灵活性,数据库中的结果集构造是很灵活的,而不是仅对应Domain Classs。另外Hibernate还要为每条结果集构造对象,数据缓存等工作,如果仅是查询,这种工作是没有必要而费时的。
   总之,我觉得Hibernate不太适合于构造简要列表时的查询,它的强项在于对一个Domain Class的增,删,改,查,而非业务数据查询。
1 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics