Hibernate笔记

Hibernate

Hibernate 简单应用(单表)
1. 导入hibernate所需要的jar包:
antlr.jar:用来解析 HQL 语句。
cglib.jar:用来修改类。
asm.jar:在运行时候修改类。依赖于
cglib.jar。commons-collections:提供集合功能,比 java 类中的集合提供更强大的功能。commons-logging.jar:记录日志。jta.jar:分布式事务。当有跨数据库访问的时候,需要这个包。dom4j.jar:用来解析 XML 文件。
(记得导入数据库
jar 包)

2. 配置hibernate.cfg.xml文件(放在“src”下)

<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN""http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd

">

<hibernate-configuration><session-factory>

<propertyname="hibernate.dialect">

>

</property

org.hibernate.dialect.MySQLDialect

批注 [z1]: 数据库的方言。

批注 [z2]: 数据库驱动的名称。

批注 [z3]: 连接数据库的 URL 地址。批注 [z4]: 用户名。
批注
[z5]: 密码。

批注 [z6]: 每次加载 hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。

批注 [z7]: 显示生成的 SQL 语句。批注 [z8]: 指定映射文件的路径。

<property
name="hibernate.connection.driver_class"> </prope

rty>
<property

name="hibernate.connection.url"> </property>

<property name="hibernate.connection.username"><property name="hibernate.connection.password"><property name="hbm2ddl.auto"> </property>

<property name="show_sql"> </property>

<mapping resource="

</session-factory></hibernate-configuration>

com.mysql.jdbc.Driver

jdbc:mysql:///zhaohan

</property>

root

</property>

123

create

true

com/it315/domain/User.hbm.xml

"/>

Validate:加载 hibernate 时,验证创建数据库表结构。
create:每次加载 hibernate,重新创建数据库表结构,这就是导致数据库表数据丢失的原因。

Hbm2ddl.auto 的配置参数:

传智博客—赵涵笔记 1

3. User.java

4. User.hbm.xml

create-drop:加载 hibernate 时创建,退出是删除表结构。update :加载 hibernate 自动更新数据库结构。

package com.it315.domain;import java.util.Date;public class User {

private long id;private String name;private Date birthday;......set,get方法省略

}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping

package=" ">

<class name="User" table="

<id name="id">
<generator class=" "/>

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

">

com.it315.domain

批注 [z9]: User.java 所在的包。
批注
[z10]: User.java 映射的表名。

批注 [z11]: hibernate 根据底层数据库自行判断采用identity,hilo,sequence 其中一种作为主键生成方式。

批注 [z12]: Name 属性对应生成表中的 user_name 字段。

UserTable

native

"></property>

user_name

<property name="birthday" column="user_birthday"></property>

</class></hibernate-mapping>

package com.it315.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.Configuration;import com.it315.domain.User;

public class Main {
public static void main(String[] args) {

Configuration = new Configuration();

批注 [z13]: Configuration 实例会根据当前的数据库配置信息,构造SessionFactory 实例并返回。

cfg

5. Main.java

传智博客—赵涵笔记 2

批注 [z14]: 如果配置文件的名称不是默认的“hibernat e.cfg .xml”,那么 configure()方法要指定文件名。

批注 [z15]: Session 是持久层操作的基础,相当于 jdbc 中的 connection.

批注 [z16]: 对数据有更改的操作都要开启事务和提交事务。Hibernate默认的事务是关闭的。

SessionFactory sessionfactory =cfg. .buildSessionFactory();

Session = sessionfactory.openSession();

User user = new User();user.setName("zhaohan");user.setBirthday(new Date());
Transaction tc = session. ;

session.save(user);

tc.commit();}

}

configure()

session

beginTransaction()

package com.it315.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public final class HibernateUtils {
private static SessionFactory
sessionFactory;static {

Configuration cfg = new Configuration();
sessionFactory = cfg.configure().buildSessionFactory();

}
public static Session
getSession(){

return sessionFactory.openSession();}

}

package com.it315.main;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.User;
import com.it315.util.HibernateUtils;

Domain Object的限制:
○1 必须有一个无参数的构造方法。
○2 有无意义的表示符
id.(可选)
○3 非 final 的,对懒加载有影响。(可选)

注意 :初始化的代码是很耗资源的,所以将上面代码修改为:HibernateUtils.java

Main.java

传智博客—赵涵笔记 3

public class Main {
public static void main(String[] args) {

Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();

User user = new User();user.setName("zhaohan");user.setBirthday(new Date());

tc = session.beginTransaction();session.save(user);
tc.commit();

} catch (Exception e) {if(tc != null){

tc.rollback();

throw new RuntimeException(e.getMessage(),e);}

} finally {
if(session != null){

session.close();}

}}

}

<id name="id"

<generator class="native"/></id>

unsaved-value="0"

>

批注 [z17]: 设置没有保存的对象的id 值为-1。调用 session
saveOr Updat e()方法,如果这个对象id 和设置的这个-1 是相等的,那么说明这个对象没有被保存过,就保存。如果不相等,那么就更新。

注意:
Hibernate 中的几个重要方法:

○1 save persist 的区别(在没有开启事务的前提下是有区别的,如果开启了事务,则效果是一样的。)

○1 save 在没有开启事务的前提下,会将数据插入数据库,但是当发现事务没有开启的话,插入的数据就会立刻回滚。

○2 persist 在没有开启事务的前提下,不会产生 insert 语句。○2 saveOrUpdate

○3 get load 的区别
□1 调用 get()方法,会立刻访问数据库。生成 select 语句。
□2 调用
load()方法,返回一个代理对象,只有在取得对象属性的时候才会真正的去访

传智博客—赵涵笔记 4

问数据库。例如:

批注 [z18]: 得到的这个 user 对象,是从 User 类继承来的。

static User getUser(long id){Session session = null;

Transaction tc = null;

try {
session = HibernateUtils.getSession();
User user = (User)session.load(User.class, id);System.out.println( );

System.out.println(user.getName());

return user;
} catch (Exception e) {

if (tc != null) {tc.rollback();

throw new RuntimeException(e.getMessage(), e);}

} finally {
if (session != null) {

session.close();}

}

return null;}

user.getClass()

package com.it315.UserDaoImpl;

Hibernate 中的对象的几种状态:
○1 瞬时:数据库中没有数据与之对应,超过作用域会被
JVM 垃圾回收器回收,一般是 new

出来且与 session 没有关联的对象。
○2 持久:数据库中有数据与之对应,当前与
session 有关联,并且相关联的 session

有关闭,事 务没有提 交,持久 对象状态 发生改变 ,在事 务提交时 会影响到 数据库

(hibernate 能检测到)。
○3 托管:数据库中有数据与之相应,但当前没有
session 与之关联。托管对象状态发生改

变,hibernate 不能检测到。

判断对象的状态是根据 session 判断的,看它与 session 是否关联。例如:刚查到的对象,在 session 还没有关闭之前,是持久状态,因为数据库中有数据与它对应,且相关联的 session 没有关闭,这时候修改它的属性,hibernate 能检测到。若在 session关闭之后,虽然数据库中也有数据与它相对应,但没有与 session 关联,所以变为托管状态。

增,删,改,查:UserDaoImpl.java

传智博客—赵涵笔记 5

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.daoI.UserDaoI;import com.it315.domain.User;
import com.it315.util.HibernateUtils;

public class UserDaoImpl implements UserDaoI {Session session = HibernateUtils.getSession();

Transaction tc = null;

@Override
public void
saveUser(User user) {

try {
tc = session.beginTransaction();session.save(user);
tc.commit();

} finally {
if (session != null) {

session.close();}

}}

@Override
public User
findUserById(long id) {

try {
User user = (User) session.get(User.class, id);return user;

} finally {
if (session != null) {

session.close();}

}}

@Override
public User
findUserByName(String name) {

try {
Query q = session

.createQuery("from User as user where user.name =?");q.setString(0, name);

传智博客—赵涵笔记 6

=:

");

/*Query q = session
.createQuery("from User as user where user.name

q.setString("*/

User user = (User) q.uniqueResult();

name

批注 [z19]: name 是随便起的。

批注 [z20]: 和上面批注的 name 保持一致。

name

", name);

return user;} finally {

if (session != null) {session.close();

}}

}

@Override
public void
updateUser(User user) {

try {
tc = session.beginTransaction();session.update(user);tc.commit();

} finally {
if (session != null) {

session.close();}

}}

public void saveOrUpdate(User user){try {

tc = session.beginTransaction();session.saveOrUpdate(user);tc.commit();

} finally {
if (session != null) {

session.close();}

}}

@Override
public void
remove(User user) {

try {
tc = session.beginTransaction();

传智博客—赵涵笔记 7

session.delete(user);

tc.commit();} finally {

if (session != null) {session.close();

}}

}}

package com.it315.test;import java.util.Date;
import org.junit.BeforeClass;import org.junit.Test;

import com.it315.UserDaoImpl.UserDaoImpl;import com.it315.daoI.UserDaoI;
import com.it315.domain.User;

public class UserDaoImplTest {static UserDaoI dao = null;static User user = null;

@BeforeClass
public static void
setUpBeforeClass() throws Exception {

dao = new UserDaoImpl();
user = new User();user.setName("zhangsan");user.setBirthday(new Date());

}

@Test
public void
testFindUserById() {

User user = dao.findUserById(19);

System.out.println(user.getName());}

@Test
public void
testFindUserByName() {

User user = dao.findUserByName("mali");

System.out.println(user.getBirthday());}

@Test

Test.java

传智博客—赵涵笔记 8

public void testRemove() {user.setId(19);dao.remove(user);

}

@Test
public void
testSaveUser() {

dao.saveUser(user);}

@Test
public void
testUpdateUser() {

user.setId(19);user.setName("maik");dao.updateUser(user);

}}

package com.it315.domain;public class Department {

private int id;private String name;get(),set()方法省略......

}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping

package="com.it315.domain">
<class name="Department" table="Department">

<id name="id">
<generator class="native"/>

</id>

<property name="name" column="department_name"></property></class>

</hibernate-mapping>

关联和集合的映射
1. 多对一(Employee-Department)○1 Department.java

○2 Department.hbm.xml

传智博客—赵涵笔记 9

○3 Employee.java

○4 Employee.hbm.xml

批注 [z21]: 员工与部门之间是多对一的关系。在这里将 Employee.java里的 depart 属性映射为 Employee 表中的 depart_id 字段。

默认是与部门的 id 进行关联,如果想指定关联的字段:<many-to-one name="depart"column= "depa rt_id "

propert y-ref ="nam e"/>

package com.it315.domain;public class Employee {

private int id;
private String name;private int age;
private Department depart;get(),set()方法省略......
}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping

package="com.it315.domain">
<class name="Employee" table="Emlpoyee">

<id name="id">
<generator class="native"/>

</id>
<property name="name" column="employee_name"></property><property name="age" column="employee_age"></property>
< column="depart_id" />

</class></hibernate-mapping>

many-to-one name="depart"

......

<mapping resource="com/it315/domain/Department.hbm.xml"/><mapping resource="com/it315/domain/Employee.hbm.xml"/>......

package com.it315.test;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Department;import com.it315.domain.Employee;import com.it315.util.HibernateUtils;

○5 hibernate.cfg.xml

○6 Test.java

传智博客—赵涵笔记 10

批注 [z22]: 清除一级缓存。读取数据时默认是先去一级缓存中查询,一级缓存中没有的话才去数据库里查询。

public class Test {
public static void main(String[] args) {

Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Department depart = new Department();depart.setName("JiShu");

session.save(depart);

Employee emp = new Employee();emp.setAge(20);emp.setName("zhaohan");emp.setDepart(depart);

session.save(emp);

session. ;

System.out.println("----------------------------");

Employee emp1 = (Employee)session.get(Employee.class,emp.getId());

System.out.println(emp1.getName());

tc.commit();

} finally {
if (session != null) {

session.close();}

}}

}

clear()

Hibernate: insert into Department (department_name) values (?)Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
----------------------------
zhaohan
JiShu

不调用 clear()方法输出的语句是:

传智博客—赵涵笔记 11

掉用 clear()方法输出的语句是:

Hibernate: insert into Department (department_name) values (?)Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
----------------------------
Hibernate: select employee0_.id as id1_0_, employee0_.employee_name asemployee2_1_0_, employee0_.employee_age as employee3_1_0_,employee0_.depart_id as depart4_1_0_ from Emlpoyee employee0_ whereemployee0_.id=?
zhaohan
Hibernate: select department0_.id as id0_0_,department0_.department_name as department2_0_0_ from Departmentdepartment0_ where department0_.id=?
JiShu

CREATE TABLE `department` (
`id` int(11) NOT NULL auto_increment,`department_name` varchar(255) default NULL,PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

CREATE TABLE `emlpoyee` (
`id` int(11) NOT NULL auto_increment,
`employee_name` varchar(255) default NULL,
`employee_age` int(11) default NULL,
`depart_id` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `FK44624656163671D3` (`depart_id`),
CONSTRAINT `FK44624656163671D3` FOREIGN KEY (`depart_id`) REFERENCES

`department` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

package com.it315.domain;import java.util.Set;

public class Department {
private int
id;
private String name;
private Set<Employee> employee;get(),set()方法省略......

表的定义语句为:

2. 一对多(Department-Employee)○1 Department.java

传智博客—赵涵笔记 12

}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Department" table="Department"><id name="id">

<generator class="native" /></id>

<property name="name" column="department_name"></property><set name=" ">

<key column="

<one-to-many class="Employee" /></set>

</class></hibernate-mapping>

employee

批注 [z23]: 映射 Department employee 属性,它的类型是 set 类型。

批注 [z24]: 生成外键的字段名。(注意这个字段名要和 Employee 表中定义的外键字段名相同。)

depart_id

" />

package com.it315.domain;public class Employee {

private int id;
private String name;private int age;
private Department depart;get(),set()方法省略......

}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping

package="com.it315.domain">
<class name="Employee" table="Emlpoyee">

<id name="id">
<generator class="native"/>

</id>
<property name="name" column="employee_name" /><property name="age" column="employee_age" /><many-to-one name="depart" column=" "/>

批注 [z25]: 这个字段名要和Department.hbm.xml set 集合映射的 key 的字段名相同。

depart_id

○2 Department.hbm.xml

○3 Employee.java

○4 Employee.hbm.xml

传智博客—赵涵笔记 13

</class></hibernate-mapping>

package com.it315.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Department;import com.it315.domain.Employee;import com.it315.util.HibernateUtils;

public class Test {
public static void main(String[] args) {

save();

test();

}
static void
save() {

Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Department depart = new Department();depart.setName("jishu");session.save(depart);

Set<Employee> set = new HashSet<Employee>();

Employee emp = new Employee();emp.setAge(20);emp.setName("lisa");emp.setDepart(depart);session.save(emp);set.add(emp);

Employee emp1 = new Employee();emp1.setAge(21);emp1.setName("zhangsan");emp1.setDepart(depart);session.save(emp1);set.add(emp1);

○5 Test.java

传智博客—赵涵笔记 14

System.out.println("-------------------");depart.setEmployee(set);
tc.commit();

} finally {
if (session != null) {

session.close();}

}}

static void test() {Session session = null;try {

session = HibernateUtils.getSession();

Department depart =(Department)session.get(Department.class, 1);

Set<Employee> set = depart.getEmployee();for(Employee emp : set){

System.out.println(emp.getName());}

} finally {
if(session != null){

session.close();}

}}

}

Hibernate: insert into Department (department_name) values (?)Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
-------------------
Hibernate: update Emlpoyee set depart_id=? where id=?
Hibernate: update Emlpoyee set depart_id=? where id=?
Hibernate: select department0_.id as id0_0_,

○6 运行结果:

传智博客—赵涵笔记 15

department0_.department_name as department2_0_0_ from Departmentdepartment0_ where department0_.id=?
Hibernate: select employee0_.depart_id as depart4_1_, employee0_.id asid1_, employee0_.id as id1_0_, employee0_.employee_name asemployee2_1_0_, employee0_.employee_age as employee3_1_0_,employee0_.depart_id as depart4_1_0_ from Emlpoyee employee0_ whereemployee0_.depart_id=?

zhangsanlisa

CREATE TABLE `department` (
`id` int(11) NOT NULL auto_increment,`department_name` varchar(255) default NULL,PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `emlpoyee` (
`id` int(11) NOT NULL auto_increment,
`employee_name` varchar(255) default NULL,
`employee_age` int(11) default NULL,
`depart_id` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `FK44624656163671D3` (`depart_id`),
CONSTRAINT `FK44624656163671D3` FOREIGN KEY (`depart_id`) REFERENCES

`department` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

package com.it315.domain;

public class Room {private int id;private int floor;private Door door;get(),set()方法省略......}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

表的定义语句为:

3. 一对一(Room-Door)○1 Room.java

○2 Room.hbm.xml

传智博客—赵涵笔记 16

批注 [z26]: 通过外键生成主键。

批注 [z27]: 告诉当前表主键上存在一个约束。

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Room" table="room"><id name="id">

<generator class="native" /></id>

<property name="floor" /><one-to-one name="door" />

</class></hibernate-mapping>

package com.it315.domain;

public class Door {private int id;private int number;private Room room;get(),set()方法省略......}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Door" table="door"><id name="id">

<generator class=" ">

<param name="property">room</param></generator>

</id>
<property name="number" />
<one-to-one name="room" />

</class></hibernate-mapping>

foreign

constrained="true"

package com.it315.test;
import org.hibernate.Session;import org.hibernate.Transaction;import com.it315.domain.Door;import com.it315.domain.Room;

○3 Door.java

○4 Door.hbm.xml

○5 Test.java

传智博客—赵涵笔记 17

import com.it315.util.HibernateUtils;

public class Test {
public static void main(String[] args) {

add();

select();

}

public static void add() {Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Room r = new Room();r.setFloor(1);

Door d = new Door();d.setNumber(2);d.setRoom(r);

session.save(r);session.save(d);

tc.commit();} finally {

if (session != null) {session.close();

}}

}

public static void select() {Session session = null;try {

session = HibernateUtils.getSession();
Room r = (Room) session.get(Room.class, 1);System.out.println(r.getDoor().getNumber());

} finally {
if (session != null) {

session.close();}

}

传智博客—赵涵笔记 18

}}

Hibernate: insert into room (floor) values (?)
Hibernate: insert into door (number, id) values (?, ?)
Hibernate: select room0_.id as id1_1_, room0_.floor as floor1_1_,door1_.id as id0_0_, door1_.number as number0_0_ from room room0_ leftouter join door door1_ on room0_.id=door1_.id where room0_.id=?
2

CREATE TABLE `room` (
`id` int(11) NOT NULL auto_increment,`floor` int(11) default NULL,
PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `door` (
`id` int(11) NOT NULL,
`number` int(11) default NULL,
PRIMARY KEY (`id`),
KEY `FK2F23AE66854F71` (`id`),
CONSTRAINT `FK2F23AE66854F71` FOREIGN KEY (`id`) REFERENCES `room`

(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Door" table="door"><id name="id">

<generator class="native" /></id>

<property name="number" />

<many-to-one name="room" column="room_id" unique="true"/></class>

</hibernate-mapping>

结果:

表的定义语句为:

两张表共用一个主键,所以只执行了一条查询语句。一对一的另一种方法:

Door.hbm.xml

传智博客—赵涵笔记 19

表的定义语句为:

CREATE TABLE `room` (
`id` int(11) NOT NULL auto_increment,`floor` int(11) default NULL,
PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `door` (
`id` int(11) NOT NULL auto_increment,
`number` int(11) default NULL,
`room_id` int(11) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `room_id` (`room_id`),
KEY `FK2F23AEB8C4C155` (`room_id`),
CONSTRAINT `FK2F23AEB8C4C155` FOREIGN KEY (`room_id`) REFERENCES `room`

(`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

package com.it315.domain;import java.util.Set;

public class Teacher {
private int
id;
private String name;
private Set<Student> students;get(),set()方法省略......

public String toString() {
return "id=" + this.id + "name=" + this.name + "students="

+ this.getStudents();

}}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Teacher" table="Teacher">

这种写法其实是多对一加了一个限制,外键只允许有一个,所以才有一对一的效果。4. 多对多(teacher-student)

○1 Teacher.java

○2 Teacher.hbm.xml

传智博客—赵涵笔记 20

批注 [z28]: 生成表的名字。生成表中有两个字段,一个是 teacher id,一个是 student id.

<id name="id">
<generator class="native" />

</id>
<property name="name" column="teacher_name" />
<set name="students" table=" ">

<key column="teacher_id"/>

<many-to-many class="Student" column="student_id"/></set>

</class></hibernate-mapping>

teacher_student

package com.it315.domain;import java.util.Set;

public class Student {
private int
id;
private String name;
private Set<Teacher> teachers;get(),set()方法省略......

public String toString() {
return "id=" + this.id + "name=" + this.name;

}}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="Student" table="Student"><id name="id">

<generator class="native" /></id>

<property name="name" column="student_name"></property><set name="teachers" table="teacher_student">

<key column="student_id" />

<many-to-many class="Teacher" column="teacher_id" /></set>

</class></hibernate-mapping>

○3 Student.java

○4 Student.hbm.xml

○5 Test.java
传智博客—赵涵笔记 21

package com.it315.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Student;import com.it315.domain.Teacher;import com.it315.util.HibernateUtils;

public class Test {
public static void main(String[] args) {

add();

select();}

static void add(){
Session session = null;Transaction ts = null;try{

session = HibernateUtils.getSession();ts = session.beginTransaction();

Set<Teacher> set1 = new HashSet<Teacher>();

Teacher teacher1 = new Teacher();teacher1.setName("t1");set1.add(teacher1);

Teacher teacher2 = new Teacher();teacher2.setName("t2");set1.add(teacher2);

Set<Student> set2 = new HashSet<Student>();

Student student1 = new Student();student1.setName("s1");set2.add(student1);

Student student2 = new Student();student2.setName("s2");set2.add(student2);

teacher1.setStudents(set2);teacher2.setStudents(set2);

传智博客—赵涵笔记 22

session.save(teacher1);session.save(teacher2);session.save(student1);session.save(student2);

ts.commit();

}finally{
if(session != null){

session.close();}

}}

static void select(){Session session = null;Transaction ts = null;try{

session = HibernateUtils.getSession();
ts = session.beginTransaction();
Teacher teacher = (Teacher)session.get(Teacher.class, 1);

System.out.println(teacher.getStudents());

}finally{
if(session != null){

session.close();}

}}

}

Hibernate: insert into Teacher (teacher_name) values (?)
Hibernate: insert into Teacher (teacher_name) values (?)
Hibernate: insert into Student (student_name) values (?)
Hibernate: insert into Student (student_name) values (?)
Hibernate: insert into teacher_student (teacher_id, student_id) values(?, ?)

Hibernate: insert into teacher_student (teacher_id, student_id) values(?, ?)
Hibernate: insert into teacher_student (teacher_id, student_id) values(?, ?)

Hibernate: insert into teacher_student (teacher_id, student_id) values

○6 运行结果:

传智博客—赵涵笔记 23

(?, ?)
Hibernate: select teacher0_.id as id0_0_, teacher0_.teacher_name asteacher2_0_0_ from Teacher teacher0_ where teacher0_.id=?
Hibernate: select students0_.teacher_id as teacher1_1_,students0_.student_id as student2_1_, student1_.id as id2_0_,student1_.student_name as student2_2_0_ from teacher_student students0_left outer join Student student1_ on students0_.student_id=student1_.idwhere students0_.teacher_id=?
[id=1name=s1, id=2name=s2]

CREATE TABLE `teacher` (
`id` int(11) NOT NULL auto_increment,`teacher_name` varchar(255) default NULL,PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

CREATE TABLE `student` (
`id` int(11) NOT NULL auto_increment,`student_name` varchar(255) default NULL,PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

CREATE TABLE `teacher_student` (
`teacher_id` int(11) NOT NULL,
`student_id` int(11) NOT NULL,
PRIMARY KEY (`student_id`,`teacher_id`),
KEY `FK2E2EF2DE7E54D71F` (`teacher_id`),
KEY `FK2E2EF2DE6DB98C7F` (`student_id`),
CONSTRAINT `FK2E2EF2DE6DB98C7F` FOREIGN KEY (`student_id`) REFERENCES

`student` (`id`),
CONSTRAINT `FK2E2EF2DE7E54D71F` FOREIGN KEY (`teacher_id`) REFERENCES

`teacher` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=gbk;

package com.it315.domain;

public class Name {
private String firstName;private String lastName;get(),set()方法省略......

}

○7 表的定义语句:

5. 组件映射(user-name)○1 Name.java

传智博客—赵涵笔记 24

○2 User.java

○3 User.hbm.xml

批注 [z29]: 说明 name 属性是由firstName lastName 两个属性组成。

package com.it315.domain;

public class User {private int id;private Name name;private int age;get(),set()方法省略......

}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping package="com.it315.domain">

<class name="User" table="User"><id name="id">

<generator class="native" /></id>

<component name="name">

</component>

<property name="age" column="user_age"></property></class>

</hibernate-mapping>

<property name="firstName" column="first_name" />

<property name="lastName" column="last_name" />

package com.it315.test;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Name;
import com.it315.domain.User;
import com.it315.util.HibernateUtils;

public class Test {
public static void
main(String[] args) {

User user = new User();user.setAge(20);

Name name = new Name();name.setFirstName("zhang");name.setLastName("san");

○4 Test.java

传智博客—赵涵笔记 25

批注 [z30]: 表中会多加一个字段,用来记录保存数据的顺序,读取的时候就会按照这个字段上的值的顺序读取。

user.setName(name);

Session session = null;Transaction tc = null;try{

session = HibernateUtils.getSession();tc = session.beginTransaction();

session.save(user);

tc.commit();}finally{

if(session != null){session.close();

}}

}}

CREATE TABLE `user` (
`id` int(11) NOT NULL auto_increment,`first_name` varchar(255) default NULL,`last_name` varchar(255) default NULL,`user_age` int(11) default NULL,PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=gbk;

......
<list name = “employee”>

<key column = “depart_id” />

<one-to-many class = “Employee” /></list>

......

<list-index column = “order_col” />

○5 表的定义语句

讨论映射集合为什么用 set?......
private list employees;......

如果改用 list 的话,读取的时候就会按照保存的顺序读取,例如:

因为我们读取数据时候对读取的顺序并没有要求,所以不必要耗费系统资源用 list 读取。如果想用 list,但又不需要顺序的话,可以这样:

传智博客—赵涵笔记 26

批注 [z31]: Bag 的底层借助 List 实现,但却屏蔽了 List 的有序性。Bag集合为无序集,且允许出现重复元素,是 Hibernate 自定义的集合类型。

批注 [z32]: 表示放弃维护关系,默认是 false.

......
< name = “employee”>

<key column = “depart_id” />

<one-to-many class = “Employee” /></bag>

......

bag

......

......

teacher1.setStudents(set2);teacher2.setStudents(set2);student1.setTeachers(set1);student2.setTeachers(set1);

......
<set name="teachers" table="teacher_student" >

<key column="student_id" />

<many-to-many class="Teacher" column="teacher_id" /></set>

......

inverse="true"

static void save() {
Session session = null;

Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Department depart = new Department();depart.setName("jishu");session.save(depart);

Set<Employee> set = new HashSet<Employee>();

Inverse和cascade(Employee-Department)○1 在上面“多对多”的例子中,如果:

这样会报 错,发 生主键 冲突。
这时候可 以放弃 学生的 维护关 系,这 样在保 存学生 的时候 就不 会在中 间表中 产生数 据。

One-to-many 维护关联关系就是更新外键;many-to-many 维护关联关系就是在中间表增减记 录。

注意:配置 one-to-one 的对象不维护关联关系。
如果使用
List 的话,为了保持顺序,不能放弃对关系的维护。

○2 在上面“一对多”的例子中,将 Test.java 中的 save()方法改为:

传智博客—赵涵笔记 27

批注 [z33]: 设置级联保存和更新。当保存部门的时候,连同与它有关的其他对象信息一并保存。

Employee emp = new Employee();emp.setAge(20);emp.setName("lisa");emp.setDepart(depart);//session.save(emp);set.add(emp);

Employee emp1 = new Employee();emp1.setAge(21);emp1.setName("zhangsan");emp1.setDepart(depart);//session.save(emp1);set.add(emp1);

System.out.println("-------------------");depart.setEmployee(set);
tc.commit();

} finally {
if (session != null) {

session.close();}

}

<set name="employee" inverse="true"

<key column="depart_id"></key><one-to-many class="Employee" />

</set>

cascade="save-update"

>

package com.it315.domain;

public class Skiller extends Employee {private String skill;get(),set()方法省略......

}

然后在 Department.hbm.xml 文件中:

一般对 many-to-one many-to-many 不设置级联,在 one-to-one one-to-many 中设置级联。

继承的映射○1 Skiller.java

传智博客—赵涵笔记 28

○2 Sales.java

○3 Employee.java

批注 [z34]: 普通员工的值是 0.

批注 [z35]: 定义了一个鉴别器,类型为 int 型,列名是 type.

批注 [z36]: 技术员工的值是 1,也可以都不赋值,如果不赋值的话,默认在表的字段中用包名+类名区分。

package com.it315.domain;

public class Sales extends Employee {private int sell;get(),set()方法省略......

}

package com.it315.domain;

public class Employee {private int id;private String name;private int age;

public String toString() {
return "id=" + this.id + "name=" + this.name;

}}

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"><hibernate-mapping

package="com.it315.domain">
<class name="Employee" table="Emlpoyee"

<id name="id">
<generator class="native"/>

</id>

<property name="name" column="employee_name" /><property name="age" column="employee_age" /><subclass name="Skiller"

<property name="skill" /></subclass>

<subclass name="Sales" discriminator-value="2"><property name="sell" />

</subclass>

</class></hibernate-mapping>

>

>

discriminator-value="0"

<discriminator type="int" column="type"/>

discriminator-value="1"

○4 Employee.hbm.xml

传智博客—赵涵笔记 29

○5 Test.java

package com.it315.test;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Employee;import com.it315.domain.Sales;
import com.it315.domain.Skiller;import com.it315.util.HibernateUtils;

public class Test {
public static void
main(String[] args) {

add();

select();}

static void add() {
Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Employee em1 = new Employee();em1.setAge(20);em1.setName("el1");

Skiller em2 = new Skiller();em2.setAge(30);em2.setName("e2");em2.setSkill("skill");

Sales em3 = new Sales();em3.setAge(40);em3.setName("e3");em3.setSell(15);

session.save(em1);session.save(em2);session.save(em3);

tc.commit();} finally {

if (session != null) {

传智博客—赵涵笔记 30

session.close();}

}}

static void select() {Session session = null;try {

session = HibernateUtils.getSession();String hql = "from Employee";
Query q = session.createQuery(hql);System.out.println(q.list());

} finally {
if (session != null) {

session.close();}

}}

}

Hibernate: insert into Emlpoyee (employee_name, employee_age, type)values (?, ?, 0)
Hibernate: insert into Emlpoyee (employee_name, employee_age, skill,type) values (?, ?, ?, 1)

Hibernate: insert into Emlpoyee (employee_name, employee_age, sell, type)values (?, ?, ?, 2)
Hibernate: select employee0_.id as id0_, employee0_.employee_name asemployee3_0_, employee0_.employee_age as employee4_0_, employee0_.skillas skill0_, employee0_.sell as sell0_, employee0_.type as type0_ fromEmlpoyee employee0_

[id=1name=el1, id=2name=e2, id=3name=e3]

CREATE TABLE `emlpoyee` (
`id` int(11) NOT NULL auto_increment,`type` int(11) NOT NULL,
`employee_name` varchar(255) default NULL,`employee_age` int(11) default NULL,`skill` varchar(255) default NULL,
`sell` int(11) default NULL,
PRIMARY KEY (`id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8;

○6 运行结果:

○7 生成表的定义语句:

传智博客—赵涵笔记 31

因为在技 术和销 售两个 类里可 能会有 多个字 段,所 以放在 一张表 里会对 系统的 优化造 成影响。所以 要将每 个子类 建立一 张表。
Employee.hbm.xml

批注 [z37]: 生成的表名:skiller.

批注 [z38]: 查询有关 skiller 的信息,会根据这个 emp-id 外键字段去查找。

<class name="Employee" table="Emlpoyee"><id name="id">

<generator class="native"/></id>

<property name="name" column="employee_name" /><property name="age" column="employee_age" /><joined-subclass name="Skiller" table=" ">

<key column="

<property name="skill" /></joined-subclass>
<joined-subclass name="Sales" table="sales">

<key column="emp_id" />

<property name="sell" /></joined-subclass>

</class>

skiller

emp_id

Hibernate: insert into Emlpoyee (employee_name, employee_age) values(?, ?)
Hibernate: insert into Emlpoyee (employee_name, employee_age) values(?, ?)

Hibernate: insert into skiller (skill, emp_id) values (?, ?)Hibernate: insert into Emlpoyee (employee_name, employee_age) values(?, ?)
Hibernate: insert into sales (sell, emp_id) values (?, ?)
Hibernate: select employee0_.id as id0_, employee0_.employee_name asemployee2_0_, employee0_.employee_age as employee3_0_,employee0_1_.skill as skill1_, employee0_2_.sell as sell2_, case whenemployee0_1_.emp_id is not null then 1 when employee0_2_.emp_id is notnull then 2 when employee0_.id is not null then 0 end as clazz_ from Emlpoyeeemployee0_ left outer join skiller employee0_1_ onemployee0_.id=employee0_1_.emp_id left outer join sales employee0_2_ onemployee0_.id=employee0_2_.emp_id
[id=1name=el1, id=2name=e2, id=3name=e3]

CREATE TABLE `emlpoyee` (
`id` int(11) NOT NULL auto_increment,`employee_name` varchar(255) default NULL,`employee_age` int(11) default NULL,

" />

运行结果:

这种映射 在效率 上不是 很理想 。生成表的 定义语 句:

传智博客—赵涵笔记

32

PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `sales` (
`emp_id` int(11) NOT NULL,
`sell` int(11) default NULL,
PRIMARY KEY (`emp_id`),
KEY `FK682490C46FD469B` (`emp_id`),
CONSTRAINT `FK682490C46FD469B` FOREIGN KEY (`emp_id`) REFERENCES

`emlpoyee` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `skiller` (
`emp_id` int(11) NOT NULL,
`skill` varchar(255) default NULL,
PRIMARY KEY (`emp_id`),
KEY `FK7FFD86BE46FD469B` (`emp_id`),
CONSTRAINT `FK7FFD86BE46FD469B` FOREIGN KEY (`emp_id`) REFERENCES

`emlpoyee` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

<class name="Employee" table="Employee"><id name="id">

<generator class="native" /></id>

<property name="name" column="employee_name"/><property name="age" column="employee_age" /><discriminator column="type" />
<subclass name="Skiller">

<property name="skill" /></subclass>

<subclass name="Sales"><join table="sales">

<key column="employee_id" />

<property name="sell" /></join>

</subclass>

</class>

如果销售 类中有 很多字 段,而 技术类 中只有 很少字 段,那 么需要 混合使 用“一 个类继 承体系 一张表”和“ 每个子 类一张 表”。

懒加载
利用上面 “组件 映射” 那个例 子:
传智博客—赵涵笔记
33

Lazy.java

批注 [z39]: 这里调用了 user getAge()方法,那么会去访问数据库,但此时 session 已经关闭,所以这里会抛出代理没有初始化的异常。

package com.it315.test;
import org.hibernate.Session;
import org.hibernate.Transaction;import com.it315.domain.Name;
import com.it315.domain.User;
import com.it315.util.HibernateUtils;

public class lazy {
public static void
main(String[] args) {

add();
User user = select();System.out.println( );

}

static void add() {
User user = new User();user.setAge(20);

Name name = new Name();name.setFirstName("zhang");name.setLastName("san");

user.setName(name);

Session session = null;Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

session.save(user);

tc.commit();} finally {

if (session != null) {session.close();

}}

}

static User select() {Session session = null;User user = null;
try {

session = HibernateUtils.getSession();

user.getAge()

传智博客—赵涵笔记 34

批注 [z40]: 调用 load()方法返回的是一个代理对象,里面没有值,只有第一次去调用它的方法的时候才会去数据库里查询。

批注 [z41]: 初始化代理对象,传的参数必须是代 理对象 。

} finally {
if (session != null) {

session.close();}

}

return user;}

}

user

= (User)session.load(User.class, 1);

static User select() {
Session session = null;

User user = null;try {

session = HibernateUtils.getSession();user = (User)session.load(User.class, 1);

;

} finally {
if (session != null) {

session.close();}

}

return user;}

}

Hibernate.initialize(user)

......
<class name="Door" table="door">

<id name="id">
<generator class="foreign">

<param name="property">room</param>

load()实现懒加载必须保证 session 没有关闭。Hibernate 提供了一种代理对象初始化的方法:

这时候再 运行上 面那段 程序, 就不会 出现异 常了。

○1 一对一懒加载
必须同时 满足下 面三个 条件, 才能实 现懒加 载。
Lazy != false
Constrained = true
Fetch = select

因为查找 room 的时候一般需要一同把 door 的信息列出来,而查找 door 的时候却不一定要把房间的信息列出来,所以在次我将 room 设为懒加载。

Door.hbm.xml

传智博客—赵涵笔记 35

批注 [z42]: 默认设置。使用代理的方式懒加载。

批注 [z43]: Fetch 是设置通过 door 获取 room 的信息时的抓取方式。Join是一条 select 语句全部查询出来,这样无法实现懒加载,所以用 select。必须通过第二条 select 语句才能查询处 room 的信息。(select 是默认配置)

批注 [z44]: Door 不是代理对象,我们设置的 Room 是代理对象,所以我们将 Room 作为参数传进去。

</generator></id>

<property name="number" />
<one-to-one name="room"
constrained="true"

/>

</class>......

lazy="proxy"

fetch="select"

package com.it315.test;
import org.hibernate.Hibernate;import org.hibernate.Session;
import com.it315.domain.Door;
import com.it315.util.HibernateUtils;

public class Lazy {
public static void
main(String[] args) {

Test.add();
Door door =
select();System.out.println(door.getRoom());

}

static Door select() {Session session = null;Door door = null;
try {

session = HibernateUtils.getSession();door = (Door) session.get(Door.class, 1);

;

} finally {
if (session != null) {

session.close();}

}

return door;}

}

Hibernate.initialize(door.getRoom())

Lazy.java

○2 一对多懒加载必须满足 以下两 个条件 :Lazy != falseFetch = select

因为默认的配置就是 lazy =传智博客—赵涵笔记

proxy,fetch =

select,所以配置文件不需要修改。

36

Lazy.java

批注 [z45]: 当确定只有一个结果的时候用 uniqueResult()方法,否则用list().

package com.it315.test;
import org.hibernate.Hibernate;import org.hibernate.Session;
import com.it315.domain.Department;import com.it315.util.HibernateUtils;

public class Lazy {
public static void main(String[] args) {

Test.save();
Department depart =
select();System.out.println(depart.getEmployee());

}
static Department
select(){

Session session = null;Department depart = null;try{

session = HibernateUtils.getSession();
depart = (Department)session.get(Department.class, 1);
Hibernate.initialize(depart.getEmployee());

}finally{
if(session != null){

session.close();}

}

return depart;}

}

static void select(){
Session session = null;

List list = null;try{

session = HibernateUtils.getSession();
String hql = "from Department as depart where depart.name=:n";Query q = session.createQuery(hql);q.setString("n","jishu");
Department depart = (Department) ;

/*

q.uniqueResult()

若不想使用懒加载,只需要在配置文件中将 lazy 的值改为 false,或者将 fetch 的值改为 join.

HQL和Criteria一.最简单 HQL 的查询:

传智博客—赵涵笔记 37

批注 [z46]: 其实索引。
批注
[z47]: 获取最大记录数。

list = q.list();
for(Iterator iter = list.iterator();iter.hasNext();){

Department depart = (Department)iter.next();

System.out.println(depart.getName());}

*/

}finally{
if(session != null){

session.close();}

}}

Query q = session.createQuery(hql);
List list = q.list();
for(Iterator iter = list.iterator();iter.hasNext();){

Object[] rs = (Object[])iter.next();Department d1 = (Department)rs[0];Employee e1 = (Employee)rs[1];

}

setFirstResult(begin)

setMaxResults(count)

;

Criteria crit = session.createCriteria(Department.class);list = crit.list();
for(Iterator iter = list.iterator();iter.hasNext();){

Department depart = (Department)iter.next();

System.out.println(depart.getName());}

Criteria crit = session.createCriteria(Department.class);

○1 如果查询语句是这样:
String hql = “select depart,emp from Department depart,Employee asemp ”+”where depart.id=emp.depart.id and depart.id=:id”;
应当这样 遍历:

查询几个 对象, 数组长 度就是 几。

○2 如果查询语句是这样:
String hql = “from java.lang.Object”;这样的 hql 语句会将所有的对象都查一遍。

○3 分页
q. ;

q.

二 . Criteria○1

○2

传智博客—赵涵笔记 38

crit.add(

crit.add(

crit.addOrder(

list = crit.list();

Restrictions.eq("name","jishu")

);

批注 [z48]: 属性 name 的值必须是jishu.

批注 [z49]: Id 必须在 1 10 之间。批注 [z50]: 按照 id 的倒序排列。

Restrictions.between("id", 1, 10)

);

Order.desc("id")

);

crit.setFirstResult(1);crit.setMaxResults(10);

static void test() {
Session session = null;

try {
session = HibernateUtils.getSession();Department depart =

(Department)session.get(Department.class, 1);System.out.println(depart.getEmployee());

System.out.println("----------");

Department depart1 =(Department)session.get(Department.class, 1);

System.out.println(depart1.getEmployee());} finally {

if(session != null){session.close();

}}

}

相当于这样的 SQl 语句:
Select * from Department where name=”jishu” and id between 1 and 10 orderby id desc

○3 分 页

缓存一.一级缓存

1

两次查询的都是 id 1 Department 对象,因为有一级缓存,所以在第一次查询到了以后,将查询到的对象以及 id 值一同保存在 Map 集合中,在第二次执行相同操作的时候,就不会从数据 库里查 询,直接 去一级 缓存中 读取数 据。这也 就是为 什么只 执行了 一个查 询语句 的原因 。

如果在System.out.println("----------");这一句后面添加:session.clear();
这样就把 一级缓 存清除 了,在第 二次查 询具有 相同id的 对象的 时候,一 级缓存 中没有 数据 ,

所以会去 数据库 中查询 ,这样 就出现 了第二 条查询 语句。
如果一级 缓存中 的对象 特别多 ,只想 清空某 一个对 象的缓 存, 可以调 用evict方法 ,传参

数是对象 类型:
传智博客—赵涵笔记
39

session.evict(depart);

注意:save,update,saveOrUpdate,load,get,list,iterate,lock这些方法都将会对象 放在一 级缓存 中,一 级缓存 不能控 制缓存 的数量 ,所以 要注意 大批量 的操作 数据时 可能造成内存 溢出。

○2

static void test() {
Session session = null;

Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();Department depart =

(Department)session.get(Department.class, 1);System.out.println(depart.getName());

depart.setName("sell");

tc.commit();} finally {

if(session != null){session.close();

}}

}

......<hibernate-configuration>

<session-factory>
<property name="hibernate.dialect">

org.hibernate.dialect.MySQLDialect</property>

<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver

</property>

此时对象为持久状态,所以它的值可以修改,并且生成了updaet语句。

如果在depart.setName(“sell”);这句下面清除一级缓存,那么将不会生成update语句,并且表中的字段也不会修改。因为它的更新是根据一级缓存来和数据库进行同步的。调用setName()方法的时候是不会更新数据的,它的属性值全在一级缓存里,只有在提交事务的时候才会更新数据库。这时候如果将一级缓存清掉,hibernate将无法检测到这种属性变化。

一级缓存的作用范围是很小的,当session关闭,那么一级缓存中的数据也不在了。

二.二级缓存

Update,saveorUpdate,list,iterator,get,load,一级Query,Criteria都会填充二 级缓存 。Save这 个 方法 不适合 native生成 方式的 主键 。
○1
hibernate.cfg.xml

传智博客—赵涵笔记 40

<property name="hibernate.connection.url">jdbc:mysql:///zhaohan

</property>
<property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">123</property><property name="hbm2ddl.auto">create</property>
<property name="show_sql">true</property>

<property name="cache.use_second_level_cache"> </property>

<property name="cache.provider_class">

</property>
<mapping resource="com/it315/domain/Department.hbm.xml" /><mapping resource="com/it315/domain/Employee.hbm.xml" />

<class-cache usage=" "

</session-factory></hibernate-configuration>

true

批注 [z51]: True 为默认值,打开二级缓存。(Hiberna te.pr oper ties文件中第 479 行。)

批注 [z52]: 表示用HashtableCacheProvider 这个缓存实现。(Hibernate.properties 文件中第 494 行提供了多种缓存实现。)

批注 [z53]: 说明缓存中的数据是只读的,不能更改,这样就不需要手工清除缓存;
usage=" read- write "说明放入缓存中的数据是可读可写的。

批注 [z54]: 表示对哪个对象实现二级缓存。

org.hibernate.cache.HashtableCacheProvider

read-write

/>

class="com.it315.domain.Department"

static void cache(){
Session session = HibernateUtils.getSession();
Department depart = (Department)session.get(Department.class,

1);

1);

System.out.println(depart.getName());session.close();

System.out.println("---------------");
Session session1 = HibernateUtils.getSession();

Department depart1 = (Department)session1.get(Department.class,

System.out.println(depart1.getName());

session1.close();}

Hibernate: select department0_.id as id0_0_,department0_.department_name as department2_0_0_ from Departmentdepartment0_ where department0_.id=?
jishu
---------------
jishu

Test.java

运行结果:

传智博客—赵涵笔记 41

两次查询 都是查 询同一id 的同一 对象, 第二次 查询默 认会 去一级 缓存中 查找, 这时候 发现session已经关闭,一级缓存中没有数据,然后会去二级缓存中查找。(二级缓存中没有才会去数据 库中查 找)发 现二级 缓存中 有这个 对象, 所以只 出现 了一条select 语句。

○2HibernateUtils.java

批注 [z55]: 打开统计信息,默认为true.

package com.it315.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;

public final class HibernateUtils {
private static SessionFactory sessionFactory;static {

Configuration cfg = new Configuration();
sessionFactory = cfg.configure().buildSessionFactory();

}
public static SessionFactory
getSessionFactory(){

return sessionFactory;}

public static Session getSession(){return sessionFactory.openSession();

}}

......

<property name="cache.use_second_level_cache">true</property><property name="cache.provider_class">

org.hibernate.cache.HashtableCacheProvider</property>

<property name="generate_statistics"> </property>

<class-cache usage="read-write"class="com.it315.domain.Employee" />

<class-cache usage="read-only"class="com.it315.domain.Department" />

......

true

public class Test {
public static void main(String[] args) {

save();cache();

Hibernate.cfg.xml

Test.java

传智博客—赵涵笔记 42

批注 [z56]: 得到统计信息。(只统计二级缓存,不统计一级缓存)

Statistics s =

System.out.println("往二级缓存中放了"+s.getSecondLevelCachePutCount()+"次");

;

System.out.println("命中了"+s.getSecondLevelCacheHitCount()+"

");

System.out.println(s.getSecondLevelCacheMissCount()+"次在缓存中没有找到");

}

static void save() {
Session session = null;

Transaction tc = null;try {

session = HibernateUtils.getSession();tc = session.beginTransaction();

Department depart = new Department();depart.setName("jishu");session.save(depart);

Set<Employee> set = new HashSet<Employee>();

Employee emp = new Employee();emp.setAge(20);emp.setName("lisa");emp.setDepart(depart);set.add(emp);

Employee emp1 = new Employee();emp1.setAge(21);emp1.setName("zhangsan");emp1.setDepart(depart);set.add(emp1);

depart.setEmployee(set);

tc.commit();

} finally {
if (session != null) {

session.close();}

}

HibernateUtils.getSessionFactory().getStatistics()

传智博客—赵涵笔记 43

}

static void cache(){
Session session = HibernateUtils.getSession();
Department depart = (Department)session.get(Department.class,

1);

1);

}

System.out.println(depart.getName());
session.close();
System.out.println("---------------");
Session session1 = HibernateUtils.getSession();
Department depart1 = (Department)session1.get(Department.class,

System.out.println(depart1.getName());session1.close();

Hibernate: insert into Department (department_name) values (?)Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
Hibernate: insert into Emlpoyee (employee_name, employee_age, depart_id)values (?, ?, ?)
Hibernate:
select department0_.id as id0_0_,department0_.department_name as department2_0_0_ from Departmentdepartment0_ where department0_.id=?
jishu
---------------
jishu

往二级缓 存中放 了1次

批注 [z57]: 这一次是第一回查询Department 对象的时候,将查询到的department 放进缓存中。

批注 [z58]: 第二次查找 Department对象的时候是从二级缓存中查找到的。

批注 [z59]: 第一次查询 Department对象的时候会去缓存中查找,没有查找到,所以去数据库中查找的。

批注 [z60]: 保存一个部门和两个员工信息的时候放进二级缓存,共放了三次。

批注 [z61]: 两次查找部门信息都是从二级缓存中读取,所以命中两次,没有生成 select 语句。

命中了1次

1次在缓存 中没有 找到

jishu---------------jishu

往二级缓 存中放 了3次

命中了2次

运行结果是:

查看命中次数 有助于 对程序 的优化,如果二 级缓存 中保存 的对象 有很多 ,而命 中率却 很少的话,那 就浪费 了资源 。

执行save操作的时候,是会把保存的对象放进二级缓存中的,因为save方法是否将对象放进二级缓存是和主键生成策略有关的,如果是native的话,就不会把对象放进二级缓存。上例中Department和Employee两个主键生成方式都是native,所以在保存两个对象的时候不会放进二级缓存中。

如果将两 个对象 的主键 生成方 式都改 成hilo,那 么执行 的结 果为:

传智博客—赵涵笔记 44

批注 [z62]: 在缓存中查找数据都查找到了,所以没有 miss.

0次在缓存 中没有 找到

static void cache(){
Session session = HibernateUtils.getSession();
Department depart = (Department)session.get(Department.class,

1);

1);

System.out.println(depart.getName());session.close();

System.out.println("---------------");
Session session1 = HibernateUtils.getSession();

Department depart1 = (Department)session1.get(Department.class,

System.out.println(depart1.getName());session1.close();

Session session2 = HibernateUtils.getSession();

String hql = "from Employee emp where emp.id = 32768";Query q = session2.createQuery(hql);
Employee em = (Employee)q.uniqueResult();System.out.println(em.getAge());

session2.close();}

jishu
---------------
jishu
Hibernate:
select employee0_.id as id1_, employee0_.employee_name asemployee2_1_, employee0_.employee_age as employee3_1_,employee0_.depart_id as depart4_1_ from Emlpoyee employee0_ whereemployee0_.id=32768
20
往二级缓 存中放 了3次
命中了2次

有三个方法会从二级缓存中读取数据:iterator,get,load。Iterator方法指的是Query的 iterator方法 。例如:

Iterator iter = query.iterate();Iter.next();

使用下面 例子进 行说明 :

○1 HQL查询

运行结果:

传智博客—赵涵笔记 45

批注 [z63]: 这个信息是从缓存中查询的。

0次在缓存 中没有 找到

static void cache(){
Session session = HibernateUtils.getSession();String hql = "from Employee";
Query q = session.createQuery(hql);
Iterator iter = q.iterate();while(iter.hasNext()){

Employee em = (Employee)iter.next();

System.out.println(em.getName());}

session.close();System.out.println("----------------");

Session session1 = HibernateUtils.getSession();
Employee em = (Employee)session1.get(Employee.class, 32768);System.out.println(em.getAge());

session1.close();}

Hibernate: select employee0_.id as col_0_0_ from Emlpoyee employee0_Hibernate: select employee0_.id as id1_0_, employee0_.employee_name asemployee2_1_0_, employee0_.employee_age as employee3_1_0_,employee0_.depart_id as depart4_1_0_ from Emlpoyee employee0_ whereemployee0_.id=?

lisa
Hibernate:
select employee0_.id as id1_0_, employee0_.employee_name asemployee2_1_0_, employee0_.employee_age as employee3_1_0_,employee0_.depart_id as depart4_1_0_ from Emlpoyee employee0_ whereemployee0_.id=?
zhangsan
----------------

往二级缓 存中放 了2次命中了1次
2次在缓存 中没有 找到

20

HQL查询会生成select语句从数据库中查找,不会去二级缓存中去查找。所以建议在根据id查找数 据的时 候要用get 方法。

○2 iterator方法

运行结果:

这样如果 有N个对 象,那 么就会 出现N+1条 查询语 句。如 果缓 存中没 有对象 但遍历 的对象 又很多的情 况下,用iterator 方法的 话并不 是很好,但若是 第二次 查询的 话,会把 系统优 化很多 。

查询缓存:

传智博客—赵涵笔记 46

上面例一中,HQL查询不会去缓存中查找,我们可以通过配置使Query和Criteria都从缓存中查 找,但是因 为命 中率较 低,所以默 认配置 是关闭 的。(hibernate.properties 文件中第484行)

通过Query或Criteria 查找数 据库得 到的结 果集,hibernate 会把 查询语 句当作key,把返回结 果的id做 为value存到 缓存里 去。那 么第二 次执 行相 同 查询语 句 的时候,发现缓 存里有相关信 息,那么 就会拿 到缓存 中所有id 的集合,然后再 根据id去 一级缓 存和二 级缓存 中去找 ,找不到就 去数据 库中查 找。

将cache.use_query_cache配置为true打开查询缓存,并且调用query.setCacheable(true)或criteria.setCacheable(true)。

注意:查 询缓存 不是一 级缓存 ,也不 是二级 缓存。 如果没 有十 足把握 ,不要 打开查 询缓存,这样 会对性 能有严 重影响 。

清除二级缓存:

批注 [z64]: 将缓存中的所有Department 对象全部清除。如果只想清除 id 1 Department 对象,只需要:
evict(D epart ment. clas s,1)

static void cache(){
Session session = HibernateUtils.getSession();
Department depart = (Department)session.get(Department.class,

1);

1);

}

System.out.println(depart.getName());session.close();

System.out.println("---------------");

Session session1 = HibernateUtils.getSession();
Department depart1 = (Department)session1.get(Department.class,

System.out.println(depart1.getName());session1.close();

HibernateUtils.getSessionFactory().evict(Department.class);

jishu
---------------
Hibernate:
select department0_.id as id0_0_,department0_.department_name as department2_0_0_ from Departmentdepartment0_ where department0_.id=?
jishu
往二级缓 存中放 了4次
命中了1次
1次在缓存 中没有 找到

.......

运行结果:

换OSCacheProvider缓存实现:

传智博客—赵涵笔记 47

批注 [z65]: “sql”参数为配置文件中的命名查询名称。

<property name="cache.provider_class">

org.hibernate.cache.OSCacheProvider

</property>

......

......

<class name="Department" table="Department"><id name="id">

<generator class="hilo" /></id>

<property name="name" column="department_name"></property><set name="employee" inverse="true" cascade="save-update">

<key column="depart_id"></key>

<one-to-many class="Employee" /></set>

</class>

<query name="sql">
from Department depart where depart.id = 1

</query>......

static void cache(){
Session session = HibernateUtils.getSession();Query q = session. ;

Department depart = (Department)q.uniqueResult();System.out.println(depart.getName());session.close();

}

getNamedQuery("sql")

for(int i=0;i<1000000;i++){

只需要将原来的缓存实现换成OSCacheProvider,并且把OSCacheProvider包oscache-2.1.jar导入。

使用缓存的条件:

1. 读取大于修改
2. 数据量不能超过内存容量3. 对数据要有独享的控制4. 可以容忍出现无效数据

将查询语句写在配置文件中

注意大批量操作的问题
大批量的 操作数 据时可 能造成 内存溢 出,解 决办法 如下:

1. 清除session中的数据

传智博客—赵涵笔记 48

批注 [z66]: 只能出现在字段上,不能出现在方法上.

批注 [z67]: 默认设置是 CLASS,但设置成 RUNTIME 才能获取到这个Annotation.

Session.save(obj);if(i%50==0){

session.flush();

session.clear();}

}

package com.it315.jpa;
import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;

@Retention(RetentionPolicy.public @interface HelloWorld {}

@Target(ElementType.FIELD)

RUNTIME

)

package com.it315.jpa;public class TestBean {

@HelloWorld
private String name;private int age;get(),set()方法省略......

}

package com.it315.jpa;
import java.lang.annotation.Annotation;import java.lang.reflect.Field;

public class Test {
public static void main(String[] args)
throws SecurityException,

每当有50条数据的 时候, 就和数 据库同 步一次 ,然 后清除 一级缓 存中的 对象。

2. 用StatelessSession接口,它没有一级缓存,也不和二级缓存,查询缓存交互,通过该接口的操作会立即发送给数据库,与JDBC的功能一样。
StatelessSession s = sessionFactory.openStatelessSession();该接口的方法和session类似。

Annotation
○1 HolloWorld.java

@Target({ElementType.METHOD,ElementType.FIELD})既可以出现在字段上,也可以出 现在方 法上。 里面是 一个数 组,要 中花括 号括起 来。

○2 Bean.java

○3 Test.java

传智博客—赵涵笔记 49

NoSuchFieldException {

test();}

static void test() throws SecurityException, NoSuchFieldException {Class = TestBean.class;

Field

Boolean b = field.
if (b) {
Annotation annotation = field. ;

System.out.println(annotation.getClass());} else {

System.out.println("没有这个Annota tion");}

}}

clazz

批注 [z68]: 得到的Class就是Bean类在硬盘上的描述信息,连同他上面的注解一同可以得到。

批注 [z69]: Name字段的信息全部封装在Field对象里去了,包括字段上的注解。

批注 [z70]: name 字段上是否有helloWorld 这个 Annotation.

批注 [z71]: 得到 HelloWorld 这个Annotation.

field

= clazz.getDeclaredField("name");

isAnnotationPresent(HelloWorld.class)

;

getAnnotation(HelloWorld.class)

package com.it315.jpa;
import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)public @interface Notnull {
}

package com.it315.jpa;

public class TestBean {@Notnull

private String name;private int age;get(),set()方法省略......

}

package com.it315.jpa;
import java.lang.annotation.Annotation;import java.lang.reflect.Field;

public class Test {
public static void
main(String[] args) throws SecurityException,

例:不允许name字段为空○1 Notnull.java

○2 Bean.java

○3 Test.java

传智博客—赵涵笔记 50

NoSuchFieldException {

Bean tb = new Bean();checkNull(tb);

}

static void checkNull(TestBean tb) throws SecurityException,NoSuchFieldException {

Class clazz = TestBean.class;
Field field = clazz.getDeclaredField("name");if(field.isAnnotationPresent(Notnull.class)){

String name = tb.getName();if(name == null){

throw new RuntimeException("名字不得为空!");}

}}

}

Exception in thread "main" java.lang.RuntimeException: 名字不得为空!at com.it315.jpa.Test.checkNull(Test.java:34)
at com.it315.jpa.Test.main(Test.java:13)

○4 运行结果(name并为赋值):

传智博客—赵涵笔记 51

你可能感兴趣的:(Hibernate笔记)