hibernate学习之第九篇

news/2024/7/5 9:33:04

hibernate中的集合类型

引入:
Hibernate可以持久化以下java集合的实例, 包括java.util.Map, java.util.Set, java.util.SortedMap, java.util.SortedSet, java.util.List, 和任何持久实体或值的数组。类型为java.util.Collection或者java.util.List的属性还可以使用"bag"语义来持久。

警告:用于持久化的集合,除了集合接口外,不能保留任何实现这些接口的类所附加的语义(例如:LinkedHashSet带来的迭代顺序)。所有的持久化集合,实际上都各自按照 HashMap, HashSet, TreeMap, TreeSet 和 ArrayList 的语义直接工作。更深入地说,对于一个包含集合的属性来说,必须把Java类型定义为接口(也就是Map, Set 或者List等),而绝不能是HashMap, TreeSet 或者 ArrayList。 存在这个限制的原因是,在你不知道的时候,Hibernate暗中把你的Map, Set 和 List 的实例替换成了它自己的关于Map, Set 或者 List 的实现。 (所以在你的程序中,谨慎使用==操作符。)(译者说明: 为了提高性能等方面的原因,在Hibernate中实现了几乎所有的Java集合的接口 。)

集合实例在数据库中根据指向对应实体的外键而得到区别。这个外键被称为集合的关键字在Hibernate配置文件中使用<key> 元素来映射这个集合的关键字。

集合可以包含几乎所有的Hibernate类型, 包括所有的基本类型, 自定义类型,实体类型和组件。 集合不能包含其他集合。这些被包含的元素的类型被称为集合元素类型。 集合的元素在Hibernate中被映射为<element>, <composite-element>, <one-to-many>, <many-to-many> 或者 <many-to-any>。
set集合类型用的比较多。
这里举得例子是部门和员工的关系。我们知道部门和员工是一对多的关系。
员工类的源代码如下:

public class Employee {
        private int id;
        private String name;
        private Department depart;

        @Override
        public String toString() {
                return "id=" + this.id + " name=" + this.name;
        }

        public int getId() {
                return id;
        }

        public void setId(int id) {
                this.id = id;
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }

        public Department getDepart() {
                return depart;
        }

        public void setDepart(Department depart) {
                this.depart = depart;
        }
}

 

员工的映射文件:

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
        package="hibernate.collections">

    <class name="Employee" >
        <id name="id">
            <generator class="native"/>
        </id>
        <property name="name" unique="true"/>
        <many-to-one name="depart" column="depart_id"/>
    </class>
</hibernate-mapping>

 

充:hibernate不允许多的这一端放弃对关系的维护。即many-to-one没有inverse=“true”这样的配置。
部门类的源代码如下:

 

public class Department {
        private int id;
        private String name;

        private Set<Employee> emps;

        // private List<Employee> emps;

        // private Map<String, Employee> emps;

        // private Employee[] emps;

        public int getId() {
                return id;
        }

        public void setId(int id) {
                this.id = id;
        }

        public String getName() {
                return name;
        }

        public void setName(String name) {
                this.name = name;
        }

        public Set<Employee> getEmps() {
                return emps;
        }

        public void setEmps(Set<Employee> emps) {
                this.emps = emps;
        }
}

 

部门类的映射文件department.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.collections">

        <class name="Department">
                <id name="id">
                        <generator class="native" />
                </id>
                <property name="name"/>

                <set name="emps" inverse="true">
                        <key column="depart_id"/>
                        <one-to-many class="Employee" />
                </set>
        </class>

</hibernate-mapping>

 

测试代码:

public class Main {
public static void main(String[] args){
    Department depart = new Department();
    depart.setName("depart");

    Employee e1 = new Employee();
    e1.setName("e1");
    e1.setDepart(depart);

    Employee e2 = new Employee();
    e2.setName("e2");
    e2.setDepart(depart);
  
    Set<Employee> emps = new HashSet<Employee>();
    emps.add(e1);
    emps.add(e2);
    depart.setEmps(emps);

    Session s = HibernateUtil.getSession();
    Transaction tx = s.beginTransaction();
    s.save(e1);
    s.save(e2);
    s.save(depart);
tx.commit();
}
}

 

执行后hibernate执行的sql语句如下:

Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Employee (name, depart_id) values (?, ?)
Hibernate: insert into Department (name) values (?)
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set name=?, depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
Hibernate: update Employee set depart_id=? where id=?
 



以上用的是set集合类型,它具有这样的特性:无重复和没有顺序。
但有时候我们需要记住元素的顺序,这时就可以采用list来保存元素。同样,在hibernate中有相应的List标签与之对应。他可以在保存的时候记住保存的顺序。例如,部门可以对其员工加入的先后进行记录。读取时,就会按照先后的顺序来获得。
只需在deparment类中把集合类型改用List,同时修改deparment.hbm.xml文件中的set标签:
                         <list name="emps">
                        <key column="depart_id" />
                        <list-index column="order_col" /> //该子元素用于记录保存的顺序,在对象模型中不存在,hibernate会在表中加入一列order_col
                        <one-to-many class="Employee" />
                     </list>
测试代码只需把set改为是有List即可,其他部分不变。

hibernate帮助生成的表结构为:
+---+-------+-----------+-----------+
| id |name |depart_id|order_col|
+----+------+-----------+-----------+
|  1  | e1    |         1    |         0    |
|  2  | e2    |         1    |         1    |
+----+------+-----------+-----------+

有时候,我们虽然在java代码中试用了List集合类型,但我们保存时并不需要记住保存的先后顺序,这时可以用bag标签代替。
<bag name="employees" order-by="id desc">  //不关心顺序,与java代码中的list对应。
    <key column="depart_id"/>
    <one-to-many class="Employee"/>
</bag>
查看表结构为:
+----+------+-----------+
| id | name | depart_id |
+----+------+-----------+
|  1  | e1    |         1    |
|  2  | e2    |         1    |
+----+------+-----------+

map在java中也是一种常用的集合类型。假设员工的名字是不一样的,可以把员工的名字作为键,员工作为map的值。
department类修改为:
public class Department {
        private int id;
        private String name;
        private Map<String, Employee> emps;
}
department.hbm.xml配置文件修改:
                <map name="emps">
                        <key column="depart_id" />
                        <map-key type="string" column="name"/>
                        <one-to-many class="Employee" />
                </map>
测试代码只需把集合类型做相应的改变即可,生成的表结构为:
department表;
+----+--------+
| id | name   |
+----+--------+
|  1 | depart |
+----+--------+
employee表:
+----+------+-----------+
| id | name |depart_id|
+----+------+-----------+
|  1   | e1   |         1    |
|  2   | e2   |         1    |
+----+------+-----------+

介绍了这么多的集合类型,那么我们在实际运用中该如何选呢?
简单使用原则:大部分情况下使用set,需要保证集合中的顺序用list,想用java.util.List又不需要保证顺序用bag。

这些集合类都是Hibernate实现的类和JAVA中的集合类不完全一样,set,list,map分别和java中的set,list,map接口对应,bag映射成java的list;这些集合的使用和java集合中对应的接口基本一致;

注意:在java的实体类中集合只能定义成接口不能定义成具体类,因为集合会在运行时被替换成Hibernate的实现。为了实现懒加载 ,hibernate把java中的集合类都重新给予了实现。你在java中使用的集合类,在保存时hibernate内部进行了替换,使用的是内置的hibernate集合。所以你在程序中用你的集合类进行强制类型转换会出错。

比如下面代码:

static void query(int id) {
        String hql = "from deparment";
        Session s = HibernateUtil.getSession();
        Transaction tx = s.beginTransaction();
        Department depart = (Department)s.get(Department.class, id);
        System.out.println();
        System.out.println(depart.getEmps());
       
    }

 

在主函数中调用该段代码打印输出:{e1=id=1 name=e1, e2=id=2 name=e2}

将以上代码的打印语句改为:System.out.println((HashMap) depart.getEmps());
把它进行强制类型转换,再运行则会报错
出错信息为:Exception in thread "main" java.lang.ClassCastException: org.hibernate.collection.PersistentMap cannot be cast to java.util.HashMap

正如上面所指出的,hibernate对java中的集合类有自己的替代实现,对于hashmap是org.hibernate.collection.PersistentMap,该类继承了java中的Map类。在我们调用session的save语句后,hibernate会将实际的HashMap进行替换,实际上程序使用的是hibernate的自身实现。所以在程序中,再用HashMap进行强制类型转换就会报错。 但是用Map就可以,因为persistentMap是Map的子类。即执行:System.out.println((Map) depart.getEmps());就不会报错。所以在程序中尽量使用java接口,这也符合面向接口编程的道理。


http://www.niftyadmin.cn/n/2864064.html

相关文章

Redis——集群方案之redis cluster的搭建部署

一.redis的集群之redis cluster的概念 对于Redis集群方案有好多种&#xff0c;基本常用的就是twemproxy&#xff0c;codis&#xff0c;redis cluster这三种解决方案。 本文介绍redis cluster。 上篇博文实现redis的高可用&#xff0c;针对的主要是master宕机的情况&#xff…

hibernate学习之第十篇

级联和关系维护 Cascade 用来说明当对主对象进行某种操作时&#xff0c;是否对其关联的从对象也作类似的操作&#xff0c;常用的cascade&#xff1a;none,all,save-update,delete,lock,refresh,evict,replicate,persist,merge,delete-orphan(one-to-many).一般对many-to-many&…

Redis——基于lamp架构做mysql的缓存服务器和配置gearman实现数据同步

一.前言 对一个关系型数据库进行调优以获得高查询性能可能会比较困难。如果对数据模型优化和对查询调优不起作用&#xff0c;DBA就可以使用缓存系统&#xff0c;比如Redis&#xff0c;它是一个可以提供内存和永久数据存储的键值数据存储系统。 由于Redis能够将数据快速读写至…

hibernate学习之第十一篇(1)

hibernate的继承映射 《一》一张表映射一棵继承树 使用discriminator&#xff08;鉴别标志&#xff09; 类Worker和Farmer都继承自Person 类Person的源代码如下&#xff1a; package hibernate.extend; public class Person { private int id; private String name; private…

Redis——redis集群方案之codis集群的搭建部署

一.什么是codis集群 codis集群简介 Codis是一个分布式的Redis解决方案&#xff0c;对于上层的应用来说&#xff0c;连接Codis Proxy和连接原生的Redis Server没有明显的区别&#xff08;不支持的命令列表&#xff09;&#xff0c;上层应用可以像使用单机的Redis一样使用&#…

hibernate学习之第十一篇(2)

《二》每个子类映射到一张表&#xff08;joined-subclass&#xff09; 配置文件修改为&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" &qu…

MFS——分布式文件系统的安装与部署

一.什么是MFS MFS简介 分布式文件系统是指文件系统管理的物理存储资源通过计算机网络与各节点相连。简单讲&#xff0c;就是把一些分散的共享文件夹&#xff0c;集合到一个文件夹内。对于用户来说&#xff0c;只需要打开该虚拟文件夹&#xff0c;就可以使用这些分散的文件夹进…

hibernate学习之第十二篇

《三》混合使用“一个类继承体系一张表”和“每个子类一张表” 比如上面的例子&#xff0c;worker类可能属性很少&#xff0c;而farmer属性却很多&#xff0c;把两者都与person放在同一张表中&#xff0c;则显得表的 结构不是很合理&#xff0c;会有很多字段是null。所以我们可…