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

来源:互联网 发布:淘宝情趣内衣买家秀图 编辑:程序博客网 时间:2024/05/16 02:01

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 在集合的各数据行中是如何进行“定位”的。)

阅读全文
0 0