`

Hibernate(四)

阅读更多
观察:二级缓存的作用
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo10 {
public static void main(String[] args) {
  Session session = new Configuration().configure().buildSessionFactory()
    .openSession();
  Person per = null;
  per = (Person) session.get(Person.class, 1);
  session.close();
  session = new Configuration().configure().buildSessionFactory()
    .openSession();
  per = (Person) session.get(Person.class, 1);
  session.close() ;
}
}
可以发现,以上的代码只执行了一次的查询语句,虽然是两个session,但是可以共享缓存的数据。
当然,也可以清空掉全部的缓存,之后重新查询。
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo11 {
public static void main(String[] args) {
  Session session = new Configuration().configure().buildSessionFactory()
    .openSession();
  Person per = null;
  per = (Person) session.get(Person.class, 1);
  new Configuration().configure().buildSessionFactory().evict(per.getClass());
  session.close();
  session = new Configuration().configure().buildSessionFactory()
    .openSession();
  per = (Person) session.get(Person.class, 1);
  session.close();
}
}
在SessionFactory中只能一个个的删除被缓存的对象,不能全部清空缓存内容。
除了以上的配置之外,缓存也可以直接在hibernate.cfg.xml文件中进行配置的。
<class-cache class="org.lxh.hibernate.demo06.Person"
   usage="read-only" />
以后直接修改hibernate.cfg.xml就可以达到缓存的配置。
3.4.3、缓存交互
缓存交互指的是一级缓存可以二级缓存进行数据的交换。
主要使用Session对象中的:public void setCacheMode(CacheMode cacheMode)
在设置交互的时候,也存在着以下的几种交互模式:
  • CacheMode.NORMAL:从二级缓存中读、写数据。
• CacheMode.GET:从二级缓存中读取数据,仅在数据更新时对二级缓存写数据。
• CacheMode.PUT:仅向二级缓存写数据,但不从二级缓存中读数据。
•CacheMode.REFRESH:仅向二级缓存写数据,但不从二级缓存中读数据。通过 hibernate.cache.use_minimal_puts的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。
import org.hibernate.CacheMode;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo12 {
public static void main(String[] args) {
  Session session1 = new Configuration().configure().buildSessionFactory()
    .openSession();
  Person per = null;
  // 此时让一级缓存中的内容不保存在二级缓存里去
  session1.setCacheMode(CacheMode.GET) ;
  per = (Person) session1.get(Person.class, 1);
  session1.close();
  Session session2 = new Configuration().configure().buildSessionFactory()
    .openSession();
  per = (Person) session2.get(Person.class, 1);
  session2.close();
}
}
此时,程序发出了两条语句,因为第一个session中并没有把查询的内容放到缓存之中。
import org.hibernate.CacheMode;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo13 {
public static void main(String[] args) {
  Session session1 = new Configuration().configure()
    .buildSessionFactory().openSession();
  Person per = null;
  per = (Person) session1.get(Person.class, 1);
  session1.close();
  Session session2 = new Configuration().configure()
    .buildSessionFactory().openSession();
  // 不从二级缓存中读,但是写
  session2.setCacheMode(CacheMode.PUT);
  per = (Person) session2.get(Person.class, 1);
  session2.close();
  Session session3 = new Configuration().configure()
    .buildSessionFactory().openSession();
  // 不从二级缓存中写,但是读
  session3.setCacheMode(CacheMode.GET);
  per = (Person) session3.get(Person.class, 1);
  session3.close();
}
}
3.4.4、查询缓存
现在有如下程序:
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo14 {
public static void main(String[] args) {
  Session session = new Configuration().configure().buildSessionFactory()
    .openSession();
  for (int x = 0; x < 100; x++) {
   Query q = session.createQuery("FROM Person p") ;
   q.list() ;
  }
  session.close();
}
}
程序运行后,可以发现发出100次的重复的查询语句,此种做法肯定不可取,所以此时就必须配置查询缓存,如果要想配置一个查询缓存,则首先必须在hibernate.cfg.xml文件中进行配置。添加属性:
hibernate.cfg.xml:
<property name="cache.use_query_cache">true</property>
以上的属性表示启动了查询缓存,但是光有此配置是不够的,还需要在查询上指定查询必须被缓存。在Query接口上有一个:
q.setCacheable(true) ;
表示启动查询缓存。执行之后,发现只发出了一条查询语句,所以此语句被缓存了。
缓存直接与程序的性能有关,尤其是在使用大数据量插入或查询的时候尤其重要。
3.5、容器映射技术(重点)
所谓的容器映射实际上就是对多张表的关系映射,但是对于整个程序来说,只有一个配置文件(*.hbm.xml),但是一个文件可以同时操作多张表。
容器映射主要是分为三种:
  • Set映射:
  • List映射:
  • Map映射:
3.5.1、Set映射(绝对重点)
Set集合中肯定不能存放重复的元素。
现在表示出如下的一种关系:一个人有多个email地址。肯定要设计出两张表:
DROP TABLE email ;
DROP TABLE person ;
CREATE TABLE person(
pid  INT    AUTO_INCREMENT   PRIMARY KEY NOT NULL ,
name VARCHAR(50)  NOT NULL ,
age  INT    NOT NULL
) ;
CREATE TABLE email(
pid  INT ,
mail VARCHAR(200)  NOT NULL ,
FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
Person是主表,email是从表,在从表中除了ID之外只有一个字段,此时就可以使用容器映射。在POJO类中必须明确的表示出此种关系:
Person.java:
import java.util.Set;
import java.util.TreeSet;
public class Person {
private int pid ;
private String name ;
private int age ;
private Set mails ;
public Person(){
  this.mails = new TreeSet() ;
}
public int getAge() {
  return age;
}
public void setAge(int age) {
  this.age = age;
}
public Set getMails() {
  return mails;
}
public void setMails(Set mails) {
  this.mails = mails;
}
public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name;
}
public int getPid() {
  return pid;
}
public void setPid(int pid) {
  this.pid = pid;
}
}
一个人有多个email地址。但是此时在POJO类中的关系必须在映射文件之中进行明显的配置,修改Person.hbm.xml文件。
Person.hbm.xml:
<hibernate-mapping>
<class name="org.lxh.hibernate.demo07.Person" table="person"
  catalog="demo">
  <id name="pid" type="java.lang.Integer">
   <column name="pid" />
   <generator class="native"></generator>
  </id>
  <property name="name" type="java.lang.String">
   <column name="name" length="50" not-null="true" />
  </property>
  <property name="age" type="java.lang.Integer">
   <column name="age" not-null="true" />
  </property>
  <set name="mails"    表示使用了一个Set集合,name表示Person类中的属性名称
   table="email">   表示此集合对应的表
   <key column="pid" />   主表与子表之间的关联字段
   <element type="java.lang.String"    表示集合中的每一个元素
    column="mail"></element>  每一个元素的值都对应着mail字段
  </set>
</class>
</hibernate-mapping>
测试代码:
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo07 {
private Session session = null;
public TestDemo07() {
  this.session = new Configuration().configure().buildSessionFactory()
    .openSession();
}
public void doCreate() {
  Person per = new Person();
  per.setName("张三");
  per.setAge(30);
  per.getMails().add("aa@aa.com");
  per.getMails().add("aa@aa.com");
  per.getMails().add("ab@aa.com");
  per.getMails().add("ac@aa.com");
  this.session.save(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
public static void main(String[] args) {
  new TestDemo07().doCreate();
}
}
程序代码执行了4条SQL语句,第一条表示的是向person表中插入数据,其他三条表示向email表中插入数据。
观察查询:
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo08 {
private Session session = null;
public TestDemo08() {
  this.session = new Configuration().configure().buildSessionFactory()
    .openSession();
}
public void find() {
  String hql = "FROM Person p WHERE p.pid=?";
  Query q = this.session.createQuery(hql);
  q.setInteger(0, 1);
  Person p = (Person) q.uniqueResult();  // 查询的只是person中的表
  p.getMails().size();     // 当用到的时候再发出查询语句
  this.session.close();
}
public static void main(String[] args) {
  new TestDemo08().find();
}
}
对于集合的数据,因为一般其内容较多,所以在Hibernate中就默认的设置其为延迟加载,当需要数据的时候再进行查询。
p.getMails().size();
对于延迟加载来说,一定要在session关闭前,将内容查询出来,否则会出现session被关闭的异常。
可以直接通过修改*.hbm.xml文件将延迟加载关闭。
  <set name="mails"
   table="email" lazy="false">
   <key column="pid" />
   <element type="java.lang.String"
    column="mail"></element>
  </set>
之后再进行查询,同时将集合的操作取消:
public void find() {
  String hql = "FROM Person p WHERE p.pid=?";
  Query q = this.session.createQuery(hql);
  q.setInteger(0, 1);
  Person p = (Person) q.uniqueResult();  // 查询的只是person中的表
  this.session.close();
}
程序发出了两条语句,不管是否使用全部查询出来。
对于Set映射中,也可以修改数据。
public void update() {
  Person per = new Person();
  per.setPid(1) ;
  per.setName("李四");
  per.setAge(31);
  per.getMails().add("Xx@aa.com");
  per.getMails().add("UU@aa.com");
  per.getMails().add("ab@aa.com");
  per.getMails().add("ac@aa.com");
  this.session.update(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
以上的Person对象是一个新的对象,此时观察执行的SQL语句:
Hibernate: update demo.person set name=?, age=? where pid=?
Hibernate: delete from email where pid=?
Hibernate: insert into email (pid, mail) values (?, ?)
Hibernate: insert into email (pid, mail) values (?, ?)
Hibernate: insert into email (pid, mail) values (?, ?)
Hibernate: insert into email (pid, mail) values (?, ?)
以上的SQL语句表示,先更新主表,之后删除全部子表中的相关数据,重新插入,因为插入的内容是一个新的实体对象。
但是,如果此时,先进行查询之后再更新呢?
public void update() {
  Person per = (Person)this.session.get(Person.class, 1) ;
  per.setPid(1) ;
  per.setName("张三");
  per.setAge(20);
  per.getMails().add("Xx@aa.com");
  per.getMails().add("UU@aa.com");
  per.getMails().add("BB@aa.com");
  per.getMails().add("CC@aa.com");
  this.session.update(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
现在的内容是先查询之后再更新的,观察执行的SQL语句:
Hibernate: select person0_.pid as pid0_0_, person0_.name as name0_0_, person0_.age as age0_0_ from demo.person person0_ where person0_.pid=?
Hibernate: select mails0_.pid as pid0_, mails0_.mail as mail0_ from email mails0_ where mails0_.pid=?   因为没有设置延迟加载,所以一起查询了
Hibernate: update demo.person set name=?, age=? where pid=?
Hibernate: insert into email (pid, mail) values (?, ?)
Hibernate: insert into email (pid, mail) values (?, ?)
因为有两个新的email地址,所以现在向表中重新插入新的内容。
因为在Hibernate中要维持一个对象的状态。
3.5.2、List映射
List映射表示的是允许有重复的元素,例如一个人有多本书,书的名字是有可能重复的。
DROP TABLE book ;
DROP TABLE person ;
CREATE TABLE person(
pid  INT    AUTO_INCREMENT   PRIMARY KEY NOT NULL ,
name VARCHAR(50)  NOT NULL ,
age  INT    NOT NULL
) ;
CREATE TABLE book(
pid  INT ,
title VARCHAR(200)  NOT NULL ,    书的名字全部一样
num  INT    NOT NULL ,    区分不同的书
FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
Person.java:
import java.util.ArrayList;
import java.util.List;
public class Person {
private int pid ;
private String name ;
private int age ;
private List books ;
public Person(){
  this.books = new ArrayList() ;
}
public int getAge() {
  return age;
}
public void setAge(int age) {
  this.age = age;
}
public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name;
}
public int getPid() {
  return pid;
}
public void setPid(int pid) {
  this.pid = pid;
}
public List getBooks() {
  return books;
}
public void setBooks(List books) {
  this.books = books;
}
}
Person.hbm.xml:
<hibernate-mapping>
    <class name="org.lxh.hibernate.demo08.Person" table="person" catalog="demo">
        <id name="pid" type="java.lang.Integer">
            <column name="pid" />
            <generator class="native"></generator>
        </id>
        <property name="name" type="java.lang.String">
            <column name="name" length="50" not-null="true" />
        </property>
        <property name="age" type="java.lang.Integer">
            <column name="age" not-null="true" />
        </property>
        <list name="books"     配置List集合
         table="book">       对应的表
         <key column="pid"></key>   关联键
         <index column="num"></index>   索引值,自动处理
         <element type="java.lang.String"
          column="title"></element>
        </list>
    </class>
</hibernate-mapping>
测试:
import org.hibernate.Session;
import org.hibernate.cfg.Configuration;
public class TestDemo07 {
private Session session = null;
public TestDemo07() {
  this.session = new Configuration().configure().buildSessionFactory()
    .openSession();
}
public void doCreate() {
  Person per = new Person();
  per.setName("张三");
  per.setAge(30);
  per.getBooks().add("C++") ;
  per.getBooks().add("C++") ;
  per.getBooks().add("C++") ;
  per.getBooks().add("JAVA") ;
  per.getBooks().add("JAVA") ;
  per.getBooks().add("JAVA") ;
  per.getBooks().add("JAVA") ;
  this.session.save(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
public static void main(String[] args) {
  new TestDemo07().doCreate();
}
}
3.5.3、Map映射
Map映射就是存放一对key  value的关联。
例如:一个人可以有多个项目,每个项目有项目的名称及描述。
DROP TABLE project ;
DROP TABLE person ;
CREATE TABLE person(
pid  INT    AUTO_INCREMENT   PRIMARY KEY NOT NULL ,
name VARCHAR(50)  NOT NULL ,
age  INT    NOT NULL
) ;
CREATE TABLE project(
pid  INT ,
name VARCHAR(200)  NOT NULL ,
descr VARCHAR(60) NOT NULL ,
FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
子表中存在着一对关联的关系:key  value。
此时,就只能在POJO类中完成Map映射了。
Person.java:
import java.util.HashMap;
import java.util.Map;
public class Person {
private int pid;
private String name;
private int age;
private Map projects;
public Person() {
  this.projects = new HashMap();
}
public int getAge() {
  return age;
}
public void setAge(int age) {
  this.age = age;
}
public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name;
}
public int getPid() {
  return pid;
}
public void setPid(int pid) {
  this.pid = pid;
}
public Map getProjects() {
  return projects;
}
public void setProjects(Map projects) {
  this.projects = projects;
}
}
在映射文件之中,表示出此种关系:
<hibernate-mapping>
<class name="org.lxh.hibernate.demo09.Person" table="person"
  catalog="demo">
  <id name="pid" type="java.lang.Integer">
   <column name="pid" />
   <generator class="native"></generator>
  </id>
  <property name="name" type="java.lang.String">
   <column name="name" length="50" not-null="true" />
  </property>
  <property name="age" type="java.lang.Integer">
   <column name="age" not-null="true" />
  </property>
  <map name="projects" table="project">
   <key column="pid"></key>
   <map-key type="java.lang.String"     配置Map中的key
    column="name"></map-key>
   <element type="java.lang.String"     配置Map中的value
    column="descr"></element>
  </map>
</class>
</hibernate-mapping>
测试:
public void doCreate() {
  Person per = new Person();
  per.setName("张三");
  per.setAge(30);
  per.getProjects().put("JAVA", "网络登陆系统") ;
  per.getProjects().put("J2EE", "ERP系统") ;
  this.session.save(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
三种容器映射技术之中,都是两张表的,但是对于Set映射来说,被关联的字表出了主键之外只能有一个字段。
如果一个被关联表中需要有更多的字段,则只能使用数据关联技术。
3.6、数据关联技术(重点中的重点)
数据关联指的是以下三种关联:
  • 一对一关联
  • 一对多关联
  • 多对多关联
3.6.1、一对一关联
例如:一个人有一张护照。应该需要两张表,一张是人员表,另外一张是护照表:
DROP TABLE passport ;
DROP TABLE person ;
CREATE TABLE person(
pid  INT    AUTO_INCREMENT   PRIMARY KEY NOT NULL ,
name VARCHAR(50)  NOT NULL ,
age  INT    NOT NULL
) ;
CREATE TABLE passport(
pid  INT ,
serial VARCHAR(30)  UNIQUE NOT NULL ,
expiry INT ,
FOREIGN KEY(pid) REFERENCES person(pid) ON DELETE CASCADE
) ;
此时被关联表中存在多个字段,所以此时在建立POJO类的时候肯定要建立两个POJO类。
Person中应该包含Passport属性,而Passport类中要包含Person的属性。
Person.java:
public class Person {
private int pid ;
private String name ;
private int age ;
private Passport passport ;
public int getAge() {
  return age;
}
public void setAge(int age) {
  this.age = age;
}
public String getName() {
  return name;
}
public void setName(String name) {
  this.name = name;
}
public Passport getPassport() {
  return passport;
}
public void setPassport(Passport passport) {
  this.passport = passport;
}
public int getPid() {
  return pid;
}
public void setPid(int pid) {
  this.pid = pid;
}
}
Passport.java:
public class Passport {
private int pid ;
private String serial ;
private int expiry ;
private Person person ;
public int getExpiry() {
  return expiry;
}
public void setExpiry(int expiry) {
  this.expiry = expiry;
}
public Person getPerson() {
  return person;
}
public void setPerson(Person person) {
  this.person = person;
}
public int getPid() {
  return pid;
}
public void setPid(int pid) {
  this.pid = pid;
}
public String getSerial() {
  return serial;
}
public void setSerial(String serial) {
  this.serial = serial;
}
}
但是两个类中的关联关系如果要想正确的时候,则必须在映射文件之中进行配置。
Person.hbm.xml:
<hibernate-mapping>
<class name="org.lxh.hibernate.demo10.Person" table="person"
  catalog="demo">
  <id name="pid" type="java.lang.Integer">
   <column name="pid" />
   <generator class="native"></generator>
  </id>
  <property name="name" type="java.lang.String">
   <column name="name" length="50" not-null="true" />
  </property>
  <property name="age" type="java.lang.Integer">
   <column name="age" not-null="true" />
  </property>
  <one-to-one name="passport"
   class="org.lxh.hibernate.demo10.Passport">
  </one-to-one>
</class>
</hibernate-mapping>
Passport.hbm.xml:
在护照表中,其编号由Person决定的,而且配置了外键的关系。
<hibernate-mapping>
<class name="org.lxh.hibernate.demo10.Passport" table="passport"
  catalog="demo">
  <id name="pid" column="pid" type="java.lang.Integer">
   <generator class="foreign">
    <param name="property">person</param>
   </generator>
  </id>
  <property name="serial" type="java.lang.String"
   column="serial">
  </property>
  <property name="expiry" type="java.lang.Integer"
   column="expiry">
  </property>
  <one-to-one name="person"
   class="org.lxh.hibernate.demo10.Person">
  </one-to-one>
</class>
</hibernate-mapping>
编写测试:
public void doCreate() {
  Person per = new Person();
  per.setName("张三");
  per.setAge(30);
  Passport pass = new Passport() ;
  pass.setSerial("1111111111111111") ;
  pass.setExpiry(30) ;
  per.setPassport(pass) ;
  pass.setPerson(per) ;
  this.session.save(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
程序执行后,只插入了一条SQL语句。
因为程序中没有配置级联关系,所以在插入人的时候虽然在类中配置好了人与护照的一对一关系,但是程序现在依然不会插入护照的信息。
  <one-to-one name="passport"
   class="org.lxh.hibernate.demo10.Passport" cascade="all">
  </one-to-one>
执行查询观察结果:
public void find1() {
  String hql = "FROM Person p WHERE p.pid=1";
  Person per = (Person) this.session.createQuery(hql).uniqueResult();
  System.out.println(per.getName());
  System.out.println(per.getPassport().getSerial());
  this.session.close();
}
public void find2() {
  Person per = (Person) this.session.get(Person.class, 1);
  System.out.println(per.getName());
  System.out.println(per.getPassport().getSerial());
  this.session.close();
}
更新操作:
public void doUpdate() {
  Person per = new Person();
  per.setPid(1) ;
  per.setName("李四");
  per.setAge(30);
  Passport pass = new Passport() ;
  pass.setSerial("222222222") ;
  pass.setExpiry(32) ;
  per.setPassport(pass) ;
  pass.setPerson(per) ;
  this.session.update(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
以上是一个新的实体,进行更新操作。
执行的SQL语句:
Hibernate: insert into demo.passport (serial, expiry, pid) values (?, ?, ?)
Hibernate: update demo.person set name=?, age=? where pid=?
出现了两条,导致了程序更新错误。
public void doUpdate2() {
  Person per = new Person();
  per.setPid(1) ;
  per.setName("李四");
  per.setAge(30);
  this.session.update(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
更新的时候如果配置好了关联关系,则有可能会执行插入新记录的操作。
public void doUpdate3() {
  Person per = (Person)this.session.get(Person.class, 1) ;
  per.setName("李四");
  per.setAge(30);
  per.getPassport().setSerial("222222222") ;
  per.getPassport().setExpiry(32) ;
  this.session.update(per);
  this.session.beginTransaction().commit();
  this.session.close();
}
执行的SQL语句:
Hibernate: update demo.passport set serial=?, expiry=? where pid=?
Hibernate: update demo.person set name=?, age=? where pid=?
因为是先查询出来的实体,所以保存了对象的状态,更新的时候就不会再进行重新插入了。
但是以上的操作都是使用update方法完成的,本身不建议这样使用,最好使用HQL中的update方法。
3.6.2、一对多关联(重点)
一个部门有多个雇员:
• 部门表
• 雇员表
DROP TABLE emp ;
DROP TABLE dept ;
CREATE TABLE dept(
deptno  INT    AUTO_INCREMENT PRIMARY KEY NOT NULL ,
dname  VARCHAR(50)  NOT NULL ,
loc   VARCHAR(50)  NOT NULL
);
CREATE TABLE emp(
empno  INT    AUTO_INCREMENT  PRIMARY KEY NOT NULL ,
ename  VARCHAR(50)  NOT NULL ,
saly  FLOAT   NOT NULL ,
hiredate DATE ,
deptno  INT ,
FOREIGN KEY(deptno) REFERENCES dept(deptno)
) ;
此时,就可以返回MyEcplise中最好用的一个功能,会自动帮用户建立好关联关系,会自动将POJO类配置好关系。
在插入数据的时候必须配置好关联关系:
public void doCreate() {
  Dept d = new Dept() ;
  d.setDname("技术部") ;
  d.setLoc("北京") ;
  Emp e = null ;
  e = new Emp() ;
  e.setEname("张三") ;
  e.setSaly(800.0f) ;
  e.setHiredate(new Date()) ;
  e.setDept(d) ;
  d.getEmps().add(e) ;
  e = new Emp() ;
  e.setEname("李四") ;
  e.setSaly(900.0f) ;
  e.setHiredate(new Date()) ;
  e.setDept(d) ;
  d.getEmps().add(e) ;
  this.session.save(d);
  this.session.beginTransaction().commit();
  this.session.close();
}
直接就可以完成插入操作。同样,在查询的时候依然存在了延迟加载的关系。
public void find1() {
  String hql = "FROM Dept d WHERE d.deptno=1";
  Dept d = (Dept) this.session.createQuery(hql).uniqueResult();
  System.out.println(d.getDname());
  Iterator iter = d.getEmps().iterator() ;
  while(iter.hasNext()){
   Emp e = (Emp)iter.next() ;
   System.out.println("\t |- " + e.getEname());
  }
  this.session.close();
}
既然存在了延迟加载,则必须在session关闭前进行加载,否则肯定会出现session已经关闭的错误。

4、总结
1、 Hibernate中推荐使用HQL的方式进行查询,通过Query接口完成
2、 Hibernate中的缓存分为一级缓存、二级缓存、查询缓存
  • 一级缓存是Session级别的
  • 二级缓存是SessionFactory,必须配置单独的缓存组件
  • 在查询缓存中配置的话,可以减少重复查询执行SQL语句的效果
3、 容器映射技术中的Set映射是无重复的,虽然只有一个POJO类文件,但是却可以同时操作两张表,而且子表中除了关联字段之外,只能存在一个字段。
4、 Hibernate中一对多关联中,存在延迟加载,所有的延迟加载要求就默认打开。
5、作业
使用Struts + Hibernate完成地区-子地区的管理和商品类别-商品子类别管理两个程序:
• 一个地区包含多个子地区,完成之后可以再将之前的AJAX + XML程序进行修改,完成级联菜单操作。
• 一个商品类别包含多个商品子类别,完成之后使用AJAX + XML完成级联菜单。
6.1、作业一:地区-子地区
地区表字段说明:
地区表
  id 地区ID(自动增长)
title 标题
子地区表字段说明:
地区子表
  id 地区子表ID(自动增长)
upid 地区表id
title 子地区名称
数据库创建脚本:
USE mldnshop ;
create table area
(
   id                             int AUTO_INCREMENT PRIMARY KEY NOT NULL,
   title                          varchar(100)     NOT NULL
) ;
CREATE TABLE areaplus (
  id     INT AUTO_INCREMENT PRIMARY KEY NOT NULL,
  upid  INT NOT NULL,
  title varchar(100) default NULL ,
  foreign key (upid) references area (id) on delete cascade
) ;
INSERT INTO area (title) VALUES
('其他'), ('北京'), ('重庆'), ('福建'), ('甘肃'), ('广东'),
('广西'), ('贵州'), ('海南'), ('河北'), ('黑龙江'), ('河南'),
('香港'), ('湖北'), ('湖南'), ('江苏'), ('江西'), ('吉林'),
('辽宁'), ('澳门'), ('内蒙古'), ('宁夏'), ('青海'), ('山东'),
('上海'), ('山西'), ('陕西'), ('四川'), ('台湾'), ('天津'),
('新疆'), ('西藏'), ('云南'), ('浙江'), ('安徽');
INSERT INTO areaplus (upid,title) VALUES
(35,'合肥'), (35,'安庆'), (35,'蚌埠'), (35,'亳州'), (35,'巢湖'), (35,'滁州'),
(35,'阜阳'), (35,'贵池'), (35,'淮北'), (35,'淮化'), (35,'淮南'), (35,'黄山'),
(35,'九华山'), (35,'六安'), (35,'马鞍山'), (35,'宿州'), (35,'铜陵'), (35,'屯溪'),
(35,'芜湖'), (35,'宣城'), (2,'北京'), (3,'重庆'), (4,'福州'), (4,'福安'),
(4,'龙岩'), (4,'南平'), (4,'宁德'), (4,'莆田'), (4,'泉州'), (4,'三明'),
(4,'邵武'), (4,'石狮'), (4,'永安'), (4,'武夷山'), (4,'厦门'), (4,'漳州'),
(5,'兰州'), (5,'白银'), (5,'定西'), (5,'敦煌'), (5,'甘南'), (5,'金昌');
INSERT INTO areaplus (upid,title) VALUES
(5,'酒泉'), (5,'临夏'), (5,'平凉'), (5,'天水'), (5,'武都'), (5,'武威'),
(5,'西峰'), (5,'张掖'), (6,'广州'), (6,'潮阳'), (6,'潮州'), (6,'澄海'),
(6,'东莞'), (6,'佛山'), (6,'河源'), (6,'惠州'), (6,'江门'), (6,'揭阳'),
(6,'开平'), (6,'茂名'), (6,'梅州'), (6,'清远'), (6,'汕头'), (6,'汕尾'),
(6,'韶关'), (6,'深圳'), (6,'顺德'), (6,'阳江'), (6,'英德'), (6,'云浮'),
(6,'增城'), (6,'湛江'), (6,'肇庆'), (6,'中山'), (6,'珠海'), (7,'南宁');
INSERT INTO areaplus (upid,title) VALUES
(7,'百色'), (7,'北海'), (7,'桂林'), (7,'防城港'), (7,'河池'), (7,'贺州'),
(7,'柳州'), (7,'钦州'), (7,'梧州'), (7,'玉林'), (8,'贵阳'), (8,'安顺'),
(8,'毕节'), (8,'都匀'), (8,'凯里'), (8,'六盘水'), (8,'铜仁'), (8,'兴义'),
(8,'玉屏'), (8,'遵义'), (9,'海口'), (9,'儋县'), (9,'陵水'), (9,'琼海'),
(9,'三亚'), (9,'五指山'), (9,'万宁'), (10,'石家庄'), (10,'保定'), (10,'北戴河'),
(10,'沧州'), (10,'承德'), (10,'丰润'), (10,'邯郸'), (10,'衡水'), (10,'廊坊');
INSERT INTO areaplus (upid,title) VALUES
(10,'南戴河'), (10,'秦皇岛'), (10,'唐山'), (10,'新城'), (10,'邢台'), (10,'张家口'),
(11,'哈尔滨'), (11,'北安'), (11,'大庆'), (11,'大兴安岭'), (11,'鹤岗'), (11,'黑河'),
(11,'佳木斯'), (11,'鸡西'), (11,'牡丹江'), (11,'齐齐哈尔'), (11,'七台河'), (11,'双鸭山'),
(11,'绥化'), (11,'伊春'), (12,'郑州'), (12,'安阳'), (12,'鹤壁'), (12,'潢川'),
(12,'焦作'), (12,'济源'), (12,'开封'), (12,'漯河'), (12,'洛阳'), (12,'南阳'), (12,'平顶山'),
(12,'濮阳'), (12,'三门峡'), (12,'商丘'), (12,'新乡');
INSERT INTO areaplus (upid,title) VALUES
(12,'信阳'), (12,'许昌'), (12,'周口'), (12,'驻马店'), (13,'香港'), (13,'九龙'),
(13,'新界'), (14,'武汉'), (14,'恩施'), (14,'鄂州'), (14,'黄冈'), (14,'黄石'),
(14,'荆门'), (14,'荆州'), (14,'潜江'), (14,'十堰'), (14,'随州'), (14,'武穴'), (14,'仙桃'),
(14,'咸宁'), (14,'襄阳'), (14,'襄樊'), (14,'孝感'), (14,'宜昌'), (15,'长沙'), (15,'常德'),
(15,'郴州'), (15,'衡阳'), (15,'怀化'), (15,'吉首'), (15,'娄底'), (15,'邵阳'), (15,'湘潭'),
(15,'益阳'), (15,'岳阳'), (15,'永州');
INSERT INTO areaplus (upid,title) VALUES
(15,'张家界'), (15,'株洲'), (16,'南京'), (16,'常熟'), (16,'常州'), (16,'海门'),
(16,'淮安'), (16,'江都'), (16,'江阴'), (16,'昆山'), (16,'连云港'), (16,'南通'),
(16,'启东'), (16,'沭阳'), (16,'宿迁'), (16,'苏州'), (16,'太仓'), (16,'泰州'),
(16,'同里'), (16,'无锡'), (16,'徐州'), (16,'盐城'), (16,'扬州'), (16,'宜兴'),
(16,'仪征'), (16,'张家港'), (16,'镇江'), (16,'周庄'), (17,'南昌'), (17,'抚州'),
(17,'赣州'), (17,'吉安'), (17,'景德镇'), (17,'井冈山'), (17,'九江'), (17,'庐山');
INSERT INTO areaplus (upid,title) VALUES
(17,'萍乡'), (17,'上饶'), (17,'新余'), (17,'宜春'), (17,'鹰潭'), (18,'长春'),
(18,'白城'), (18,'白山'), (18,'珲春'), (18,'辽源'), (18,'梅河'), (18,'吉林'),
(18,'四平'), (18,'松原'), (18,'通化'), (18,'延吉'), (19,'沈阳'), (19,'鞍山'),
(19,'本溪'), (19,'朝阳'), (19,'大连'), (19,'丹东'), (19,'抚顺'), (19,'阜新'),
(19,'葫芦岛'), (19,'锦州'), (19,'辽阳'), (19,'盘锦'), (19,'铁岭'), (19,'营口'),
(20,'澳门'), (21,'呼和浩特'), (21,'阿拉善盟'), (21,'包头'), (21,'赤峰'), (21,'东胜');
INSERT INTO areaplus (upid,title) VALUES
(21,'海拉尔'), (21,'集宁'), (21,'临河'), (21,'通辽'), (21,'乌海'), (21,'乌兰浩特'),
(21,'锡林浩特'), (22,'银川'), (22,'固原'), (22,'石嘴山'), (22,'吴忠'), (23,'西宁'),
(23,'德令哈'), (23,'格尔木'), (23,'共和'), (23,'海东'), (23,'海晏'), (23,'玛沁'),
(23,'同仁'), (23,'玉树'), (24,'济南'), (24,'滨州'), (24,'兖州'), (24,'德州'),
(24,'东营'), (24,'菏泽'), (24,'济宁'), (24,'莱芜'), (24,'聊城'), (24,'临沂'),
(24,'蓬莱'), (24,'青岛'), (24,'曲阜'), (24,'日照'), (24,'泰安');
INSERT INTO areaplus (upid,title) VALUES
(24,'潍坊'), (24,'威海'), (24,'烟台'), (24,'枣庄'), (24,'淄博'), (25,'上海'),
(25,'崇明'), (25,'朱家角'), (26,'太原'), (26,'长治'), (26,'大同'), (26,'候马'),
(26,'晋城'), (26,'离石'), (26,'临汾'), (26,'宁武'), (26,'朔州'), (26,'忻州'),
(26,'阳泉'), (26,'榆次'), (26,'运城'), (27,'西安'), (27,'安康'), (27,'宝鸡'),
(27,'汉中'), (27,'渭南'), (27,'商州'), (27,'绥德'), (27,'铜川'), (27,'咸阳'),
(27,'延安'), (27,'榆林'), (28,'成都'), (28,'巴中'), (28,'达州'), (28,'德阳');
INSERT INTO areaplus (upid,title) VALUES
(28,'都江堰'), (28,'峨眉山'), (28,'涪陵'), (28,'广安'), (28,'广元'), (28,'九寨沟'),
(28,'康定'), (28,'乐山'), (28,'泸州'), (28,'马尔康'), (28,'绵阳'), (28,'眉山'),
(28,'南充'), (28,'内江'), (28,'攀枝花'), (28,'遂宁'), (28,'汶川'), (28,'西昌'),
(28,'雅安'), (28,'宜宾'), (28,'自贡'), (28,'资阳'), (29,'台北'), (29,'基隆'),
(29,'台南'), (29,'台中'), (30,'天津'), (31,'乌鲁木齐'), (31,'阿克苏'), (31,'阿勒泰'),
(31,'阿图什'), (31,'博乐'), (31,'昌吉'), (31,'东山'), (31,'哈密');
INSERT INTO areaplus (upid,title) VALUES
(31,'和田'), (31,'喀什'), (31,'克拉玛依'), (31,'库车'), (31,'库尔勒'), (31,'奎屯'),
(31,'石河子'), (31,'塔城'), (31,'吐鲁番'), (31,'伊宁'), (32,'拉萨'), (32,'阿里'),
(32,'昌都'), (32,'林芝'), (32,'那曲'), (32,'日喀则'), (32,'山南'), (33,'昆明'),
(33,'大理'), (33,'保山'), (33,'楚雄'), (33,'东川'), (33,'个旧'),
(33,'景洪'), (33,'开远'), (33,'临沧'), (33,'丽江'), (33,'六库'), (33,'潞西'),
(33,'曲靖'), (33,'思茅'), (33,'文山'), (33,'西双版纳'), (33,'玉溪');
INSERT INTO areaplus (upid,title) VALUES
(33,'中甸'), (33,'昭通'), (34,'杭州'), (34,'安吉'), (34,'慈溪'), (34,'定海'),
(34,'奉化'), (34,'海盐'), (34,'黄岩'), (34,'湖州'), (34,'嘉兴'), (34,'金华'),
(34,'临安'), (34,'临海'), (34,'丽水'), (34,'宁波'), (34,'瓯海'), (34,'平湖'),
(34,'千岛湖'), (34,'衢州'), (34,'江山'), (34,'瑞安'), (34,'绍兴'), (34,'嵊州'),
(34,'台州'), (34,'温岭'), (34,'温州'), (34,'舟山'), (1,'其他');
6.2、作业二:商品类别-商品类别子
商品类别表:
商品类别表
  id 类别编号(自动增长)
title 类别名称
img 类别图片
description 类别描述
商品子类别表:
商品类别子表
  id 子类别编号
upid 父类别id编号
title 子类别名称
数据库创建脚本:
use mshop ;
DROP TABLE IF EXISTS catalogplus;
DROP TABLE IF EXISTS catalog;
CREATE TABLE catalog (
  id int AUTO_INCREMENT PRIMARY KEY NOT NULL ,
  title varchar(100) default NULL,
  img varchar(100) default NULL,
  description varchar(255) default NULL
) ;
CREATE TABLE catalogplus (
  id int AUTO_INCREMENT PRIMARY KEY NOT NULL,
  upid int NOT NULL ,
  title varchar(100) default NULL,
  foreign key (upid) references catalog (id) on delete cascade
) ;
INSERT INTO catalog (title,img,description) VALUES
('电脑、软件、网络','11540709315040.jpg','杂志 小说 瑞丽 外语 考研 求职'),
('MP3、MP4、音响','11540722111920.gif','手机 CDMA 智能 充值 配件 小灵通 蓝牙 诺基亚 三星 索爱 MOTO 拍卖'),
('手机、通讯设备、卡','11540721784890.gif','ZIPPO 打火机 瑞士军刀 刀具 男包 饰品 烟具 烟斗 酒具 配件 剃须刀'),
('数码相机、摄影摄像','11540708454570.gif','走过路过千万别错过,各种品牌液精大优惠'),
('珠宝首饰、手表、眼镜','11540708241600.jpg','HIFI音响 纽曼 CD MD 一元 99元 199元 森海塞尔'),
('彩妆、香水、护肤','11540708010040.gif','佳能 索尼 尼康 三星 配件 闪存卡 数码相机 数码单反 DV 镜头 读卡器'),
('女装、女士精品','11540707778790.gif','银饰 韩国 水晶 外贸原单 Swatch 施华洛世奇 名表 发夹 项链 钻石'),
('男装、服饰配件','11540707582540.gif','各种品牌笔记本电脑全线大优惠'),
('网络游戏虚拟商品','11540707403320.gif','各种时尚、高档MP3、MP3'),
('音乐、影视、明星、娱乐','11540707172390.gif','这是一个美得上帝也要叹息的地方!它被浓阴华盖遮蔽,恬静、怡然,没有一丝尘世的喧嚣');
INSERT INTO catalogplus (upid,title) VALUES
(1,'硬件'), (1,'全新笔记本'), (1,'二手笔记本'), (1,'PDA'), (1,'笔记本配件'),
(1,'电脑周边'), (1,'网络服务'), (3,'手机'), (3,'CDMA'), (3,'配件'),
(3,'小灵通'), (2,'便携视听'), (2,'HIFI音响'), (2,'电脑音箱'), (4,'数码相机'),
(4,'数码单反'), (4,'专业相机'), (4,'DV'), (5,'银饰'), (5,'韩国'), (5,'水晶'),
(5,'外贸'), (6,'丰胸'), (6,'Swarovski'), (6,'减肥'), (6,'护肤'), (6,'香水'),
(6,'面膜'), (6,'雅芳'), (7,'吊带衫'), (7,'背心'), (7,'针织衫'), (7,'毛衣'),
(7,'衬衫'), (7,'T恤'), (8,'毛衣'), (8,'线衫'), (8,'外套'), (8,'帽衫'),
(8,'西装'), (8,'风衣'), (9,'梦幻/大话'), (9,'魔兽'), (9,'QQ 点卡'), (9,'装备'),
(9,'帐号'), (10,'韩剧'), (10,'明星'), (10,'演唱会'), (10,'音乐CD'), (10,'电影DVD');
分享到:
评论

相关推荐

    Hibernate四大属性

    "Hibernate四大属性"是指在配置Hibernate时,我们经常会遇到的四个关键属性,它们对于理解Hibernate的工作原理和优化数据库操作至关重要。这四个属性分别是:`connection.datasource`、`hibernate.hbm2ddl.auto`、`...

    hibernate

    这四个概念在处理对象关系映射(ORM)时非常重要,尤其是在Java环境下使用Hibernate框架进行数据库操作时。 ### Hibernate Fetch 模式 在Hibernate中,Fetch模式用于控制关联数据的加载方式。主要有两种取值:`...

    hibernate学习笔记第四天的源码

    **hibernate学习笔记第四天源码解析** 在hibernate学习的过程中,第四天通常会深入探讨实体类、映射文件、配置文件以及查询语言等方面的内容。这些是hibernate框架的基础,也是开发者掌握持久化操作的关键。让我们...

    使用注解整合ext dwr spring hibernate

    本话题主要关注如何通过注解方式集成EXT、DWR、Spring和Hibernate四个组件,构建一个高效的数据展示和交互的Web应用程序。 首先,EXT(Ext JS)是一个JavaScript库,用于构建用户界面,尤其适合创建富互联网应用...

    hibernate教程hibernate教程

    **四、延迟加载(Lazy Loading)** 延迟加载是一种优化策略,允许在真正需要时才加载关联的对象,以减少不必要的数据库查询。例如,当加载一个Customer对象时,其对应的Orders可以被延迟加载,直到真正需要时才执行...

    通用开发平台(spring mvc + spring + bootstrap + hibernate)

    这个框架整合了Spring MVC、Spring、Bootstrap和Hibernate四个核心组件,旨在提高开发效率,提供统一的开发规范,并优化用户体验。 1. Spring MVC:作为Spring框架的一部分,Spring MVC是用于构建Web应用程序的模型...

    Hibernate-extensions 完整安装包

    四、时间戳更新 在数据库操作中,有时我们需要记录对象最后修改的时间。Hibernate-Extensions提供了一种自动化方式来处理这些时间戳,比如在对象更新时自动更新某个字段,无需手动设置。 五、其他功能 除了上述...

    基于springsecurity+springmvc+spring+hibernate的权限管理系统源码.rar

    这是一个基于Java技术栈开发的权限管理系统源码,主要利用了Spring Security、Spring MVC、Spring和Hibernate四个核心框架。下面将详细解析这些技术及其在权限管理中的应用。 **Spring Security** Spring Security...

    hibernate annotation hibernate3

    四、继承策略注解 1. `@Inheritance`和`@Inheritance(strategy=InheritanceType.SINGLE_TABLE)` 单表继承策略,所有子类数据存储在同一张表中,通过一个字段来区分不同类型的实体。 2. `@Inheritance(strategy=...

    基于jsp+struts+spring+hibernate的土地管理系统源码.zip

    下面将详细解释这四个主要技术及其在系统中的作用。 1. **JSP(JavaServer Pages)**: JSP是Java的一种动态网页技术,用于创建交互式的、数据驱动的Web应用。在这个系统中,JSP主要用于展现视图层的内容,接收...

    hibernate实战 英文版

    #### 四、适用人群与学习建议 - **适用人群**: - Java开发人员,特别是那些希望深入学习和掌握Hibernate框架的开发者。 - 数据库管理员和架构师,希望通过ORM工具简化数据库操作的人员。 - 学生和技术爱好者,...

    hibernate-3.2源代码

    四、实体类与映射文件 Hibernate通过XML映射文件(.hbm.xml)或注解来定义实体类与数据库表的对应关系。映射文件中定义了实体属性、主键生成策略、关联关系等。 五、对象状态与生命周期 在Hibernate中,对象有三种...

    精通hibernate3.0(第三版).rar

    《精通Hibernate 3.0(第三版)》是Java开发者深入理解对象持久化技术的一本经典教程。本书全面覆盖了Hibernate 3.0的核心概念、API以及最佳实践,旨在帮助读者掌握这一强大的ORM(对象关系映射)框架,提升开发效率...

    Could not roll back Hibernate transaction.doc

    四、Hibernate事务管理机制 Hibernate的事务管理机制是基于JDBC的,它提供了对数据库的事务管理功能。Hibernate的事务管理机制可以自动管理事务的提交和回滚,确保数据库的一致性和完整性。 五、Hibernate事务回滚...

    hibernate框架开发2016版视频 四天学习笔记完整版

    【hibernate框架开发2016版视频 四天学习笔记完整版】 在软件开发领域,特别是Java Web开发中,Hibernate是一个非常重要的对象关系映射(ORM)框架,它极大地简化了数据库操作,使开发者可以更专注于业务逻辑而不是...

    hibernate经典教材从入门到精通(共四篇)

    第四篇通常会涵盖一些实战和最佳实践,如性能优化技巧,如何减少数据库访问次数、提高查询效率,以及如何避免常见的性能瓶颈。此外,还可能讨论Hibernate与其他技术的集成,如Spring框架的整合,以及在实际项目中的...

    Hibernate知识点总结

    #### 四、Hibernate常用接口和类 - **Configuration**:负责管理Hibernate的配置信息,包括数据库连接信息、持久化类与数据表的映射关系等。 - **ServiceRegistry**:用于管理Hibernate的服务和配置,确保服务的...

    jsf2(primefaces3)+spring+hibernate案例下载

    这是一个基于Java技术栈的Web应用开发案例,使用了JSF2、PrimeFaces3、Spring和Hibernate四个核心框架。首先,让我们逐一深入理解这些技术及其在项目中的作用。 **JSF2 (JavaServer Faces 2)** 是一个用于构建用户...

    hibernate开发所依赖的jar包

    在Java世界中,Hibernate是一个非常流行的对象关系映射(ORM)框架,它允许开发者使用面向对象的方式来操作数据库,极大地简化了数据库操作。本压缩包包含了进行普通Hibernate开发所需的最基本jar包,确保你能顺利...

    hibernate_reference中文版和Hibernate中文手册

    6. 对象状态:Hibernate区分了瞬时、持久化、托管和脱管四种对象状态,理解这些状态有助于正确管理对象的生命周期。 7. 关联映射:包括一对一(@OneToOne)、一对多(@OneToMany)、多对一(@ManyToOne)、多对多...

Global site tag (gtag.js) - Google Analytics