一,创建映射
1,多的一段 java文件中需要有一的属性,配置文件需要用 many-to-one
2,一的一段 java文件中需要有set的多的属性,配置文件需要用 one-to-many
3,many-to-one one-to-many的column属性值要相同。
实例:人有多个地址。
1,Person类
package com.supan.bean;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Person {
private int id;
private String name;
private int age;
private Set<Address> addresss = new HashSet<Address>();
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 int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Set<Address> getAddresss() {
return addresss;
}
public void setAddresss(Set<Address> addresss) {
this.addresss = addresss;
}
}
Person的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-lazy="true" default-access="property" package="com.supan.bean" >
<class name="Person" dynamic-update="true" dynamic-insert="true" table="myperson">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="name" type="string" column="name" length="20"/>
<property name="age" type="integer" column="age" length="3"/>
<set name="addresss" inverse="true">
<key column="personid"/>
<one-to-many class="Address"/>
</set>
</class>
</hibernate-mapping>
2,Address类
package com.supan.bean;
public class Address {
private int id;
private String name;
private String info;
private String remark;
private Person person;
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
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 getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
}
Address类的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping default-lazy="true" default-access="property" package="com.supan.bean" >
<class name="Address" dynamic-update="true" dynamic-insert="true" table="address">
<id name="id" column="id" type="integer">
<generator class="native"/>
</id>
<property name="name" type="string" column="NAME" length="20"/>
<property name="info" type="string" column="INFO" length="30"/>
<property name="remark" type="string" column="REMARK" length="30"/>
<many-to-one name="person" class="Person" column="personid" not-null="true"></many-to-one>
</class>
</hibernate-mapping>
二:一对多的插入
一对多双向关联效率最高的插入方法:
1,先持久化Person对象,因为我们希望我们在持久化Address的时候已经有Person可以被
Address关联(关联关系由多的一方维护)。
2,先从Address 设置Person和Address的关系,再持久化Address对象,因为如果顺序颠倒过来,我们在持久化Address的时候还有关联Person和Address的关系,这个时候Address已经被持久化了,等要设置关联关系的时候hibernate还要发送一个udpate语句,影响效率。 当前如果你执意要颠倒过来的话就必须设置Address配置文件中many-to-one标签的nut-null为false,否则会报错
3,不要通过Person对象来设置关联关系,因为我们已经在Person映射文件的Set标签中已经制定了inverse 为true
package com.supan.test;
import junit.framework.TestCase;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.supan.bean.Address;
import com.supan.bean.Person;
public class HibernateCrudTest extends TestCase {
public void testInsert(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
Person person = new Person();
person.setName("陈超阳");
person.setAge(27);
sess.save(person);
Address address = new Address();
address.setName("吉祥地铁站");
address.setInfo("那是我第一次来深圳住的地方");
address.setRemark("目前已经不再那里居住了");
address.setPerson(person);
sess.persist(address);
Address address2 = new Address();
address2.setName("坂田五里围");
address2.setInfo("我目前居住的地方");
address2.setRemark("附近的消费很低");
address2.setPerson(person);
sess.persist(address2);
tx.commit();
sess.close();
}
}
二:一对多的查询
1,查询一的对象,会自动的把它关联的多的一段的都查出来,一般需要设置懒加载为true
public void testQuery(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
String hql = "from Person";
List<Person> persons = sess.createQuery(hql).list();
for(Person person : persons){
for(Address address : person.getAddresss()){
System.out.println(address.getName());
}
}
tx.commit();
sess.close();
}
2,查询多的一段,会自动的把一的一段查询出来,懒加载与否无所谓
public void testQuery2(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
String hql = "from Address";
List<Address> address = sess.createQuery(hql).list();
for(Address tempaddress : address){
System.out.println(tempaddress.getPerson().getName());
}
tx.commit();
sess.close();
}
3,关联查询
1,隐式关联查询 用.
public void testQuery3(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
String hql = "from Address ad where ad.person.name = :myname ";
List<Address> address = sess.createQuery(hql).setString("myname", "陈超阳").list();
for(Address tempaddress : address){
System.out.println(tempaddress.getPerson().getName());
}
tx.commit();
sess.close();
}
hibernate发送的查询sql(其实是自然连接),特别注意:查询出来的是Address实体的list列表。
Hibernate:
select
address0_.id as id1_,
address0_.NAME as NAME1_,
address0_.INFO as INFO1_,
address0_.REMARK as REMARK1_,
address0_.personid as personid1_
from
address address0_,
myperson person1_
where
address0_.personid=person1_.id
and person1_.name=?
Hibernate:
select
person0_.id as id0_0_,
person0_.name as name0_0_,
person0_.age as age0_0_
from
myperson person0_
where
person0_.id=?
2,内连接 inner join
public void testQuery3(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
String hql = "from Address a inner join a.person p where p.name = :myname ";
List result = sess.createQuery(hql).setString("myname", "陈超阳").list();
for(int i=0; i< result.size(); i++){
Object[] temp = (Object[])result.get(i);
Address addressTemp = (Address)temp[0];
System.out.println(addressTemp.getName());
Person personTemp = (Person)temp[1];
System.out.println(personTemp.getName());
}
tx.commit();
sess.close();
}
hibernate发送的sql语句,特别注意:查询出来的是address,person组合的实体
Hibernate:
select
address0_.id as id1_0_,
person1_.id as id0_1_,
address0_.NAME as NAME1_0_,
address0_.INFO as INFO1_0_,
address0_.REMARK as REMARK1_0_,
address0_.personid as personid1_0_,
person1_.name as name0_1_,
person1_.age as age0_1_
from
address address0_
inner join
myperson person1_
on address0_.personid=person1_.id
where
person1_.name=?
关于隐式连接查询,和显示连接查询的结果是截然不同的:
1,当hql语句中省略了select关键字时,使用隐式连接查询返回的结果是多个被查询实体组成的集合,
2,当使用显示连接省略select关键字时候,返回的结果也是集合,但是集合元素是被查询持久的对象,所有被关联的持久化对象所组成的数组,如上面的sql语句所示,它同事选择了Person,address表中的所有数据列,查询到的结果集的每条记录既包含了Person实体的全部属性,也包含了Address实体的全部属性,。hibernate会把每条记录封装成一个集合元素,用属于Person的属性创建Person对象,用属于Address的属性创建Address对象,多个持久化实体最后封装成一个数组。
三,一对多删除
1,删除一的时候
一的配置文件中有:
<set name="addresss" inverse="true" >
<key column="personid"/>
<one-to-many class="Address"/>
</set>
public void testDelete(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
Person person = (Person)sess.get(Person.class, 1);
sess.delete(person);
tx.commit();
sess.close();
}
报错如下:
java.lang.IllegalArgumentException: attempt to create delete event with null entity
at org.hibernate.event.DeleteEvent.<init>(DeleteEvent.java:47)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:772)
at com.supan.test.HibernateCrudTest.testDelete(HibernateCrudTest.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:130)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
原因:没有设置级联,删除一个时候,hibernate查到了这个一有多个Address引用,所以不能删除,
解决办法:
在Person的配置文件中添加:
<set name="addresss" inverse="true" cascade="all" >
<key column="personid"/>
<one-to-many class="Address"/>
</set>
设置之后删除一个一端,会连带多的一端一起删掉
2,删除多的一段
如果多的一端的many-to-one标签没有设置cascade="all"那么仅仅会删除多的一端,如果设置了cascade="all"那么就会连带一的一端也会删除。hibernate真是牛逼。
public void testDelete2(){
Configuration config = new Configuration().configure();
SessionFactory sf = config.buildSessionFactory();
Session sess = sf.openSession();
Transaction tx = (Transaction) sess.beginTransaction();
Address address = (Address)sess.get(Address.class, 9);
sess.delete(address);
tx.commit();
sess.close();
}