您的位置:首页 > 其它

Hibernate4学习总结(2)--配置形式的集合映射,关联关系映射

2016-03-31 00:52 756 查看
本文包括以下四个部分:

增删改查(CDUR)方法。
集合映射。

关联关系映射。
Inverse属性和cascade属性。

一、增删改查方法

需求:将客户对象保存进数据库。

User.java

package edu.scut.b_curd;
public class User {
private int id;
private String name;
private String password;
private String email;
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 String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", password=" + password
+ ", email=" + email + "]";
}
}
User表



User.hbm.xml

<pre name="code" class="html"><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="edu.scut.b_curd.User" table="t_user">
<!-- 主键 -->
<id name="id" column="t_id">
<generator class="assigned"></generator>
</id>

<!-- 普通属性 -->
<property name="name" column="t_name" type="string" length="20"></property>
<property name="password" column="t_password" length="20"></property>
<property name="email" column="t_email" length="50"></property>
</class>
</hibernate-mapping>




1.1 保存

在事务当中,如果发生异常,就需要回滚,将数据还原为之前的状态。

public void test1(){
//1 获取session对象
Session session = HibernateUtil.getSession();

//2 开启事务
session.beginTransaction();

try {
//3 保存user
User user = new User();
user.setId(2);
user.setName("张三丰");
user.setPassword("666666");
user.setEmail("1156744308@qq.com");

session.save(user);

//4 提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//出现异常,回滚事务
session.getTransaction().rollback();
} finally{
//关闭资源
HibernateUtil.close(session);
}
}


1.2 更新

有两种方式,第一种方式需要对对象的每一项数据都要修改,否则将成为null;第二种只操作需要修改的属性,更为常用。

public void test2(){
//1 获取session对象
Session session = HibernateUtil.getSession();
//2 打开事务
session.beginTransaction();

try {
//3 更新操作,有两种方式
/*
* 第一种方式:
* <1>必须给id赋值;
* <2>hibernate会把所有字段都更新,如果对象的属性不赋值,则设置null
*/
/*User user = new User();
user.setId(1);
user.setName("荆天明");
user.setPassword("666666");
user.setEmail("1156744308@163.com");
session.update(user);
*/

/*
* 第二种方式(推荐的方式)
* <1>先把需要更新的对象查询出来
* <2>参数一:查询的对象
* <3>参数二:ID值
*/
User user = (User) session.get(User.class,1);
//修改需要更新的属性
user.setName("盖聂");
user.setPassword("88888888");

//4 提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//有异常,回滚事务
session.getTransaction().rollback();
} finally{
//5 关闭资源
HibernateUtil.close(session);
}
}


1.3 查询

较常用的是以下三种方式。

public void test3(){
//1 获取session对象
Session session = HibernateUtil.getSession();
//2 打开事务
session.beginTransaction();

try {
//3 查询用户
//<1>查询所有用户,hql
Query query = session.createQuery("from User");
List<User> users = query.list();
for (User user : users) {
System.out.println(user);
}

//<2>查询一个用户
User user = (User) session.get(User.class,1);
System.out.println(user);

//<3>条件查询一个用户
Query q = session.createQuery("select u from User u where name=? ");
q.setParameter(0, "盖聂");
User u = (User) q.uniqueResult();
System.out.println(u);

//4 提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//有异常,回滚事务
session.getTransaction().rollback();
} finally{
//5 关闭资源
HibernateUtil.close(session);
}
}


1.4 删除

两种删除方式,推荐使用第一种。

public void test4(){
//1 获取session对象
Session session = HibernateUtil.getSession();
//2 打开事务
session.beginTransaction();

try {
//3 删除用户
//第一种,先查询出来
User user = (User) session.get(User.class, 1);
if(user!=null){
session.delete(user);
}

//第二种(不推荐)
User user2 = new User();
user2.setId(2);
session.delete(user2);

//4 提交事务
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
//有异常,回滚事务
session.getTransaction().rollback();
} finally{
//5 关闭资源
HibernateUtil.close(session);
}
}


二、集合映射

需求:

客户购物时填写收货地址,收货地址是基本类型,而且有多个,这时应采用集合对地址进行封装。

1.1 Set集合

客户类属性:

private int id;
private String name;

//使用Set集合来存储收货地址:元素无序的
private Set<String> addressSet = new HashSet<String>();
User.hbm.xml

<!-- 映射set集合
name:Set集合的属性名称
table:存储收货地址数据的表
key:配置用户的外键
-->
<set name="addressSet" table="t_address">
<!-- 外键 -->
<key column="u_id"></key>
<!-- Set元素的信息
type:数据类型
column:存放Set的数据字段名称
-->
<element column="address_name" type="string"></element>
</set>

1.2 List集合

客户类属性:

private int id;
private String name;
//使用List集合来存储收货地址:元素是有序的
private List<String> addressList = new ArrayList<String>();
User.hbm.xml

<!-- 映射List集合 -->
<list name="addressList" table="t_address_list">
<!-- 外键 -->
<key column="u_id"></key>
<!-- list的索引字段(排序) -->
<list-index column="idx"></list-index>
<!-- list元素 -->
<element column="address_name" type="string" ></element>
</list>

1.3 Map集合

客户类属性

<pre name="code" class="html">        private int id;
private String name;


//使用Map集合来存储收货地址:元素是无序的 private Map<String, String> addressMap = new HashMap<String, String>();


User.hbm.xml
<!-- 映射Map集合 -->
<map name="addressMap" table="t_address_map">
<!-- 外键 -->
<key column="u_id"></key>
<!-- key元素 -->
<map-key type="string" column="address_no"></map-key>
<!-- value元素 -->
<element type="string" column="address_name"></element>
</map>


三、关联关系映射

本文只对常用的集中映射关系做讲解。

一对多(单向)、多对一(单向)、一对多(双向)这三类映射采用客户(Customers)和订单(Orders)举例子,其中Customers是一方,Orders是多方。

3.1 多对一(单向)

a. 关系映射图解



注意:多对一(单向)要在多方的属性当中加入一方,以此来建立单向关联。

本例中在多方实体类中添加:private Customers customers;

b. Customers.hbm.xml

<hibernate-mapping>
<class name="edu.scut.a_many2one_single.Customers" table="t_customers">
<id name="id" column="c_id">
<generator class="increment"></generator>
</id>

<property name="name" column="c_name"></property>
</class>
</hibernate-mapping>


c. Orders.hbm.xml

<hibernate-mapping>
<class name="edu.scut.a_many2one_single.Orders" table="t_orders">
<id name="id" column="o_id">
<generator class="increment"></generator>
</id>

<property name="orderno" column="o_orderno"></property>

<!-- 配置多对一的关系
cascade:级联操作
save-uodate:保存或者修改订单的同时,修改客户
delete:删除订单的同时删除客户
all:save+update+delete的功能之和
none:默认,没有级联操作
-->
<many-to-one name="customers"
column="c_id"
class="edu.scut.a_many2one_single.Customers"
cascade="all"></many-to-one>
</class>
</hibernate-mapping>


d. 测试类(以save()方法为例)

建立了关系,并且配置了cascade,就可以实现级联操作。

public void test1(){
//打开session
Session session = HibernateUtil.getSession();
//打开事务
s ession.beginTransaction();
//添加用户
Customers customers = new Customers();
customers.setName("东方朔");
//添加订单
Orders o1 = new Orders();
o1.setOrderno("5166001");

Orders o2 = new Orders();
o2.setOrderno("5166002");

//建立关系(orders>>customers)
o1.setCustomers(customers);
o2.setCustomers(customers);

//保存数据
//如果采用了级联操作,直接保存订单,客户也可以保存
//如果不配置相应的级联操作,那么会出现异常:(object references an unsaved transient instance - save the transient )
session.save(o1);
session.save(o2);

//提交事务
session.getTransaction().commit();

//关闭资源
HibernateUtil.close(session);
}


3.2 一对多(单向)

a. 关系映射图解



注意:一对多(单向)要在一方的属性当中加入集合来封装多方数据,以此来建立单向关联。

本例在一方实体类中添加:private Set<Orders> orders = new HashSet<Orders>();

b. Customers.hbm.xml

<hibernate-mapping>
<class name="edu.scut.b_one2many_single.Customers" table="t_customers">
<id name="id" column="c_id">
<generator class="increment"></generator>
</id>

<property name="name" column="c_name"></property>

<!-- 配置一对多的关系
name:属性名称
-->
<set name="orders" cascade="all">
<!-- key:外键字段名称 -->
<key column="c_id"></key>
<!-- set集合的元素类型 -->
<one-to-many class="edu.scut.b_one2many_single.Orders"/>
</set>
</class>
</hibernate-mapping>


c. Orders.hbm.xml

<hibernate-mapping>
<class name="edu.scut.b_one2many_single.Orders" table="t_orders">
<id name="id" column="o_id">
<generator class="increment"></generator>
</id>

<property name="orderno" column="o_orderno"></property>

</class>
</hibernate-mapping>


d. 测试类(以save()方法为例)

建立了关系,并且配置了cascade,就可以实现级联操作。

public void test1(){
//打开session
Session session = HibernateUtil.getSession();
//打开事务
session.beginTransaction();
//添加用户
Customers customers = new Customers();
customers.setName("项羽");
//添加订单
Orders o1 = new Orders();
o1.setOrderno("4326001");

Orders o2 = new Orders();
o2.setOrderno("5436002");

//建立关系(customers>>orders)
customers.getOrders().add(o1);
customers.getOrders().add(o2);

//保存数据
session.save(customers);

//提交事务
session.getTransaction().commit();

//关闭资源
HibernateUtil.close(session);
}


3.3 一对多/多对一(双向)

将一对多(单向)和多对一(单向)同时配置,并建立双向关系就是一会多(双向)。

注意:一对多(双向)要在一方的属性当中加入集合来封装多方数据,并在多方的属性当中加入一方的对象,以此来建立双向关联。

本例在一方实体类中添加:private Set<Orders> orders = new HashSet<Orders>();在多方实体类中添加: private Customers customers;

a. Customers.hbm.xml

<hibernate-mapping>
<class name="edu.scut.c_one2many_double.Customers" table="t_customers">
<id name="id" column="c_id">
<generator class="increment"></generator>
</id>

<property name="name" column="c_name"></property>

<!-- 配置一对多的关系
name:属性名称
-->
<p align="left">                <!-- inverse=true,如果出现在单方的话,表示由多方维护关系,默认是false,表示双方共同维护关系</p><p align="left">          如果双方共同维护关系的话,就会出现如下二种情况:</p><p align="left">          1)SQL多余了,但不出错 -》一对多双向关联</p><p align="left">          2)SQL多余了,但出错    -》多对多双向关联</p><p align="left">            --></p><p align="left"><span style="color:red;">               </span> <set name="orders" cascade="all" inverse="true">
</p>			 <!-- key:外键字段名称 -->
<key column="c_id"></key>
<!-- set集合的元素类型 -->
<one-to-many class="edu.scut.c_one2many_double.Orders"/>
</set>
</class>
</hibernate-mapping>


b. Orders.hbm.xml

<hibernate-mapping>
<class name="edu.scut.c_one2many_double.Orders" table="t_orders">
<id name="id" column="o_id">
<generator class="increment"></generator>
</id>

<property name="orderno" column="o_orderno"></property>

<!-- 配置多对一的关系 -->
<many-to-one name="customers"
column="c_id"
class="edu.scut.c_one2many_double.Customers"
cascade="all"
/>
</class>
</hibernate-mapping>


d. 测试类(以save()方法为例)

建立了双向关系,并且配置了cascade,就可以实现级联操作。

public void test1(){
//打开session
Session session = HibernateUtil.getSession();
//打开事务
session.beginTransaction();
//添加用户
Customers customers = new Customers();
customers.setName("项羽");
//添加订单
Orders o1 = new Orders();
o1.setOrderno("4326001");

Orders o2 = new Orders();
o2.setOrderno("5436002");

//建立双向关系
//客户>>订单
customers.getOrders().add(o1);
customers.getOrders().add(o2);
//订单>>客户
o1.setCustomers(customers);
o2.setCustomers(customers);

//保存数据,保存客户和订单的任意一方,都可级联保存另一方
session.save(customers);

//提交事务
session.getTransaction().commit();

//关闭资源
HibernateUtil.close(session);
}

问题:有了一对多关联之后,保存数据时,会多余两条update语句!

解决方案:在一对多的关联关系配置中,在一方 把inverse="true"即可!

3.4 多对多(双向

多对多(双向)采用老师(Teacher)和学生(Student)举例子。

注意:多对多(双向)要在双方的实体类中同时加入集合封装对方的数据,以此来建立双向关联。多对多(双向)的关联中存在一个中间表,依赖中间表来建立两个表之间的关系。

本例在Student实体类中添加:private Set<Teachers> teachers = new HashSet<Teachers>();

在Teacher实体类中添加: private Set<Students> students = new HashSet<Students>();

a. 关系映射图解



b. Students.hbm.xml

<hibernate-mapping>
<class name="edu.scut.d_many2many_double.Students" table="t_student">
<id name="id" column="s_id">
<generator class="increment"></generator>
</id>

<property name="name" column="s_name"></property>

<!-- 配置多对多的关系
table:中间表的名称
-->
<set name="teachers" table="student_teacher" inverse="true">
<!-- 当前对象所在中间表的外键 -->
<key column="s_id"></key>
<!-- set集合的元素类型 -->
<!-- column:集合类型所在中间表的外键 -->
<many-to-many class="edu.scut.d_many2many_double.Teachers" column="t_id"></many-to-many>
</set>
</class>
</hibernate-mapping>


c. Teachers.hbm.xml

<hibernate-mapping>
<class name="edu.scut.d_many2many_double.Teachers" table="t_teacher">
<id name="id" column="t_id">
<generator class="increment"></generator>
</id>

<property name="name" column="t_name"></property>

<!-- 配置多对一的关系 -->
<set name="students" table="student_teacher" cascade="all">
<!-- 当前对象所在中间表的外键 -->
<key column="t_id"></key>
<!-- set集合类型 -->
<!-- column:集合类型所在中间表的外键 -->
<many-to-many class="edu.scut.d_many2many_double.Students" column="s_id"></many-to-many>
</set>
</class>
</hibernate-mapping>


d. 测试类(以save()方法为例)

建立了双向关系,并且配置了cascade,就可以实现级联操作。

public void test1(){
//打开session
Session session = HibernateUtil.getSession();
//打开事务
session.beginTransaction();

//保存学生
Students s1 = new Students();
s1.setName("小强");
Students s2 = new Students();
s2.setName("小花");

//保存老师
Teachers t1 = new Teachers();
t1.setName("李老师");
Teachers t2 = new Teachers();
t2.setName("卢老师");

//建立双向关系
//学生>>老师
s1.getTeachers().add(t1);
s1.getTeachers().add(t2);
s2.getTeachers().add(t1);
s2.getTeachers().add(t2);

//老师>>学生
t1.getStudents().add(s1);
t1.getStudents().add(s2);
t2.getStudents().add(s1);
t2.getStudents().add(s2);

//保存数据,保存客户和订单的任意一方,都可级联保存另一方
session.save(t1);
session.save(t2);

//提交事务
session.getTransaction().commit();

//关闭资源
HibernateUtil.close(session);
}


问题:在多对多双向关联中,SQL多余了,而且报错。

解决方案:在任的多方把inverse="true"即可!

3.5 一对一(双向

一对一(双向)采用公民和身份证举例子。

注意:一对一(双向)要在双方的实体类中同时加入对方的对象,以此来建立双向关联。

本例在Personst实体类中添加:private IdCards idcards;

在IdCards实体类中添加: private Persons persons;

a. 关系映射图解



b. IdCards.hnm.xml

有两种方式建立一对一(双向)的关系。

<hibernate-mapping>
<class name="edu.scut.e_one2one_double.IdCards" table="t_idcards">
<id name="id" column="i_id">
<generator class="increment"></generator>
</id>

<property name="cardno" column="i_cardno"></property>

<!-- 一对一配置方式有两种 -->
<!-- 第一种:唯一外键
是一种特殊的多选一方式,但是外键多了unique约束
-->
<!-- <many-to-one name="persons"
class="edu.scut.e_one2one_double.Persons"
column="p_id"
unique="true">
</many-to-one> -->

<!-- 第二种:主键关联
constrained:是否把主键作为外键
false:不作为外键
true:作为外键
-->
<one-to-one name="persons"
class="edu.scut.e_one2one_double.Persons"
constrained="true">
</one-to-one>
</class>
</hibernate-mapping>


c. Persons.hbm.xml

<hibernate-mapping>
<class name="edu.scut.e_one2one_double.Persons" table="t_persons">
<id name="id" column="p_id">
<generator class="increment"></generator>
</id>

<property name="name" column="p_name"></property>

<!-- 配置一对一的关系 -->
<one-to-one name="idcards"
class="edu.scut.e_one2one_double.IdCards"
cascade="all">
</one-to-one>
</class>
</hibernate-mapping>


d. 测试类(以save()方法为例)

建立了双向关系,并且配置了cascade,就可以实现级联操作。

public void test1(){
//打开session
Session session = HibernateUtil.getSession();
//打开事务
session.beginTransaction();

//公民
Persons p = new Persons();
p.setName("杨过");

//身份证
IdCards ic = new IdCards();
ic.setCardno("6104271990");

//建立关系
//公民>>身份证
p.setIdcards(ic);

//身份证>>公民
ic.setPersons(p);

//保存数据
session.save(p);

//提交事务
session.getTransaction().commit();

//关闭资源
HibernateUtil.close(session);
}


四、Inverse属性和cascade属性



4.1 Inverse属性

Inverse属性是在维护关联关系的时候起作用的,表示控制权是否转移。

Inverse= false 不反转; 当前方有控制权。

Inverse= True 控制反转; 当前方没有控制权。

默认是 Inverse= false,在一对多(双向)和多对多(双向)的关联关系中,如果不明确配置,则默认Inverse= false,即两边都具有控制权,在执行保存操作的时候,双方能否会维护表。导致一对多(双向)的关联关系出现出现多余的SQL语句,而多对多(双向)关联中直接报错(org.hibernate.exception.ConstraintViolationException:could not execute
statement, Caused by:com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry '7-7' for key 'PRIMARY'),提示中间表有重复的主键。因此,需要自己手动配置Inverse=“true”。

4.2 cascade属性

cascade 表示级联操作(可以设置到一的一方或多的一方)

none:不级联操作, 默认值。
save-update:级联保存或更新。
delete:级联删除。
save-update,delete:级联保存、更新、删除。
all:同上。级联保存、更新、删除。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: