1、Configuration接口:负责配置并启动Hibernate
2、SessionFactory接口:负责初始化Hibernate
3、Session接口:负责持久化对象的CRUD操作
4、Transaction接口:负责事务
5、Query接口和Criteria接口:负责执行各种数据库查询
注意:Configuration实例是一个启动期间的对象,一旦SessionFactory创建完成它就被丢弃了。
Spring配置文件中读取WEB-INF目录下properties文件信息
<bean id="propertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location"> <value>/WEB-INF/config.properties</value> </property> </bean> <property name="configLocation" value="/WEB-INF/hibernate.cfg.xml"></property>
Spring + SpringMVC + Hibernate
<!-- 配置数据源 c3p0 --> <bean id="jdbcDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass"> <value>${driver}</value> </property> <property name="jdbcUrl"> <value>${url}</value> </property> <property name="user"> <value>${username}</value> </property> <property name="password"> <value></value> </property> <!-- 请求超时时间 --> <property name="checkoutTimeout" value="30000" /> <!-- 每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 --> <property name="idleConnectionTestPeriod" value="30" /> <!-- 连接数据库连接池最大空闲时间 --> <property name="maxIdleTime" value="30" /> <!-- 连接池初始化连接数 --> <property name="initialPoolSize" value="5" /> <property name="minPoolSize" value="5" /> <property name="maxPoolSize" value="20" /> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 --> <property name="acquireIncrement" value="5" /> </bean> <!-- 配置SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <!-- 指定hibernate的配置文件位置 --> <property name="configLocation" value="/WEB-INF/hibernate.cfg.xml"></property> <!-- 配置c3p0数据库连接池 --> <property name="dataSource" ref="jdbcDataSource"> </property> </bean>
对象三种状态
持久化对象可以是普通的Javabeans,惟一特殊的是它们与(仅一个)Session相关联。JavaBeans在Hibernate中存在三种状态:
1.临时状态(transient):当一个JavaBean对象在内存中孤立存在,不与数据库中的数据有任何关联关系时,那么这个JavaBeans对象就称为临时对象(Transient Object)。
2.持久化状态(persistent):当一个JavaBean对象与一个Session相关联时,就变成持久化对象(Persistent Object)
3.脱管状态(detached):在这个Session被关闭的同时,这个对象也会脱离持久化状态,就变成脱管状态(Detached Object),可以被应用程序的任何层自由使用,例如可以做与表示层打交道的数据舆对象(Data Transfer Object)。
flush()
当执行session.flush时,会强制将之前session里面的对象进行持久化
Hibernate 查询
1.查询整个映射对象所有字段
String hql = "from Users"; Query query = session.createQuery(hql); List<Users> users = query.list();
2.查询单个字段
String hql = " select name from Users"; Query query = session.createQuery(hql); List<String> list = query.list();
3.查询其中几个字段
String hql = " select name,passwd from Users"; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组 List<Object[]> list = query.list();
4.修改默认查询结果(query.list())不以Object[]数组形式返回,以List形式返回
String hql = " select new list(name,passwd) from Users"; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是List集合了 List<List> list = query.list();
5.修改默认查询结果(query.list())不以Object[]数组形式返回,以Map形式返回
String hql = " select new map(name,passwd) from Users"; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是Map集合了 List<Map> list = query.list();
6.修改默认查询结果(query.list())不以Object[]数组形式返回,以自定义类型返回
//通过query.list()出来的list里存放的不再是默认的Object数组了,而是自定义的类MyUser,必须加包名,String hql = "from Users";中的Users类也是必须加包名的,但是因为再Users.hbm.xml里<hibernate-mapping auto-import="true"> auto-import默认值为true(所以auto-import属性也可以不写),自动导入了
String hql = " select new com.domain.MyUser(name,passwd) from Users"; Query query = session.createQuery(hql); //默认查询出来的list里存放的是一个Object数组,但是在这里list里存放的不再是默认的Object数组了,而是MyUser对象了 List<MyUser> myUsers = query.list();
7:条件查询
(1) //条件查询,参数索引值从0开始,索引位置。通过setString,setParameter设置参数
String hql = "from Users where name=? and passwd=?"; Query query = session.createQuery(hql); //第1种方式 // query.setString(0, "name1"); // query.setString(1, "password1"); //第2种方式 query.setParameter(0, "name1",Hibernate.STRING); query.setParameter(1, "password1",Hibernate.STRING);
(2) //条件查询,自定义索引名(参数名):username,:password.通过setString,setParameter设置参数
String hql = "from Users where name=:username and passwd=:password"; Query query = session.createQuery(hql); //第1种方式 // query.setString("username", "name1"); // query.setString("password", "password1"); //第2种方式,第3个参数确定类型 query.setParameter("username", "name1",Hibernate.STRING); query.setParameter("password", "password1",Hibernate.STRING);
关系映射
多对一
<many-to-one name="" class="" column=""/>
一对多
(Set)
<set name=""> <key column=""></key> <one-to-many class=""/> </set>
多对多
(Set)
<set name="" table=""> <key column=""></key> <many-to-many class="" column=""/> </set>
• name属性:属性名
• class属性:关联的实体类型
• column属性:
○ <many-to-one column="..">:一般可以写成属性名加Id后缀,如属性为group,则column值写成groupId。
○ 一对多中的<key column="..">:从关联的对方(对方是多对一)映射中把column值拷贝过来。
○ 多对多中的<key column=“..”>:一般可以写成本对象的名加Id后缀,如本对象名为User,则写为userId。
○ 多对多中的<many-to-many column=“..”>:一般可以写为关联对象的名称加Id后缀。
多对一
1. <!-- group属性,表达的是本对象与Group的多对一的关系-->
2. <many-to-one name="group" class="Group" column="groupid"></many-to-one>
单向一对一
当从表中的外键即是主键时,称为基于主键的一对一关联主表的hbm.xml中使用<one-to-one>配置从表的hbm.xml中也使用<one-to-one>配置,同时使用<generator class=“foreign”>,指定其主键与外键相同。
当从表中的外键拥有uinique约束时,称为基于唯一外键的一对一关联主表的hbm.xml中使用<one-to-one>配置从表的hbm.xml中使用<many-to-one>配置,并指定unique属性为true
(主键关联)
<!-- idCard属性,表达的是本对象与IdCard的一对一关系。 --> <id name="id"> <!-- 采用foreign生成策略,forgeign会取得另外一个关联对象的标识 --> <generator class="foreign" > <param name="property">idCard</param> </generator> </id> <one-to-one name="idCard" class="IdCard" constrained="true"></one-to-one>
one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
也就是拿到关系字段值,根据对端的主键来加载关联对象
constrained="true"表示约束,当前主键(person的主键)还是一个外键
参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
(唯一外键关联)
<id name="id"> <generator class="native" ></generator> </id> <!-- 由于它是一对一的唯一外键关联,它是多对一关联的特例,注释可以直接写成多对一关联--> <!-- idCard属性,表达的是本对象与IdCard的多对一关系。 --> <many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>
双向一对一
(唯一主键关联)
Card
<!-- 怎么加载对象,抓取策略:join联合查询(默认),select:一条条的查询 --> <one-to-one name="person" class="Person" fetch="join"></one-to-one>
Person:
<one-to-one name="idCard" class="IdCard" constrained="true"></one-to-one>
(唯一外键关联)
Person
<!-- 由于它是一对一的唯一外键关联,它是多对一关联的特例,注释可以直接写成多对一关联--> <!-- idCard属性,表达的是本对象与IdCard的多对一关系。 --> <many-to-one name="idCard" class="IdCard" column="idCardId" unique="true"></many-to-one>
Card:
<!-- 一对一唯一外键关联双向采用<one-to-one>标签来映射,必须指定<one-to-one> 标签中的property-ref属性为关系字段的名称 --> <one-to-one name="person" class="Person" property-ref="idCard"></one-to-one>
单向一对多
<!-- users属性,表达的是本对象与User的一对多的关系 --> <set name="users"> <!--当前表(Group)的主键--> <key column="groupid"/> <one-to-many class="com.liang.hibernate.User"/> </set>
双向一对多
Group:
<!-- 影响控制反转:inverse="false",多的一端维护关系,让一的一端失效 --> <set name="users" inverse="true"> <key column="groupid" not-null="true"/> <one-to-many class="User"/> </set>
User:
<!-- groups属性,表达的是本对象与Group的多对一的关系 --> <many-to-one name="groups" class="Group" column="groupid"/>
双向多对多
User:
<!-- roles属性,表达的是本对象(User)与Role的多对多的关系 --> <set name="roles" table="t_user_role"> <!--当前表(User)的主键--> <key column="user_id"></key> <many-to-many class="Role" column="role_id"></many-to-many> </set>
Role
<!-- users属性,表达的是本对象(Role)与User的多对多的关系 --> <set name="users" table="t_user_role"> <!--当前表(Role)的主键--> <key column="role_id"></key> <many-to-many class="User" column="user_id"></many-to-many> </set>
fetch 抓取策略
当fetch的值为select时,会先查询出主持久化对象,然后再根据持久化对象的外键去查询关联对象,所以若是带查询的持久化对象有N个,则会先用一条SQL查询所有的持久化对象,然后再发送N条根据每个持久化对象外键关联查询重表。所以会产生N+1的问题。(若是只有一个主的持久化对象则不碍)
fetch为join时,会使用一条SQL语句查询出主对象以及关联的对象。因此不会产生N+1问题。
constrained
constrained默认值为false
constrained只能在one-to-one的映射中使用,(一般在主表的映射中,有外键的那个表)。如果constrained=true,则表明存在外键与关联表对应,并且关联表中肯定存在对应的键与其对应, 另外该选项最关键的是影响save和delete的先后顺序。例如增加的时候,如果constainted=true,则会先增加关联表,然后增加本表。删除的时候反之。
one-to-one的单向关联中,如果constrained=false,则会在查询时就全部取出来,用left outer join的方式。如果constrained=true,hibernate即会延迟加载sql,只把主表的查出来,等有用到关联表的再发sql取。
one-to-one的双向关联中,必须设置constrained=true,要不然会有重复数据读,如2个表user,car;在位false时sql如下:select * from user a left outer join car b on a.id=b.id left outer join on user c on a.id=c.id where a.id=? 删除的时候最好删除从表,删除主表会先查询下主表,在联合查询下。
inverse
inverse属性可以用在一对多和多对多双向关联上,inverse属性默认为false,为false表示本端维护关系,如果inverse为true,则本端不能维护关系,会交给另一端维护关系,本端失效。所以一对多关联映射我们通常在多的一端维护关系,让一的一端失效,所以设置为inverse为true。
Hibernate缓存机制
Hibernate一级缓存又称为“Session的缓存”。2.Hibernate二级缓存又称为“SessionFactory的缓存”。
什么样的数据适合存放到第二级缓存中?
1) 很少被修改的数据
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 常量数据
不适合存放到第二级缓存的数据?
1) 经常被修改的数据
2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3) 与其他应用共享的数据。
ehcache
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property> <!-- Enable Second-Level Cache and Query Cache Settings --> <property name="hibernate.cache.use_second_level_cache">true</property> <property name="hibernate.cache.use_query_cache">true</property> <class-cache usage="read-only" class="com.sds.bean.Person"/>
事务隔离
在Hibernate的配置文件中可以显式的设置隔离级别。每一种隔离级别都对应一个整数:
1:Read Uncommitted
2:Read Committed
4:Repeatable Read
8:Serializable
例如,以下代码把hibernate.cfg.xml文件中的隔离级别设为Read Committed:
hibernate.connection.isolation=2
对于从数据库连接池中获得的每个连接,Hibernate都会把它改为使用Read Committed隔离级别。