zoukankan      html  css  js  c++  java
  • Hibernate的映射文件

    映射文件的结构和属性

    一个映射文件(mapping file)由一个根节点<hibernate-mapping>和多个<class>节点组成,

    首先看看根节点<hibernate-mapping>支持什么属性:

    1 <hibernate-mapping
    2          schema="schemaName"                               (1)
    3          catalog="catalogName"                             (2)
    4          default-cascade="cascade_style"                   (3)
    5          default-access="field|property|ClassName"         (4)
    6          default-lazy="true|false"                         (5)
    7          auto-import="true|false"                          (6)
    8          package="package.name"                            (7)
    9  />

    这8个属性都是可选的,下面解释几个重要的属性,

    default-lazy:延迟加载,默认为true,Hibernate通过默认加载提升性能,通常建议设置为true。在后面的配置属性和集合映射时也可以指定lazy值

    auto-import:是否允许查询语句中使用非全限定类名,默认为true,当一个映射文件中有两个持久化类,包名不同,类名相同时,需要设置auto-import为false才能区分。

    package:设置该值之后,映射文件就不再需要指定全限定类名

    再看看<class>标签支持什么样的属性,

     1 <class
     2         name="ClassName"                                   (1)
     3         table="tableName"                                  (2)
     4         discriminator-value="discriminator_value"          (3)
     5         mutable="true|false"                               (4)
     6         schema="owner"                                     (5)
     7         catalog="catalog"                                  (6)
     8         proxy="ProxyInterface"                             (7)
     9         dynamic-update="true|false"                        (8)
    10         dynamic-insert="true|false"                        (9)
    11         select-before-update="true|false"                  (10)
    12         polymorphism="implicit|explicit"                   (11)
    13         where="arbitrary sql where condition"              (12)
    14         persister="PersisterClass"                         (13)
    15         batch-size="N"                                     (14)
    16         optimistic-lock="none|version|dirty|all"           (15)
    17         lazy="true|false"                                  (16)
    18         entity-name="EntityName"                           (17)
    19         check="arbitrary sql check condition"              (18)
    20         rowxml:id="rowid"                                  (19)
    21         subselect="SQL expression"                         (20)
    22         abstract="true|false"                              (21)
    23         node="element-name"
    24 />

    一对<class>就代表一个持久化实体类,即数据库中的表,在<class>元素下,通常还会有<id>和<property>子元素,用来构成表的各个字段,<id>通常用来映射主键,<property>则用来映射普通字段,另外还可以通过<set> <map>等映射集合字段,下面一一讲解。

    映射主键(<id...>

    Hibernate建议为持久化类定义一个标识属性(identifier property),如private int id, 标识属性映射数据库底层的主键字段(primary key column )。在映射文件中,标识属性用<id>表示,<id>标签支持以下属性:

     1 <id
     2         name="propertyName"                                (1)
     3         type="typename"                                    (2)
     4         column="column_name"                               (3)
     5         unsaved-value="null|any|none|undefined|id_value"   (4)
     6         access="field|property|ClassName">                 (5)
     7         node="element-name|@attribute-name|element/@attribute|."
     8 
     9         <generator class="generatorClass"/>
    10 </id>

    unsaved-value:指定刚创建尚未保存时的标识属性值,用来区分已经加载到session但未再次持久化的实例,Hibernate 3中已经不需要指定这个属性。

    上面几个属性通常只需要指定 name, type, column这三个属性,在泛型中,type属性也不需要指定,Hibernate会通过反射获取字段类型

    在Hibernate中,提供了一个逻辑主键生成器,在映射文件中通过<id>元素的子元素<generator>表示,可以为每个持久化类生成唯一逻辑主键,

    主键生成器<generator>的class属性支持以下值,代表不同种类的主键生成器策略,

    1 <generator class="increment|identity|sequence|hilo|seqhilo|uuid|guid|native|assigned|select|foreign" />

    其中最常用的identiry,适合DB2,MySQL, MSSQL等支持自增长字段的数据库,可以返回long, short, int等。

    sequence,适合DB2,Oracle等。

    映射普通属性(<property...>

    <property>标签支持以下属性,

     1 <property
     2         name="propertyName"                                (1)
     3         column="column_name"                               (2)
     4         type="typename"                                    (3)
     5         update="true|false"                                (4)
     6         insert="true|false"                                (4)
     7         formula="arbitrary SQL expression"                 (5)
     8         access="field|property|ClassName"                  (6)
     9         lazy="true|false"                                  (7)
    10         unique="true|false"                                (8)
    11         not-null="true|false"                              (9)
    12         optimistic-lock="true|false"                       (10)
    13         generated="never|insert|always"                    (11)
    14         node="element-name|@attribute-name|element/@attribute|."
    15         index="index_name"
    16         unique_key="unique_key_id"
    17         length="L"
    18         precision="P"
    19         scale="S"
    20 />

    通常情况下只需指定name, column, type的值, 另外部分属性解释如下

    update和insert:输入属性值不需要Hibernate生成,则指定为false

    formula=(sql):直接写SQL获取数据,括号不能少

    lazy:是否延迟加载,默认为false

    下面演示一下formula的用法,

    如果我们在实体类Person.java中有一个普通属性 private String fullContent;

    1 private String fullContent;

    在映射文件中,这个属性的值是通过formula的方式获取的,则映射文件应该这么写,

    1 ...
    2 <property name="fullContent" formula="(select concat(p.name,p.age) from person_inf p where p.person_id = person_id)" />
    3 ...

    这样,我们在测试类中如果要获取这个属性值的话,就会取formula的值

    1 Person p = (Person)sess.get(Person.class, 3);
    2 System.out.println(p.getFullContent());

    上面的例子只是得到一个实体类的属性字段值,但是在数据库层面并没有生成这个字段,

    要想数据库也生成这个字段,则要通过<property>标签的generated属性来指定, 例如

    1 ...
    2 <property name="fullContent" column="full_content" type="string" generated="insert" />
    3 ...

    同时,需要有一个数据库的触发器配合使用才能实现上面的功能,

     1 drop database test;
     2 create database test;
     3 use test;
     4 create table person_inf
     5 (
     6 id auto_increment primary key,
     7 title varchar(255) not null,
     8 content varchar(255)
     9 full_content varchar(255)
    10 );
    11 DELEMITER |
    12 create trigger t_full_content_gen BEFORE INSERT ON person_inf
    13     FOR EACH ROW BEGIN
    14         set person_inf.full_content=concat(person_inf.title, person_inf.content);
    15     END;
    16 |
    17 DELIMITER ;

    先执行上面的SQL脚本,然后才执行java程序,另外需要将hibernate.cfg.xml的hbm2ddl.auto改为update,避免重建数据库时丢失触发器。

    之后,便可以像上面那样访问这个属性了,

    1 Person p = (Person)sess.get(Person.class, 3);
    2 System.out.println(p.getFullContent());

    映射集合属性

    在一个实体类中,有标志属性,普通属性,经常还会有集合属性,集合属性中会包含多个值,多个值与实体类形成一对多的关联关系。

    例如Set集合,List集合,Map集合等等,比如下面这样的实体类定义,

    1 public class SetPerson {
    2         private int id;
    3         private String name;
    4         private int age;
    5         private Set<String> schools = new HashSet<String>();
    6 ...

    这里的schools就是一个集合属性。

    Hibernate要求集合属性必须声明为接口而不是实现类,可以是java.util.Set, java.util.List, java.util.Map等。

    集合属性将会保存在单独的表中,当实体类对象保存时,集合属性也会自动持久化(即保存到单独表中去),当实体类对象删除时,集合属性也会自动删除;当集合从一个实体类对象传递到另一个持久化对象时,集合记录也会从一个表转移到另一个表。

    -集合标签

    常用的集合属性在映射文件中的元素有 <list>, <set>, <map>, <array>, <bag>,<idbag>, <rimitive-array>等,这些集合属性元素标签也有自己的属性,部分属性解释如下:

    table:表名(集合属性元素需要单独存在一张表里)

    lazy:默认为true,延迟加载

    inverse:反转集合属性与实体类关联的控制权,这个对于Set之类的无序集合在性能提升上有用

    sort:有序集合排序属性

    order-by:也是指定排序,不过是通过SQL语句实现

    -外键

    由于集合元素和实体类是一个从属关系,所以在集合元素中需要有一个外键,与实体类的标志属性相关联。这个外键在映射文件中通常用<key>标签标识,<key>标签也有自己的属性,如column, on-delete, property-ref,update,unique等等。

    -索引

    对于有序集合,都需要指定一个索引列,无序集合(Set,bag)则不需要。例如在

    <list-index>,List或者数组集合中用来表示索引,

    <map-key>,映射Map集合,基本数据列的索引

    <map-key-many-to-many>, 映射Map集合,实体引用类索引

    <composite-map-key>, 映射Map集合,复合数据类型的索引

    -数据列

    在映射文件中的集合元素,通常还会有一个数据列,根据不同的数据类型,在映射文件中的标签可能不同,通常会有以下几种

    <element> 基本数据类型,或者其包装类型

    <composite-element>复合类型

    <one-to-many>或<many-to-many>引用类型

    下面,将针对List, Set, Map, SortedMap等不同的集合属性具体说明每种集合属性的特性

    List集合属性

    List是有序集合, 因此需要一个索引列来表示集合的次序。 下面演示List集合属性的用法,

    首先定义一个持久化实体类ListPerson, 类中定义了一个List集合属性 schools.

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 public class ListPerson {
     7     private int id;
     8     private String name;
     9     private int age;
    10     private List<String> schools = new ArrayList<String>();
    11     
    12     public int getId() {
    13         return id;
    14     }
    15     public void setId(int id) {
    16         this.id = id;
    17     }
    18     public String getName() {
    19         return name;
    20     }
    21     public void setName(String name) {
    22         this.name = name;
    23     }
    24     public int getAge() {
    25         return age;
    26     }
    27     public void setAge(int age) {
    28         this.age = age;
    29     }
    30     
    31     public List<String> getSchools() {
    32         return this.schools;
    33     }
    34     public void setSchools(List<String> schools) {
    35         this.schools = schools;
    36     }
    37     
    38 }

    对于这个持久化类, 其映射文件如下, 在映射文件中,我们定义了外键标签<key>用来关联集合属性和持久化类,

    定义了索引列<list-index>来记录集合属性元素的次序,定义了数据列<element>来保存集合元素的值

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="ListPerson" table="Person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <list name="schools" table="school">
    13             <!-- 外键列-->
    14             <key column="personid" not-null="true"/>
    15             <!-- 索引列 -->
    16             <list-index column="list_order"/>
    17             <!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
    18             <element type="string" column="school_name" />
    19         </list>
    20     </class>
    21 </hibernate-mapping>

    下面写一个测试类用来测试上面的持久化类,

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashMap;
     5 import java.util.HashSet;
     6 import java.util.List;
     7 import java.util.Map;
     8 import java.util.Set;
     9 import java.util.SortedSet;
    10 import java.util.TreeSet;
    11 
    12 import org.hibernate.Session;
    13 import org.hibernate.SessionFactory;
    14 import org.hibernate.Transaction;
    15 import org.hibernate.cfg.Configuration;
    16 import org.hibernate.tool.hbm2ddl.SchemaExport;
    17 
    18 public class PersonManager {
    19     private static void exec(String resource, Object obj) {
    20         // 打开线程安全的session
    21         Configuration conf = new Configuration().configure();
    22         conf.addResource("hib/"+resource);
    23         // 用Configuration创建SessionFactory
    24         SessionFactory sf = conf.buildSessionFactory();
    25         // 用SessionFactory打开Session
    26         Session sess = sf.openSession();
    27         Transaction tx = sess.beginTransaction();
    28         sess.save(obj);
    29         tx.commit();
    30         sess.close();
    31         sf.close();
    32     }
    33     private static void listTest() {
    34         ListPerson    lp = new ListPerson();
    35         lp.setAge(20);
    36         lp.setName("xiao ming");
    37         List<String> schools = new ArrayList<String>();
    38         schools.add("小学");
    39         schools.add("中学");
    40         lp.setSchools(schools);
    41         exec("ListPerson.hbm.xml", lp);
    42     }
    43     
    44     public static void main(String[] args) {
    45         listTest();
    46     }
    47 }

    PersonManager类中定义了一个通用方法private static void exec(String resource, Object obj)用来保存持久化类实例,

    在方法listTest()中,实例化了一个持久化类ListPerson, 并且实例化了一个集合属性schools并赋值。

    运行PersonManager.java之后,发现数据库中多了两张表,person_inf和school,且两张表通过personid关联(即在school表中增加了外键约束如下:FK_48amgp8tko414xxqs1q1vaat4)。

    eclipse中执行结果,

     1 Hibernate: drop table if exists Person_inf
     2 Hibernate: drop table if exists school
     3 Hibernate: create table Person_inf (person_id integer not null auto_increment, name varchar(255), age integer, primary key (person_id))
     4 Hibernate: create table school (personid integer not null, school_name varchar(255), list_order integer not null, primary key (personid, list_order))
     5 Hibernate: alter table school add constraint FK_48amgp8tko414xxqs1q1vaat4 foreign key (personid) references Person_inf (person_id)
     6 十二月 29, 2016 11:11:30 下午 org.hibernate.tool.hbm2ddl.SchemaExport execute
     7 INFO: HHH000230: Schema export complete
     8 Hibernate: insert into Person_inf (name, age) values (?, ?)
     9 Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
    10 Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)

    mysql中的数据,

    总共有两张表

    MariaDB [information_schema]>
    MariaDB [information_schema]> select table_name from tables where table_schema =
    'test';
    +------------+
    | table_name |
    +------------+
    | person_inf |
    | school |
    +------------+
    2 rows in set (0.00 sec)

    实体类表

    MariaDB [(none)]> use test;
    Database changed
    MariaDB [test]>
    MariaDB [test]> select * from person_inf;
    +-----------+-----------+------+
    | person_id | name | age |
    +-----------+-----------+------+
    | 1 | xiao ming | 20 |
    +-----------+-----------+------+
    1 row in set (0.00 sec)

    MariaDB [test]>

    集合属性表

    MariaDB [test]> select * from school;
    +----------+-------------+------------+
    | personid | school_name | list_order |
    +----------+-------------+------------+
    | 1     | 小学      | 0     |
    | 1     | 中学       | 1     |
    +----------+-------------+------------+
    2 rows in set (0.00 sec)

    数组集合属性

    Hibernate对数组和List的处理非常相似,只是前者长度不可变,后者可变而已,也因此数组集合一般是无法实现延迟加载的(长度不可变)。

    将上面的list集合修改成数组集合,代码如下,

    持久化类,

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 public class ArrayPerson {
     7     private int id;
     8     private String name;
     9     private int age;
    10     
    11     public int getId() {
    12         return id;
    13     }
    14     public void setId(int id) {
    15         this.id = id;
    16     }
    17     public String getName() {
    18         return name;
    19     }
    20     public void setName(String name) {
    21         this.name = name;
    22     }
    23     public int getAge() {
    24         return age;
    25     }
    26     public void setAge(int age) {
    27         this.age = age;
    28     }
    29     
    30     public String[] getSchools() {
    31         return schools;
    32     }
    33     public void setSchools(String[] schools) {
    34         this.schools = schools;
    35     }
    36 
    37     private String[] schools;
    38 }

    映射文件,

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="ArrayPerson" table="Person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <array name="schools" table="school">
    13             <!-- 外键列-->
    14             <key column="personid" not-null="true"/>
    15             <!-- 索引列 -->
    16             <list-index column="list_order"/>
    17             <!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
    18             <element type="string" column="school_name" />
    19         </array>
    20     </class>
    21 </hibernate-mapping>

    在测试类PersonManager.java中,新家一个测试方法arrayTest(),

    1 private static void arrayTest() {
    2     ArrayPerson    ap = new ArrayPerson();
    3     ap.setAge(20);
    4     ap.setName("xiao ming");
    5     String[] schools = new String[] {"小学","中学","大学"};
    6     ap.setSchools(schools);
    7     exec("ArrayPerson.hbm.xml", ap);
    8 }

    执行PersonManager.java, 看到hibernate生成的sql如下,

    1 ...
    2 Hibernate: insert into person_inf (name, age) values (?, ?)
    3 Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
    4 Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
    5 Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)

    mysql中的数据,

    person_inf表,

    school表,

    Set集合属性

    Set集合与List集合不同,Set是无序集合,因此映射文件中就没有像list那样的索引列<list-index>。作为一个与持久化实例管理的集合属性,Set集合也是需要一个<key>外键来关联的,Set集合演示如下,

    持久化类,

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashSet;
     5 import java.util.List;
     6 import java.util.Set;
     7 
     8 public class SetPerson {
     9         private int id;
    10         private String name;
    11         private int age;
    12         
    13         public int getId() {
    14             return id;
    15         }
    16         public void setId(int id) {
    17             this.id = id;
    18         }
    19         public String getName() {
    20             return name;
    21         }
    22         public void setName(String name) {
    23             this.name = name;
    24         }
    25         public int getAge() {
    26             return age;
    27         }
    28         public void setAge(int age) {
    29             this.age = age;
    30         }
    31         
    32         public Set<String> getSchools() {
    33             return this.schools;
    34         }
    35         public void setSchools(Set<String> schools) {
    36             this.schools = schools;
    37         }
    38         private Set<String> schools = new HashSet<String>();
    39         
    40     }

    映射文件,

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="SetPerson" table="Person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <set name="schools" table="school">
    13             <!-- 外键列-->
    14             <key column="personid" not-null="true"/>
    15             <!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
    16             <element type="string" column="school_name" not-null="true" />
    17         </set>
    18     </class>
    19 </hibernate-mapping>

    在PersonManager.java中新增一个测试方法setTest(),

     1 private static void setTest() {
     2     SetPerson sp = new SetPerson();
     3     sp.setAge(20);
     4     sp.setName("xiao ming");
     5     Set<String> schools = new HashSet<String>();
     6     schools.add("小学");
     7     schools.add("中学");
     8     sp.setSchools(schools);
     9     exec("SetPerson.hbm.xml", sp);
    10 }

    运行PersonManager.java,查看mysql,能得到前面类似的结果

    bag集合元素映射

    <bag>可以映射list,映射Set,甚至映射Collection,但是不论映射成哪种集合,<bag>都会将它们映射为无序集合。

    <bag>集合对应的表没有主键,在映射文件中通过<key>与持久化类关联,用<element>保存元素值,下面演示<bag>集合映射成Collection集合属性,

    持久化类,

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.Collection;
     5 import java.util.List;
     6 
     7 public class BagPerson {
     8     private int id;
     9     private String name;
    10     private int age;
    11     
    12     public int getId() {
    13         return id;
    14     }
    15     public void setId(int id) {
    16         this.id = id;
    17     }
    18     public String getName() {
    19         return name;
    20     }
    21     public void setName(String name) {
    22         this.name = name;
    23     }
    24     public int getAge() {
    25         return age;
    26     }
    27     public void setAge(int age) {
    28         this.age = age;
    29     }
    30     
    31     public Collection<String> getSchools() {
    32         return schools;
    33     }
    34     public void setSchools(Collection<String> schools) {
    35         this.schools = schools;
    36     }
    37 
    38     private Collection<String> schools = new ArrayList<String>();
    39 }

    映射文件, 注意在无序集合中<bag>标签中,可以添加一个order-by属性,直接以SQL实现,这个排序将会添加进hibernate生成的SQL中,通过数据库来实现排序,而不是在程序运行内存中排序。

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="BagPerson" table="Person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <bag name="schools" table="school" order-by="school_name asc">
    13             <!-- 外键列-->
    14             <key column="personid" not-null="true"/>
    15             <!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
    16             <element type="string" column="school_name" not-null="true"/>
    17         </bag>
    18     </class>
    19 </hibernate-mapping>

    在PersonManager.java中,添加一个新的测试方法bagTest(),

     1 private static void bagTest() {
     2     BagPerson sp = new BagPerson();
     3     sp.setAge(20);
     4     sp.setName("xiao ming");
     5     Set<String> schools = new HashSet<String>();
     6     schools.add("小学");
     7     schools.add("中学");
     8     sp.setSchools(schools);
     9     exec("BagPerson.hbm.xml", sp);
    10 }

    执行PersonManager.java后会发现school表中只有两列,外键列和数据列,没有索引列,因为<bag>是无序集合,

    Map集合属性

    Map集合属性使用<map>标签,需要使用<key>列作为外键列和持久化类关联。Map是有序集合,因此还需要<may-key>类作为Map集合的索引。Map集合对应的表将以外键列和索引列作为联合主键。下面演示Map集合用法,

     1 package hib;
     2 
     3 import java.util.ArrayList;
     4 import java.util.HashMap;
     5 import java.util.List;
     6 import java.util.Map;
     7 
     8 public class MapPerson {
     9     private int id;
    10     private String name;
    11     private int age;
    12     
    13     public int getId() {
    14         return id;
    15     }
    16     public void setId(int id) {
    17         this.id = id;
    18     }
    19     public String getName() {
    20         return name;
    21     }
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25     public int getAge() {
    26         return age;
    27     }
    28     public void setAge(int age) {
    29         this.age = age;
    30     }
    31     
    32 
    33     public Map<String, Float> getScores() {
    34         return scores;
    35     }
    36     public void setScores(Map<String, Float> scores) {
    37         this.scores = scores;
    38     }
    39 
    40     private Map<String, Float> scores = new HashMap<String, Float>();
    41     
    42 }

    映射文件,

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="MapPerson" table="Person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <map name="scores" table="score">
    13             <!-- 外键列-->
    14             <key column="person_id" not-null="true"/>
    15             <!-- 索引列 -->
    16             <map-key column="subject" type="string"/>
    17             <!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
    18             <element column="grade" type="float" />
    19         </map>
    20     </class>
    21 </hibernate-mapping>

    在PersonManager.java中新增一个测试方法mapTest(),

     1 private static void mapTest() {
     2     MapPerson mp = new MapPerson();
     3     mp.setAge(20);
     4     mp.setName("xiao ming");
     5     Map<String, Float> scores = new HashMap<String, Float>();
     6     scores.put("语文", new Float(100.01));
     7     scores.put("数学", new Float(130.05));
     8     mp.setScores(scores);
     9     exec("MapPerson.hbm.xml", mp);
    10 }

    执行PersonManager.java, mysql中score表的数据如下,subject将作为map集合索引, person_id + subject 将作为表的联合主键。

    SortedSet和SortedMap集合映射

    使用这两个集合作为集合实现类时,需要为<set>或者<map>标签指定sort属性,sort支持unsorted, natural, 以及通过java.utilComparator自定义排序。

    下面演示一个SortedSet的用法,

    持久化类,

     1 package hib;
     2 
     3 import java.util.HashMap;
     4 import java.util.Map;
     5 import java.util.SortedSet;
     6 import java.util.TreeSet;
     7 
     8 public class SortedPerson {
     9     private int id;
    10     private String name;
    11     private int age;
    12     
    13     public int getId() {
    14         return id;
    15     }
    16     public void setId(int id) {
    17         this.id = id;
    18     }
    19     public String getName() {
    20         return name;
    21     }
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25     public int getAge() {
    26         return age;
    27     }
    28     public void setAge(int age) {
    29         this.age = age;
    30     }
    31     
    32     public SortedSet<String> getTrainings() {
    33         return trainings;
    34     }
    35     public void setTrainings(SortedSet<String> trainings) {
    36         this.trainings = trainings;
    37     }
    38 
    39     private SortedSet<String> trainings = new TreeSet<String>();
    40 }

    映射文件, 需要在<set>上添加sort属性,

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping package="hib">
     6     <class name="SortedPerson" table="person_inf">
     7         <id name="id" column="person_id" type="int">
     8             <generator class="identity" />
     9         </id>
    10         <property name="name" type="string" />
    11         <property name="age" type="int" />
    12         <set name="trainings" table="training" sort="natural">
    13             <!-- 外键列-->
    14             <key column="person_id" not-null="true"/>
    15             <!-- 数据列 -->
    16             <element column="training_name" type="string" not-null="true"/>
    17         </set>
    18     </class>
    19 </hibernate-mapping>

    在PersonManager.java中添加测试方法sortedSetTest(),

     1 private static void sortedSetTest() {
     2     SortedPerson ssp = new SortedPerson();
     3     ssp.setAge(20);
     4     ssp.setName("xiao ming");
     5     SortedSet<String> trainings = new TreeSet<String>();
     6     trainings.add("Wild Java Camp");
     7     trainings.add("Sun SCJP");
     8     ssp.setTrainings(trainings);
     9     exec("SortedPerson.hbm.xml", ssp);
    10 }

    执行PersonManager.java,发现mysql中training表记录已经按照element列按字母排序,

    数据库SQL排序

    上面这种排序是在程序运行内存中实现的,之后再将已排序记录持久化到数据库中。

    如果我们不希望用程序内心来排序,而是希望通过数据来排序,则可以在<set> <map> <bag>中添加order-by属性。

    这种方式是通过继承LinkedHashSet或者LinkedHashMap来实现的,因此确保你的JDK版本至少大于1.4

    例如我们可以在上面的SetPerson.hbm.xml中,在<set>标签中添加order-by属性,

    1 <set name="schools" table="school" order-by="school_name asc">

    集合属性的性能分析

    延迟加载

    Hibernate对集合属性默认采用延迟加载策略,即lazy="true". 因为集合属性很可能有成千上万条数据,而持久化类在实例化的时候并不一定会马上用关联的集合属性。

    修改属性(增删改)的性能

     集合可分两类

    有序集合:集合元素可根据key或者index访问

    无序集合:集合元素只能遍历

    对于有序集合,因为有联合主键存在(主键已被索引),因此可以直接定位到相应元素进行修改,效率高。

    对于无序集合,只有外键,没有索引,也就没有联合主键,也就没法按主键索引定位元素(可能可以建立索引,但性能可能非常差),修改这种集合性能将会很低。

    因此对于<bag>这种集合,即没有索引字段,同时还不允许元素重复,hibernate无法直接判断元素是否重复,当需要修改集合属性值时,只能先删除全部集合,再重新创建集合,因此性能是最差的。

    所以,对于有序集合属性的增,删,改将会有比较好的性能。(数组也是有序集合,但数组属性不支持延迟加载(因为长度固定),所以数组属性性能其实很低的)

    延迟更新

    对于多对多关联,值数据而言,如果改变Set集合的某个元素,hibernate并不能立即更新该元素对应的数据行。对于Set而言,只有在插入和删除操作时改变才有效。

    反向集合(inverse="true")

    修改Set集合属性性能并不高,但Hibernate还是处处采用了Set集合,这一方面是因为Set更贴近集合语意,

    另一方面,在1-N关联中,1的一端通常都带有inverse="true"属性,即这种关联关系不再由一的一端维护,更新操作将在N的一端处理,这种情况下,无序考虑集合性能。

    映射数据库对象

    最后,还要来看看映射文件映射数据库对象,数据库对象指的是触发器,存储过程等等。Hibernate中使用<database-object>标签来映射数据库对象,用<create><drop>等标签标识具体的数据库操作,

    下面演示映射创建数据表(DDL语句),

    首先要定义一个映射文件,映射文件中可以用<create><drop>等指定具体的操作,然后直接将sql语句写在标签中。还可以添加一些<dialect>之类的标签指定更多属性,例如只在MySQL中有效,

     1 <?xml version="1.0"  encoding="UTF-8"?>    
     2 <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"  
     3 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">  
     4 
     5 <hibernate-mapping>
     6     <database-object>
     7         <create>create table test(t_name varchar(255));</create>
     8         <drop></drop>
     9     </database-object>
    10 </hibernate-mapping>

    此映射文件不需要持久化类,我们直接在测试类中初始化一个Configuration对象并加载配置文件,打开一个SessionFactory,此映射文件就会生效,

    在PersonManager.java中,新增测试方法dbObject()

    1 private static void dbObject() {
    2     //加载数据触发器来创建表
    3     Configuration conf = new Configuration().configure();
    4     conf.addResource("hib/DbObject.hbm.xml");
    5     SessionFactory sf = conf.buildSessionFactory();
    6 }

    注意,通过这种方式创建表,好一定要将hibernate.cfg.xml中的hbm2ddl.auto设置为create才能生效

    1 <property name="hbm2ddl.auto">create</property>

    执行PersonManager.java将会创建一张test表,

    除了上面根据配置文件生成表的方法之外,还可以使用hibernate自带工具SchemaExport(可直接命令行执行), 使用工具的代码如下,

    映射文件保持不变,在PersonManager.java中,将dbObject()方法修改为,

     1 private static void dbObject() {
     2     //加载数据触发器来创建表
     3     Configuration conf = new Configuration().configure();
     4     conf.addResource("hib/DbObject.hbm.xml");
     5     //SessionFactory sf = conf.buildSessionFactory();
     6 
     7     SchemaExport se = new SchemaExport(conf);
     8     se.setFormat(true).setOutputFile("new.sql").create(true, true);
     9     
    10 }

    注意如果通过SchemaExport的方式创建表,hibernate.cfg.xml中的hbm2ddl.auto就不需要强制设置为create了,update也行。

    执行PersonManger.java,也能创建test表。

  • 相关阅读:
    [译]C++如何切分字符串
    Reverse Words in a String
    excel 获取中文拼音首字母
    jquery 获取css position的值
    excel 截取单元格部分内容(从指定位置截取)
    excel 根据单元格内容自动调整列宽
    excel 如何为列添加指定内容(字符串)
    android_handler(二)
    &quot;Simple Factory&quot; vs &quot;Factory Method&quot; vs &quot;Abstract Factory&quot; vs &quot;Reflect&quot;
    HDU 5074 Hatsune Miku 2014 Asia AnShan Regional Contest dp(水
  • 原文地址:https://www.cnblogs.com/fysola/p/6233909.html
Copyright © 2011-2022 走看看