*************
City.java
************
package blog.hibernate.domain;
public class City {
private int id;
private String name;
private String postcode;
private Nation nation;
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
public Nation getNation() {
return nation;
}
public void setNation(Nation nation) {
this.nation = nation;
}
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;
}
}
*************
City.hbm.xml
************
*************
Nation.java
************
package blog.hibernate.domain;
import java.util.Map;
public class Nation {
private int id;
private String name;
private Map citys;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public Map getCitys() {
return citys;
}
public void setCitys(Map citys) {
this.citys = citys;
}
}
*************
Nation.hbm.xml
************
*************
hibernate.cfg.xml
************
org.gjt.mm.mysql.Driver
jdbc:mysql://localhost:3306/hibernate
root
1234
org.hibernate.dialect.MySQLDialect
create
true
*************
HibernateUtil.java
************
package blog.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
public final class HibernateUtil {
private static SessionFactory sessionFactory;
private HibernateUtil(){}
static{
Configuration cfg = new Configuration();
sessionFactory = cfg.configure("hibernate.cfg.xml").buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
public static Session getSession(){
return sessionFactory.openSession();
}
}
*************
junit test
************
package juint.test;
import blog.hibernate.domain.Nation;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.BeforeClass;
import org.junit.Test;
import blog.hibernate.HibernateUtil;
import blog.hibernate.domain.City;
import java.util.HashMap;
import java.util.Map;
public class Many2OneAndOne2Many {
@BeforeClass
public static void setUpBeforeClass() throws Exception {
}
@Test
public void test() {
Map_Add();
}
public void Map_Add() {
Session session = null;
Transaction tx = null;
try {
City city1 = new City();
city1.setName("中国·唐山");
city1.setPostcode("063009");
City city2 = new City();
city2.setName("中国·天津");
city2.setPostcode("356148");
Map citys = new HashMap();
citys.put("唐山", city1);
citys.put("天津", city2);
Nation nation = new Nation();
nation.setName("中国");
nation.setCitys(citys);
//当Nation.hbm.xml文件中map节点的inverse = "false"或不写时(即默认,false)
//这行代码的作用是Hibernate可以根据nation中的citys去更新city表中的CITYNAME
//如果没有setCitys则city表中的CITYNAME为null
//当Nation.hbm.xml文件中map节点的inverse = "true"时不起作用
city1.setNation(nation);
city2.setNation(nation);
session = HibernateUtil.getSession();
tx = session.beginTransaction();
session.save(nation);
session.save(city1);
session.save(city2);
tx.commit();
} catch (Exception ex) {
Logger.getLogger(Many2OneAndOne2Many.class.getName()).log(Level.SEVERE, null, ex);
if (tx != null) {
tx.rollback();
}
} finally {
if (session != null) {
session.close();
}
}
}
}
---------------------------------------------------------------------------------------------------------------------------------------
注意:
City.hbm.xml中
属性name 不为空:
属性nation 不为空:
Nation.hbm.xml中
属性name 不为空:
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
类Many2OneAndOne2Many中的Map_Add()方法中的代码:nation.setCitys(citys);的作用:
当Nation.hbm.xml文件中map节点的inverse = "false"或不写时(即默认,false)
这行代码的作用是Hibernate可以根据nation中的citys去更新city表中的CITYNAME,也就是下面Hibernate会打印update语句的原因
如果没有setCitys则city表中的CITYNAME为null,Hibernate不会去更新city表,也就不会打印update语句
当Nation.hbm.xml文件中map节点的inverse = "true"时,这行代码不起作用
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
>
inverse = false
Hibernate打印出的sql语句为:
Hibernate: insert into nation (NATION_NAME) values (?)
Hibernate: insert into city (CITY_NAME, POST_CODE, NATION_ID) values (?, ?, ?)
Hibernate: insert into city (CITY_NAME, POST_CODE, NATION_ID) values (?, ?, ?)
Hibernate: update city set NATION_ID=?, CITYNAME=? where CITY_ID=?
Hibernate: update city set NATION_ID=?, CITYNAME=? where CITY_ID=?
数据库内容为:
+---------+------------+-----------+-----------+----------+
| CITY_ID | CITY_NAME | POST_CODE | NATION_ID | CITYNAME |
+---------+------------+-----------+-----------+----------+
| 1 | 中国·唐山 | 063009 | 1 | 唐山 |
| 2 | 中国·天津 | 356148 | 1 | 天津 |
+---------+------------+-----------+-----------+----------+
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
2、当属性citys中 inverse 为 true时
>
inverse = true
Hibernate: insert into nation (NATION_NAME) values (?)
Hibernate: insert into city (CITY_NAME, POST_CODE, NATION_ID) values (?, ?, ?)
Hibernate: insert into city (CITY_NAME, POST_CODE, NATION_ID) values (?, ?, ?)
+---------+------------+-----------+-----------+----------+
| CITY_ID | CITY_NAME | POST_CODE | NATION_ID | CITYNAME |
+---------+------------+-----------+-----------+----------+
| 1 | 中国·唐山 | 063009 | 1 | NULL |
| 2 | 中国·天津 | 356148 | 1 | NULL |
+---------+------------+-----------+-----------+----------+
而数据库中的CITYNAME是通过nation.setCitys(citys);这行代码注入值的。
---------------------------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------------------------
结论:
在操作两个实例之间的链接时,如果没有inverse属性(也就是默认的inverse = false),hibernate会试图执行两个不同的sql语句,这两者更新同一个外键列。通过指定
inverse = "true"时,显式地告诉Hibernate链接的哪一端不应该与数据库同步。这个例子中,告诉Hibernate它应该把在关联的City端所做的变化传播到数据库,忽略只对citys集合所做的变化。
但是值得注意的是,inverse在有序的集合里是不能使用的,这点要尤其注意。
---------------------------------------------------------------------------------------------------------------------------------------