hibernate笔记

  Hibernate初始了解笔记汇集 收藏

一个User 属性id的类型定义错(定义为String)出项了错误,应为int,在many2one的工程中出项了异常,且数据库操作也发生了异常。
String做主键用uuid整数做主键用native

下面介绍一下hibernate的配置问题:
第一个hibernate项目

1、新建java项目

2、创建User Library,加入如下jar
 * HIBERNATE_HOME/hibernate3.jar
 * HIBERNATE_HOME/lib/*.jar
 * MySql jdbc驱动
 
3、创建hibernate配置文件hibernate.cfg.xml,为了便于调试最好加入log4j配置文件
如果不加入log4j的话,会出现异常。
下面是hibernate.cfg.xml文件的内容。

<!DOCTYPE hibernate-configuration PUBLIC
 "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
<session-factory>
 <property name="hibernate.connection.url">
  jdbc:mysql://localhost/hibernate_first
 </property>
 <property name="hibernate.connection.driver_class">
  com.mysql.jdbc.Driver
 </property>
 <property name="hibernate.connection.username">root</property>
 <property name="hibernate.connection.password">sunyuan</property>
 <property name="hibernate.dialect">
  org.hibernate.dialect.MySQLDialect
 </property>
 <property name="hibernate.show_sql">true</property>
 

 <mapping resource="com/bjsxt/hibernate/User.hbm.xml" />
</session-factory>
</hibernate-configuration>

4、定义实体类

5、定义User类的映射文件User.hbm.xml

6、将User.hbml.xml文件加入到
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.sy.hibernate.User">
  <id name="id">
   <generator class="uuid"/><!-- 主键设置方式,String类型的为uuid Int的是native-->
  </id>
  <property name="name"/>
  <property name="password"/>
  <property name="createTime"/>
  <property name="expireTime"/>
 </class>
</hibernate-mapping>hibernate.cfg.xml文件中其实就是<mapping resource="com/sy/hibernate/User.hbm.xml" />

7、编写hbm2ddl工具类,将实体类生成数据库表
主要代码:

  //读取hibernate.cfg.xml文件
  Configuration cfg = new Configuration().configure();
  
  SchemaExport export = new SchemaExport(cfg);
  
  export.create(true, true);

8、开发客户端
 
为了方便跟踪sql执行,在hibernate.cfg.xml文件中加入<property name="hibernate.show_sql">true</property>

测试实体对象的生命周期

junit简介:
 * 编写测试类xxxTest,需要继承TestCase即,junit.framework.TestCase
 * 编写单元测试方法,测试方法必须以test开头,测试方法不能含有参数和返回值,如:
   public void testHello1() {}
 * 最好单元测试的代码单独建立一个目录,解决这个问题可以采用新建一个SourceFolder,然后再建一个和源文件一样的名字的包即可。

 
了解Hibernate中CRUD操作

了解get和load的区别?
 * get不支持lazy,load支持lazy
就是说,//马上发出查询sql,加载User对象
   User user = (User)session.get(User.class, "402880d01b9bf210011b9bf2a2ff0001");

//不会发出查询sql,因为load方法实现了lazy(懒加载或延迟加载)
   //延迟加载:只有真正使用这个对象的时候,才加载(发出sql语句)如:System.out.println("user.name=" + user.getName());才加载。
   //hibernate延迟加载实现原理是代理方式
   User user = (User)session.load(User.class, "402880d01b9bf210011b9bf2a2ff0001");
 * 采用get加载数据,如果没有匹配的数据,返回null,而load则抛出异常
 
transient状态的特征?
 * 在数据库中没有与之匹配的数据
 * 没有纳入session的管理
 
persistent状态的特征?
 * persistent状态的对象在数据库中有与之匹配的数据
 * 纳入了session的管理
 * 在清理缓存(脏数据检查)的时候,会和数据库同步
 
detached状态的特征?
 * 在数据库中有与之匹配的数据
 * 没有纳入session的管理    
//手动构造的detached状态的对象即将id设为数据库中存在的即可。
User user = new User();
user.setId("43553545");//这里的id必须在数据库中存在。否则抛出org.hibernate.StaleObjectStateException

 
hibernate基本映射

实体类---表
实体类中的普通属性---表字段

采用<class>标签映射成数据库表,通过<property>标签将普通属性映射成表字段
所谓普通属性指不包括自定义类、集合和数组等

注意:如果实体类和实体类中的属性和sql中的关键字重复,必须采用table或column重新命名

实体类的设计原则:
 * 实现一个默认的(即无参数的)构造方法(constructor)
 * 提供一个标识属性(identifier property)(可选)
 * 使用非final的类 (可选)
 * 为持久化字段声明访问器(accessors) 

主键生成策略:
 uuid、native和assigned


hibernate一对一主键关联映射(单向关联Person---->IdCard)

一对一主键关联映射:让两个实体对象的id保持相同,这样可以避免多余的字段被创建

具体映射:

 <id name="id">
  <!-- person的主键来源idCard,也就是共享idCard的主键 -->
  <generator class="foreign">
   <param name="property">idCard</param>
  </generator>
 </id>
 <property name="name"/>
 <!-- one-to-one标签的含义,指示hibernate怎么加载它的关联对象,默认根据主键加载,
 constrained="true", 表明当前主键上存在一个约束,person的主键作为外键参照了idCard 
  -->
 <one-to-one name="idCard" constrained="true"/>


hibernate一对一主键关联映射(双向关联Person<---->IdCard)

需要在idcard映射文件中加入<one-to-one>标签指向person,指示hibernate如何加载person
默认根据主键加载
如:IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="cardNo"/>
  <one-to-one name="person"/>
 </class>
</hibernate-mapping>

Person.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Person" table="t_person">
  <id name="id">
   <generator class="foreign">
    <param name="property">idCard</param>
   </generator>
  </id>
  <property name="name"/>
  <one-to-one name="idCard" constrained="true"/>
 </class>
</hibernate-mapping>
如果为双向的映射,其实就是在原来单项映射的基础上,在idcard映射文件中加入<one-to-one>标签指向person,指示hibernate如何加载即:<one-to-one name="person"/>,其实两个相关联的实体相关的.hbm.xml文件,是相互的,无论哪一个写的具体,哪一个写的简单,都是可以的。就是所谓的此消彼长吧。


hibernate一对一唯一外键关联映射(单向关联Person---->IdCard)

一对唯一外键关联映射是多对一关联映射的特例

可以采用<many-to-one>标签,指定多的一端的unique=true,这样就限制了多的一端的

多重性为一。
<class name="Person" table="t_person">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<many-to-one name="idCard" unique="true"/>
</class>

主要是unique属性的设置。

其中IdCard.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="cardNo"/>
 </class>
</hibernate-mapping>

Person.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Person" table="t_person">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <many-to-one name="idCard" unique="true" column="asd"/>
 </class>
</hibernate-mapping>


hibernate一对一唯一外键关联映射(双向关联Person<---->IdCard)

一对一唯一外键关联双向,需要在另一端(idcard),添加<one-to-one>标签,指示hibernate如何加载
其关联对象,默认根据主键加载person,外键关联映射中,因为两个实体采用的是person的外键维护的关系,
所以不能指定主键加载person,而要根据person的外键加载,所以采用如下映射方式:
<one-to-one name="person" property-ref="idCard"/>

Person.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Person" table="t_person">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <many-to-one name="idCard" unique="true"/>
 </class>
</hibernate-mapping>

IdCard.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.IdCard" table="t_idcard">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="cardNo"/>
  <one-to-one name="person" property-ref="idCard"/>
 </class>
</hibernate-mapping>

session flush测试:

session flush方法主要做了两件事:
 * 清理缓存
 * 执行sql
 
session在什么情况下执行flush
 * 默认在事务提交时
 * 显示的调用flush
 * 在执行查询前,如:iterate
 
hibernate按照save(insert),update、delete顺序提交相关操作 


   //因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
   //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
   session.save(user);
   
   //调用flush,hibernate会清理缓存,执行sql
   //如果数据库的隔离级别设置为为提交读,那么我们可以看到flush过的数据
   //并且session中existsInDatebase状态为true
   session.flush();
   
   //提交事务
   //默认情况下commit操作会先执行flush清理缓存,所以不用显示的调用flush
   //commit后数据是无法回滚的
   tx.commit();

//因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id
   //纳入了session的管理,修改了session中existsInDatebase状态为true
   //如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
   session.save(user);
   tx.commit();


//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
   //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
   session.save(user);
   
   //将user对象从session中逐出,即session的EntityEntries属性中逐出
   session.evict(user);
   
   //无法成功提交,因为hibernate在清理缓存时,在session的insertions集合中取出user对象进行insert操作后
   //需要更新entityEntries属性中的existsInDatabase为true,而我们采用evict已经将user从session的entityEntries
   //中逐出了,所以找不到相关数据,无法更新,抛出异常
   tx.commit();

//因为user的主键生成侧路采用的是uuid,所以调用完成save后,只是将user纳入到了session的管理
   //不会发出insert语句,但是id已经生成,session中existsInDatebase状态为false
   session.save(user);
   
   //flush后hibernate会清理缓存,会将user对象保存到数据库中,将session中的insertions中的user对象
   //清除,并且设置session中existsInDatebase的状态为true
   session.flush();
   
   //将user对象从session中逐出,即session的EntityEntries属性中逐出
   session.evict(user);
   
   //可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象
   //所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态
   tx.commit();

   //因为user的主键生成策略为native,所以调用session.save后,将执行insert语句,返回有数据库生成的id
   //纳入了session的管理,修改了session中existsInDatebase状态为true
   //如果数据库的隔离级别设置为为提交读,那么我们可以看到save过的数据
   session.save(user);
   
   //将user对象从session中逐出,即session的EntityEntries属性中逐出
   session.evict(user);
   
   //可以成功提交,因为hibernate在清理缓存时,在session的insertions集合中无法找到user对象
   //所以就不会发出insert语句,也不会更新session中的existsInDatabase的状态
   tx.commit();

////////////////////////////////////////

 User3 user = new User3();
   user.setId("001");
   user.setName("张三");
   
   session.save(user);
   
   user.setName("王五");
   session.update(user);
   
   User3 user3 = new User3();
   user3.setId("002");
   user3.setName("李四");
   session.save(user3);
//////////////////////////////////////   
   //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
   //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
   //Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?
   //hibernate按照save(insert),update、delete顺序提交相关操作,意思是无论上述的顺序怎么样,即使update在save前面,始终hibernate按照save(insert) ,update,delete的顺序执行。最后是delete


///////////////////////////////////////////////////////////////////////////////

   User3 user = new User3();
   user.setId("003");
   user.setName("张三");
   
   session.save(user);
   
   user.setName("王五");
   session.update(user);
   
   session.flush();
   
   User3 user3 = new User3();
   user3.setId("004");
   user3.setName("李四");
   session.save(user3);
   
   //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
   //Hibernate: update t_user3 set name=?, password=?, create_time=?, expire_time=? where user_id=?
   //Hibernate: insert into t_user3 (name, password, create_time, expire_time, user_id) values (?, ?, ?, ?, ?)
   //因为我们在session.udpate(user)后执行了flush,所以在清理缓存时执行flush前的sql不会生成
   //sql会按照我们的意愿执行
   tx.commit();
这时,会执行按顺序。主要在于flush方法的执行。

//////////////////////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
hihernate一对多关联映射(单向Classes----->Student)
/////////////////////////////////
public class Classes {
 
 private int id;
 
 private String name;
 
 private Set students; 
//////////////////////////////////
public class Student {
 
 private int id;
 
 private String name;

//////////////////////////////////
Classes.hbm.xml
///////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
 <class name="Classes" table="t_classes">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <set name="students">
   <key column="classesid"/>
   <one-to-many class="Student"/>
  </set>
 </class>
</hibernate-mapping>

////////////////////////////
Student.hbm.xml
/////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Student" table="t_student">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
 </class>
</hibernate-mapping>

////////////////////////////////
生成的表为Student和Classes两个表,其中Student表中包含属性有name id classid
Classes表中包含属性有name id
这是怎么做到的映射呢?下面主要介绍一下文件的配置。在Classes.hbm.xml中怎么将class的id映射到Student表中呢?
主要用到<set name="students">
<key column="classesid"/>
<one-to-many class="Student">
</set>这里的students是Classes类的属性。
而在Student.hbm.xml中实际要三个属性标签,而只写了两个属性,而classesid在Classes.hbm.xml中已经关联了。
改天再把hibernate映射的源码看看。

//////////////////////////////////
一对多关联映射利用了多对一关联映射原理

多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一
一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多

也就是说一对多和多对一的映射策略是一样的,只是站的角度不同。


在一一端维护关系的缺点:
 * 如果将t_student表里的classesid字段设置为非空,则无法保存

 * 因为不是在student这一端维护关系,所以student不知道是哪个班的,

   所以需要发出多余的update语句来更新关系
////////////////////////////////////////////////////////////////////////////////

hihernate一对多关联映射(双向Classes<----->Student)

一对多双向关联映射:
 * 在一一端的集合上使用<key>,在对方表中加入一个外键指向一一端
 * 在多一端采用<many-to-one>
 
注意:<key>标签指定的外键字段必须和<many-to-one>指定的外键字段一致,否则引用字段的错误
 
如果在”一“一端维护一对多关联关系,hibernate会发出多余的udpate语句,所以我们一般在多
的一端来维护关联关系

inverse的值有两种,“true”和“false”。inverse="false"是默认的值
inverse的作用:在hibernate中是通过inverse的设置来决定是有谁来维护表和表之间的关系的。

我们说inverse设立不当会导致性能低下,其实是说inverse设立不当,会产生多余重复的SQL语句甚至致使JDBC exception的throw。这是我们在建立实体类关系时必须需要关注的地方。一般来说,inverse=true是推荐使用,双向关联中双方都设置 inverse=false的话,必会导致双方都重复更新同一个关系。但是如果双方都设立inverse=true的话,双方都不维护关系的更新,这也是 不行的,好在一对多中的一端:many-to-one默认是inverse=false,避免了这种错误的产生。但是多对多就没有这个默认设置了,所以很 多人经常在多对多的两端都使用inverse=true,结果导致连接表的数据根本没有记录,就是因为他们双分都没有责任维护关系。所以说,双向关联中最 好的设置是一端为inverse=true,一端为inverse=false。一般inverse=false会放在多的一端,那么有人提问了, many-to-many两边都是多的,inverse到底放在哪儿?其实hibernate建立多对多关系也是将他们分离成两个一对多关系,中间连接一个连接表。所以通用存在一对多的关系,也可以这样说:一对多是多对多的基本组成部分。

关于inverse属性:
 inverse主要用在一对多和多对多双向关联上,inverse可以被设置到集合标签<set>上,
 默认inverse为false,所以我们可以从”一“一端和”多“一端维护关联关系,
 如果设置成inverse为true,则我们只能从多一端来维护关联关系
 
 注意:inverse属性,只影响数据的存储,也就是持久化
  
inverse和cascade
 * inverse是关联关系的控制方向


 * cascade操作上的连锁反应


双向关联:

Student.hbm.xml
////////////////////////////////////////

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Student" table="t_student">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <many-to-one name="classes" column="classesid"/>
 </class>
</hibernate-mapping>
////////////////////////////////////////
Class.hbm.xml
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
 <class name="Classes" table="t_classes">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <set name="students" inverse="true" cascade="all">
   <key column="classesid"/>
   <one-to-many class="Student"/>
  </set>
 </class>
</hibernate-mapping>


////////////////////////////////////////
hibernate多对多关联映射(单向User---->Role)
///////////////////////////////////////
User.hbm.xml
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.User" table="t_user">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <set name="roles" table="t_user_role">
   <key column="userid"/>
   <many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
  </set>
 </class>
</hibernate-mapping>
////////////////////////////////////////Role.hbm.xml
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Role" table="t_role">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
 </class>
</hibernate-mapping>
////////////////////////////////////////
hibernate多对多关联映射(双向User<---->Role)
////////////////////////////////////////

User.hbm.xml
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.User" table="t_user">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <set name="roles" table="t_user_role">
   <key column="userid"/>
   <many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
  </set>
 </class>
</hibernate-mapping>
////////////////////////////////////////
Role.hbm.xml
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.Role" table="t_role">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <set name="users" table="t_user_role" order-by="userid">
   <key column="roleid"/>
   <many-to-many class="com.bjsxt.hibernate.User" column="userid"/>
  </set>
 </class>
</hibernate-mapping>


////////////////////////////////////////映射方法:
  <set name="roles" table="t_user_role">
   <key column="userid"/>
   <many-to-many class="com.bjsxt.hibernate.Role" column="roleid"/>
  </set>
table属性值必须和单向关联中的table属性值一致
<key>中column属性值要与单向关联中的<many-to-many>标签中的column属性值一致
在<many-to-many>中的column属性值要与单向关联中<key>标签的column属性值一致
////////////////////////////////////////


hibernate lazy策略可以使用在:
 * <class>标签上,可以取值:true/false
 * <property>标签上,可以取值:true/false需要类增强工具
 * <set><list>标签上,可以取值:true/false/extra
 * <one-to-one><many-to-one>单端关联上,可以取值:false/proxy/noproxy
 
lazy概念:只有真正使用该对象时,才会创建,对于hibernate而言,正真使用的时候才会发出sql

hibernate支持lazy策略只有在session打开状态下有效
例如:
Session session = null;
  Group group = null;
  try {
   session = HibernateUtils.getSession();
   session.beginTransaction();
   
   group = (Group)session.load(Group.class, 1);
   
   session.getTransaction().commit();
  }catch(Exception e) {
   e.printStackTrace();
   session.getTransaction().rollback();
  }finally {
   HibernateUtils.closeSession(session);
  }
  
  //不能正确输出,抛出LazyInitializationException 异常,因为session已经关闭
  //hibernate支持lazy策略只有在session打开状态下有效
  System.out.println("group.name=" + group.getName());
////////////////////////////////////////

<class>标签上的lazy特性只对普通属性起作用

////////////////////////////////////////
class Classes
int id;String name;Set students;

class Student 
int id;String name;Classes classes;

class.hbf.xml
<hibernate-mapping package="com.bjsxt.hibernate">
<class name="Classes" table="t_classes">
<id name="id">
<generator class="native"/>
</id>
<property name="name"/>
<set name="students" inverse="true" cascade="all" >
<key column="classesid"/>
<one-to-many class="Student"/>
</set>
</class>
</hibernate-mapping>


设置<class>标签上的lazy=true,或者默认TRUE。其它默认
<class name="Classes" table="t_classes" lazy="true">

test1   
//不发sql
Classes classes = (Classes)session.load(Classes.class, 1);
//发sql,查询class
System.out.println("classes.name=" + classes.getName());
//不发sql
Set students = classes.getStudents();
//发sql,查询全部符合条件student的语句
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println("student.name=" + student.getName());
}

test2
//不发sql
Classes classes = (Classes)session.load(Classes.class, 1);
//发sql,查询class
System.out.println("classes.name=" + classes.getName());
//不发sql
Set students = classes.getStudents();
//发sql,查询全部符合条件student的语句
System.out.println("student.count=" + students.size());

设置<class>标签上的lazy=false,集合的lazy为默认(true)
<class name="Classes" table="t_classes" lazy="false">

test3
//发sql,查询student
Classes classes = (Classes)session.load(Classes.class, 1);
//不发sql
System.out.println("classes.name=" + classes.getName());
//不发sql
Set students = classes.getStudents();
//发sql,查询符合条件的student语句
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println("student.name=" + student.getName());
}

设置集合上的lazy=false,其它默认
<set name="students" inverse="true" cascade="all" lazy="false">
<key column="classesid"/>
<one-to-many class="Student"/>
</set>

test4
//不发sql
Classes classes = (Classes)session.load(Classes.class, 1);
//不发sql
System.out.println("classes.name=" + classes.getName());
//发sql,分别查询出classes和student
Set students = classes.getStudents();
//不发sql
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println("student.name=" + student.getName());
}

test5
Classes classes = (Classes)session.load(Classes.class, 1);
//不发sql
System.out.println("classes.name=" + classes.getName());
//发sql,分别查询出classes和student
Set students = classes.getStudents();
//不发sql
System.out.println("student.count=" + students.size());


设置集合上的lazy=extra,其它默认
<set name="students" inverse="true" cascade="all" lazy="extra">
<key column="classesid"/>
<one-to-many class="Student"/>
</set>

test6
//不发sql
Classes classes = (Classes)session.load(Classes.class, 1);
//发sql,查询出classes
System.out.println("classes.name=" + classes.getName());
//不发sql
Set students = classes.getStudents();
//发sql,查询出student
for (Iterator iter=students.iterator(); iter.hasNext();) {
Student student = (Student)iter.next();
System.out.println("student.name=" + student.getName());
}


test7   
//不发sql
Classes classes = (Classes)session.load(Classes.class, 1);
//发sql,查询出classes
System.out.println("classes.name=" + classes.getName());
//不发sql
Set students = classes.getStudents();
//发sql,智能的sql语句,查询出数目
System.out.println("student.count=" + students.size());

 
 ////////////////////////////////////////
hibernate在单端关联上的lazy策略,可以取值:false/proxy/noproxy

<class>标签上的lazy不会影响到单端关联上的lazy特性
////////////////////////////////////////
下面的User.hbm.xml
/.//////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
 <class name="com.bjsxt.hibernate.User" table="t_user" lazy="false">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <!-- 
  <many-to-one name="group" column="groupid" cascade="all"/>
   -->
   <many-to-one name="group" column="groupid" />
 </class>
</hibernate-mapping>
则这里的 <many-to-one name="group" column="groupid" lazy=""/>中lazy不受class中lazy的关联,就是说class中lazy的属性值与many-to-one中的lazy无关。如果,lazy设为false,那么在执行//不会发出sql
   User user = (User)session.load(User.class, 1);
   
   //会发出sql,发出两条sql分别加载User和Group
   System.out.println("user.name=" + user.getName());
时,会发出两条sql语句。lazy的延迟机制在这里不做解释了。
//////////////////////////////////////// 原先看到在Hibernate3之后可以在Many to one 的关系映射中设置lazy属性, 
  <many-to-one name="brother" cascade="none" lazy="no-proxy" insert="true" column="brotherId" outer-join="false" update="false"> 
  还以为和one to many一样,只要将lazy设为true就可以在不加载关联的对象呢,结果这个lazy的属性值只有proxy no-proxy 和false,试了其中任何一个值,结果都还是加载了关联的对象,后来想起class可以设置lazy的属性,就把关联的brother对象的类的lazy属性设为true,然后many to one中的lazy设为no-proxy后就实现了延迟加载,如果将many to one中的lazy属性设为false,系统还是会自动初始化brother对象。 
  </many-to-one><class name="com.demo.bean.Brother" lazy="true" table="brother"> 
//////////////////////////////////////////
总之,class中的lazy只会对普通属性相关联,与集合,many-to-one one-to-many 都无关。//////////////////////////////////////


每棵继承树映射成一张表

1、理解如何映射
  因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。
 这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
 父类用普通的<class>标签定义
 在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
 如:<discriminator column=”XXX” type=”string”/>
 子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:
 Subclass标签的name属性是子类的全路径名
 在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)
 的值Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标
 签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值
 是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

2、理解如何存储
 存储的时候hibernate会自动将鉴别字段值插入到数据库中,在加载数据的时候,hibernate能根据这个鉴别值
 正确的加载对象
 
多态查询:在hibernate加载数据的时候能鉴别出正真的类型(instanceOf)

get支持多态查询
load只有在lazy=false,才支持多态查询 
hql支持多态查询 
////////////////////////////////////////
在这个试验中,有三个类Animal、Bird、Pig,它们的关系是,Animal是基类,其他两个是子类,Brid除了Animal的属性外,还有一个属性height,Pig有weight,在hibernate中生成一个表t_animal
对应的xml文件为:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
 <class name="Animal" table="t_animal" lazy="false">
  <id name="id">
   <generator class="native"/>
  </id>
  <discriminator column="type" type="string"/><!--这里type="string"是hibernate自带的,与Java中的String没有关系。且该标签必须紧跟在标签<id>后-->
  <property name="name"/>
  <property name="sex"/>
  <subclass name="Pig" discriminator-value="P">
   <property name="weight"/>
  </subclass>
  <subclass name="Bird" discriminator-value="B">
   <property name="height"/>
  </subclass>
 </class>
</hibernate-mapping>
//////////////////////////////////////// 
部分代码:
////////////////////////////////////////
session = HibernateUtils.getSession();
   session.beginTransaction();
   
   Animal animal = (Animal)session.load(Animal.class, 1);
   
   //因为load默认只是lazy,因为我们看到的是Animal的代理对象
   //所以通过instanceof是反应不出正真的对象类型的
   //因此load在默认情况下是不支持多态查询的
   if (animal instanceof Pig) {
    System.out.println(animal.getName());
   }else {
    System.out.println("不是猪");
   }
   session.getTransaction().commit();
////////////////////////////////////////


上述中,介绍了怎么生成一张表,但是每个类都生成一个表,包括Animal类对应的表。类的关联和上述一样。
////////////////////////////////////////对应的xml文件
////////////////////////////////////////<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">
 <class name="Animal" table="t_animal">
  <id name="id">
   <generator class="native"/>
  </id>
  <property name="name"/>
  <property name="sex"/>
  <joined-subclass name="Pig" table="t_pig">
   <key column="pid"/>
   <property name="weight"/>
  </joined-subclass>
  <joined-subclass name="Bird" table="t_bird">
   <key column="bid"/>
   <property name="height"/>
  </joined-subclass>
 </class>
</hibernate-mapping>
////////////////////////////////////////
这和生成一张表的区别是:前者用到<joined-subclass>而一张表的是<subclass>其他的细节这里不再叙述。
////////////////////////////////////////
get支持多态查询,load不支持多态查询。只有将lazy设置为false,才支持多态查询,否则实行的是代理proxy
////////////////////////////////////////

那么,将每个具体类都映射成一张表,即生成t_bird和t_pig表分别含有字段
id name sex height
id name sex weight
而父类Animal不映射成表。
///////////////////////////////////////
对应的xml文件:
////////////////////////////////////////
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
 "
http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.bjsxt.hibernate">

 <class name="Animal" abstract="true">
  <id>
   <generator class="assigned"/>
  </id>
  <property name="name"/>
  <property name="sex"/>
  <union-subclass  name="Pig" table="t_pig">
   <property name="weight"/>
  </union-subclass>
  <union-subclass name="Bird" table="t_bird">
   <property name="height"/>
  </union-subclass>
 </class>
</hibernate-mapping>
////////////////////////////////////////

margin-top: 1em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; p

分享到:
评论

你可能感兴趣的:(sql,Hibernate,xml,.net,配置管理)