Hibenate技术详解

 
一:Hibernate的基本用法:
1,Hibernate的数据库操作:
        在所有的ORM框架中有一个非常重要的媒介:PO(Persistence Object,持久化对象),持久化对象的作用是完成持久化操作,简单的说,通过该对象可以对数据进行增删改查的操作。
        Hibernate的PO是非常简单的,Hibernate是低侵入式设计,完全采用普通的Java对象来作为持久化对象。 看下面的 一个普通的Java对象:
public class News
{
    //消息类的标识属性
    private int id;
    //消息标题
    private String title;
    //消息内容
    private String content;
    //构造器
    public News()
    {
    }
    //标识属性的setter和getter方法
    public void setId(int id) 
    {
        this.id = id; 
    }
    public int getId()
    {
        return (this.id); 
    }
    //消息标题的setter方法和getter方法
    public void setTitle(String title) 
    {
        this.title = title; 
    }
    public String getTitle() 
    {
        return (this.title); 
    }

    //消息内容的setter方法和getter方法
    public void setContent(String content)
    {
        this.content = content; 
    }
    public String getContent()
    {
        return (this.content); 
    }
}
News.hbm.xml:
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="cn.huaxia.domain"
default-access="field">
<classname="News"table="table_news">
<idname="id">
<generatorclass="native"/>
</id>
<propertyname="name"column="uname"/>
<propertyname="sex"/>
<propertyname="age"/>
</class>
</hibernate-mapping>
这个普通的javaBean目前还不具备持久化操作的能力,为了使其具备持久化操作的能力,Hibernate采用XML映射文件, 如:
hibernate.cfg.xml:
<!DOCTYPEhibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factoryname="foo">
<propertyname="show_sql">true</property>
<propertyname="hibernate.connection.username">sa</property>
<propertyname="hibernate.connection.password">123</property>
<propertyname="ibernate.connection.pool_size">1000</property>
<propertyname="ibernate.connection.driver_class">com.microsoft.sqlserver.jdbc.SQLServerDriver</property>
<propertyname="hibernate.connection.url">jdbc:sqlserver://localhost:1433;DataBaseName=WebExma</property>
<propertyname="hibernate.c3p0.min_size">5</property>
<propertyname="hibernate.c3p0.max_size">20</property>
<propertyname="hibernate.c3p0.timeout">1800</property>
<propertyname="hibernate.c3p0.max_statements">50</property>
<propertyname="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
<propertyname="hibernate.hbm2ddl.auto">update</property>
<mappingresource="cn/huaxia/domain/News.hbm.xml"/>
</session-factory>
</hibernate-configuration>
hibernate-mapping元素下的class子元素,每一个class映射一个PO,所以可以这样说:
                 PO=POJO+映射文件
Hibernate的配置文件可以是一个properties文件也可以是一个xml文件,在实际应用中,通常使用xml文件, 例如:
 
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate配置文件的DTD信息 -->
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<!-- hibernate- configuration是连接配置文件的根元素 -->
<hibernate-configuration>
    <session-factory>
        <!-- 指定连接数据库所用的驱动 -->
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <!-- 指定连接数据库的url,hibernate连接的数据库名 -->
        <property name="connection.url">jdbc:mysql://localhost/hibernate</property>
        <!-- 指定连接数据库的用户名 -->
        <property name="connection.username">root</property>
        <!-- 指定连接数据库的密码 -->
        <property name="connection.password">32147</property>
        <!-- 指定连接池里最大连接数 -->
        <property name="hibernate.c3p0.max_size">20</property>
        <!-- 指定连接池里最小连接数 -->
        <property name="hibernate.c3p0.min_size">1</property>
        <!-- 指定连接池里连接的超时时长 -->
        <property name="hibernate.c3p0.timeout">5000</property>
        <!-- 指定连接池里最大缓存多少个Statement对象 -->
        <property name="hibernate.c3p0.max_statements">100</property>
        <property name="hibernate.c3p0.idle_test_period">3000</property>
        <property name="hibernate.c3p0.acquire_increment">2</property>
        <property name="hibernate.c3p0.validate">true</property>
        <!-- 指定数据库方言 -->
        <property name="dialect">org.hibernate.dialect.MySQLInnoDBDialect</property>
        <!-- 根据需要自动创建数据库 -->
        <property name="hbm2ddl.auto">create</property>
        <!-- 罗列所有的映射文件 -->
        <mapping resource="News.hbm.xml"/>
    </session-factory>
</hibernate-configuration>
Hibernate不推荐使用DriverManager来连接数据库,推荐使用C3P0数据源。
随着PO与Session的关联关系,PO有如下3种状态:
瞬时状态:如果PO实例从未与Session关联过,该PO实例处于瞬时状态。
持久状态:如果PO实例域Session关联起来,且该实例对应数据库记录,则该实例处于持久化状态。
脱管状态:如果PO实例曾与Session关联过,但因为Session关闭等原因,PO实例脱离了Session的管理,这种状态称之为脱管状态。
        对PO的操作必须在Session管理下才能同步到数据库,Session由SessionFactory产生,SessionFactory是数据库编译后的内存镜像,通常一个应用对应一个SessionFactory对象。SessionFactory由Configuration对象产生,Configuration对象负责加载Hibernate配置文件。如:
publicclass NewsTest {
    publicstatic void add(Object obj) {
        Configuration conf =new Configuration().configure();
        SessionFactory sessionFactory = conf.buildSessionFactory();
        Session session = sessionFactory.openSession();
        Transaction tr = session.beginTransaction();
        session.save(obj);
        tr.commit();
    }
    publicstatic void main(String[] args) {
        News news =new News();
        news.setAge(20);
        news.setSex("男");
        news.setName("johnny");
        add(news);
    }
}
2,JNDI数据源的连接属性:
        如果无需使用hibernate自己管理数据源,而是直接访问容器管理数据源,hibernate可使用JNDI数据源的相关配置,下面是连接 JNDI数据源的主要配置属性:
hibernate.connection.datasource:指定数据源JNDI名字;
hibernate.jndi.url:指定JNDI提供者的URL,该属性是看可选的,如果JNDI与hibernate持久访问的代码处于同一个应用中,则无需指定该属性;
hibernate.jndi.class:指定JNDI InitialContextFactory的实现类,该属性也是可选的,如果JNDI与hibernate持久访问的代码处于同一个应用中,则无需指定该属性;
hibernate.connection.username:指定连接数据库的用户名;
hibernate.connection.password:指定连接数据库的密码。
注意:即使使用jndi数据源,一样需要指定连接数据库的方言,虽然设置数据库方言不是必须的,但是对于优化持久访问层很有必要。
3,改变持久化对象的状态的方法:
        根据前面的介绍的内容,我们知道通过new新建一个持久化实例时,该实例处于瞬时状态,为了让瞬时对象转换为持久化状态,Hibernate Session提供如下几个方法:
Serializable save(Object obj)将Object 对象转变成持久化状态,该对象的属性值被保存到数据库中。
void persist(Object obj):将对象转化成持久化状态,该对象的属性保存到数据库中。
Serializable save(Object obj,Object pk):将obj对象保存到数据库中,保存到数据库时,指定主键值。
void persist(Object obj,Object  pk):将obj对象保存到数据库中,包存到数据库时,指定主键值。
save方法和persist方法的区别:
使用save方法保存持久化对象时,该方法返回该持久化对象的标识属性值(即对应的主键值),但使用persist方法保存持久化对象时,该方法没有任何返回值,因为save方法需要立即返回持久化对象的标识属性,所以执行save方法会立即把持久化对象插入数据库;而persist方法则保证当它在一个事务外部被调用时,并不立即转化成insert语句,这个功能很有用,当我们封装一个长长的会话流程的时候,persist方法显得尤其重要。
load()和get()方法:
也可以通过load方法来加载一个持久化实例,如:
session.load(News.class,new Integer(pk));
上面的pk就是持久化对象的标识属性,如果没有匹配的数据库记录,load方法可能会抛出异常;如果在类配置文件中指定了延迟加载,则load方法会返回一个未初始化的代理对象,这个代理对象没有装载数据记录。
get方法也用于根据主键装载持久化对象,但get()方法会立即访问数据库,如果没有对应的数据,会返回一个null,
        一旦加载该持久化对象后,在代码中对持久化实例做的修改如:
        n.setName("johnny");
这种修改将会保存到数据库中,程序对持久化实例做的修改会在session flush之前自动保存到数据库,无需调用其他方法,也就是说,修改对象的最简单的方法就是在session处于打开状态时load它,然后直接修改。
        这种做法,有极大的性能缺陷,当我们修改某条记录时,这种做法将会产生2条SQL语句,一条用于查询该记录,另一条用来修改该记录。
但是实际情况下无需考虑这种情况,对于一个Java EE而言,Hibernate的处理流程通常是从数据库里加载数据————>发给表现层以供用户修改————>将所做的修改保存到数据库里。这种情况下,应用本身就需要两条SQL语句。
        当我们使用load或get方法来加载持久化对象时,还可以指定一个“锁模式”参数,Hibernate使用LockMode,LockMode提供READ/UPDATE两个静态属性来代表共享修改锁,如果需要加载某个对象以提供修改,则可以用一下代码:
News n =  Session.get(News.class,new Integer(pk),LockMode.UPDATE);
    lock方法也可将某个脱管状态的对象重新持久化,但该脱管对象必须是一个没有被修改的。如:
sess.lock(news,LockMode.NONE);
Hibernate 的update()、merge()和updateOrSave():
        对于一个曾经持久化过的、但现在已经脱离了Session管理的持久化对象,把它称为脱管状态。
当我们修改脱管对象的状态后,程序应该使用新的Session来保存这些修改。如:
    News n=  session.load(News.class,new Integer(pk))
    session.close();
    n.setTitle("news1");
    //打开第二个Session
    Session session2 = .....;
    session2.update(n);
注意:merge方法也可以将程序对脱管对象所做的修改保存到数据库中,但是,merge与update方法最大的区别是merge方法不会持久化给定的对象,也就是对象依然不是持久化状态,仍然与Session没有关系。
 4,深入Hibernate的映射文件:
①映射主键:
标识属性通过<id../>元素指定,<id../>元素的name属性的值就是持久化类标识属性名,除此之外<id../>元素还可以指定如下属性:
type指定该标识属性的类型,该类型可以是 Hibernate内建类型,也可以是Java类型。通常建议设置该属性,提高性能。
column:略。
unsaved-value:在Hibernate3中,无需指定该属性。
access:指定Hibernate访问该标识属性的访问策略。
②映射集合属性:
        集合属性大致分为2种,第一种是单纯的机会属性,例如像:List、Set或数组等集合属性;还有一种是Map结构的集合属性,每个属性都有对应的key映射。
        Hibernate要求持久化集合字段必须声明为接口,实际的接口可以为,java.util.Set,java.util.Collection,java.util.List,java.util,MaP.........甚至是自定义类型
(只需要实现org.hibernae,usertype.userCollectionType接口即可)。
        因为集合属性需要保存到另一个数据库表中,所欲i保存集合属性的数据表需要包含一个外键列,用于参照主键列,该外键列通过在<set.../>,<list.../>等集合元素中使用<key../>元素来映射, 如图
上图的集合属性数据表的外键列需要<key../>元素指定。
             ——————List集合属性:
List是有序集合因此持久化到数据库必须增加一列来表示集合元素的次序,如:
public class Person
{
    //标识属性
    private int id;
    //普通属性name
    private String name;
    //普通属性age
    private int age;
    //集合属性,保留该对象关联的学校
    private List schools = new ArrayList();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , String name , int age , List schools)
    {
        this.id = id;
        this.name = name;
        this.age = age;
        this.schools = schools;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //schools属性的setter和getter方法
    public void setSchools(List schools)
    {
        this.schools = schools;
    }
    public List getSchools()
    {
        return this.schools;
    }

}
映射文件:Person.hbm.xml
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射List集合属性 -->
         <list name="schools" table="school">
            <!-- 映射集合属性数据表的外键列 -->
            <key column="personid" not-null="true"/>
            <!-- 映射集合属性数据表的集合索引列 -->
             <list-index column="list_order"/>
            <!-- 映射保存集合元素的数据列 -->
            <element type="string" column="school_name"/>
         </list>
    </class>
</hibernate-mapping>
PersonManager.java:
public class PersonManager
{
    public static void main(String[] args)
    {
        PersonManager mgr = new PersonManager();
        mgr.createAndStorePerson();
        HibernateUtil.sessionFactory.close();
    }
    //创建并保存Person对象
    private void createAndStorePerson()
    {
        //打开线程安全的session对象
        Session session = HibernateUtil.currentSession();
        //打开事务
        Transaction tx = session.beginTransaction();
        //创建Person对象
        Person yeeku = new Person();
        //为Person对象设置属性
        yeeku.setAge(29);
        yeeku.setName("Yeeku.H.Lee");
        //创建List集合
        List schools = new ArrayList();
        schools.add("小学");
        schools.add("中学");
        //设置List集合属性
        yeeku.setSchools(schools);
        session.save(yeeku);
        tx.commit();
        HibernateUtil.closeSession();
    }
}
——————数组属性:
Hibernate对数组和List的处理方式非常相似,实际上,List和数组也非常像,尤其是jdk1.5增加了自动装箱和拆箱功能,它们用法的区别只是List的长度可以变化,而数组长度不可变而已。例如:
public class Person
{
    //标识属性
    private int id;
    //普通属性name
    private String name;
    //普通属性age
    private int age;
    //数组属性,保留该对象关联的学校
    private String[] schools;

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , String name , int age , String[] schools)
    {
        this.id = id;
        this.name = name;
        this.age = age;
        this.schools = schools;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //schools属性的setter和getter方法
    public void setSchools(String[] schools)
    {
        this.schools = schools;
    }
    public String[] getSchools()
    {
        return this.schools;
    }

}
数组集合属性应该 使用<array../>元素完成映射,而<array../>的子元素和<list../>元素一样,如: Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射数组属性 -->
         <array name="schools" table="school">
            <!-- 映射集合属性数据表的外键列 -->
            <key column="personid" not-null="true"/>
            <!-- 映射集合属性数据表的集合索引列 -->
            <list-index column="list_order"/>
            <!-- 映射保存集合元素的数据列 -->
            <element type="string" column="school_name"/>
        </array>
    </class>
</hibernate-mapping>
由此可见Hibernate对List和数组的处理几乎完全一样。
             ————Set集合属性
Set集合与List集合有点不同,因为Set是无序的,不可重复的集合,因此<set../>元素无需使用<list-index../>元素来映射集合元素的索引列。
如: Person.class:
public class Person
{
    //标识属性
    private int id;
    //普通属性name
    private String name;
    //普通属性age
    private int age;
    //集合属性,保留该对象关联的学校
    private Set<String> schools = 
        new HashSet<String>();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , String name , int age , Set<String> schools)
    {
        this.id = id;
        this.name = name;
        this.age = age;
        this.schools = schools;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //schools属性的setter和getter方法
    public void setSchools(Set<String> schools)
    {
        this.schools = schools;
    }
    public Set<String> getSchools()
    {
        return this.schools;
    }

}
下面是 Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射Set集合属性 -->
         <set name="schools" table="school">
            <!-- 映射集合属性数据表的外键列 -->
            <key column="personid" not-null="true"/>
            <!-- 映射保存集合元素的数据列,增加非空约束 -->
            <element type="string" column="school_name"
                not-null="true"/>
        </set>
    </class>
</hibernate-mapping>
PersonManager.java:
public class PersonManager
{
    public static void main(String[] args)
    {
        PersonManager mgr = new PersonManager();
        mgr.createAndStorePerson();
        HibernateUtil.sessionFactory.close();
    }

    private void createAndStorePerson()
    {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();
        //创建Person对象
        Person yeeku = new Person();
        //为Person对象设置属性
        yeeku.setAge(29);
        yeeku.setName("Yeeku.H.Lee");
        //创建Set集合
        Set<String> s = new HashSet<String>();
        s.add("小学");
        s.add("中学");
        //设置Set集合属性
        yeeku.setSchools(s);
        session.save(yeeku);
        tx.commit();
        HibernateUtil.closeSession();
    }
}
        对比发现List和Set两种集合属性,发现List集合属性的元素是有序的,而Set集合元素没有顺序,当集合属性在另一张表中存储时,List集合可以用关联持久化类的外键和集合索引列作为联合主键,但是Set集合没有索引列,则以关联持久化类的外键和元素列作为联合主键,前提是元素列不能为空。
 
                ————bag元素映射:
<bag../>元素即可映射List集合属性,也可以映射Set集合属性,甚至可以映射Connllection集合属性。不管是那种集合属性,使用<bag../>元素都被将映射成无序集合,集合属性对应的表没有主键。
 
                ————map集合属性:
map集合属性必须需要使用<map../>元素进行映射,当配置<map../>元素时需要使用<key..>元素映射外键列,除此之外,Map集合属性还需要映射Map key。映射Map集合的key的元素比较多,当Map的key是字符串、日期类型时,可以直接使用<map-key../>元素来映射Map key。
Hibernate以外键列和key作为联合主键。
示例:
public class Person
{
    //标识属性
    private int id;
    //普通属性name
    private String name;
    //普通属性age
    private int age;
    //集合属性,保留该对象关联的考试成绩
    private Map scores = new HashMap();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , String name , int age , Map scores)
    {
        this.id = id;
        this.name = name;
        this.age = age;
        this.scores = scores;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //scores属性的setter和getter方法
    public void setScores(Map scores)
    {
        this.scores = scores;
    }
    public Map getScores()
    {
        return this.scores;
    }
}
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射Map集合属性 -->
         <map name="scores" table="score">
            <!-- 映射集合属性数据表的外键列 -->
            < key column="personid" not-null="true"/>
            <!-- 映射集合属性数据表的Map key列 -->
            < map-key column="subject" type="string"/>
            <!-- 映射保存集合元素的数据列 -->
            <element column="grade" type="float"/>
         </map>
    </class>
</hibernate-mapping>
映射scores属性时指定<map-key../>和<element../>两个子元素,由于程序定义Map集合时,没有使用泛型来限制Map集合。所以Hibernate无法通过反射来获取Map集合的key和value的数据类型,所以配置<map-key../>和<element.../>元素时必须指定type属性。
                     ————集合属性的性能分析:
略;
                     ————映射组件属性:
        
组件属性的意思是持久化对类的属性不是一个基本数据类型,也不是字符串、日期等类型的变量,而是一个被包含的对象,在持久化的过程中,它仅仅被当作值类型,而非一个实体引用。如:

public class Person
{
    //标识属性
    private int id;
    //普通属性age
    private int age;
    //组件属性name
     private Name name;

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , 
        int age , Name name)
    {
        this.id = id;
        this.age = age;
        this.name = name;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //name属性的setter和getter方法
    public void setName(Name name)
    {
        this.name = name;
    }
    public Name getName()
    {
        return this.name;
    }
}
Name.java:

public class Name
{
    //定义first属性
    private String first;
    //定义last属性
    private String last;
    //引用拥有该Name的Person对象
    private Person owner;

    //无参数的构造器
    public Name()
    {
    }
    //初始化first、last属性的构造器
    public Name(String first , String last)
    {
        this.first = first;
        this.last = last;
    }

    //first属性的setter和getter方法
    public void setFirst(String first)
    {
        this.first = first;
    }
    public String getFirst()
    {
        return this.first;
    }

    //last属性的setter和getter方法
    public void setLast(String last)
    {
        this.last = last;
    }
    public String getLast()
    {
        return this.last;
    }

    //owner属性的setter和getter方法
    public void setOwner(Person owner)
    {
        this.owner = owner;
    }
    public Person getOwner()
    {
        return this.owner;
    }
}
        显然,一个普通的数据列无法存储Name对象,因此我们不能用<property../>元素进行映射,除此之外,上面的Name类包含一个owner属性,该owner属性指向包含该Name属性的容器实体(也就是Person对象)。Hibernate提供了>component../>元素,每一个component元素映射一个组件属性。
        使用<component.../>元素还需要如下几个属性:
class:指定组件类的名称,如果不指定该属性,Hibernate将通过反射来该组件的类型。
insert:指定被映射的字段是否出现在SQL的insert语句中。
update:指定被映射的字段是否出现在SQL的update语句中。
access:指定Hibernate访问该组件属性的策略,默认是property。
lazy:设置该组件是否在持久化对象第一次访问时启用延迟加载,默认为true。
optimistic- lock:设置更新该组件的属性是否获取乐观锁,如果设置为true,当修改该组件属性时,持久化对象的版本号会增加。
unique:指定是否在该组件映射的所有字段上添加唯一约束。
        除此之外,还可以在<comonent../>元素内插入一个< parent../>子元素,用于映射组件类内一个指向其容器实体的反向引用,定义一个<parent../>子元素时只需要指定一个name属性,其值为引用容器实体的属性名。
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
        <!-- 映射组件属性name,组件属性的类型为Name -->
         <component name="name" 
            class="Name" unique="true">
            <!-- 指定owner属性代表容器实体 -->
             <parent name="owner"/>
            <!-- 映射组件属性的first属性 -->
            <property name="first"/>
            <!-- 映射组件属性的last属性 -->
            <property name="last"/>
         </component>
    </class>
</hibernate-mapping>
 
public class PersonManager
{
    public static void main(String[] args)
    {
        PersonManager mgr = new PersonManager();
        mgr.createAndStorePerson();
        HibernateUtil.sessionFactory.close();
    }

    private void createAndStorePerson()
    {
        Session session = HibernateUtil.currentSession();
        Transaction tx = session.beginTransaction();
        //创建Person对象
        Person yeeku = new Person();
        //为Person对象设置属性
        yeeku.setAge(29);
        Name n = new Name("Yeeku" , "Lee");
        yeeku.setName(n);
        session.save(yeeku);
        tx.commit();
        HibernateUtil.closeSession();
    }
}
                    ————组件的属性为集合:
如果组件类再次包含了List、Set、Map等级和属性,则我们可以在<comonent../>元素里使用<list../><mao../><set../>子元素来映射这些集合属性。
如:

public class Name
{
    //定义first属性
    private String first;
    //定义last属性
    private String last;
    //引用拥有该Name的Person对象
    private Person owner;
     private Map power = new HashMap();


    //无参数的构造器
    public Name()
    {
    }
    //初始化全部属性的构造器
    public Name(String first , String last)
    {
        this.first = first;
        this.last = last;
    }

    //first属性的setter和getter方法
    public void setFirst(String first)
    {
        this.first = first;
    }
    public String getFirst()
    {
        return this.first;
    }

    //last属性的setter和getter方法
    public void setLast(String last)
    {
        this.last = last;
    }
    public String getLast()
    {
        return this.last;
    }

    //owner属性的setter和getter方法
    public void setOwner(Person owner)
    {
        this.owner = owner;
    }
    public Person getOwner()
    {
        return this.owner;
    }

    //power属性的setter和getter方法
    public void setPower(Map power)
    {
        this.power = power;
    }
    public Map getPower()
    {
        return this.power;
    }
}
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
        <!-- 映射组件属性name,组件属性的类型为Name -->
        <component name="name" 
            class="Name" unique="true">
            <!-- 指定owner属性代表容器实体 -->
            <parent name="owner"/>
            <!-- 映射组件属性的first属性 -->
            <property name="first"/>
            <!-- 映射组件属性的last属性 -->
            <property name="last"/>
            <!-- 映射组件属性里的Map集合属性 -->
             <map name="power" table="power">
                <!-- 映射集合属性数据表的外键列 -->
                <key column="person_name_id" not-null="true"/>
                <!-- 映射集合属性数据表的Map key列 -->
                <map-key column="name_aspect" type="string"/>
                <!-- 映射保存集合元素的数据列 -->
                <element column="name_power" type="int"/>
             </map>
        </component>
    </class>
</hibernate-mapping>
从上面对配置文件可以看出,该<map../>元素配置方法与前面的映射集合属性时 所用的<map../>元素没有任何区别。只是<map../>成了<comonent../>子元素。
            ———— 集合属性的元素为组件:
例如:

public class Person
{
    //标识属性
    private int id;
    //普通属性age
    private int age;
    //组件属性name
     private Map<String , Name> nicks
        = new HashMap<String , Name>();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , int age , Map<String,Name> nicks)
    {
        this.id = id;
        this.age = age;
        this.nicks = nicks;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //nicks属性的setter和getter方法
    public void setNicks(Map<String , Name> nicks)
    {
        this.nicks = nicks;
    }
    public Map<String , Name> getNicks()
    {
        return this.nicks;
    }
}
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
        <!-- 映射nicks集合属性,集合属性对应的数据表为nick_table -->
         <map name="nicks" table="nick_table">
            <!-- 映射集合属性数据表的外键列 -->
            <key column="person_id" not-null="true"/>
            <!-- 映射集合属性数据表的Map key列 -->
            <map-key column="phase" type="string"/>
            <!-- 映射保存集合里的组件元素 -->
            <composite-element class="lee.Name">
                <!-- 指定owner属性代表容器实体 -->
                <parent name="owner"/>
                <!-- 映射组件属性的first属性 -->
                <property name="first"/>
                <!-- 映射组件属性的last属性 -->
                <property name="last"/>
            </composite-element>
        </map>
    </class>
</hibernate-mapping>
组件为Map的索引:

public class Person
{
    //标识属性
    private int id;
    //普通属性age
    private int age;
    //组件属性name
    private Map<Name , Integer> nickPower
        = new HashMap<Name , Integer>();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int id , int age , 
        Map<Name , Integer> nickPower)
    {
        this.id = id;
        this.age = age;
        this.nickPower = nickPower;
    }

    //id属性的setter和getter方法
    public void setId(int id)
    {
        this.id = id;
    }
    public int getId()
    {
        return this.id;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //nickPower属性的setter和getter方法
    public void setNickPower(Map<Name , Integer> nickPower)
    {
        this.nickPower = nickPower;
    }
    public Map<Name , Integer> getNickPower()
    {
        return this.nickPower;
    }
}
 

public class Name
{
    //定义first属性
    private String first;
    //定义last属性
    private String last;
    //引用拥有该Name的Person对象
    private Person owner;

    //无参数的构造器
    public Name()
    {
    }
    //初始化全部属性的构造器
    public Name(String first , String last)
    {
        this.first = first;
        this.last = last;
    }

    //first属性的setter和getter方法
    public void setFirst(String first)
    {
        this.first = first;
    }
    public String getFirst()
    {
        return this.first;
    }

    //last属性的setter和getter方法
    public void setLast(String last)
    {
        this.last = last;
    }
    public String getLast()
    {
        return this.last;
    }

    //owner属性的setter和getter方法
    public void setOwner(Person owner)
    {
        this.owner = owner;
    }
    public Person getOwner()
    {
        return this.owner;
    }

    //重写equals方法,根据first、last进行判断
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj != null 
            && obj.getClass() == Name.class)
        {
            Name target = (Name)obj;
            if (target.getFirst().equals(getFirst())
                && target.getLast().equals(getLast()))
            {
                return true;
            }
        }
        return false;
    }
    //重写hashCode方法,根据first、last计算hashCode值
    public int hashCode()
    {
        return getFirst().hashCode() * 7 
            + getLast().hashCode();
    }
}
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射标识属性 -->
        <id name="id" column="personid">
            <!-- 指定主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
        <!-- 映射nickPower集合属性,集合属性对应的数据表为nick_power -->
        <map name="nickPower" table="nick_power">
            <!-- 映射集合属性数据表的外键列 -->
            <key column="person_id" not-null="true"/>
            <!-- 映射集合属性数据表的Map key列 ,
                因为Map key的数据类型是复合类型,所以使用如下元素-->
            <composite-map-key class="lee.Name">
                <!-- 映射复合组件的属性 -->
                <key-property name="first" type="string"/>
                <key-property name="last" type="string"/>
            </composite-map-key>
            <!-- 映射集合元素的数据列 -->
            <element column="nick_power" type="int"/>
        </map>
    </class>
</hibernate-mapping>
组件为复合主键:

public class Person
{
    //以Name组件作为标识属性
    private Name name;
    //普通属性age
    private int age;
    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(Name name , int age)
    {
        this.name = name;
        this.age = age;
    }
    //name属性的setter和getter方法
    public void setName(Name name)
    {
        this.name = name;
    }
    public Name getName()
    {
        return this.name;
    }
    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }
}
 

public class Name implements
    java.io.Serializable
{
    //定义first属性
    private String first;
    //定义last属性
    private String last;

    //无参数的构造器
    public Name()
    {
    }
    //初始化全部属性的构造器
    public Name(String first , String last)
    {
        this.first = first;
        this.last = last;
    }

    //first属性的setter和getter方法
    public void setFirst(String first)
    {
        this.first = first;
    }
    public String getFirst()
    {
        return this.first;
    }

    //last属性的setter和getter方法
    public void setLast(String last)
    {
        this.last = last;
    }
    public String getLast()
    {
        return this.last;
    }

    //重写equals方法,根据first、last进行判断
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj != null 
            && obj.getClass() == Name.class)
        {
            Name target = (Name)obj;
            if (target.getFirst().equals(getFirst())
                && target.getLast().equals(getLast()))
            {
                return true;
            }
        }
        return false;
    }
    //重写hashCode方法,根据first、last计算hashCode值
    public int hashCode()
    {
        return getFirst().hashCode() * 7 
            + getLast().hashCode();
    }
}
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 映射组件类型的标识属性 -->
        <composite-id name="name" class="lee.Name">
            <!-- 映射组件主键里的各属性 -->
            <key-property name="first" type="string"/>
            <key-property name="last" type="string"/>
        </composite-id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
    </class>
</hibernate-mapping>
 
多列作为复合主键:

public class Person implements 
    java.io.Serializable
{
    //定义first属性,作为标识属性的成员
    private String first;
    //定义last属性,作为标识属性的成员
    private String last;
    //普通属性age
    private int age;

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(String first , String last , int age)
    {
        this.first = first;
        this.last = last;
        this.age = age;
    }

    //first属性的setter和getter方法
    public void setFirst(String first)
    {
        this.first = first;
    }
    public String getFirst()
    {
        return this.first;
    }

    //last属性的setter和getter方法
    public void setLast(String last)
    {
        this.last = last;
    }
    public String getLast()
    {
        return this.last;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //重写equals方法,根据first、last进行判断
    public boolean equals(Object obj)
    {
        if (this == obj)
        {
            return true;
        }
        if (obj != null 
            && obj.getClass() == Person.class)
        {
            Person target = (Person)obj;
            if (target.getFirst().equals(getFirst())
                && target.getLast().equals(getLast()))
            {
                return true;
            }
        }
        return false;
    }
    //重写hashCode方法,根据first、last计算hashCode值
    public int hashCode()
    {
        return getFirst().hashCode() * 7 
            + getLast().hashCode();
    }
}
Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <class name="Person">
        <!-- 直接使用composite-id映射多列联合主键 -->
        <composite-id>
            <!-- 映射组件主键里的各属性 -->
            <key-property name="first" type="string"/>
            <key-property name="last" type="string"/>
        </composite-id>
        <!-- 映射普通属性 -->
        <property name="age" type="int"/>
    </class>
</hibernate-mapping>
        二:深入使用Hibernate:
1,hibernate的关联映射:
关联关系是面向对象分析、面向对象设计最重要的知识,Hibernate可以完全理解这种关系,如果映射得当,Hibernate的关联映射将可以大大简化持久层数据的访问,关联关系大致有如下分类:
单向关系:只能单向访问关联端,例如,只能通过老师访问学生,或者只能通过学生访问老师。
双向关心:关联的两端可以互相访问。例如:老师和学生之间可以互相访问。
单向关联可以分为:
单向1——1;
单向1——N;
单向N——1;
单向N——N;
双向关联可以分为:
双向1——1;
双向1——N;
双向N——N;
①无连接表  单向N——1:
N——1是非常常见的关联关系,最常见的父子关系也是N——1,单向的N——1关联只需从N可以访问1的一段。
例如:
Person.java:
publicclass Person {
privateint personid;
private Stringname;
privateint age;
private Addressaddress;
publicint getPersonid() {
returnpersonid;
}
publicvoid setPersonid(int personid) {
this.personid = personid;
}
public String getName() {
returnname;
}
publicvoid setName(String name) {
this.name = name;
}
publicint getAge() {
returnage;
}
publicvoid setAge(int age) {
this.age = age;
}
public Address getAddress() {
returnaddress;
}
publicvoid setAddress(Address address) {
this.address = address;
}
}
 
Address.java:
publicclass Address {
privateint addressid;
private Stringdetail;
publicint getAddressid() {
returnaddressid;
}
publicvoid setAddressid(int addressid) {
this.addressid = addressid;
}
public String getDetail() {
returndetail;
}
publicvoid setDetail(String detail) {
this.detail = detail;
}
}
Address.hbm.xml:
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="cn.huaxia.domain"
default-access="field">
<classname="Address"table="table_address">
<idname="addressid">
<generatorclass="native"/>
</id>
<propertyname="detail"column="detail"/>
</class>
</hibernate-mapping>
 
Person.hbm.xml:
<?xmlversion="1.0"?>
<!DOCTYPEhibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="cn.huaxia.domain"
default-access="field">
<classname="Person"table="table_person">
<idname="personid">
<generatorclass="native"/>
</id>
<propertyname="name"column="pname"/>
<propertyname="age"/>
<many-to-onename="address"column="addressid"cascade="all"class="Address"/>
</class>
</hibernate-mapping>
     以上程序创建了一个瞬时Address对像,当程序执行到session.persist(p),系统准备保存Person对象,系统将要向数据表中插入一条记录,但是该记录参照的主表记录还不曾被保存(Address对象还处于瞬时状态)这时有2中情况发生:
    系统抛出TransientObjectException异常:object references an unsaved transient instance,因为主表不曾插入,所以参照该记录的从表无法插入。
    系统自动级联插入主表,再插入从表记录。
也就是说,上面的配置文件中少了cascade="all",这以为着执行到session.persist(p)会抛出异常。
 
注意:在所有既有的基于外键约束的关联关系中,都必须牢记:要么总是先持久化主表对应实体,要么设置级联操作,否则当Hibernate试图向从表插入数据的时候,如果发现该从表记录参照的主表记录不存在就报异常。
 
②有连接表的N--1关联:
对于绝大多数单向 N--1关联而言,使用基于外键的关联映射已经足够了,但因为底层数据库建模时可以使用连接表来建立这种关系。
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 使用join元素强制使用连接表 -->
         <join table="person_address" >
            <!-- 映射连接表中参照本表主键的外键列 -->
            <key column="personid"/>
            <!-- 映射连接表中参照关联实体的外键列 -->
            <many-to-one name="address" cascade="all"
                class="Address" column="addressId"/>
        </join>
    </class>
</hibernate-mapping>
③单向1--1关联:
        对于单向的1--1关联关系,需要在持久化类里为关联实体 的引用属性增加setter和getter方法,从持久化类上看,单向的 1--1与单向 N--1没有任何区别。因为 N的一端,或者1的一端都是直接访问关联实体
        事实上,单向1--1和N--1的映射配置也非常相似,只需要原有的many-to-one元素增加unique="true"属性,用以表示N端必须唯一,那么就成了1--1了
基于外键的单向1--1:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 用于映射N-1关联实体,指定关联实体类为Address
            指定外键列名为addressId,并指定级联全部操作 -->
        < many-to-one name="address" cascade="all"
             unique="true" class="Address" 
            column="addressId"/>
    </class>
</hibernate-mapping>
            这意味着在person表的addressid外键列上增加唯一约束。
 
有连接表的单向1--1:
虽然这种情况少见,但是Hibernate也支持:
 
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 使用join元素强制使用连接表 -->
        <join table=" person_address" >
            <!-- 映射连接表中参照本表主键的外键列 -->
            <key column="personid"/>
            <!-- 映射连接表中参照关联实体的外键列 -->
            < many-to-one name="address" cascade="all"
                 unique="true" class="Address" 
                column="addressId"/>
        </join>
    </class>
</hibernate-mapping>
            基于主键的单向1--1:
    1--1的关联可以基于主键关联,基于主键关联的持久化类不能拥有自己定的主键生成器,他的主键由关联类负责生成。
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" column="addressid">          
            <!-- 基于主键关联时,主键生成策略是foreign,
                表明根据关联类的主键来生成本表主键 -->
             <generator class="foreign">
                <!-- 指定引用关联实体的属性名 -->
                <param name="property">address</param>
            </generator>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 下面映射基于主键的1-1关联 -->
         <one-to-one name="address"/>
    </class>
</hibernate-mapping>
④无关联表的 单向1--N关联:

public class Person
{
    //标识属性
    private int personid;
    //Person的name属性
    private String name;
    //保留Person的age属性
    private int age;
    //1-N关联关系,使用Set来保存关联实体
     private Set<Address> addresses
        = new HashSet<Address>();

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(int personid , String name , int age)
    {
        this.personid = personid;
        this.name = name;
        this.age = age;
    }

    //personid属性的setter和getter方法
    public void setPersonid(int personid)
    {
        this.personid = personid;
    }
    public int getPersonid()
    {
        return this.personid;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //age属性的setter和getter方法
    public void setAge(int age)
    {
        this.age = age;
    }
    public int getAge()
    {
        return this.age;
    }

    //addresses属性的setter和getter方法
    public void setAddresses(Set<Address> addresses)
    {
        this.addresses = addresses;
    }
    public Set<Address> getAddresses()
    {
        return this.addresses;
    }
}
 
 
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射集合属性,集合元素是其他持久化实体
            没有指定cascade属性 -->
         <set name="addresses">
            <!-- 指定关联的外键列 -->
            <key column="personId"/>
            <!-- 用以映射到关联类属性 -->
            <one-to-many class="Address"/>
        </set>
    </class>
</hibernate-mapping>
⑤ 有连接表的单向1--N:
使用<many-to-many>元素,但是为了保证当前实体是1的一端,因此需要为元素指定unique="true"。
<many-to-many>元素的 unique属性:指定本持久化实体是否 增加唯一约束,默认是false。
同理:<many-to-one>元素的unique属性等于true的话,那么就相当于1--1。
如:Person.hbm.xml:
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射集合属性,集合元素是其他持久化实体
            指定连接表的表名-->
        <set name="addresses" table="person_address">
            <!-- 指定连接表中参照本表记录的外键列名 -->
            <key column="person_id" />
             <!-- 使用many-to-many来映射1-N关联,
                增加unique="true" -->
            < many-to-many class="Address"
                 unique="true"/>
        </set>
    </class>
</hibernate-mapping>
⑥单向N--N关联:
单向的N--N关联和1--N关联的持久化类代码完全相同,控制关系的一端需要增加一个set集合属性,被关联的持久化实体以集合的形式存在。
N--N必须使用链表。
<?xml version="1.0" encoding="GBK"?>
<!-- 指定Hibernate的DTD信息 -->
<!DOCTYPE hibernate-mapping
    PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="lee">
    <!-- 映射Person持久化类-->
    <class name="Person">
        <!-- 映射标识属性personid -->
        <id name="personid" >
            <!-- 定义主键生成器策略 -->
            <generator class="identity"/>
        </id>
        <!-- 用于映射普通属性 -->
        <property name="name" type="string"/>
        <property name="age" type="int"/>
        <!-- 映射集合属性,集合元素是其他持久化实体
            指定连接表的表名-->
         <set name="addresses" table="person_address">
            <!-- 指定连接表中参照本表记录的外键列名 -->
            <key column="person_id" />
             <!-- 使用many-to-many来映射1-N关联,
                增加unique="true" -->
             <many-to-many class="Address"/>
         </set>
    </class>
</hibernate-mapping>
⑦双向一系列的关联略。
2,传播性持久化:
        每一个Hibernate session的基本操作,包括persist(),merge(),saveOrUpdate(),delete(),lock(),refesh(),evict(),replication()都有对应的级联风格。这些级联风格命名为create,merge,save-update,delete,lock,refesh,evict,replication。如果程序希望某个操作能被级联传播到关联实体,则可以在配置关联映射时通过cascade属性来指定。且级联风格是可以组合,如 :<one-to-one name="person" cascade="create,delete,lock"/>
        Hibernate有一个特殊的级联策略:delete-orphan(删除孤儿),此级联策略只对 one-to-many关联有效,表明delete()操作将被级联到所有从关联中删除对象。对于级联策略的设定,Hibernate有如下建议:
         <many-to-one>或者<many-to-many>关系中指定级联没有什么意义,级联通常在<one-to-one>和<one-to-many>关系中比较有用,因为级联操作应该是由主表记录传播到从表记录,而从表记录不能传播到主表记录。
        如果从表记录完全限制在主表记录之内(当主表记录被删除后,从表记录就没有存在的意义),则可以指定cascade="all,delete-orphan"级联策略,将从表实体的生命周期完全交给主表管理。
        如果经常在某个事务中同时使用主表实体和从表实体,则可以考虑指定cascade="create,merege,save-update"级联策略。
3,继承映射:
        对于面向对象的程序设计语言,继承和多态是两个最基本的概念,Hibernate几种继承映射策略,不管哪种继承映射策略,Hibernate的多态查询都可以运行良好。
        Peroson类是本应用继承树结构的父类:

public class Person
{
    //标识属性
    private long id;
    //定义该Person实体的名字属性
    private String name;
    //定义该Person实体的性别属性
    private char gender;
    //定义该Person实体的组件属性:address
    private Address address;

    //无参数的构造器
    public Person()
    {
    }
    //初始化全部属性的构造器
    public Person(long id , String name , char gender)
    {
        this.id = id;
        this.name = name;
        this.gender = gender;
    }

    //id属性的setter和getter方法
    public void setId(long id)
    {
        this.id = id;
    }
    public long getId()
    {
        return this.id;
    }

    //name属性的setter和getter方法
    public void setName(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }

    //gender属性的setter和getter方法
    public void setGender(char gender)
    {
        this.gender = gender;
    }
    public char getGender()
    {
        return this.gender;
    }

    //address属性的setter和getter方法
    public void setAddress(Address address)
    {
        this.address = address;
    }
    public Address getAddress()
    {
        return this.address;
    }
}
 

public class Address
{
    //定义该Address的详细信息
    private String detail;
    //定义该Address的邮编信息
    private String zip;
    //定义该Address的国家信息
    private String country;

    //无参数的构造器
    public Address()
    {
    }
    //初始化全部属性的构造器
    public Address(String detail , String zip , String country)
    {
        this.detail = detail;
        this.zip = zip;
        this.country = country;
    }

    //detail属性的setter和getter方法
    public void setDetail(String detail)
    {
        this.detail = detail;
    }
    public String getDetail()
    {
        return this.detail;
    }

    //zip属性的setter和getter方法
    public void setZip(String zip)
    {
        this.zip = zip;
    }
    public String getZip()
    {
        return this.zip;
    }

    //country属性的setter和getter方法
    public void setCountry(String country)
    {
        this.country = country;
    }
    public String getCountry()
    {
        return this.country;
    }
}
三种映射文件略。
4,Hibernate的批量处理:
         ————批量插入:
如果需要将100000条数据插入数据库,通过Hibernate可能会采用这样的做法:
for(int i=0;i<100000;i++){
    User user= new User(....);
    session.save(user);
}
    但随着这个程序的运行,总会在某个时候运行失败,并且抛出内存溢出,这是因为Hibernate的Session持有一个必选的一级缓存,所有的User实例都将在Session级别的缓存区进行缓存的缘故。
    解决这个问题,有一个非常简单的思路,定时将Session缓存的数据刷入数据库,而不是一直在Session级别缓存,可以考虑设计一个累加器,如:

public class UserManager
{
    public static void main(String[] args)throws Exception
    {
        UserManager mgr = new UserManager();
        mgr.testUser();
        HibernateUtil.sessionFactory.close();
    }

    private void testUser()throws Exception
    {
        //打开Session
        Session session = HibernateUtil.currentSession();
        //开始事务
        Transaction tx = session.beginTransaction();
        //循环100000次,插入100000条记录
        for (int i = 0 ; i < 100000 ; i++ )
        {
            //创建User实例
            User u1 = new User();
            u1.setName("xxxxx" + i);
            u1.setAge(i);
            u1.setNationality("china");
            //在Session级别缓存User实例
            session.save(u1);
            //每当累加器是20的倍数时,将Session中数据刷入数据库,
            //并清空Session缓存。
            if (i % 20 == 0)
            {
                 session.flush();
                session.clear();
            }
        }
        //提交事务
        tx.commit();
        //关闭事务
        HibernateUtil.closeSession();
    }
}
上面的代码中当i%20==0时,手动将Session处缓存的数据邪途数据库,并且清空Session缓存里的数据,除了对Session级别缓存进行处理外,还应该通过如下配置关闭SessionFactory的二级缓存:
         hibernate.cache.use_second_level_cache false
......
 
 
 
 
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值