首页 > 其他分享 >Hibernate基础

Hibernate基础

时间:2023-06-13 10:02:04浏览次数:44  
标签:Hibernate class dao 基础 event session new Event


Hibernate基础
[code]
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); 


 /code]

标签:Hibernate,class,dao,基础,event,session,new,Event
From: https://blog.51cto.com/u_16087012/6467263

相关文章

  • DQL-基础查询
         ......
  • MOS管基础知识:轻松理解MOS管工作原理
    MOS管是一种利用电场效应来控制其电流大小的半导体三端器件,很多特性和应用方向都与三极管类似。这种器件不仅体积小、质量轻、耗电省、寿命长、而且还具有输入阻抗高、噪声低、热稳定性好、抗辐射能力强等优点,应用广泛,特别是在大规模的集成电路中。根据导电沟道的不同,MOS管可分为......
  • Hibernate数据校验简介
    Hibernate数据校验简介我们在业务中经常会遇到参数校验问题,比如前端参数校验、Kafka消息参数校验等,如果业务逻辑比较复杂,各种实体比较多的时候,我们通过代码对这些数据一一校验,会出现大量的重复代码以及和主要业务无关的逻辑。SpringMVC提供了参数校验机制,但是其底层还是通过Hib......
  • 代码随想录算法训练营第24天 | ● 理论基础 ● 77. 组合 - 第7章 回溯算法part01
     第七章 回溯算法part01今日内容: ●  理论基础 ●  77. 组合    详细布置   理论基础  其实在讲解二叉树的时候,就给大家介绍过回溯,这次正式开启回溯算法,大家可以先看视频,对回溯算法有一个整体的了解。 题目链接/文章讲解:https://programmercar......
  • 【基础算法】单链表的OJ练习(1) # 反转链表 # 合并两个有序链表 #
    前言上一章讲解了单链表==->==传送门==<-==,后面几章就对单链表进行一些简单的题目练习,目的是为了更好的理解单链表的实现以及加深对某些函数接口的熟练度。本章带来了两个题目。一是<fontcolor=red>反转链表</font>,二是<fontcolor=red>合并两个有序链表</font>,整体难......
  • 1.基础知识
    1.HTML简介网页的基本组成什么是HTML常用的浏览器web的标准三大组成部分1.1什么是网页网站:指在因特网上根据一定的规则,使用HTML等制作的用于展示特定内容相关的网页集合网页:网站中的一“页”,通常是HTML格式的文件,它要通过浏览器来阅读网页是构成网站的基本元素,它通常由图......
  • Linux基础命令
    Linux基础命令(1)ctrlc:取消命令,并且换行(2)ctrlu:清空本行命令(3)tab键:可以补全命令和文件名,如果补全不了快速按两下tab键,可以显示备选选项(4)ls:列出当前目录下所有文件,蓝色的是文件夹,白色的是普通文件,绿色的是可执行文件(5)pwd:显示当前路径(6)cdXXX:进入X......
  • opcenter camstar designer基础知识--Fields
    点击工具栏的Fields 最左侧的窗格包含一个选择树,其中列出了所有可用的字段类型类别。展开类别可显示更具体的字段类型定义。右键单击字段类型可执行以下任务:• add添加字段定义• Rename重命名字段定义• Remove移除字段定义“重命名字段定义”和“移除字段......
  • Python基础之os模块
    OS模块os.makedirs('dirname1/dirname2')可生成多层递归目录os.removedirs('dirname1')若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推os.mkdir('dirname')生成单级目录;相当于shell中mkdirdirnameos.rmdir('dirname')删除单级空目录,若目录不为......
  • python基础day23 os模块和序列化模块
    os模块(重要,多)os模块是与操作系统交互的一个接口('a/aa/aaa/aaaa/aaaaa')#递归创建文件夹os.removedirs('a/aa/aaa')#上推删除空文件夹os.mkdir('aaa')#当前文件所在位置创建一个新的文件夹或文件os.mkdir('a.txt')os.rmdir('aaa')#删除当前文件所在位置平级......