Hibernate学习---第六节:数组&list&map&set的映射配置

1、实体类,代码如下:

package learn.hibernate.bean;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 持久化类设计
 * 注意:
 *         持久化类通常建议要有一个持久化标识符(ID)
 *         持久化标识符通常建议使用封装类(例如:Integer  因为基本类型存在默认值)
 *         持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的)
 *         属性通常建议提供  getter/setter 方法
 *         持久化类不能使用 final 修饰
 *         持久化类中如果使用了集合类型数据,只能使用集合所对应的接口类型来声明(List/Map/Set)
 *              如下:ArrayList list = new ArrayList();  不行
 *                 List list = new ArrayList(); 可行
 */
public class Person {

    private Integer id;
    private String name;
    private int age;
    private int passwork;
    private Date birthday;
    /**
     * 数组  同构类型数据 (效率低)
     * 通过 下标 访问数组中的元素
     */
    private String[] myArr;
    /**
     * List
     * 通过 下标 访问数组中的元素
     */
    private List myList;
    /**
     * 通过 key 访问value
     */
    private Map myMap;
    /**
     * 只有值本身
     */
    private Set mySet;

    public Person() {

    }

    public Person(String name, int age, int passwork, Date birthday) {
        super();
        this.name = name;
        this.age = age;
        this.passwork = passwork;
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "Person [id=" + id + ", name=" + name + ", age=" + age
                + ", passwork=" + passwork + ", birthday=" + birthday + "]";
    }

    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getPasswork() {
        return passwork;
    }
    public void setPasswork(int passwork) {
        this.passwork = passwork;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String[] getMyArr() {
        return myArr;
    }

    public void setMyArr(String[] myArr) {
        this.myArr = myArr;
    }

    public List getMyList() {
        return myList;
    }

    public void setMyList(List myList) {
        this.myList = myList;
    }

    public Map getMyMap() {
        return myMap;
    }

    public void setMyMap(Map myMap) {
        this.myMap = myMap;
    }

    public Set getMySet() {
        return mySet;
    }

    public void setMySet(Set mySet) {
        this.mySet = mySet;
    }

}

2、映射文件,代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="learn.hibernate.bean">
    <class name="Person" table="t_person">
        <id name="id" column="person_id">
            <generator class="native"/>
        </id>
        <property name="name" column="t_name"/>
        <property name="age"/>
        <property name="passwork"/>
        <property name="birthday"/>
        <!-- 数组的映射配置  table 可选-->
        <array name="myArr" table="t_array">
            <!--
                t_array 表保存数组中的数据,需要和 t_person 表建立关联关系(一对多),所有需要一个 key
                list-index 指定数组下标存储列的映射
                element 表示数组中的元素存储列的映射
             -->
            <key column="id"/>
            <list-index column="arr_indexs"/>
            <element column="arr_values"/>
        </array>
        <!-- list 的映射配置 list 和 array 一样-->
        <list name="myList">
            <key column="id"/>
            <list-index column="list_indexs"/>
            <element column="list_values"/>
        </list>
        <!-- map 的映射配置 -->
        <map name="myMap">
            <!--
                map-key 指定 map 集合的 key 数据存储的列映射,并指定类型
                element 表示 map 中的元素存储列的映射
             -->
            <key column="id"/>
            <map-key column="map_keys" type="string"/>
            <element column="map_values"/>
        </map>
        <!-- set 的映射配置
            set没有下标和 key,只需要元素即可
         -->
        <set name="mySet">
            <key column="id"/>
            <element column="set_values"/>
        </set>
    </class>
</hibernate-mapping>

3、测试代码:

package learn.hibernate.test;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import learn.hibernate.bean.Person;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.ServiceRegistryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestHibernate {

    SessionFactory factory = null;
    Session session = null;
    Transaction tx = null;

    /**
     * 测试之前初始化数据
     * @throws Exception
     */
    @SuppressWarnings("deprecation")
    @Before
    public void setUp() throws Exception {
        System.out.println("---------初始化数据----------");

        Configuration config = new Configuration().configure();
        ServiceRegistry sr = new ServiceRegistryBuilder()
        .applySettings(config.getProperties()).buildServiceRegistry();
        factory = config.buildSessionFactory(sr);
        session = factory.openSession();
    }

    /**
     * 测试之后释放(销毁)数据
     * @throws Exception
     */
    @After
    public void tearDown() throws Exception {
        System.out.println("---------释放数据----------");
        if(session.isOpen()){
            session.close();
        }
    }

    @Test
    public void testAdd(){
        Person p = new Person("June",22,123456,new Date());

        String[] myArr = {"A","B","C","D"};

        List myList = new ArrayList();
        myList.add("北京");
        myList.add("上海");
        myList.add("长沙");
        myList.add("深圳");

        Map myMap = new HashMap();
        myMap.put(1, "中国");
        myMap.put(2, "湖南");
        myMap.put(3, "郴州");
        myMap.put(4, "桂阳");

        Set mySet = new HashSet();
        mySet.add("跑步");
        mySet.add("游泳");
        mySet.add("篮球");

        p.setMyArr(myArr);
        p.setMyList(myList);
        p.setMyMap(myMap);
        p.setMySet(mySet);

        tx = session.beginTransaction();
        session.persist(p);
        tx.commit();
    }
}

4、测试,会发现报错:

org.hibernate.MappingException: No type name
    at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:319)
    at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:310)
    at org.hibernate.mapping.Collection.validate(Collection.java:315)
    at org.hibernate.mapping.IndexedCollection.validate(IndexedCollection.java:89)
    at org.hibernate.cfg.Configuration.validate(Configuration.java:1362)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1849)
    at learn.hibernate.test.TestHibernate.setUp(TestHibernate.java:44)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

java.lang.NullPointerException
    at learn.hibernate.test.TestHibernate.tearDown(TestHibernate.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

原因是没有给映射文件中的字段指定数据类型

修改映射文件,代码如下:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="learn.hibernate.bean">
    <class name="Person" table="t_person">
        <id name="id" column="person_id">
            <generator class="native"/>
        </id>
        <property name="name" column="t_name"/>
        <property name="age"/>
        <property name="passwork"/>
        <property name="birthday"/>
        <!-- 数组的映射配置  table 可选-->
        <array name="myArr" table="t_array">
            <!--
                t_array 表保存数组中的数据,需要和 t_person 表建立关联关系(一对多),所有需要一个 key
                list-index 指定数组下标存储列的映射
                element 表示数组中的元素存储列的映射
             -->
            <key column="id"/>
            <list-index column="arr_indexs"/>
            <element type="java.lang.String" column="arr_values"/>
        </array>
        <!-- list 的映射配置 list 和 array 一样-->
        <list name="myList">
            <key column="id"/>
            <list-index column="list_indexs"/>
            <element type="java.lang.String" column="list_values"/>
        </list>
        <!-- map 的映射配置 -->
        <map name="myMap">
            <!--
                map-key 指定 map 集合的 key 数据存储的列映射,并指定类型
                element 表示 map 中的元素存储列的映射
             -->
            <key column="id"/>
            <map-key type="java.lang.String" column="map_keys"/>
            <element type="java.lang.String" column="map_values"/>
        </map>
        <!-- set 的映射配置
            set没有下标和 key,只需要元素即可
         -->
        <set name="mySet">
            <key column="id"/>
            <element type="java.lang.String" column="set_values"/>
        </set>

        <!-- bag 可以重复存放数据,但是修改和删除的时候没有 id 值,所以不知道具体是哪一条,所以会将全部数据删除,重新插入新数据 -->
        <!-- <bag name="items" table="t_item">
            <key column="id"/>
            <element type="java.lang.String" column="name"/>
        </bag> -->

        <!-- bag 的一个升级  数据带ID -->
        <!-- <idbag name="items" table="t_item">
            <collection-id type="java.lang.String" column="cid">
                <generator class="uuid.hex"/>
            </collection-id>
            <key column="id"/>
            <element type="java.lang.String" column="name"/>
        </idbag> -->
    </class>
</hibernate-mapping>

所有的有序集合类(maps,lists,arrays)都拥有一个由 <key> 和 <index> 组成的主键。这种情况下集合类的更新是非常高效的 — 主键已经被有效的索引,因此当 Hibernate 试图更新或删除一行时,可以迅速找到该行数据。

集合(sets)的主键由 <key> 和其他元素字段构成。对于有些元素类型来说,这很低效,特别是组合元素或者大文本、大二进制字段;数据库可能无法有效的对复杂的主键进行索引。另一方面,对于一对多、多对多关联,特别是合成的标识符来说,集合也可以达到同样的高效性能。( 附注:如果你希望 SchemaExport 为你的 <set> 创建主键,你必须把所有的字段都声明为 not-null="true"。)

<idbag> 映射定义了代理键,因此它总是可以很高效的被更新。事实上,<idbag> 拥有着最好的性能表现。

Bag 是最差的。因为 bag 允许重复的元素值,也没有索引字段,因此不可能定义主键。 Hibernate 无法判断出重复的行。当这种集合被更改时,Hibernate 将会先完整地移除 (通过一个(in a single DELETE))整个集合,然后再重新创建整个集合。因此 Bag 是非常低效的。

请注意:对于一对多关联来说,“主键”很可能并不是数据库表的物理主键。但就算在此情况下,上面的分类仍然是有用的。(它仍然反映了 Hibernate 在集合的各数据行中是如何进行“定位”的。)

文字部分来自:

http://ears.iteye.com/blog/1508557

也可以查看:

http://www.cnblogs.com/otomedaybreak/archive/2012/01/18/2325993.html

时间: 2024-10-13 08:56:26

Hibernate学习---第六节:数组&list&map&set的映射配置的相关文章

Linux学习第六节课-用户、组合权限

Linux学习第六节课 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- 三十四.安全3A 认证Authentication 授权Authorization 审计Accounting 三十五.用户和组的配置文件 /etc/pas

《Hibernate学习笔记之三》:联合主键的映射

<Hibernate学习笔记之三>:联合主键的映射 就如在前面所举的例子一样,是使用的id作为唯一的主键,一般情况下我们也只使用唯一的一个属性作为主键,但是在实际中,我们可能会遇到几个属性作为主键的情况,因此,在本篇博文中,就来介绍下,联合主键的映射关系应该如何来做?? 联合主键的映射有两种方式来进行实现. 1.使用映射文件 XXX.bhm.xml 2.使用Annotation Hibernate首先需要使用联合主键的实体类必须实现Serializable接口,即为了使序列能够被序列化进行传输

Hibernate学习---第七节:关联关系

一.关联关系一对一外键(双向) 1.实体类,代码如下: package learn.hibernate.bean; import java.util.Date; /** * 持久化类设计 * 注意: * 持久化类通常建议要有一个持久化标识符(ID) * 持久化标识符通常建议使用封装类(例如:Integer 因为基本类型存在默认值) * 持久化类通常建议手动添加一个无参构造函数 (因为有些操作是通过放射机制进行的) * 属性通常建议提供 getter/setter 方法 * 持久化类不能使用 fi

Hibernate学习---第五节:普通组件和动态组件

一.普通组件映射配置 1.创建组件类,代码如下: package learn.hibernate.bean; /** * 组件类 */ public class Phones { private String companyPhone; private String homePhone; private String personalPhone; public Phones() { } public Phones(String companyPhone, String homePhone, St

Hibernate学习---第十一节:Hibernate之数据抓取策略&amp;批量抓取

1.hibernate 也可以通过标准的 SQL 进行查询 (1).将SQL查询写在 java 代码中 /** * 查询所有 */ @Test public void testQuery(){ // 基于标准的 sql 语句查询 String sql = "select * from t_person"; // 通过 createSQLQuery 获取 SQLQuery,而 SQLQuer 是 Query的子类 SQLQuery query = session.createSQLQue

Hibernate学习(六) HQL

Hql语句学习: (1)Hql初步认识 ① Hql是面向对象查询语言,查询时用的是类名和属性名:Sql 查询时用的是表名和字段名 ② 大小写敏感 ③ 包名:如果类名没有重复的话,不用写包名,如果不同包下面有相同的类,那么需要加包名. (2)hql使用 a. 获取唯一值 String hql="select count(*) from Student"; Query q=session.createQuery(hql); Number number=(Number) q.uniqueRe

Hibernate学习---第四节:一级缓存

一.Hibernate 一级缓存的概念: 一级缓存生命周期很短与 session 生命周期一致,所以一级缓存也叫 session 级缓存或事务级缓存.位于缓存中的对象处于持久化状态,它和表中的相关记录对应,session 能够在某些时间点,按照缓存中持久化对象的属性变化来同步数据库中表的记录,这一过程称为清理缓存. (1).一级缓存实现原理.session 缓存是由它的实现类 sessionImpl 中定义的一些集合属性构成的,原理是保证有一个引用在关联着某个持久化对象,保持它的生命周期不会结束

Hibernate学习笔记(六) — Hibernate的二级缓存

我们知道hibernate的一级缓存是将数据缓存到了session中从而减少与数据库的交互.那么二级缓存呢? 一.应用场合 比如,在12306购票时,需要选择出发地与目的地,如果每点一次都与数据库交互一次,这就很不合适,这些地点数据在相当长的一段时间内是不会发生变化的(山东省在相当长的时间内还叫山东省),所以应该缓存起来,没必要每次都与数据库交互,而且该类数据安全性也不是很高. 适合二级缓存的数据: 在现代软件开发中,确实存在一类数据没有什么私有性,为公开的数据,数据基本上不发生变化,该数据保密

前端学习(39)~js学习(十六):数组

数组简介 数组(Array)是属于内置对象,我们可以在MDN网站上查询各种方法. 数组和普通对象的功能类似,也是用来存储一些值的.不同的是: 普通对象是使用字符串作为属性名的,而数组是使用数字来作为索引来操作元素.索引:从0开始的整数就是索引. 数组的存储性能比普通对象要好.在实际开发中我们经常使用数组来存储一些数据,使用频率非常高. 数组中的元素可以是任意的数据类型,也可以是对象,也可以是函数,也可以是数组.数组的元素中,如果存放的是数组,我们就称这种数组为二维数组. 接下来,我们讲一讲数组的