Hibernate3.0
预备知识
:
Core Java
JDBC
SQL
Hibernate
理论基础
1.
什么是
hibernate?
2.
hibernate
的知识内容
3.
什么是对象持久化
?
对象持久化有什么用
?(
解决的问题
)
4.
如何对象持久化
?
5.
如何用数据库的方法做对象持久化
?
6.
ORM(
对象关系映射
)
是什么
?
有什么作用
?
7.
ORM
从对象到表所要考虑的问题
8.
什么是
ORM
框架
?
有什么用
?
9.
使用
hibernate
的方法做对象持久化的工作
,
程序员应该怎么做
?
10.
hibernate
有什么用
?
11.
程序员和
hibernate
的整体工作流程
什么是
hibernate:
持久化的框架
,
属于设计方面的内容
,
类库
,
用来做对象持久化的
,
什么是对象持久化呢
?
Hibernate
的知识内容
:
语法部分
(
类库
)
程序设计思想
,
也就是持久层的设计
什么是对象持久化
?
对象持久化有什么用
?(
解决的问题
):
发现问题
:
程序设计的架构
:
表现层
—
业务层
—
持久层
—
数据库层
,
其中表现层和业务层是
JVM
来执行
,
应用程序会产生许多的对象
,
如果断电了
,
对象就消失了
,
也就是说在内存中的对象是不稳定的
,
状态不能持久
发现问题
:
将一个对象从
A
电脑复制到
B
电脑
,
如何做到呢
?
那么有三种方法解决上面的问题
:
1.
序列化
:
通过网络传递
,
或者硬盘共享
2.
存储到数据库中
,
谁想用
,
从数据库中拿
3.
EJB Entity Bean(
实体
Bean)
序列化的方法比较死板
:
如果当一个对象的结构比较复杂的时候
,
我们这时只需要一部分内容
,
没有办法
,
只能整个写入到文件
,
整个读取
序列化的缺点
:
不能检索
,
不能分离一个对象
,
不方便共享
所以说第一种方法只能用于做临时的持久化
,
简单的传输
,
但不适合复杂的持久化工作
第二种方法
(
数据库持久化
):
检索方便
,
分布式共享
,
永久数据
总结
:
什么是对象持久化
:
对象持久化就是把内存中的对象永久的保存起来
,
保护对象的状态
,
方便使用
对象持久化有什么用
: 1.
解决掉电的问题
2.
共享方便
3.
保证对象安全
检索方便
如何对象持久化
:
1.
对象序列化
2.
数据库
(JDBC,EJB,Hibernate)
如何用数据库的方法做对象持久化
:
1.
JDBC
发现问题
:
需要做大量的工作
,
难度大
2.
EJB
使用的是其中的一个功能来做持久化
,
解决了使用
JDBC
方法的的大量工作的问题
发现问题
: EJB
是重量级的组件
,
要使用它
,
有两个问题
1.
成本
2.
性能
发现问题
:
以上两种方式还有个共同的问题
,
对象不是简单存储在数据库中的
,
比如多态的特点就不能处理
A b=new B(); B
为
A
的子类
3.
Hibernate
解决了以上的所有问题
,
作用
:1.
不用做大量的工作
2.
移植性能好
3.
提高了代码的质量
,
简单
4.
检索
共享
重用
成本
调试
ORM(
对象关系映射
)
是什么
?
有什么作用
?
发现问题
:
java
中的对象的属性类型和数据库中的字段类型是不一样的
,
那么如何来存储
java
中的对象呢
?
这就需要做对象关系的映射
,
也就是
ORM
什么是
ORM:
将内存中的对象和数据库做转化
,
这样就实现了
java
与数据库之间的访问等功能
ORM
从对象到表所要考虑的问题
:
Orm
的复杂问题
:
1.
数据库如何保证对象的唯一性
:
在内存中
,
两个对象属性值都一样
,
但是内存地址不一样
,
可以做区分
,
但是在数据库中如何分辨呢
?
2.
继承关系如何转化
3.
集合如何映射呢
?
什么是
ORM
框架
?
有什么用
?
就是一个类库
,
通过这个类库完成持久化层的设计
使用
hibernate
的方法做对象持久化的工作
,
程序员应该怎么做
?
1.
将
ORM
方案定下来
,
就是类到数据库的转化
2.
利用
hibernate
生成代码
hibernate
有什么用
?
1.
完成
jdbc
的代码
2.
管理持久化对象的状态
3.
提供一个查询的
API
程序员和
hibernate
的整体工作流程
程序员
:
1.
设计
ORM
方案
2.
写配置文件
3.
调用
Hibernate
的
API,
向
Hibernate
发出命令
hibernate:
4.
读配置文件
5.
生成
jdbc
代码
6.
执行
Hibernate
简单实例
Hibernate
语法
:
作用
:
数据库的增删改查
HQL
面向对象的查询语句
大致步骤
:
1.
设置环境
类库
2.
定义映射
A
定义映射的实体
po
B
建立数据库表
C
写
XML
配置文件
(
表
,
数据库
)
3.
调用
Hibernate API
A
管理
po
的状态
(
增删改
,
恢复
po
状态
)
B
检索
(
查询
)
Hibernate
第一个简单的实例
:
引例
(frisHbn
包
)
1.
设置环境
hibernate
配置环境需要的资源
Hibernate
的
jar
包
: lib.zip dtd.zip: dtd.zip
可以不设置
2.
定义映射
建立项目
:
bussiness
包
: entity
包
Biz
包
业务
client
包
:
测试
util
包
:
工具
先写持久化类
:
以花为实体
,
建立花类
,
并且建立数据库表
/**
*
建表语句
:
* CREATE TABLE T_FRUIT(
FID NUMBER(10) PRIMARY KEY,
NAME VARCHAR(20) NOT NULL,
COMMENTS VARCHAR(50),
PRICE NUMBER(5) NOT NULL
);
*/
package Yuchen.fristHbn.business.entity;
//
持久化类
(
花类
),
注意因为采用的是
hilo
的方式获得
id,
所以需要有
setid
的方法
public class Fruit {
private Integer fid;//hibernate
中的
id
不能识别
int
private String name;
private String comments;
private int price;
public Fruit() {
super();
}
public Fruit(String name, String comments, int price) {
super();
this.name = name;
this.comments = comments;
this.price = price;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Integer getFid() {
return fid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void setFid(Integer fid) {
this.fid = fid;
}
}
使用
hilo
的方式获得
id:
建表语句
:
CREATE TABLE T_HILO(HILO_ID NUMBER(10));
INSERT INTO T_HILO VALUES(1);
写
hibernate
的连接数据库的配置文件
:
<?xml version="1.0"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="show_sql">true</property>
<property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@127.0.0.1:1521:name</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<property name="connection.isolation">2</property>
<property name="dialect">org.hibernate.dialect.Oracle9Dialect</property>
<mapping resource="Yuchen/fristHbn/business/entity/Fruit.hbm.xml"/>
</session-factory>
</hibernate-configuration>
写映射配置文件
:
<?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="Yuchen.fristHbn.business.entity">
<class name="Fruit" table="T_FRUIT">
<id name="fid" column="fid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="name" column="name" />
<property name="comments" column="comments"></property>
<property name="price" column="price"></property>
</class>
</hibernate-mapping>
A.
类名
—
表名
B.
id—id
获得
id
的方式
详细信息
(
如
: hilo
的表名和字段
)
C.
属性
—
字段
使用
hibernate API(FruitManager.java):
package Yuchen.fristHbn.business.Biz;
//
业务逻辑类
:
负责增删改查
通过使用
hibernate API
进行
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import Yuchen.fristHbn.business.entity.Fruit;
public class FruitManager {
public void insert(Fruit fruit){
Configuration config=new Configuration();
config.configure();//
读配置文件
SessionFactory sf=config.buildSessionFactory();//
得到工厂
Session session=sf.openSession();//
得到
session
Transaction tt=session.beginTransaction();//
检查事务开启
session.save(fruit);//
存储
insert
tt.commit();//
提交
session.close();//
关闭资源
}
}
写测试类
:
插入一个对象到数据库中
/**
*
知识点
:
* hibernate
基础
:
练习语法部分
API
和简单的映射关系
*
程序目标
:
*
使用
hibernate
方法将对象进行持久化
*
实现数据库的增删改查
* API:
* 1.Configuration:
这个类负责读取
XML
文档
(
映射配置文件
)
* configure():
读
xml
* buildSessionFactory():
创建一个生产
session
对象的工厂
,
其实是再次检查
*
因为
hibernate
和
jdbc
不一样
,jdbc
是如果不手动设置开启事务
,
那它
*
就是马上执行
sql
的
,hibernate
的不会马上执行
,
是事务提交后执行
*
默认情况下就是打开事务的状态
,
这里只是再检查以下
* 2.SessionFactory:
负责生产
session
对象
* openSession():
创建一个
session
* 3.Session
类
:
这个是主要的类
,
负责增删改查
,
开启事务等
* beginTransaction():
产生一个事务对象
(Transaction)
* save():
增加相当于操作
sql
中的
insert
语句
* 4.Transaction
类
:
负责管理事务的
* commit():
提交一个事务
*
*/
package Yuchen.fristHbn.client;
import Yuchen.fristHbn.business.Biz.FruitManager;
import Yuchen.fristHbn.business.entity.Fruit;
public class Test {
public static void test1(){
Fruit fruit=new Fruit("lisi","hello",100);
// fruit.setName("zhangsan");
// fruit.setComments("hello");
// fruit.setPrice(100);
FruitManager fm=new FruitManager();
fm.insert(fruit);
}
public static void main(String[] args) {
// TODO
自动生成方法存根
Test t=new Test();
t.test1();
}
}
hibernate API(
一
):
Configuration:
读取配置文件信息
用来初始化的
SessionFactory:
重量级对象
,
特点
:
消耗资源大
,
线程是安全
,
所以可以被共享
上面两个对象只实例化一个就行了
,
都是用于初始化的
Session:
线程是不安全的
,
所以要避免多个线程共享它
,
是轻量级的对象
,
使用后关闭
Session
对象的状态
:
顺态
:
还没有被持久化
,
也就是说数据库中没有该对象的记录
,
并且
Session
中的缓冲区里没有这个对象的引用
持久态
:
在数据库中有该对象的记录
,
并且在
session
中的缓冲区里有这个对象的引用
,
和顺态正好相反
游离态
:
在数据库中有记录
,
但是不在
session
的缓冲区里
对象状态的转换
:
做一个工具类
,
将
hibernate
中重复的代码包装起来
:
package Yuchen.fristHbn.util;
//
生产
session
对象的工具类
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HbnUtil {
private static SessionFactory sf;
static{
sf=new Configuration().configure().buildSessionFactory();
}
public static Session getSession(){
return sf.openSession();
}
}
完善
FruitManager
类
:
package Yuchen.fristHbn.business.Biz;
//
业务逻辑类
:
负责增删改查
通过使用
hibernate API
进行
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import Yuchen.fristHbn.business.entity.Fruit;
import Yuchen.fristHbn.util.HbnUtil;
public class FruitManager {
public Integer insert(Fruit fruit){
Session session=HbnUtil.getSession();//
通过工具更方便了
Integer id=null;
// Configuration config=new Configuration();
// config.configure();//
读配置文件
// SessionFactory sf=config.buildSessionFactory();//
得到工厂
// Session session=sf.openSession();//
得到
session
Transaction tt=session.beginTransaction();//
检查事务开启
id=(Integer)session.save(fruit);//
存储
insert
tt.commit();//
提交
session.close();//
关闭资源
return id;
}
public Fruit selectId(Integer id){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Fruit fruit=(Fruit)session.get(Fruit.class, id);
t.commit();
session.close();
return fruit;
}
public void remove(Fruit fruit){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
session.delete(fruit);
t.commit();
session.close();
}
}
测试对象状态的转换
:
/**
*
知识点
:
* hibernate
基础
:
练习语法部分
API
和简单的映射关系
*
程序目标
:
*
使用
hibernate
方法将对象进行持久化
*
实现数据库的增删改查
* API:
* 1.Configuration:
这个类负责读取
XML
文档
(
映射配置文件
)
* configure():
读
xml
* buildSessionFactory():
创建一个生产
session
对象的工厂
,
其实是再次检查
*
因为
hibernate
和
jdbc
不一样
,jdbc
是如果不手动设置开启事务
,
那它
*
就是马上执行
sql
的
,hibernate
的不会马上执行
,
是事务提交后执行
*
默认情况下就是打开事务的状态
,
这里只是再检查以下
* 2.SessionFactory:
负责生产
session
对象
* openSession():
创建一个
session
* 3.Session
类
:
这个是主要的类
,
负责增删改查
,
开启事务等
* beginTransaction():
产生一个事务对象
(Transaction)
* save():
增加相当于操作
sql
中的
insert
语句
* 4.Transaction
类
:
负责管理事务的
* commit():
提交一个事务
* test1():
测试插入的功能
* test2():
测试数据同步更新的功能
* test3():
测试
saveOrUpdate()
* test4():
测试
clear()
和
flush()
*/
package Yuchen.fristHbn.client;
import org.hibernate.Session;
import org.hibernate.Transaction;
import Yuchen.fristHbn.business.Biz.FruitManager;
import Yuchen.fristHbn.business.entity.Fruit;
import Yuchen.fristHbn.util.HbnUtil;
public class Test {
public void test1(){
Fruit fruit=new Fruit("lisi","hello",100);
// fruit.setName("zhangsan");
// fruit.setComments("hello");
// fruit.setPrice(100);
FruitManager fm=new FruitManager();
fm.insert(fruit);
}
public void test2(){
//
测试同步更新的功能
Fruit fruit=new Fruit("meigui","hongse",70);//
顺态
FruitManager fm=new FruitManager();
Fruit fruit2=new Fruit();
Integer id=fm.insert(fruit);
fruit2=fm.selectId(id);
System.out.println(fruit2.getFid());
System.out.println(fruit2.getName());
fruit.setName("ziluolan");//
这里修改了对象
fruit2=fm.selectId(id);
System.out.println(fruit2.getFid());//
但是结果没有更新
System.out.println(fruit2.getName());
//
因为
fruit
在
Integer id=fm.insert(fruit);
后变成游离态了
//
也就是说只有持久态才能实现同步更新
System.out.println(fruit.getFid());
System.out.println(fruit.getName());
}
public void test3(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Fruit fruit=new Fruit("ziluolan","lanse",100);//
顺态
Fruit fruit2=new Fruit();
FruitManager fm=new FruitManager();
session.save(fruit);//fruit
在运行完此句后变为游离态
fruit2=(Fruit) session.get(Fruit.class, fruit.getFid());
//
从数据库读并打印出来
System.out.println(fruit2.getFid()+":"+fruit2.getName());
session.saveOrUpdate(fruit);//
如果该对象为游历态就更新数据库
update
//
否则就是顺态
,
增加
insert
fruit2=(Fruit) session.get(Fruit.class, fruit.getFid());
//saveOrUpdate
后再从数据库读并打印出来
System.out.println(fruit2.getFid()+":"+fruit2.getName());
//
两个打印结果一样
,saveOrUpdate
方法判断如果
id
为
null,
就
//
顺态
,
否则就是游离态
t.commit();
session.close();
}
public void test4(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Fruit fruit=new Fruit("guihua","fense",300);//
顺态
Fruit fruit2=new Fruit();
session.saveOrUpdate(fruit);//
执行
insert
因为对象为顺态
// session.flush();
session.clear();//fruit
变成游离态了
,
并且不会执行
insert
语句
//
因为
hibernate
不是马上执行
sql,
而是等
t.commit()
提交事务
//
后才执行
,clear
后
,
对象为游离态
session.saveOrUpdate(fruit);//
这里验证上面的话
,
执行
update
//
做个
select
查看一下
,
可以证明
,
因为
clear
后
,
没有马上执行
//sql
语句
,
所以表里没有数据
,
这里
update
也没有用
,
所以表中
//
一个对象也没插入
,
但是如果加入
flush()
刷新就是马上执行
sql
了
t.commit();
session.close();
}
public static void main(String[] args) {
// TODO
自动生成方法存根
Test t=new Test();
// t.test1();
// t.test2();
// t.test3();
t.test4();
}
}
hibernate API(
二
):
flush():
从上面的例子可以看出
,flush
是刷新
session
的缓冲区
,
并执行里面的命令
flush()
的事务管理模式
: flushMode()
里面有三个常量
,
可以用数字来表示
Load():
另一种读取数据的方法
,
和
get
的区别是
: 1.
异常处理
: load
有异常处理
,get
没有
,
它返回
null,2.get
从数据库读数据
,load
可能去读缓冲区
事务的隔离级别
:
在
hibernate
的数据库配置文件中设置
数字
1
为可以脏读
,
数字
2
为不能
,
这个是最常用的
锁机制
:
避免并发冲突
,
在数据库中写数据是自动加锁的
,
读一般不加
,
有悲观锁和乐观锁
乐观锁是可以是
hibernate
程序自己加
实现乐观锁
:
引例
(hbn2
包
)
步骤
:
1.
在表中加个
version
字段
2.
在持久类里加个
version
属性
3.
配置文件
<version name=”versopm”>
每存一次值加
1
引例
:hbn2
包
复杂的映射
:
1.
基数关系映射
2.
继承关系映射
3.
组件关系映射
4.
集合映射
基数关系的映射
—one to one:
基数关系的映射需要考虑的问题
:
1.
数量问题
2.
方向问题
在
one to one
的关系中
,
我们有两种方法可以体现类与类之间的关系
1.
共享主键
2.
外键唯一
引例
: Joto
包
-
此包引用了
fristHbn
包
建立与
Fruit
类有一对一关系的类
:
我们认为一个花有一个产地
,
一个产地生产一种花
,
所以要建立产地类
package Yuchen.Joto.business.entity;
//
花的地址类
//
问题
:
为什么不能在构造函数中写
Fruit?
因为生成对象后要持久化
//
这个对象
,
但是数据库的表中不能插入另一个类的值
,
写上
null
又不
//
大合适
,
所以就去掉它
public class Address {
private Integer aid;
private String nation;
private String postcode;
private Fruit fruit;
public Address() {
}
public Address(String nation, String postcode) {
super();
this.nation = nation;
this.postcode = postcode;
}
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public Fruit getFruit() {
return fruit;
}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
// fruit.setAddress(this);
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
修改
Fruit
类
:
package Yuchen.Joto.business.entity;
//
持久化类
(
花类
),
注意因为采用的是
hilo
的方式获得
id,
所以需要有
setid
的方法
public class Fruit {
private Integer fid;//hibernate
中的
id
不能识别
int
private String name;
private String comments;
private int price;
private Address address;//
一朵花对应一个地址
public Fruit() {
super();
}
public Fruit(String name, String comments, int price) {
super();
this.name = name;
this.comments = comments;
this.price = price;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
address.setFruit(this);//
因为当你给一个花设置产地的时候
//
该产地也有了花
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Integer getFid() {
return fid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public void setFid(Integer fid) {
this.fid = fid;
}
}
为地址实体类建表
:
//oto
共享主键方式
create table t_address(
aid number(10) primary key,
nation varchar2(30) not null,
postcode varchar2(10) not null,
constraint address_fruit foreign key(aid) references T_FRUIT(fid)
);
注意建表的方式不同
,
所对应的映射文件也有些区别
共享主键方式的映射文件
:
<?xml version="1.0"?>
<?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="Yuchen.Joto.business.entity">
<class name="Fruit" table="T_FRUIT">
<id name="fid" column="fid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="name" column="name" />
<property name="comments" column="comments"></property>
<property name="price" column="price"></property>
<one-to-one name="address" cascade="all" />
</class>
<class name="Address" table="t_address">
<id name="aid" column="aid">
<generator class="foreign">
<param name="property">fruit</param>
</generator>
</id>
<property name="nation" column="nation"></property>
<property name="postcode" column="postcode"></property>
<one-to-one name="fruit" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
思路
:
写类
—
表
,
类中的属性
—
字段
,
类关系
(
从数据库的角度出发
)
外键唯一的方式
:建表:
create table t_address(
aid number(10) primary key,
nation varchar2(30) not null,
postcode varchar2(10) not null,
fid number(10) not null unique,
constraint address_fruit foreign key(fid) references T_FRUIT(fid)
);
配置文件中修改
<one-to-one name="fruit"
constrained="true"></one-to-one>
为
<many-to-one name="fruit" column="fid" unique="true" cascade="all" />
client
程序
:
/**
/**
*
知识点
:
*
基数关系映射
:one to one
*
程序目标
:
* 1.
写持久类
,
建立持久类之间的关系
* 2.
定义映射关系
,
为
po
建表
:
两种建表方式
*
第一种
:
共享主键
*
第二种
:
外键唯一
* 3.
写映射文件
*
共享主键情况下映射文件的写法
:
* A.
主键方
:<one-to-one name="
引用类型变量名
" cascade="all">
* B.
外键方
:<one-to-one name="
引用类型变量名
" constrained="true">
*
外键唯一情况下映射文件的写法
:
* A.
主键方
:<one-to-one name="
引用类型变量名
" cascade="all">
* B.
外键方
:<many-to-one name="
引用类型变量名
" column="fid" unique="true" cascade="all" />
*/
package Yuchen.Joto.client;
import org.hibernate.Session;
import org.hibernate.Transaction;
import Yuchen.Joto.business.entity.Address;
import Yuchen.Joto.business.entity.Fruit;
import Yuchen.Joto.util.HbnUtil;
public class Test {
public void test1(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Fruit fruit=new Fruit("
掉蓝
","
绿色
",260);
Address arddess=new Address("
中国
","
崛起
");
fruit.setAddress(arddess);
session.save(fruit);
t.commit();
session.close();
}
public static void main(String[] args) {
// TODO
自动生成方法存根
Test t=new Test();
t.test1();
}
}
基数关系的映射
(one to many):
引例
:Jotm
包
我们认为一种花有多个产地
:
建立花类
:
package Yuchen.Jotm.business.entity;
//
花类
import java.util.HashSet;
import java.util.Set;
public class Fruit {
private Integer fid;
private String name;
private String comments;
private int price;
private Set addresses = new HashSet();//
一种花有多个产地
public Fruit() {
super();
}
public Fruit(String name, String comments, int price) {
super();
this.name = name;
this.comments = comments;
this.price = price;
}
public void setAddress(Address address) {
addresses.add(address);
address.setFruit(this);
}
public Set getAddresses() {
return addresses;
}
public void setAddresses(Set addresses) {
this.addresses = addresses;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public Integer getFid() {
return fid;
}
public void setFid(Integer fid) {
this.fid = fid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
建立产地类
:
package Yuchen.Jotm.business.entity;
//
地址类
public class Address {
private Integer aid;
private String nation;
private String postcode;
private Fruit fruit;//
一个地址对应一种花
public Address() {
super();
}
public Address(String nation, String postcode) {
super();
this.nation = nation;
this.postcode = postcode;
}
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public Fruit getFruit() {
return fruit;
}
public void setFruit(Fruit fruit) {
this.fruit = fruit;
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
建立数据库表
:
Fruit
类
:
create table T_FRUIT_many2one(
FID number(10) PRIMARY KEY,
NAME VARCHAR2(20) NOT NULL,
COMMENTS VARCHAR2(50),
PRICE number(5) NOT NULL
);
Address
类
:
这个是多的一方
,
所以他的外键的值要引用
Fruit
类的主键值
CREATE TABLE T_ADDRESS_many2one(
AID number(10) PRIMARY KEY,
NATION VARCHAR2(30) NOT NULL,
POSTCODE VARCHAR2(10) NOT NULL,
AFID number(10) NOT NULL,
CONSTRAINT ADDRESS_FRUIT_many2one FOREIGN KEY(AFID)
REFERENCES T_FRUIT_many2one(FID)
);
写映射配置文件
:
<?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="Yuchen.Jotm.business.entity">
<class name="Fruit" table="T_FRUIT_many2one">
<id name="fid" column="fid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="name" column="name" />
<property name="comments" column="comments"></property>
<property name="price" column="price"></property>
<set name="addresses" inverse="true" cascade="all">
<key column="afid"></key>
<one-to-many class="Address"></one-to-many>
</set>
</class>
<class name="Address" table="t_address_many2one">
<id name="aid" column="aid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="nation" column="nation"></property>
<property name="postcode" column="postcode"></property>
<many-to-one name="fruit" column="afid" cascade="all"></many-to-one>
</class>
</hibernate-mapping>
client
类
:
/**
*
知识点
:
*
基数关系映射
:one to many
*
程序目标
:
*
映射文件的写法
:
* 1.
主键方
:
* <set name="
引用类型的变量
" inverse="true" cascade="all">
* <key column="
外键名
">
* <one-to-many class="
外键的类名
"></one-to-many>
* 2.
外键方
:
* <many-to-one name="
引用类型的变量
" column="
外键名
" cascade="all">
*/
package Yuchen.Jotm.client;
import Yuchen.Jotm.business.Biz.FruitManager;
import Yuchen.Jotm.business.entity.Address;
import Yuchen.Jotm.business.entity.Fruit;
public class Test {
public static void main(String[] args){
FruitManager fm=new FruitManager();
Address address1=new Address("
北京
","0000");
Address address2=new Address("
上海
","000340");
Fruit fruit=new Fruit("
玫瑰
","
红色
",2000);
fruit.setAddress(address1);
fruit.setAddress(address2);
fm.insert(fruit);
}
}
基数关系的映射
(many to many):
我们把花和产地看为多对多的关系
:
引例
:Jmtn
包
修改产地类
:
package Yuchen.Jmtn.business.entity;
import java.util.HashSet;
import java.util.Set;
//
产地类
public class Address {
private Integer aid;
private String nation;
private String postcode;
private Set fruits=new HashSet();//
一个地址对应一种花
public Address() {
super();
}
public Address(String nation, String postcode) {
super();
this.nation = nation;
this.postcode = postcode;
}
public Set getFruits() {
return fruits;
}
public void setFruits(Set fruits) {
this.fruits = fruits;
}
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public void setFruit(Fruit fruit) {
fruits.add(fruit);
// fruit.setAddress(this);
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getPostcode() {
return postcode;
}
public void setPostcode(String postcode) {
this.postcode = postcode;
}
}
建表
:
Fruit
类
:
create table T_FRUIT_many2many(
FID number(10) PRIMARY KEY,
NAME VARCHAR2(20) NOT NULL,
COMMENTS VARCHAR2(50),
PRICE number(5) NOT NULL
);
Address
类
:
这个是多的一方
,
所以他的外键的值要引用
Fruit
类的主键值
CREATE TABLE T_ADDRESS_many2many(
AID number(10) PRIMARY KEY,
NATION VARCHAR2(30) NOT NULL,
POSTCODE VARCHAR2(10) NOT NULL
);
中间表
:
CREATE TABLE FRUIT_ADDRESS(
FID number(10) NOT NULL REFERENCES T_FRUIT_MANY2MANY(FID),
AID number(10) NOT NULL REFERENCES T_ADDRESS_MANY2MANY(AID),
PRIMARY KEY(FID,AID)
);
映射配置文件
:
<?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="Yuchen.Jmtn.business.entity">
<class name="Fruit" table="T_FRUIT_many2many">
<id name="fid" column="fid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="name" column="name" />
<property name="comments" column="comments"></property>
<property name="price" column="price"></property>
<set name="addresses" table="fruit_address" inverse="true" cascade="save-update">
<key column="fid"></key>
<many-to-many class="Address" column="aid"></many-to-many>
</set>
</class>
<class name="Address" table="t_address_many2many">
<id name="aid" column="aid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="nation" column="nation"></property>
<property name="postcode" column="postcode"></property>
<set name="fruits" table="fruit_address" cascade="save-update">
<key column="aid"></key>
<many-to-many class="Fruit" column="fid"></many-to-many>
</set>
</class>
</hibernate-mapping>
cline
类
:
/**
*
知识点
:
*
基数关系映射
:many to many
*/
package Yuchen.Jmtn.client;
import Yuchen.Jmtn.business.Biz.FruitManager;
import Yuchen.Jmtn.business.entity.Address;
import Yuchen.Jmtn.business.entity.Fruit;
public class Test {
public static void main(String[] args){
FruitManager fm=new FruitManager();
Address address1=new Address("
北京
","0000");
Address address2=new Address("
上海
","000340");
Fruit fruit=new Fruit("
玫瑰
","
红色
",2000);
Fruit fruit2=new Fruit("
紫罗兰
","
紫色
",1000);
fruit.setAddress(address1);
fruit.setAddress(address2);
fruit2.setAddress(address1);
fm.insert(fruit);
fm.insert(fruit2);
}
}
继承关系的映射
:
三个表
发现问题
:
如何体现继承关系呢
?
两种方式
:1.
共享主键
2.
外键唯一
继承中子类有一个
supper,
也就是有一个父类
,
但是父类中没有子类
,
所以是单向的一对一的关系
,
因此在继承中不考虑数量的问题
优点
:
和面向对象的概念相似
,
支持多态
缺点
:
子类的数据会存放很多
,
效率也不高
,
表也多
,
但是数据没有冗余
引例
:Extends
包
1.
建立工具包类
(
省略
)
2.
建立实体类
付款方式
:
现金
银行
package Yuchen.Extends.business.entity;
//
父类
:
付款方式
public abstract class Payment {
private Integer pid;
private String reason;//
付款原因
private Double amount;//
付款金额
public Payment() {
super();
}
public Payment(String reason, Double amount) {
super();
this.reason = reason;
this.amount = amount;
}
public Double getAmount() {
return amount;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}
package Yuchen.Extends.business.entity;
//
银行付款
public class CardPayment extends Payment{
private Integer pid;
private String bank;//
银行卡
public CardPayment() {
super();
}
public CardPayment(String reason, Double omount, String bank) {
super(reason,omount);
this.bank = bank;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getBank() {
return bank;
}
public void setBank(String bank) {
this.bank = bank;
}
}
package Yuchen.Extends.business.entity;
//
现金
public class CashPayment extends Payment{
private Integer pid;
private String cash;//
货币类型
public CashPayment(){
}
public CashPayment(String reason,double amount, String cash) {
super(reason,amount);
this.cash = cash;
}
public String getCash() {
return cash;
}
public void setCash(String cash) {
this.cash = cash;
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
}
建表
:
1.Payment
create table t_payment (
pid number(10) primary key,
reason varchar2(30) not null,
amount number(30) not null
);
2.CardPayment
//
共享主键
create table t_cardpayment(
pid number(10) primary key references t_payment(pid),
bank varchar2(30) not null
);
3.CashPayment
//
共享主键
create table t_cashpayment(
pid number(10) primary key references t_payment(pid),
cash varchar2(30) not null
);
写配置文件
:
<?xml version="1.0"?>
<?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="Yuchen.Extends.business.entity">
<class name="Payment" table="t_payment">
<id name="pid" column="pid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="reason"></property>
<property name="amount"></property>
<joined-subclass name="CardPayment" table="t_cardpayment">
<key column="pid"></key>
<property name="bank"></property>
</joined-subclass>
<joined-subclass name="CashPayment" table="t_cashpayment">
<key column="pid"></key>
<property name="cash"></property>
</joined-subclass>
</class>
</hibernate-mapping>
client:
/**
*
知识点
:
*
继承关系映射
* test1():
三个表
*/
package Yuchen.Extends.client;
import org.hibernate.Session;
import org.hibernate.Transaction;
import Yuchen.Extends.business.entity.CardPayment;
import Yuchen.Extends.util.HbnUtil;
public class Test {
public static void test1(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
CardPayment card=new CardPayment("
买杂志
",100.0,"
人民币
");
session.save(card);
t.commit();
session.close();
}
public static void main(String[] args) {
// TODO
自动生成方法存根
Test.test1();
}
}
继承关系的映射
:
两个表
一个子类一个表
,
父类不建表
,
但是每个子类需要加入父类的属性
缺点
:
不支持多态的查询
,
特点不明显
,
用的很少
建表
:
两个表
:
1.CardPayment
create table t_cardpayment_concrete(
pid integer(10) primary key,
reason varchar(30) not null,
amount double not null,
bank varchar(10) not null
);
2.CashPayment
create table t_cashpayment_concrete(
pid integer(10) primary key,
reason varchar(30) not null,
amount double not null,
cash varchar(10) not null
);
修改配置文件
:
<?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="Yuchen.Extends.business.entity">
<class name="Payment">
<id name="pid" column="pid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="reason"></property>
<property name="amount"></property>
<union-subclass name="CardPayment" table="t_cardpayment_concrete">
<property name="bank"></property>
</union-subclass>
<union-subclass name="CashPayment" table="t_cashpayment_concrete">
<property name="cash"></property>
</union-subclass>
</class>
</hibernate-mapping>
继承关系的映射
:
一个表
优点
:1.
生成报表快
2.
易于实现
3.
支持多态
缺点
:
修改和维护比较麻烦
如果类中的属性太多用这个方法就不大合适了
建表
:
一个表
:
create table t_payment_hierarchy(
pid number(10) primary key,
reason varchar2(30) not null,
amount number not null,
cash varchar2(10) not null,
bank varchar2(10) not null,
type varchar2(10) not null
);
修改配置文件
:
<?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="Yuchen.Extends.business.entity">
<class name="Payment" table="t_payment_hierarchy">
<id name="pid" column="pid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<discriminator column="type"></discriminator>
<property name="reason"></property>
<property name="amount"></property>
<subclass name="CardPayment" discriminator-value="card">
<property name="bank"></property>
</subclass>
<subclass name="CashPayment" discriminator-value="cash">
<property name="cash"></property>
</subclass>
</class>
</hibernate-mapping>
组件映射
and Query:
什么是组件映射
?
我们知道在类的关联关系中有一种关系叫组合关系
,
什么是组合关系呢
?
就是不能独立存在的类
,
我们以前在映射这种关系的时候在一对一的情况下使用的是
one to one
的映射方法
,
这种方法比较复杂
,
那么我们可以使用组件映射的方法使得映射更简单
语法
:
1.
被包含的对象没有
oid,
组件类不能看做
po
2.
组件类不映射一个表
作用
:
只有一个表
,
没有
1to1
的关系
,
使得映射更简单
引例
:
银行帐户
,
有两个类
,
一个是帐户基本信息类
,
另一个是帐户人详细地址类
建立实体类
:
地址类属于值对象
,
帐户类属于实体对象
,
两者之间是组合关系
package Yuchen.component.business.entity;
//
帐号信息类
public class Account{
private Integer aid;
private String name;
private Address address;//
地址
public Account() {
super();
}
public Account(String name, Address address) {
super();
this.name = name;
this.address = address;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public Integer getAid() {
return aid;
}
public void setAid(Integer aid) {
this.aid = aid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package Yuchen.component.business.entity;
//
详细地址类
:
注意不需要
id,
因为要和
Account
建一个表里
public class Address{
private String street;//
街道
private String city;//
城市
private String zipcode;//
邮编
public Address() {
super();
}
public Address(String street, String city, String zipcode) {
super();
this.street = street;
this.city = city;
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
public String getZipcode() {
return zipcode;
}
public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}
}
建表
:
create table t_component(
aid number(10) primary key,
name varchar2(30) not null,
street varchar(30) not null,
city varchar(30) not null,
zipcode varchar(30) not null
);
映射文件
:
<?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="Yuchen.component.business.entity">
<class name="Account" table="t_component">
<id name="aid" column="aid">
<generator class="hilo">
<param name="table">t_hilo</param>
<param name="column">hilo_id</param>
</generator>
</id>
<property name="name" />
<component name="address">
<property name="street" />
<property name="city" />
<property name="zipcode" />
</component>
</class>
</hibernate-mapping>
client:
/**
*
知识点
:
*
组件映射
*/
package Yuchen.component.client;
import org.hibernate.Session;
import org.hibernate.Transaction;
import Yuchen.component.business.entity.Account;
import Yuchen.component.business.entity.Address;
import Yuchen.component.util.HbnUtil;
public class Test{
public static void test(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Address address=new Address("
湖南路
","
上海
","010000");
Account account=new Account("lisi",address);
session.save(account);
t.commit();
session.close();
}
public static void main(String[] args){
Test.test();
}
}
Query:
/**
*
知识点
:
*
组件映射
,Query
查询
* test1():
组件映射
* test2():1.
条件查询
2.from Object 3.uniqueResult()
* test3():
复杂的条件查询
(
支持
like
等
)
* test4():
加参数的查询
* test5():
使用
select:1.
查询一个类中引用类型的属性值
* 2.
查询一个类中引用类型的对象
* test6():
查看两个对象的属性
(
对象数组太麻烦
)
* test7():
使用中间对象查看两个对象的属性
* 1.
建一个中间对象类
* 2.
写
select HQL
语句调用
API
* test8():
命名查询
* 1.
修改配置文件
* 2.
执行
API
* API:
* uniqueResult():
返回唯一的对象
* getNameQuery():
得到变量名所指定的
sql
语句
*/
package Yuchen.component.client;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import Yuchen.component.business.entity.Account;
import Yuchen.component.business.entity.AccountAddress;
import Yuchen.component.business.entity.Address;
import Yuchen.component.util.HbnUtil;
public class Test{
public static void test(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Address address=new Address("
湖南路
","
上海
","010000");
Account account=new Account("lisi",address);
session.save(account);
t.commit();
session.close();
}
public static void test2()
{
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
// Query q=session.createQuery("from Account where name='lisi'");
Query q=session.createQuery("from java.lang.Object");
List list=q.list();
Account account=(Account) list.get(1);
// Account account=(Account) q.uniqueResult();
System.out.println(account.getName());
t.commit();
session.close();
}
public static void test3(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Query q=session.createQuery("from Account a where a.name like '%si'");
Account account=(Account) q.uniqueResult();
System.out.println(account.getName());
t.commit();
session.close();
}
public static void test4(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Query q=session.createQuery("from Account a where a.name like :x");
q.setString("x", "%si");
Account account=(Account) q.uniqueResult();
System.out.println(account.getName());
t.commit();
session.close();
}
public static void test5(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
// Query q=session.createQuery("select a.address.city from Account a where a.name='lisi'");
Query q=session.createQuery("select a.address from Account a where a.name='lisi'");
Address address=(Address) q.uniqueResult();
System.out.println(address.getCity());
// String city=(String) q.uniqueResult();
// System.out.println(city);
t.commit();
session.close();
}
public static void test6(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Query q=session.createQuery("select a.name,a.address from Account a");
List list=q.list();
Object[] obj=(Object[]) list.get(0);//
第一条
(name,address
组成的对象数组
)
// Object[] obj2=(Object[]) list.get(1);//
第二条
System.out.println(obj[0]);
System.out.println(((Address)obj[1]).getCity());
t.commit();
session.close();
}
public static void test7(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Query q=session.createQuery("select new Yuchen.component.business.entity.AccountAddress(a.name,a.address.zipcode) from Account a");
List list=q.list();
Iterator it=list.iterator();
while(it.hasNext()){
AccountAddress aa=(AccountAddress) it.next();
System.out.println(aa.getName());
System.out.println(aa.getZipcode());
}
t.commit();
session.close();
}
public static void test8(){
Session session=HbnUtil.getSession();
Transaction t=session.beginTransaction();
Query query=session.getNamedQuery("mingming");
query.setString("name","%si");
Account aa=(Account) query.uniqueResult();
System.out.println(aa.getName());
t.commit();
session.close();
}
public static void main(String[] args){
Test.test8();
}
}
修改配置文件
:
在
class
后加入
:
<query name="mingming"><![CDATA[from Account a where a.name like :name]]></query>