hibernate映射配置:
-------------------------------------------------------------------------------------------------------
集合映射:集合映射,在本质上是一种一对多的映射们只是多的一方并没有持久化类罢了,因此
也就导致了一个结果,就是,如果只是使用集合映射的话,那么那个保存这个集合的表里面就只
能够有一个固定的字段了,比如使用set集合映射,那么set所对应的表里面只能够有两个字段
一个是用来记录外键的,一个是用来记录值的,而如果是list则只能够有三个字段,如果是Map
也只能够有三个字段,但是一对多就不一样了,多的一方虽然在一的一方中虽然也是使用的set
但是因为它有持久化类,所以它可以拥有很多的字段.
以下是集合映射的配置例子:
set集合
<set name="useremails" table="userEmail">
<key foreign-key="id">
<column name="uid"></column>
</key>
<element type="java.lang.String"
column="email"></element>
</set>
list集合
<list name="useremails" table="useremail">
<key foreign-key="id">
<column name="uid"></column>
</key>
<index column="idx" type="java.lang.Integer"></index>
<element column="email"
type="java.lang.String"></element>
</list>
Map集合
<map name="idbagms" table="idbagm">
<key column="id" foreign-key="id"></key>这个地方指的是外
键的生成策略
<map-key type="string" column="position">
</map-key>
<element column="name" type="string"></element>
</map>
三种集合的区别:
set完全可以替换为list但是list是要记录先后顺序的,所以在使用list的时候
还是要对数据表进行一定的修改的,对于要记录顺序的数据表要添加一个字段
就是index字段,它的作用是记录下来元素的添加顺序,而且需要在hibernate
的文件中进行配置,配置的时候把set给变成list,然后提供一个供程序排序的
字段,必须要是integer类型的才可以.
还有可以使用hibernate自带的bag集合,它的特点是可以有重复但是不对它们
进行排序,而set是不可以重复,而list可以重复,因此bag兼顾了这两种特点.
但是呢,因为它的与众不同,所以在使用它的时候要用到的集合也跟它们两个
不一样,而是使用的Collection这个接口,在使用的时候需要实际的类为ArrayList
或者其他的实现类都是可以的,但是一定要注意的一点是:在生成get和set方法
的时候返回的类型使用的不是具体的实现类的类型,而是Collection的类型,否则
就会出错的,而且不容易找到原因,而最简单的做法就是使用MyEclipse自己的
getters和setters的方法自动的帮助我来生成.
当然添加和删除都是一样的就是说在添加的时候使用的什么,那么在输出的时候
也需要使用相同的接口来输出.
在使用bag的时候,在删除对应的重复记录的时候,每一条删除语句只能够删除一条数据
因此如果想把所有的重复语句全部删除的话,需要提供跟插入的语句数相同数目的语句才行.
idBag是bag的扩展,可以为数据提供一个id值.
-------------------------------------------------------------------------------------------------------
组件映射:
在一个类里面如果属性过多的情况下就可以考虑把其他的属性给放入到组件中去映射
例子:
<component name="profile" class="com.dada.foreigh.Profile">
<property name="phone" type="string" column="phone"></property>
<property name="email" type="string" column="email"></property>
</component>
这个component里面包含的是其他的属性,然后就是需要把这些个属性给放入到一个
叫做profile的类里面就可以了.
在主类里面包含一个对profile类的一个引用就够了.
集合映射中是不存在双向关联的,只有在组件映射还有其他的一对一,一对多,多对一
以及多对多中才会有的.
这个时候只能够做到根据主类找到组件类,但是不可以根据组件类而找到父类,这个时候
怎么搞呢?需要在配置文件中加上这样的一句话就是:
<parent name="user"/>配置如下:
<component name="profile" class="com.dada.foreigh.Profile">
<parent name="user"/>
<property name="phone" type="string" column="phone"></property>
<property name="email" type="string" column="email"></property>
</component>
-------------------------------------------------------------------------------------------------------
联合主键映射:
联合组件映射:
<hibernate-mapping>
<class name="com.dada.foreign.Two2" table="two2" catalog="hibernate">
<!-- 要注意的是,在composite中的id和数据库的中的id是不一样的,
设置它的目的在于要确定数据库中的它代表的是数据库中的唯一主键的生成策略,
是单一的主键那么就代表的是单一的,如果是复合主键那么就代表的是复合的多个
列.
-->
<composite-id>
<key-property name="name" type="java.lang.String">
<column name="name" length="11" />
</key-property>
<key-property name="age" type="java.lang.Integer">
<column name="age" />
</key-property>
</composite-id>
<property name="password" type="java.lang.Integer">
<column name="password" />
</property>
</class>
</hibernate-mapping>
-------------------------------------------------------------------------------------------------------
一对一映射:一对一的映射是两个表表之间的关系为一对一,因此它们的特点就是一对一
它们都有持久化类,否则就无法完成对数据库的操作了,只是在配置的时候配置好对应的
标签就好了,它里面又分为两种情况:
1.主键映射,就是另外的一方的主键参照一方的主键来生成.
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="foreign"></generator>
</id>
<one-to-one name="husband" class="com.dada.entities.Husband"
constrained="true"></one-to-one>
在实际的开发过程中可以使用hibernate逆向工程的时候,在被动关联的那一方的主键生成策略设置为
foreign
这样设置好之后它在生成的时候即直接的生成好了.
2.外键映射,它实际上是一对多的特殊情况,设置的时候,在主动关联方设置为<one-to-one>
被动关联方设置为<many-to-one>然后就是被动关联方在设置unique="true",就可以了.
主动方:
<one-to-one name="wife" class="com.dada.entities.Wife" cascade="save-update"></one-
to-one>
被动方:
<many-to-one name="husband" class="com.dada.entities.Husband" fetch="select">
<column name="hushbandid" unique="true"/>
</many-to-one>
-------------------------------------------------------------------------------------------------------
*****表和表之间的关系是通过外键来设定的,而持久化类之间的关系是通过集合或者属性来设定
的.******
--------------------------------------------------------------------------
<many-to-one name="catagory" class="com.dada.entities.Catagory" outer-join="true">
这句话的作用就是在查询多的一方的时候自动的把一的那一方也给查询出来.
一对多是通过集合来体现的所以配置如下:
--------------------------------------------------------------------------
多对一的映射:
<many-to-one name="catagory" class="com.dada.entities.Catagory" outer-join="true">
<column name="catagoryid"></column>
</many-to-one>
其中name代表的是这个实体类中所包含的那个1的一方的引用的变量名称,class指的是它的位置
column指的是本实体所对应的在数据库中的表所被指定的外键的列名称.
--------------------------------------------------------------------------
一对多映射:
<set name="products">
<key column="catagoryid" />
<one-to-many class="com.dada.entities.Product" />
</set>
这里的name也是值的在本实体类中的多的那一方的引用的变量名,key指的是在对方的实体
中代表
外键的那个列的名字,而下面就没有什么了.
--------------------------------------------------------------------------
如果想要对事物进行重新的更改之后再去查询与它相关的内容的话,就应该使用两个事务
第一个事务用来进行修改,第二个事务用来进行读取.
一般情况下cascade使用的都是save-update这个选项.
--------------------------------------------------------------------------
插入多条记录
在使用一对多的双向关联的时候,会发现先在进行插入的操作的时候,插入的语句会多出几条
多出的语句的数量跟插入的多方的记录条数是相等的,底层实现的原理是
在第一次插入多方的记录的时候,hibernate默认的是插入的外键值为空,然后等到都插入好的
时候再把外键值给修改update为一方的那个主键值,因此就会多出一条语句来.
如果想要去掉那多余的几条语句的话就需要在多的一方的<set>标签内设置invers="true"
这样的话,在插入的时候,多的一方就知道他的外键值了,因此在插入的时候就直接给外键赋值了.
--------------------------------------------------------------------------
一对一关联
一对一的关联其实完全可以使用一张表来表示,比如:用户表
userid,username,password,age,birthday,phone,mobile,address;
把它拆分开为:只保存用户最基本的最常用的信息:user表
userid,username,password;
不常用的不经常修改的信息:detail表
userid,age,birthday,phone,mobile,address;
但是为什么会出现一对一呢?这主要是为了性能的考虑,如果把不经常使用的表也放进这个表里面
效率是非常差的,比如detail表,它里面保存的信息,很少被使用,也更少被修改因此最好在使用到
它的时候才去读取它,对它进行操作,这个时候呢就可以使用一对一的关联了.
配置文件的设置:
主动关联配置文件
<one-to-one name="profile1to1" class="com.dada.entities.Profile1to1">
</one-to-one>
被动关联配置文件
被动关联文件的主键生成策略,由主动关联表来提供:
<id name="uid" type="java.lang.Integer">
<column name="uid" />
<generator class="foreign">
<param name="property">user1to1</param>
</generator>
</id>
一对一的关系双向关联只需要设置好从表的主键生成策略,然后设置好<one-to-one>标签就好了.
<one-to-one name="user1to1" class="com.dada.entities.User1to1"></one-to-one>
一对一关联的唯一外键关联--->是多对一的特殊的情况,因此它的设置是在主动关联hbm文件里面设置
的
是<one-to-one>的标签,而在被动关联的hbm文件里面设置的是<many-to-one>这个标签,这个时候
呢
在这个标签中加上unique="true"就可以了.
这个时候两个表中都是由主键的,并且被动关联表里面有一个外键.
--------------------------------------------------------------------------
多对多的表之间的关联的查询是很耗内存的.
单相关联只需要配置这其中的一个就可以了,如果是双向的关联就需要把这两个都配置了
就是说,你中有我,我中有你的意思.
<set name="goods" table="goodorder">
<key column="orderid"></key>
<many-to-many class="com.dada.entities.Goods" column="goodid"/>
</set>
配置的解释:name指的是这个映射文件所对应的类里面的对对方引用的集合的名称,table指
的是中间表的名称,<key>标签指的是本映射所代表的表里面的主键在中间表中所对应的列名
下面class指的是对方类的位置,column指的是对方的表的主键在中间表中的对应列的名称.
<set name="order1s" table="goodorder">
<key column="goodid"></key>
<many-to-many class="com.dada.entities.Order1" column="orderid"></many-to-
many>
</set>
需要注意的是,如果设置的是双向关联的话,那么就这样设置就好了:
<set name="goods" table="goodorder">
<key column="orderid"></key>
<many-to-many class="com.dada.entities.Goods" />
</set>
<set name="order1s" table="goodorder">
<key column="goodid"></key>
<many-to-many class="com.dada.entities.Order1" />
</set>
为什么这么设置呢?因为现在是双向关联,所以呢每一个关联只需要设置好自己的
<key>标签就可以了.
但是上面这种一对多会出现一个问题就是无法记录购买商品的数量,商品的价格也是随时变化
的,因此这个时候需要对中间表进行扩充,因为原来的方式是无法向这种带有中间表的
多对多里面插入其他的值的,因此就需要重新的多一个类出来,就是中间表类,这个时候这个类
所包含的字段就不再是一个了,而是很多的,任意的字段,它的作用就是作为两个一对多的中间
表,而不只是记录了以个多对多中两个表的主键的表了.
多对多被拆分为两个一对多:
使用程序自动提供的类来生成会有四个类,一个类用来生成联合主键
这个时候把不经常使用的那一方的关联给去掉,然后在使用它的时候,要先生成多对多的表里面的
数据然后再生成中间表里面的数据,生成是有顺序的,这个时候主动关联表的配置如下:
<set name="productusers" inverse="true">
<key>
<column name="userid" />
</key>
<one-to-many class="com.dada.entities.Productuser" />
</set>
被动关联表的配置:把set标签去掉就行了
中间表配置:
<class name="com.dada.entities.Productuser" table="productuser"
catalog="hibernate">
<composite-id name="id" class="com.dada.entities.ProductuserId">
<key-many-to-one name="user" class="com.dada.entities.User">
<column name="userid" />
</key-many-to-one>
<key-many-to-one name="product" class="com.dada.entities.Product">
<column name="productid" />
</key-many-to-one>
<key-property name="price" type="java.lang.Integer">
<column name="price" />
</key-property>
</composite-id>
<many-to-one name="product" class="com.dada.entities.Product" update="false"
insert="false" fetch="select">
<column name="productid" />
</many-to-one>
<many-to-one name="user" class="com.dada.entities.User" update="false"
insert="false" fetch="select">
<column name="userid" />
</many-to-one>
</class>
插入的顺序如下:
@Test
public void addUser() {
Session session = sf.getCurrentSession();
Transaction tx = session.beginTransaction();
User u = new User();
u.setName("dada");
Product p = new Product();
p.setName("lenovo");
p.setDiscription("computer");
ProductuserId pui = new ProductuserId();
pui.setPrice(300);
pui.setProduct(p);
pui.setUser(u);
Productuser pu = new Productuser();
pu.setId(pui);
pu.setUser(u);
pu.setProduct(p);
session.save(u);
session.save(p);
session.save(pu);
tx.commit();
}
--------------------------------------------------------------------------
表的自身可以给自身设置外键的.