Hibernate基础 
  
  
    
  Part 1 
  
  
    
      1.
      
      
    
    持久化对象 
  
  
    
  Event event = new Event(); 
  
  
    
  // populate the event 
  
  
    
  Session session = factory.openSession(); 
  
  
    
  session.save(event); 
  
  
    
  session.flush(); 
  
  
    
  session.close(); 
  
  
    
  当保存一个对象的时候,hibernate出于性能的考虑不会马上将改对象写到db。如果想要强制写,就要用flush()方法。 
  
  
    
  经常将save和update合在一起使用,为saveOrUpdate()。Hibernate根据对象的id是null(或0),还是已经存在来判断应该save还是update。 
  
  
    
      2.
      
      
    
    读取对象 
  
  
    
  根据id 
  
  
    
  Event event = (Event) session.load(Event.class, eventId); 
  
  
    
  session.close(); 
  
  
    
  使用hql 
  
  
    
  Query query = session.createQuery("from Event"); 
  
  
    
  List events = query.list(); 
  
  
    
      3.
      
      
    
    会话缓存session cache 
  
  
    
  出于性能的考虑,默认情况hibernate并不将一个操作立即反映到db中,而是做一些缓存的处理。 
  
  
    
  对一个会话期间的被load或save的每个对象,都能支持一个相应的缓存。 
  
  
    
  比如可以在一次会话中对对象a做load,update等多个处理,最后才flush提交,如 
  
  
    
  Session session = factory.openSession(); 
  
  
    
  Event e = (Event) session.load(Event.class, myEventId); 
  
  
    
  e.setName("New Event Name"); 
  
  
    
  session.saveOrUpdate(e); 
  
  
    
  // later, with the same Session instance 
  
  
    
  Event e = (Event) session.load(Event.class, myEventId); 
  
  
    
  e.setDuration(180); 
  
  
    
  session.saveOrUpdate(e); 
  
  
    
  session.flush(); 
  
  
    
  缓存会带来一些问题: 
  
  
    
  初学者容易犯NonUniqueObjectException,即在一个会话中对同一个对象做了不同步的操作,比如: 
  
  
    
  Session session = factory.openSession(); 
  
  
    
  Event firstEvent = (Event) session.load(Event.class, myEventId); 
  
  
    
  // ... perform some operation on firstEvent 
  
  
    
  Event secondEvent = new Event(); 
  
  
    
  secondEvent.setId(myEventId); 
  
  
    
  session.save(secondEvent); 
  
  
    
  可以看到secondEvent是一个与firstEvent同ID的对象,最后却使用save,而不是update,显然不对了。 
  
  
    
  对每个“经过”了会话的对象,都会被加到会话的缓存中。 
  
  
    
  “经过”的含义:保存对象,读取对象。 
  
  
    
  session.contains()可以检查某个对象是否在缓存中。 
  
  
    
  session.evict()可以将对象从缓存中清除。 
  
  
    
  session.clear()可以将所有对象从缓存清除。 
  
  
    
  Session session = factory.openSession(); 
  
  
    
  Event firstEvent = (Event) session.load(Event.class, myEventId); 
  
  
    
  // ... perform some operation on firstEvent 
  
  
    
  if (session.contains(firstEvent)) { 
  
  
    
  session.evict(firstEvent); 
  
  
    
  } 
  
  
    
  Event secondEvent = new Event(); 
  
  
    
  secondEvent.setId(myEventId); 
  
  
    
  session.save(secondEvent); 
  
  
    
  Part 2 
  
  
    
      1.
      
      
    
    连接池connection pools 
  
  
    
  出于性能的考虑,不能为每一个到数据库的请求,都给一个连接。而是使用连接池。 
  
  
    
  连接池保存了可以重用的一组到数据库的连接。 
  
  
    
  应用服务器通常通过JNDI数据源datasource,提供自己的连接池支持,hibernate利用了服务器的这个特性。并且对没有连接池支持的服务器也有相关支持,参见C3P0。 
  
  
    
      2.
      
      
    
    事务 
  
  
    
  有的服务器支持简单的JDBC事务,有的则能支持java transaction api(JTA)。 
  
  
    
  Jdbc和jta是两种事务策略,到底使用哪种策略,可以在hibernate.cfg.xml设置。Jta的好处是可以允许你将多个独立的事务当作一个事务对待。 
  
  
    
  在Hibernate中,对多个事务的处理是这样的: 
  
  
    
  Transaction tx0 = session.beginTransaction(); 
  
  
    
  Event event = new Event(); 
  
  
    
  // ... populate the event instance 
  
  
    
  session.saveOrUpdate(event); 
  
  
    
  Transaction tx1 = session.beginTransaction(); 
  
  
    
  Location location = new Location(); 
  
  
    
  // ... populate the Location instance 
  
  
    
  session.saveOrUpdate(location); 
  
  
    
  tx0.commit(); 
  
  
    
  tx1.commit(); 
  
  
    
  上面,用一个会话创建了两个事务,但是无论哪个事务的操作都会当作是第一个事务的操作来处理。显然,是一个问题。(利用jta?) 
  
  
    
  <property name="transaction.factory_class"> 
  
  
    
  org.hibernate.transaction.JTATransactionFactory 
  
  
    
  </property> 
  
  
    
  <property name="jta.UserTransaction"> 
  
  
    
  java:comp/UserTransaction 
  
  
    
  </property> 
  
  
    
  当前,默认是使用jdbc的。 
  
  
    
  事务的一个示例: 
  
  
    
  Session session = factory.openSession(); 
  
  
    
  Transaction tx = session.beginTransaction(); 
  
  
    
  Event event = new Event(); 
  
  
    
  // ... populate the Event instance 
  
  
    
  session.saveOrUpdate(event); 
  
  
    
  tx.commit(); 
  
  
    
  注意:这里没有使用flush方法来强制将event写入db,因为提交操作commit时会完成写入。 
  
  
    
  Cache提供者provider 
  
  
    
  未完......................................... 
 
    
    
  
  
    
  Part 3 HQL 
  
  
    
      1.
      
      
    
    Hql具有properties: 
  
  
    
  Id和class 
  
  
    
  使用id可以引用对象的primary key,而不论你实际使用的是什么名字,例如: 
  
  
    
  from MyObject m where m.id > 50 
  
  
    
  查询所有主健大于50的。 
  
  
    
  class是对象的完整java名字,如: 
  
  
    
  from Attendee a join a.payment p where p.class = 
  
  
    
  com.manning.hq.ch06.CashPayment 
  
  
    
  class属性在对象树结构中很有用。 
  
  
    
      2.
      
      
    
    表达式 
  
  
    
  hql支持通常的sql表达式,比如: 
  
  
    
  size:返回子集合中的元素个数 
  
  
    
       from Event e where size(e.attendees) > 0
    
  
  
    
  对有序集合: 
  
  
  
    
  支持的逻辑操作: 
  
  
    
  and, any, between, exists, in, 
  
  
    
  like, not, or, and some 
  
  
    
  支持的比较操作: 
  
  
    
  =, >, <, >=, 
  
  
    
  <=, and <> 
  
  
    
      3.
      
      
    
    条件查询criteria query 
  
  
    
  条件查询为查询提供了灵活性。当查询参数的数目不定时,使用。 
  
  
    
  但是,条件查询不支持聚集函数,并且只能得到这个对象,而不能只得到部分。 
  
  
    
  即,条件查询没有hql的全部功能,但是提高了灵活性。 
  
  
    
  两种使用方式: 
  
  
    
  List results = session.createCriteria(Event.class). 
  
  
    
  .add( Restrictions.between("duration", new Integer(60), 
  
  
    
  new Integer(90) ) 
  
  
    
  .add( Restrictions.like("name", "Presen%") ) 
  
  
    
  .addOrder( Order.asc("name") ) 
  
  
    
  .list(); 
  
  
    
  以及: 
  
  
    
  Criteria criteria = session.createCriteria(Event.class); 
  
  
    
  criteria.add(Restrictions.between("duration", 
  
  
    
  new Integer(60), new Integer(90) ); 
  
  
    
  criteria.add( Restrictions.like("name", "Presen%") ); 
  
  
    
  criteria.addOrder( Order.asc("name") ); 
  
  
    
  List results = criteria.list(); 
  
  
    
  Part 4 利用spring和dao 
  
  
    
      1.
      
      
    
    Dao 
  
  
    
  为了将所有的hql(好处显然:管理),有如下分解,将对象与db见加入一个专门处理持久化的对象dao。 
  
  
  
    
  可以为每一个类建立一个dao,可以为一个应用建立一个dao,建议前者。 
  
  
    
  简单dao: 
  
  
    
  为具体对象承担了如下责任: 
  
  
    
  每一个操作一个会话; 
  
  
    
  每一个操作一个事务,并负责打开和关闭事务; 
  
  
    
  处理异常; 
  
  
    
  客户代码不必考虑对象cast。 
  
  
    
  从Dao程序片断体会上面的责任: 
  
  
    
  public class SimpleEventDao { 
  
  
    
      Log
    
     log = LogFactory.getLog(SimpleEventDao.class); 
  
  
    
  private 
 
    
      Session
    
     session; 
  
  
    
  private 
 
    
      Transaction
    
     tx; 
  
  
    
  public SimpleEventDao() { 
  
  
    
  HibernateFactory.buildIfNeeded(); 
  
  
    
  } 
  
  
    
  public void delete(Event event) 
  
  
    
  throws DataAccessLayerException { 
  
  
    
  try { 
  
  
    
  startOperation(); 
  
  
    
  session.delete(event); 
  
  
    
  tx.commit(); 
  
  
    
  } catch (HibernateException e) { 
  
  
    
  handleException(e); 
  
  
    
  } finally { 
  
  
    
  HibernateFactory.close(session); 
  
  
    
  } 
  
  
    
  } 
  
  
    
  ... 
  
  
    
  } 
  
  
    
  注意:其他真正的功能代码只有一行session.delete(event),其他代码被称为excise税,消费税。编程时的内存管理是典型的税代码,java帮我们上了税,程序员就用再管了。 
  
  
    
      2.
      
      
    
    层次化的dao 
  
  
    
  其他的CRUD操作都是类似上面的结构, 
  
  
    
  因此:可以在简单dao中不同的方法里看到结构和内容重复的代码。 
  
  
    
  所以,需要简化dao,见下: 
  
  
    
  将公共行为提取到父类。 
  
  
    
  父类中的delete片断,可以对比前面的delete,区别只在参数一个是具体对象,一个是Object,而对象的cast问题就交给子类dao。 
  
  
    
  protected void delete(Object obj) { 
  
  
    
  try { 
  
  
    
  startOperation(); 
  
  
    
  session.delete(obj); 
  
  
    
  tx.commit(); 
  
  
    
  } catch (HibernateException e) { 
  
  
    
  handleException(e); 
  
  
    
  } finally { 
  
  
    
  HibernateFactory.close(session); 
  
  
    
  } 
  
  
    
  } 
  
  
    
  dao还要一些问题:因为每个操作一个会话,一个事务,因此一个按id号更新对象的过程,因为有两个操作find和update,所以使用了两个会话(每个会话又分别使用一事务)来完成,如下: 
  
  
    
  Event foundEvent = eventDao.find(event.getId()); 
  
  
    
  foundEvent.setDuration(30); 
  
  
    
  eventDao.update(foundEvent); 
  
  
    
  但是,从效率上来说,一个会话,一个事务就可以了。 
  
  
    
      3.
      
      
    
    Spring的HibernateTemplate 
  
  
    
  Spring对hibernate的支持体现在为hibernate和重要的jdbc需求处理了资源管理税代码resource management excise。 
  
  
    
  前面谈到dao中有重复代码,重复代码可以通过重构的手段解决,而dao中的重复代码跟资源管理有关,因此Spring引入template来完成所有的资源处理部分, 
  
  
    
  Spring的HibernateTemplate帮我们完成了如下工作: 
  
  
    
  获取会话, 
  
  
    
  开始事务, 
  
  
    
  处理异常, 
  
  
    
  显式提交变化到db, 
  
  
    
  关闭会话。 
  
  
    
  可以看到,上面的流程就却那个起到功能作用的方法(如CRUD了,因此dao中可以简化为 
  
  
    
  protected void create(Event event) { 
  
  
    
  SessionFactory sf = HibernateFactory.getSessionFactory(); 
  
  
    
  HibernateTemplate template = new HibernateTemplate(sf); 
  
  
    
  template.saveOrUpdate(event); 
  
  
    
  } 
  
  
    
  但是可以注意到上面的代码还是使用的一个操作一个事务的模式。 
  
  
    
  有两种方式与HibernateTemplate交互: 
  
  
    
  持久化方法和回调: 
  
  
    
  使用持久化方法的片断: 
  
  
    
  SessionFactory sessionFactory = 
  
  
    
  HibernateFactory.getSessionFactory(); 
  
  
    
  HibernateTemplate template = 
  
  
    
  new HibernateTemplate(sessionFactory); 
  
  
    
  Event event1 = new Event(); 
  
  
    
  event1.setName("Event 1"); 
  
  
    
  Event event2 = new Event(); 
  
  
    
  event2.setName("Event 2"); 
  
  
    
  try { 
  
  
    
  template.save (event1); 
  
  
    
  template.save (event2); 
  
  
    
  Event obj = (Event) template.load(Event.class, 
  
  
    
  event1.getId()); 
  
  
    
  System.out.println("Loaded the event" + obj.getName()); 
  
  
    
  List events = (List) template.find("from Event"); 
  
  
    
  System.out.println("# of Events " + events.size()); 
  
  
    
  } finally { 
  
  
    
  template.delete(event1); 
  
  
    
  template.delete(event2); 
  
  
    
  } 
  
  
    
  不是所有的操作(如非CRUD)都可以简化为事务中的一个query。这时spring提供回调接口,写将在HibernateTemplate中调用的回调函数。比如,有这样一个操作根据一个复杂查询的结果,更新结果集中的对象的属性,最后保存。这是一个复杂的操作,要前面的CRUD是无法完成的,因此利用HibernateTemplate可以这样做: 
  
  
    
  template.execute(new HibernateCallback() { 
  
  
    
  public Object doInHibernate(Session session) 
  
  
    
  throws HibernateException, SQLException { 
  
  
    
  Query query = session.createQuery("from Event"); 
  
  
    
  query.setMaxResults(2); 
  
  
    
  List events = query.list(); 
  
  
    
  for (Iterator it = events.iterator(); it.hasNext();) { 
  
  
    
  Event event = (Event) it.next(); 
  
  
    
  event.setDuration(60); 
  
  
    
  } 
  
  
    
  return null; 
  
  
    
  } 
  
  
    
  }); 
  
  
    
  HibernateTemplate的接口就是一个实现doInHibernate方法的 
  
  
    
  HibernateCallback对象。 
  
  
    
  Execute方法以HibernateCallback对象为参数,应该还是替客户代码处理了资源处理税代码的。 
  
  
    
      4.
      
      
    
    Spring对java bean的配置和管理功能 
  
  
    
  Spring擅长配置和使用简单的java bean。Spring可以做为一个工厂factory来配置和建造bean。 
  
  
    
  基于上面的功能,spring可以用来配置configure很多已存在的结构和类库,比如hibernate。 
  
  
    
  Spring通过配置文件来管理bean。 
  
  
    
  配置文件指定了如何创建各种对象,包括Datasource,SessionFactory,所有的dao。 
  
  
    
  因此,可以从配置文件中:查找dao。 
  
  
    
  典型的spring配置文件ApplicaitonContext.xml如下: 
  
  
    
  <?xml version="1.0" encoding="UTF-8"?> 
  
  
    
  <!DOCTYPE beans PUBLIC 
  
  
    
  "-//SPRING//DTD BEAN//EN" 
  
  
    
  "http://www.springframework.org/dtd/spring-beans.dtd"> 
  
  
    
  <beans> 
  
  
    
  <bean id=" 
 
    
      
        dataSource
      
    
    " 
  
  
    
  class="org.apache.commons.dbcp.BasicDataSource" 
  
  
    
  destroy-method="close"> 
  
  
    
  <property name="driverClassName"> 
  
  
    
  <value>com.mysql.jdbc.Driver</value> 
  
  
    
  </property> 
  
  
    
  <property name="url"> 
  
  
    
  <value>jdbc:mysql://localhost/events_calendar</value> 
  
  
    
  </property> 
  
  
    
  <property name="username"> 
  
  
    
  <value>root</value> 
  
  
    
  </property> 
  
  
    
  <property name="password"> 
  
  
    
  <value></value> 
  
  
    
  </property> 
  
  
    
  </bean> 
  
  
    
  <bean id=" 
 
    
      
        factory
      
    
    " 
  
  
    
  class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
  
  
    
  <property name="mappingResources"> 
  
  
    
  <list> 
  
  
    
  <value>com/manning/hq/ch07/Event.hbm.xml</value> 
  
  
    
  <value>com/manning/hq/ch07/Location.hbm.xml</value> 
  
  
    
  </list> 
  
  
    
  </property> 
  
  
    
  <property name="hibernateProperties"> 
  
  
    
  <props> 
  
  
    
  <prop key="hibernate.dialect"> 
  
  
    
  org.hibernate.dialect.MySQLDialect 
  
  
    
  </prop> 
  
  
    
  <prop key="hibernate.show_sql">false</prop> 
  
  
    
  </props> 
  
  
    
  </property> 
  
  
    
  <property name="dataSource"> 
  
  
    
  <ref bean="dataSource"/> 
  
  
    
  </property> 
  
  
    
  </bean> 
  
  
    
  <bean id=" 
 
    
      
        eventDao
      
    
    " 
  
  
    
  class="com.manning.hq.ch07.EventSpringDao"> 
  
  
    
  <property name="sessionFactory"> 
  
  
    
  <ref bean="factory" /> 
  
  
    
  </property> 
  
  
    
  </bean> 
  
  
    
  </beans> 
  
  
  
  
  
    
  如上,来分析spring的配置文件: 
  
  
    
  1处利用Apache Commons database connection pool (DBCP)定义了使用的数据源,DBCP是在hibernate中集成了的。 
  
  
    
  2处利用spring内建的LocalSessionFactoryBean创建一个SessionFactory。并在3处连接到数据源。 
  
  
    
  4处配置dao,并在5处将dao连接到SessionFactory,这让dao能够打开会话,处理查询。 
  
  
    
  Spring的applicationContext.xml可以替代hibernate的 
  
  
    
  hibernate.cfg.xml。 
  
  
    
  另外,有点spring比hibernate进步的地方: 
  
  
    
  对比前面的dao,在dao的构造函数中有这样的代码(来自hibernate quickly,其中HibernateFactory是hibernate quickly自己写的。) 
  
  
    
  public SimpleEventDao() { 
  
  
    
      
        HibernateFactory.buildIfNeeded()
      
    
    ; 
  
  
    
  } 
  
  
    
  dao利用这段代码会调用一个configureSessionFactory方法,根据hibernate的配置文件创建session,如下 
  
  
    
  private static SessionFactory configureSessionFactory() throws HibernateException { 
  
  
    
       Configuration configuration = new Configuration();
    
  
  
    
       configuration.configure();
    
  
  
    
       sessionFactory = configuration.buildSessionFactory();
    
  
  
    
       return sessionFactory;
    
  
  
    
  } 
  
  
    
  spring中不需要用代码显式创建SessionFactory,只要读 
  
  
    
  applicationContext.xml,其中有LocalSessionFactoryBean来处理创建 
  
  
    
  SessionFactory的问题。 
  
  
    
  结合下面的代码和上面SimpleEventDao的构造器 
  
  
    
  Event event = new Event(); 
  
  
    
  event.setName("A new Event"); 
  
  
    
  EventDao eventDao = new EventDao(); 
  
  
    
  eventDao.create(event); 
  
  
    
  可以看到:使用dao的步骤是,先创建dao对象,然后dao对象会创建SessionFactory。 
  
  
    
  Spring中不用显示创建SessionFactory(这是第一点), 
  
  
    
  ClassPathXmlApplicationContext ctx = new 
  
  
    
  ClassPathXmlApplicationContext("applicationContext.xml"); 
  
  
    
      
        EventSpringDao eventDao = (EventSpringDao) ctx.getBean("eventDao", 
      
    
  
  
    
      
        EventSpringDao.class);
      
    
  
  
    
  Event event = new Event(); 
  
  
    
  eventDao.saveOrUpdate(event); 
  
  
    
  注意:applicationContext.xml应该放在classpath里指定的path的root(似乎)。 
  
  
    
  总结一下就是: 
  
  
    
  在Hibernate中用户代码的责任: 
  
  
    
  创建dao对象,用new的方式, 
  
  
    
  dao对象创建SessionFactory对象,供dao中的CRUD操作使用。 
  
  
    
  而在spring中用户代码的责任: 
  
  
    
  创建dao对象,用getBean的方式(这似乎是一种create method方法,参见《重构与模式》中6.1《用Creation Method替换构造函数》)。 
  
  
    
  其实,上面提到“spring擅长配置和使用简单的java bean”,所以使用上面代码中的 
  
  
    
  ClassPathXmlApplicationContext.getBean()方法来完成。 
  
  
    
  Spring对层次化的dao的支持: 
  
  
    
  org.springframework.orm.hibernate3.support.HibernateDaoSupport。 
  
  
    
  其代码: 
  
  
    
  public abstract class HibernateDaoSupport 
  
  
    
  implements InitializingBean { 
  
  
    
  protected final Log logger; 
  
  
    
  private HibernateTemplate hibernateTemplate; 
  
  
    
  public final void 
  
  
    
      setSessionFactory
    
    (SessionFactory sessionFactory); 
  
  
    
  public final SessionFactory getSessionFactory(); 
  
  
    
  public final void 
  
  
    
  setHibernateTemplate(HibernateTemplate hibernateTemplate); 
  
  
    
  public final HibernateTemplate getHibernateTemplate(); 
  
  
    
  protected final Session 
 
    
      getSession
    
    () 
  
  
    
  throws DataAccessResourceFailureException, 
  
  
    
  IllegalStateException; 
  
  
    
  protected final void 
 
    
      closeSessionIfNecessary
    
    (Session session); 
  
  
    
  } 
  
  
    
  可以看到:HibernateDaoSupport的支持support体现在: 
  
  
    
  提供logger,以支持日志功能; 
  
  
    
  管理HibernateTemplate(有一个私有的hibernateTemplate); 
  
  
    
  管理SessionFactory(HibernateTemplate从HibernateAccessor继承了SessionFactory); 
  
  
    
  上面的代码虽然表明HibernateDaoSupport是抽象类,但是每个方式实际上有实现的(为什么?)。所以,关于SessionFactory,Session,HibernateTemplate的操作可以直接在客户代码中使用,而不用重载然后实现之。所以从该类继承一个dao的话,可以简化操作,如: 
  
  
    
  public abstract class AbstractSpringDao 
  
  
    
  extends HibernateDaoSupport{ 
  
  
    
  public AbstractSpringDao() { } 
  
  
    
  protected void saveOrUpdate(Object obj) { 
  
  
    
  getHibernateTemplate().saveOrUpdate(obj); 
  
  
    
  } 
  
  
    
  protected void delete(Object obj) { 
  
  
    
  getHibernateTemplate().delete(obj); 
  
  
    
  } 
  
  
    
  protected Object find(Class clazz, Long id) { 
  
  
    
  return getHibernateTemplate().load(clazz, id); 
  
  
    
  } 
  
  
    
  protected List findAll(Class clazz) { 
  
  
    
  return getHibernateTemplate().find( 
  
  
    
  "from " + clazz.getName()); 
  
  
    
  } 
  
  
    
  } 
  
  
    
  其实,上面的类已经是可以实例化的类了,不必标记为abstract。 
  
  
    
  上面的dao再被继承为eventDao:一个dao应该有一个对应的session,dao的所有对数据库的操作都要基于这个session里来完成(考察最初形式的dao可以看到Session类的变量),这个问题在配置文件中指明了一个SessionFactory来创建需要的Session: 
  
  
    
  <bean id="eventDao" class="com.manning.hq.ch07.EventSpringDao> 
  
  
    
  <property name="sessionFactory"> 
  
  
    
  <ref bean="factory" /> 
  
  
    
  </property> 
  
  
    
  </bean> 
  
  
    
      5.
      
      
    
    集成spring对hibernate的支持,简化代码 
  
  
    
  下面用一个类来集成spring对hibernate的支持 
  
  
    
  public class CalendarRegistry { 
  
  
    
  private static ApplicationContext ctx; 
  
  
    
  static { 
  
  
    
  ctx = new ClassPathXmlApplicationContext( 
  
  
    
  "applicationContext.xml"); 
  
  
    
  } 
  
  
    
  private CalendarRegistry() { 
  
  
    
  } 
  
  
    
  public static SessionFactory getSessionFactory() { 
  
  
    
  return (SessionFactory) ctx.getBean( 
  
  
    
  "factory", SessionFactory.class); 
  
  
    
  } 
  
  
    
  public static EventSpringDao getEventDao() { 
  
  
    
  return (EventSpringDao)ctx.getBean( 
  
  
    
  "eventDao", EventSpringDao.class); 
  
  
    
  } 
  
  
    
  } 
  
  
    
  客户代码: 
  
  
    
  EventSpringDao eventDao = CalendarRegistry.getEventDao(); 
  
  
    
  eventDao.saveOrUpdate(event); 
  
  

