hibernate知识点

1.结构

    Session:负责保存、更新、删除、加载和find()。

    Transaction:管理事务。 session.beginTransaction();  tx.commit;

   Query和Criteria接口:执行数据库查询。

       Query query = session.createQuery("from OaAdrgrpB where groupname = :name");
        query.setString("name", name_f);

   Configuration接口:配置Hibernate,根启动Hibernate,创建SessionFactory对象。

  SessionFactory接口:初始化Hibernate,创建Session对象。

 

2.  spring封装的类:

   (1) HibernateDaoSupport  MyHibernateDao继承此类。

       1) 需要注入 <propertyname="sessionFactory"><ref local="sessionFactory"/>

       2) 继承了HibernateDaoSupport类的类获取session时,已不可用SessionFactory.OpenSessioon的形式来获取Session了,由于HibernateDaoSupport本身已有获取session的方法getSession(),所以直接用Session se=this.getSession();来获取,

      2)  在继承 HibrnateDaoSupport的 DAO 实现里,Hibernate Session 的管理完全不需要Hibernate代码打开,而由 Spring 来管理。 Spring 会根据实际的操作,采用"每次事务打开一次 session" 的策略,自动提高了数据库访问的性能。

     3)  在依据hql获取用户信息时,继承了HibernateDaoSupport类的类中不能在使用Query类了,而是用List<Ssh> list = this.getHibernateTemplate().find(hql);形式来获取实体类集合

 

     (2)HibernateTemplate 提供了非常多的常用方法来完成基本的操作,比如增加、删除、修改及查询等操作,Spring 2.0 更增加对命名 SQL 查询的支持,也增加对分页的支持。

        hibernateTemplate = new HibernateTemplate(sessionFactory);

 

     (3)Spring+hibernate 访问数据库有三种方法 :

           1) 继承 继承 HibernateDaoSupport   注入 SessionFactory

spring 配置文件中,对 Dao 注入 sessionFactory. 比较简单。

:

< bean id = "UserInfoDao"  class = "com.hr2job.dao.impl.UserInfoDaoImpl">

          < property name = "sessionFactory"  ref = "sessionFactory"></ property >

</ bean >

优点:不再需要关心关闭、是否连接成功等问题。主要是很方便。缺点:继承了,不能继承其它类了。

          2) 在自己的DAO 注入 HibernateTemplate

     要先配置好 HibernateTemplate:

     <bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
       </bean>

     3) 注入 jdbcTemplate


2. Hibernate连接池的配置
    方式1:使用Hibernate自带的连接池。 (性能差,有小bug)
    方式2:使用配置文件指定的数据库连接池。 (c3po,proxool)
    方式3:从容器中获取得到连接池(如:Tomcat)

   在hibernate.cfg.xml中

方式1:

<hibernate-configuration>
<session-factory >
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>

<property name="connection.url">jdbc:mysql://localhost:3306/feifei </property>

 

方式3:

假定已经配好了一个JNDI名为“jdbc/feifei”的数据源。 在hibernate.cfg.xml中指定使用这个名为“jdbc/feifei”的JNDI
    <property name=”hibernate.connection.datasource”>java:/comp/env/jdbc/feifei </property>

 

 

3. cascade和inverse

    有省份表和城市表,其中城市表有一个外键province_id引用到省份表的主键。这样,可以把省份表看成是父表,把城市表看成是子表,城市表记录的存在依赖于省份表的记录,城市表有一个外键province_id引用到省份表的主键,在Hibernate变成了双向的映射关系:City类有一个类型为Province的province属性,关联到省份表,在映射文件中是many-to-one的关系;Province类有一个Set<City>的cities属性,关联到城市表,在映射文件中是one-to-many的关系。
在Hibernate的映射文件里,同样可以设置cascade属性来控制父子关系。通常在父表设置cascade属性,有以下几种情况:
1、没有设置cascade属性
用方法addInNoCascade()增加记录“广东”和“广州”,再用方法delete()删除“广东”,将会出现异常,系统会说因为“广东”被城市表外键关联了而不能删除。
cascade属性通常在one-to-many关系里应用

第2个外键是用SQL建表时生成的,设置了on delete cascade;而第1个外键应该是用Hibernate操作数据库时,Hibernate自动建立的。第1个外键的On delete被设置为No action,因此删除“广东”的时候,受到这个外键的限制,导致删除失败。

2、设置cascade属性为delete-orphan
在映射文件Province.hbm.xml中,在one-to-many关系对应的Set里,设置cascade="delete-orphan",此功能与MySQL里设置外键设置为on delete cascade相同。再用方法delete()删除“广东”,删除成功。即是,设置cascade为delete-orphan以后,对删除父表记录的时候,会同时删除子表的相关记录。

3、设置cascade属性为all

cascade的属性,除了可以是delete-orphan,还可以是create、update、delete、all等等。all代表除 delete-orphan以外的所有属性值,当设置cascade为all以后,对父表记录的增加、修改操作,会影响到子表的相关记录。

在映射文件Province.hbm.xml中,在one-to-many关系对应的Set里,设置cascade="all"。用方法 addInCascadeOfAll()增加记录“广东”,方法里只有save“广东”,并没有save“深圳”,只是用属性关联了“广东”和“深圳”的关系。结果显示,深圳也被添加到数据库里,这就是cascade="all"的作用,使对父表的操作影响到子表。

注意:A、delete-orphan是一个特别的属性值,只能应用在one-to-many关系的cascade属性。
      B、cascade属性通常在one-to-one和one-to-many关系里应用,不推荐在many-to-one或者many-to- many关系里应用。

 

 

inverse属性决定是否把对set的改动反映到数据库中去。
inverse=false————反映(默认);inverse=true————不反映”

 

  * inverse只对set+one-to-many(或many-to-many)有效,对many-to-one, one-to-one无效。

  例:在一对多关系中的province    1------> 0..* city,  province.citys.add(new City());

   inverse=false, cascade=all,则执行save(province)时SQL语句

insert into province (pid, pname) values (01, "广东“)  --这一条都会有
insert into city (cid,cname,pid) values (001, "深圳“, 01) --由于设置了cascade=all,这意味着同时维护子表
update city set pid=01 where cid=001  --由于设置了inverse=false, 这意味着porvince还要维护关系

 

 

2.排序

     (1) 内存排序

       映像文件中设定sort属性,例如若为Set,则如下设定:
<set name="addrs" table="ADDRS" sort="natural" >
<key column="USER_ID"/>
<element type="string" column="ADDRESS" not-null="true"/>
</set>
    藉由指定sort为natural,Hibernate在加载数据库的数据时,将使用java.util.SortedSet型态对象,如果是String,则根据compareTo()方法来进行排序。
如果是Map的话,则如下设定:
<map name="files" table="FILES" sort="natural">
<key column="USER_ID"/>
<index column="DESCRIPTION" type="string"/>
<element type="string" column="FILENAME" not-null="true"/>
</map>
上面的设定将使用java.util.SortedTree,根据DESCRIPTION进行排序,sort除了设定natural之外,也可以指定一个实现java.util.Comparator的类别名称。
eg:
public class UpPurviewComparator implements Comparator{
    public UpPurviewComparator() {   }

    public int compare(Object o1, Object o2){
        if(o1 == null){
            return o2 == null ? 0 : 1;
        }
        if(o2 == null){
            return -1;
        }
       
        if(o1 instanceof UpPurview && o2 instanceof UpPurview){
            UpPurview p1=  (UpPurview)o1;
            UpPurview p2=  (UpPurview)o2;
            String name1=p1.getModelname();
            String name2=p2.getModelname();
            if(p1.getId().compareTo(p2.getId())==0) return 0;
            if(name1.compareTo(name2)>0) return -1;
            if(name1.compareTo(name2)<0) return 1;
           
            else return -1;
        }
       
        return -1;
    }
}

<set name="upPurviews" cascade="none" table="UP_ROLE_PV_R" sort="com.ztenc.oa.mfp.dao.user.UpPurviewComparator" >
            <key>
                <column name="role_id" not-null="true" />
            </key>
            <many-to-many column="purview_id" class="com.ztenc.oa.mfp.bean.UpPurview" />
        </set>

private Set upPurviews = new TreeSet(new UpPurviewComparator());

    2.数据库排序
<set name="addrs" table="ADDRS" order-by="ADDRESS desc" >
<key column="USER_ID"/>
<element type="string" column="ADDRESS" not-null="true"/>
</set>
在类中:
private Set  properties= new TreeSet ();
在Map中也是相同的设定方式,您也可以利用数据库中的函式功能,例如:
<map name="files" table="FILES" order-by="lower(FILENAME)">
<key column="USER_ID"/>
<index column="DESCRIPTION" type="string"/>
<element type="string" column="FILENAME" not-null="true"/>
</map>
使用这个方法进行排序时,Hibernate会使用LinkedHashSet或LinkedHashMap实现查询时的排序,所以这个方法仅适用于JDK 1.4或以上的版本。  

 

  2.检索

    (1) HQL检索

      Query query=session.createQuery("from Customer as c where "
+" c.name=:customerName "
+"and c.age=:customerAge");
//动态绑定参数
query.setString("customerName","Tom");
query.setInteger("customerAge",21);
//执行查询语句,返回查询结果
List result= query.list();

 

    (2) QBC

    QBC检索方式
//创建一个Criteria对象
Criteria criteria=session.createCriteria(Customer.class);
//设定查询条件,然后把查询条件加入到Criteria中
Criterion criterion1= Expression.like("name", "T%") ;
Criterion criterion2= Expression.eq("age", new Integer(21)) ;
criteria=criteria.add(criterion1);
criteria=criteria.add(criterion2);
//执行查询语句,返回查询结果
List result=criteria.list();

 

 

    (3) 分页查询
Query query = session.createQuery("from
Customer c
order by c.name asc");
query.setFirstResult(0);
query.setMaxResults(10);
List result = query.list();

 

   (4)使用本地SQL查询
List cats  =  sess.createSQLQuery( " select * from cats " ).addEntity(Cat. class ).list();
这里,结果集字段名被假设为与映射文件中指明的字段名相同。对于连接了多个表的查询,这就可能造成问题,因为可能在多个表中出现同样名字的字段。下面的方法就可以避免字段名重复的问题:

List cats  =  sess.createSQLQuery( " select {cat.*} from cats cat " ).addEntity( " cat " , Cat. class ).list();

 

     (5)命名SQL查询
可以在映射文档中定义查询的名字,然后就可以象调用一个命名的HQL查询一样直接调用命名SQL查询.在这种情况下,我们不 需要调用addEntity()方法.
< sql - query name = " persons " >
  < return  alias = " person "   class = " eg.Person " />
   Select person.NAME AS {person.name},person.AGE AS {person.age},person.SEX AS {person.sex} FROM PERSON person Where person.NAME LIKE :namePattern
</ sql - query >
List people  =  sess.getNamedQuery( " persons " ).setString( " namePattern " , namePattern)
.setMaxResults( 50 ).list();

 

 

3.数据关联

   (1)一对多关系:
 person 1--->* event
person.hbm.xml
<class name="events.Person" table="PERSON">
        <id name="id" column="PERSON_ID">
            <generator class="native" />
        </id>
        <property name="age"/>
        <property name="firstname"/>
        <property name="lastname"/>
        <set name="events" >
             <key column="EVENT_ID"/>
             <one-to-many class="events.Event"/>
        </set>
    </class>

运行代码:
 Event theEvent=new Event();
theEvent.setTitle("lmb");
        theEvent.setDate(new Date());
       
        Person person = new Person();
        person.setAge(20);
        person.setFirstname("long");
        person.setLastname("minbo");
        person.getEvents().add(theEvent);
       
        session.save(person);       
        session.getTransaction().commit();

运行异常:
Hibernate: insert into PERSON (age, firstname, lastname) values (?, ?, ?)
Hibernate: update EVENTS set EVENT_ID=? where EVENT_ID=?
Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: events.Event
分析原因:
配置文件设定结果:先保存person的内容,然后修改关系,并没有保存personr属性event,没有设定cascade

改正:
        <set name="events" >  改为 <set name="events" cascade="all" >, 挺奇怪:加入和不加入table="EVENT"属性都是结果,系统会自动找到这个表格。cascade指当主控方执行操作时,关联对象(被动方)是否执行同一操作。如果设定为all,则代表无论主控方执行什么操作,都对其关联类执行同样的操作。
运行结果:
Hibernate: insert into PERSON (age, firstname, lastname) values (?, ?, ?)
Hibernate: insert into EVENTS (EVENT_DATE, title) values (?, ?)
Hibernate: update EVENTS set EVENT_ID=? where EVENT_ID=?
Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not insert collection: [events.Person.events#3]

     (2) 自身关联:
映射一对多双向自身关联关系(例如树型目录)      
<
many-to-one name = "parenCategory" column = "CATEGORY_ID" class = "Category" />
由于可以是 0 个或一个父类,所以没有设置 not-null = "true"      
< set name = "childCategories" inverse = "true" cascade = "save-update" >      
    
< key column = "CATEGORY_ID" />           
   < one-to-many class = "Category" />
 </ set >

     (3)多对多关联的inverse属性

     inverse 属性默认是false的,就是说关系的两端都来维护关系。这个意思就是说,如有一个Student, Teacher和TeacherStudent表,Student和Teacher是多对多对多关系,这个关系由TeacherStudent这个表来表 现。那么什么时候插入或删除TeacherStudent表中的记录来维护关系呢?在用hibernate时,我们不会显示的对 TeacherStudent表做操作。对TeacherStudent的操作是hibernate帮我们做的。hibernate就是看hbm文件中指 定的是"谁"维护关系,那个在插入或删除"谁"时,就会处发对关系表的操作。前提是"谁"这个对象已经知道这个关系了,就是说关系另一头的对象已经set 或是add到"谁"这个对象里来了。前面说过inverse默认是false,就是关系的两端都维护关系,对其中任一个操作都会处发对表系表的操作。当在 关系的一头,如Student中的bag或set中用了inverse="true"时,那就代表关系是由另一关维护的(Teacher)。就是说当这插 入Student时,不会操作TeacherStudent表,即使Student已经知道了关系。只有当Teacher插入或删除时才会处发对关系表的 操作。所以,当关系的两头都用inverse="true"是不对的,就会导致任何操作都不处发对关系表的操作。当两端都是inverse= "false"或是default值是,在代码对关系显示的维护也是不对的,会导致在关系表中插入两次关系。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值