基础
#
优点
完全面向对象编程思想,无sql
减少代码
控制数据库访问,降低访问数据库的频率(第一次访问后,数据存储在内存的缓存中),提升效率
hibernate具有独立性(访问层随时可以更换)
特性
不写hbm.xml映射文件,而是基于注解的验证
对象、集合、属性的延迟加载
dao层之外使用延迟对象时,由于连接已关闭, 会报Nosession异常
目录
. # hibernate程序包
documentation # 文档
lib # 所有依赖包
project # 源码文件
加载顺序
后面的覆盖前面的
hibernate.properties中的配置被覆盖
# 因为该文件中的配置在new Configuration() 的时候就加载,而之后的xml配置文件是调用configuration.addResource()的方法加载的,新加载的配置覆盖了原来的配置 hibernate3.6之后可以基于注解对javaBean的数据进行验证(jsr303标准)
开发流程
加载配置: jdbc参数,数据库方言,hbm映射
创建SessionFactory # 内有连接池
创建session
事务处理
关闭session
关闭连接池
对象状态
𣊬时态 # 没有OID(持久化标识), 没有关联session
持久态 # 有OID, 与session关联, 事务未提交
脱管态 # 有OID, 没有关联session
缓存机制
一级缓存(session)
事务级,事务结束缓存失效 # 请求同一对象,取得同一实例
总是打开
二级缓存
SessionFactory级别,session共享
缓存散装持久化实例, 有不同缓存策略
先设置策略,再设置过期时间与cache提供器
优点
提高速度、减小压力
缓存失效时,不立即查找,而是合并sql查找
查询方式
HQL
QBC(命名查询)
SQL
get与load
get立即加载,load延时加载
get先查一级缓存,再查二级缓存,再查数据库, load查一级缓存,没有时创建代理对象,需要时再查二级缓存和数据库
# 代理对象只存id
get没有时返回null, load抛异常
检索策略 # 取关联对象
立即检索 # 一次全加载, select多
延迟检索 # 访问游离状态代理类,需要在持久化状态时已被初始化
迫切左外连接检索 # 用外连接取代select,全加载
优化
#
数据库设计调整
HQL优化
api正确使用
配置参数 # 日志、查询缓存,fetch_size, batch_size等
映射文件优化 # id生成策略,二级缓存,延迟加载,关联优化
一级缓存管理, 二级缓存策略
事务控制策略
基本概念
#
o-> hibernate 相当于dao层,层次划分中是访问层,解决增、删、改、查、批处理五个问题
o-> hibernate实现orm(对象关系映射标准,完全面向对象编程思想)
DBUtils与i/mybatis 与hibernate 是同样的,同样实现的是orm标准
它们的区别在于
hibernate中不写sql语句
ibatis中写少量sql语句
DBUtils中写sql语句
它们的另一个相同点是
底层全都是jdbc
o-> 结构对应 javabean中的 类,对象,属性
数据库中的 表,记录,字段
o-> hql hibernate query language,hibernate自己的sql语言,需要使用antlr jar包中的方法内部转换成sql语言才能使用
o-> 正向工程:JavaBean生成表,反向工程:表生成JavaBean
使用
#
1.导入核心包(10 + 1个)
hibernate3.jar # 核心包
c3p0-0.9.1.jar
antlr-2.7.6.jar # 转换hql到sql
commons-collections-3.1.jar # apache的集合增强包
dom4j-1.6.1.jar
javassist-3.9.0.GA.jar # 动态代理
jta-1.1.jar # java transaction api 处理事务用
slf4j-api-1.5.8.jar
log4j.jar
slf4j-log4j12.jar # 三个日志
+
mysql-connector-java-5.1.7.bin.jar
2.建立目录
hibernate.dao
demo.java
hibernate.db
xx.sql
hibernate.domain
xx.java
hibernate.util
HibernateUtil.java
3.创建映射文件
xx.java文件的同目录下,创建
xx.hbm.xml
4.创建配置文件
src/hibernate.cfg.xml (可变)
src/hibernate.properties
5.写提供hibernate session的工具类
HibernateUtil
6.demo中用hibernate session创建事务进行数据库操作
demo.java
session
#
查询不需要事务,其它都需要事务
流程
Session session = HibernateUtil.getSession();
Transaction t = session.getTransaction();
t.begin();
session.update(hero);
session.delete(hero);
t.comment();
批量
t.begin();
session.save(hero);
t.commit();
session.clear();
查询
Query query = session.createQuery(hql);
List<Hero> heroList = query.list();
查询2
Query query = session.createQuery(hql);
query.setString(0,name); // hql中参数从0开始
query.setString(1,des);
Hero hero = (Hero) query.uniqueResult(); // 只有一个结果时使用
修改
Query query = session.createQuery(hql);
int i = query.executeUpdate();
结尾
}catch(Exception e){
e.printStackTrace();
t.rollback();
}finally{
HibernateUtil.closeSession(); // session.close();
}
session
元素的状态
# oid: object id,hibernate 的id值唯一并且与表中的数据一一对应
## hibernate中分辨数据只看oid
临时(new),无oid,不在session中.生成sql语句
持久化(persistence object):session.save(hero),有oid,在session中;(saveOrUpdate(hero))
游离:session.evict(hero),有oid,不在session中,session.update(hero)重新持久化
删除:sesssion.delete(hero),有oid,不在session中,不可恢复,提交后可修改数据库
# 隐含将po对象转成持久化状态,并生成delete语句。提交后成delete状态,执行语句
## 临时、持久、游离都可以调用
## 临时调用delete时会删除数据库中相应id的值 ,危险
函数
get 与 load
session.get(hero.class,1),从数据库得到持久状态对象
与数据库交互
查到时返回po
查不到时返回null
session.load(hero.class,1)
不与数据库交互,返回自己创建的po(只有id)
访问非id值的时候,与数据库交互
session.clear() # session中的引用变量清空
session.close() # clear() + 关闭session对象,回收资源,但session非空
session.isOpen()
session.flush() # 对session中的更改部分生成相应的sql语句,只在session中,不访问数据库
session.update() # 只是将游离重新持久化,不产生sql语句。(执行更新语句时加上它增加可读性)
## update()方法执行时会检验一级缓存(session)中是否有 oid相同的po
## ,同时会连接数据库,查询一级缓存中po与数据库中记录的一一对应关系
session.commit() # flush() + 提交事务
hibernate.cfg.xml
#
必要性
必须配置
目录与文件名
任意,建议 src/hibernate.cfg.xml
源码中的案例文件:
\project\tutorials\web\src\main\resources\hibernate.cfg.xml
\project\etc\hibernate.cfg.xml
约束文件位置
hibernate3.jar/org/hibernate/hibernate-configuration-3.0.dtd
数据库连接属性与方言属性的属性名和值可以查找
\project\etc\hibernate.properties # 由于xml文件中配置要覆盖的是hibernate.properties文件中的属性
## 所以属性内容从hibernate.properties文件的属性中查找
方言类的位置是:hibernate3.jar/org.hibernate/dialect/中查找到相应的类,
这是最终的路径,(oracle的通用方言类的类路径 可以用这种方法找到,hibernate.properties配置文件中没有写)
加载
该配置文件属于纯人为配置,需要在Configuration类的实例中调用addResource("")方法加载
addResource()方法中的参数是本配置文件相对于src/目录的全限定名
作用
1.映射数据库
2.配置 类-表映射 资源xml文件的路径
内容
<?xml version="1.0" encoding="UTF-8"?>
<!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="connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
<property name="connection.url">jdbc:oracle:thin:@localhost:1521:orcl</property>
<property name="connection.username">scott</property>
<property name="connection.password">tiger</property>
<!-- 配置方言 通知hibernate访问哪种数据库的语法结构-->
<property name="dialect">org.hibernate.dialect.OracleDialect</property>
<!-- 类表映射文件 -->
<mapping resource="hibernate/domain/Hero.hbm.xml"/>
</session-factory>
</hibernate-configuration>
hibernate.properties
#
必要性
不必须配置
位置:
该文件的位置在src/目录下是不可以改变的,是hibernate加载配置的入口
源码中的参考文件:
/project/etc/hibernate.properties
# oracle的通用驱动可以从hibernate3.jar/org.hibernate/dialect包中查找
作用
1.配置连接的数据库,更换数据库只需要更改配置文件即可
2.配置数据库方言
3.其它控制开关
方言的作用
更换数据库访问形式,实现通用性
内容
hibernate.dialect org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class com.mysql.jdbc.Driver
hibernate.connection.url jdbc:mysql:///outrun
hibernate.connection.username outrun
hibernate.connection.password asdf
hibernate.show_sql true # 开关:显示实际操作数据库的sql语句
自动创建表
hibernate.hbm2ddl.auto=create # 每次都创建
hibernate.hbm2ddl.auto=update # 没有时再创建(有但是结构不同时会按照酌情增加列字段)
## 当更新或插入记录不满足条件时会出错
缓存
hibernate.cache.provider_class # 开启二级缓存中的普通区
hibernate.cache.use_query_cache # 开启二级缓存中的查询区
HibernateUtil
#
目的
对SessionFactory返回Session的方式进行了重构,通过调用该静态工具方法
实现只有一个SessionFactory实例,由它产生和销毁很多Session的工厂机制。
缓存
SessionFactory 是二级缓存
Session 是一级缓存
# 查询时,先在二级缓存中查找,没有数据时查找一级缓存,最后查询数据库
# 缓存中的数据会用镜像联系着数据库,如果数据库有更新,缓存中的数据会自动更新
SessionFactory对象与Session对象
SessionFactory:只创建一次,重量级对象,线程安全,可以共享,实例变量,开始时创建
Session:创建多次,轻量级对象,线程不安全,不可以共享,局部变量,临时创建
实现代码
/**
* 提供hibernate session
* 并且用threadLocal跟踪实现无参删除
*
* @author Administrator
*
*/
public final class HibernateUtil {
// 单例的SessionFactory工厂
private static SessionFactory sessionFactory;
// 单例的ThreadLocal<Session>实例,但是每个调用者都有自己独有的方法?
private static ThreadLocal<Session> threadLocal;
/**
* 解析配置文件(properties,xml)到hibernate 的配置JavaBean,常驻内存
*
*/
static{
// 在这里加载了hibernate.properties配置文件(这里可以配置数据库),执行其它配置
// 相当于jdbc中的DriverManager类(如果配置了数据库,相当于也注册了连接数据库的类文件 【Class.forName("..Driver")语句 ..Driver 新建实例的时候自动向DriverManager注册自己】)
Configuration config = new Configuration();
// 这里写xml配置文件对于src/目录的相对路径,加载映射用xml文件
config.addResource("hibernate.hbm.xml");
// 加载src/目录下的hibernate.cfg.xml配置文件
config.configure(); # configure("classpath:hibernate.cfg.xml");
1.configure方法中可以加路径
2.classpath:代表src/目录
// 导入org.hibernate.SessionFactory类而非org.hibernate.classic.SessionFactory类
sessionFactory = config.buildSessionFactory();
}
/**
* 从单例工厂中得到被跟踪定位(每个调用者)的Session对象,没有就创建
*
* @return
*/
public static Session getSession(){
/* 根据不同的调用者返回跟踪的不同的Session对象,如果是第一次调用,就创建新的session,绑定到单例的ThreadLocal对象中记录,返回给调用者
* 如果不是第一次调用 ,也能返回让其得到原来为它创建的Session对象
*/
Session session = threadLocal.get();
if(session == null){
session = sessionFactory.openSession();
threadLocal.set(session);
}
return session;
}
/**
* 删除调用者在ThreadLocal实例中的跟踪记录,并且关闭该Session实例
*
*/
public static void closeSession(){
Session session = threadLocal.get();
if(session != null){
session.close();
threadLocal.remove();
}
}
}
hql
#
hql特性
1.hql是hibernate专用,有专用的技术转换hql到sql,但降低效率
2.hql完全面向对象,只出现类,属性,操作符和关键字,例如sum(),order by
而sql是面向关系的语言
使用语句
Query query = session.createQuery(hql);
Customer c = (Customer)query.uniqueResult(); # 只返回一条结果
List<Customer> list = query.list(); # 返回多条结果
常用 api
session.createQuery()
session.getNamedQuery() # 从映射文件中加载<query>标签配置的与<class>标签同级的hql语句
query.setString("","")
Object o = query.uniqueResult();
List list = query.list();
分页
query.setFirstResult(0); # 开始标号
setMaxResults(3); # 最多显示的条数
query语句 习惯用别名替代类名
# from后面出现的是类名,where中比较的是对象属性(已经在映射文件中映射到了表名与字段名)
占位符
冒号占位符
"from Customer c where c.name = :cname"
query.setString("cname","司马懿");
问号占位符
"from Customer c where c.name = ?"
query.setString(0,"司马懿");
映射文件中分离hql语句
# <query>标签与<class>标签同级
<Query name="findCustomerByAge">
<![CDATA[
from Customer c where c.age < ?
]]>
Query query = session.getNamedQuery("findCustomerByAge");
query.setInteger(0,60);
查询
"from Customer where id = 1"
"from Customer as c where c.name = '司马懿' "
"from java.lang.Object" # 映射中没有,写类的全称。查找 src/hibernate.cfg.xml中加载到内存中的映射的类对应的表中的所有记录
"from Order o order by o.price desc"
投影查询
1."select c.name,c.age from Customer c "
List<Object[]> list = query.list(); # Object[]中存储的是查询的select 语句中的数值
for(Object [] o : list){
System.out.println(o[0]);
System.out.println(o[1]);
}
2."select count(o), sum(o.price),min(o.price) from Order o" # count()中的是表类名,统计实例数,查询Order表记录对象的个数
3."select o.customer.id from Order o"
用到过的hql
级联抓取
FROM Role r LEFT JOIN FETCH r.privilegeSet WHERE r.id = :id
级联抓取顶级权限表(去重复)
SELECT DISTINCT p FROM Privilege p LEFT JOIN FETCH p.childrenSet WHERE p.parent IS NULL
级联抓取角色
FROM Account a LEFT JOIN FETCH a.roleSet WHERE a.id = :id
三级级联抓取 # 对抓取的集合也可以直接抓取下一层
FROM Account a LEFT JOIN FETCH a.roleSet r LEFT JOIN FETCH r.privilegeSet WHERE a.login = :login AND a.pass = :pass
案例
#
编码
hibernate用用户操作系统的编码作为自己的编码
mysql5.5中设置编码:根目录下my文件 default-character-set=gbk
查询
#
hibernate的查询方式
1.session.get(字节码,1)
2.session.load(字节码,1)
3.HQL查询session.createQuery() session.getNamedQuery() # 后面是从配置文件中载入hql语句
4.对象导航,如多表映射中
# 以对象的形式操作数据库中的表,如
## p是person表的一个对象,c是card(身份证表)表的一个对象,p通过配置外键时定义的属性card得到自己的身份证表对象
## 1.从表对象中:Card c = p.getCard();
## 2.从hql语句中:select o.customer.id,o.customer.name,sum(o.price) from Order o group by o.customer.id
5.createSQLQuery原生sql语句查询: # 不要用,用了以后 hibernate跨平台的特性就没有了
String sql = "select {a.*} from sysgroup {a} where department regexp ?";
Query query = session.createSQLQuery(sql).addEntity("a",SysGroup.class);
# addEntity将表的别名与类字节码关联起来(否则返回的表字段数据是Object类型,jsp页面读取时会出错)
连接查询的hql语法
# 只能连接有外键关系的表类,用表类中的关系类来表示第二张表,不能用笛卡尔积查询
## 也就是说只能查一个表类
注意
hql连接查询的语法中用where替代了sql语法中的on
外连接与 sql不同,只能查询与一个表类有关系的外连接表(from语句后面不能写两个表类)
内连接
from Customer c join c.orderSet o where c.id = o.customer.id
外连接 # 这里与 sql不同,只能查询与一个表类有关系的外连接表
select c.name,count(o.orderno) from Customer c left join c.orderSet o group by c.name;
自连接
select a.name, b.name from emp a, emp b where a.mgr=b.id;
多表映射
#
主控方 # 就是只有主控方的操作成立,非主控方的改变忽略
inverse="true"
# false:主表管理,主表插入成功后,再发送n条更新语句来更新外键
## true:从表管理,自己插入时加上:自己javabean中存放的外键关联
# 所以购物项中要关联购物车,由于购物车中已经一对多购物项,所以形成了双向关联
有该属性的标签
<set>
缺少主控方出现的问题
双向一对多中
1.hibernate生成的sql语句产生重复
2.主键冲突 # 插入操作时,由于“一”表级联插入“多”表,“多”表也要插入自己,它们的主键是相同的,会引起主键冲突
级联 # 数据库只有级联删除
cascade="save-update" # 插入和更新
# 一般使用save-update,因为表一般软删除,(更新也没有,因为主键不更新,但是hibernate没有单save)
cascade="delete"; # 删除订单,级联删上层客户
cascade="none" # 什么都不做(默认)
cascade="all" # save-update + delete
有级联属性的标签
class标签下的
<set>
<one-to-one>
<many-to-one>
注意
级联插入的子表的id内容要为空,否则会变成级联更新 # 这里和单个数据插入时设置对象的id属性不起作用【只有hibernate的主键增长策略起作用】是不同的
单向一对多 # 集合映射的一种
“一”的类中
private Set<Order> orderSet = new LinkedHashSet<Order>();
映射xml文件中
<!-- set标签用于映射单向一对多
name表示单方的关联属性
table表示多方对应表的名字
key-column表示多方对应表的外健
one-to-many-class表示单方关联属性中的每个元素的类型
-->
<set name="orderSet" table="ORDERS" cascade="all">
<key column="CUSTOMERS_ID"/>
<one-to-many class="Order"/>
</set>
单向多对一 # 常用
映射xml文件中
<!--
many-to-one映射多方的关联属性
name表示多方的关联属性名
column表示多方对应表的外健(存储关联类对应表的主键)
cascade 级联
lazy表示“一”的类数据是否在一开始的时候就查询 # 如果lazy="proxy"【相当于懒加载】,action类中加载“一”方数据时会出错,因为调用service类结束后线程中的session销毁,延迟加载找不到session会失败
fetch表示抓取策略
# 这里产生了hibernate的n+1问题:一条查询语句查出"一"的集合,n条查询语句查出集合中每个元素的一
join代表用join语句查询(一条语句),但是hibernate在多对一的时候不支持fetch="join"
默认是select,每次查询用一条select语句(多条语句)
解决:自己写新的查询方法查询,执行hql如:FROM Category c LEFT JOIN FETCH c.account
-->
<many-to-one
name="customer"
column="CUSTOMERS_ID"
cascade="all"
/>
双向一对多 # 双向映射就存在主控方的问题
## 主表从表(外键【可以为空】)
## 集合映射的应用
1.同时配置单向一对多与单向多对一
2.在"一"表中配置inverse="true",反转权力,“多”表为主控方
双向一对一 # 主表从表(从表id既是主键又是外键)
## 双方都是主控方
1.两表都配置<one-to-one/>
2.主表配置cascade
3.从表中constrained=true属性(主键是否同时为外键约束)
多对多(单向左到右,单向右到左,双向) # 集合映射的应用
## 多对多关系中一定要有主控方,否则主键冲突问题
1.创建中间表
# 中间表可以没有自己的JavaBean类文件对应,这时默认有联合主键(联合主键分别是保存的两个外键)
students_id
teachers_id
# student_id 与 teachers_id为联合主键
## sql语句是primary key(student_id,teacher_id);
创建中间表原因:
之所以中间表是因为两边的表中主键唯一,所以不能在一个记录中对对应另一个表的多个记录
中间表相当于把多对多分成两个一对多。
2.表对象类中都有对方表的set集合
3.映射xml中 # 可以用inverse,cascade
## cascade="none"时,middle表中的记录也会被删除
## 不配置主控方的话一边更新另一边,另一边也更新自己,会出错
<set table="MIDDLES" name="teacherSet">
<key columnet="STUDENTS_ID"/>
<many-to-many class="Teacher" column="TEACHERS_ID"/>
4.dao中
在cascade="all"的配置下实现只删除老师与middle表中的教学关系 # 手工解除关系
# 不手工解除关系的话, 表记录对象:Teacher t1
,t1删除时,级联删除middle表中数据,middle表中对应了学生的外键
,由于多对一级联,会删除学生,由于该学生的主键可能会被middle表中的其它记录作为外键引用,所以不能删除,删除时会出错。
查询1号老师对应的学生,并解除关系
Teacher t1
for(Student s: t1.getStudentSet()){
s.getTeacherSet().remove(t1);
}
1号老师解除关系
t1.setStudentSet(null);
session.delete(t1);
缓存
#
缓存
1.一级缓存(session)中的数据是独享的,二级缓存(sessionFactory)中的数据是共享的
2.一级缓存中的数据改变时会更新二级缓存(如果二级缓存设置为read-only时,会更新出错)
3.二级缓存默认不能存po(持久化对象) ,只存放连接数据库的信息和映射文件
# 这时查询数据时的顺序是 一级缓存 -> 数据库
启用二级缓存 # 开启的二级缓存中可以保存po
## 二级缓存的两个空间:普通缓存区(get、load)、查询缓存区(query对象查询)
普通缓存区
hibernate.properties文件中配置
hibernate.cache.provider_class
org.hibernate.cache.HashtableCacheProvider # 只能内存缓存
org.hibernate.cache.EhCacheProvider # 也能磁盘缓存ehcache的jar包中ehcache-failsafe.xml配置文件中可以查到默认缓存配置
# 可以在hibernate的中文官方教程中查到缓存策略提供商的类
## hibernate3.2之前缓存类jar包是集成的,默认是EhCache
## hibernate3.2之后缓存类jar包要自己导入
## ...Provider类并不是实现类,而是桥接类
cache.use_second_level_cache
true # 开启二级缓存(默认是true,但是没有配置缓存提供商之前不开启)
hibernate.cfg.xml文件中配置使用二级缓存的类 # 可以设置<cache>的标签<class><set>
## 设置<set>时,set对应表类的也要设置<cache>标签
<class-cache usage="read-write" class="pojo.Goods" />
usage属性
read-only:二级缓存只读(只是不能进行修改,但是从表中读取数据时一级缓存可以向二级缓存中放入数据)
read-write:可读写
查询缓存区(hql语句):默认不开启
# 因为hql命中率低(要求hql语句相同才行,模糊查询每次基本不同),每次查找会到缓存,找不到再到数据库,查询完数据再存入缓存,效率低
## 不配置的话查询还会存到缓存,但只提供get使用,hql自己不用
1.首先开启普通缓存区(设置了表类可以缓存)
2.在query对象中开启查询缓存区
query.setCacheable(true);
查询顺序:一级缓存 -> 二级缓存 -> 数据库
缓存提供商配置
ehcache缓存提供商
创建src/ehcache.xml配置文件,使用ehcache缓存时会自动加载其中的配置
<diskStore path="java.io.tmpdir"/> # 设置缓存目录,java.io.tmpdir指操作系统的临时目录
diskPersistent
diskExpiryThreadIntervalSeconds # 这两个集群中使用,上面是是否集群持久化,下面是设置持久化时间
maxElementsInMemory # 内存支持最大对象数目(溢出的对象会存到硬盘中)
overflowToDisk # 内在到最大数目时是否缓存到硬盘
eternal # 缓存是否永久有效,如果为true,则timeToIdleSeconds与timeToLiveSeconds不起作用
timeToLiveSeconds # 内存中缓存最大存活时间,服务器启动的时间加入其中
timeToIdleSeconds # 缓存不被访问时最大存活时间
memoryStoreEvictionPolicy # 内存中对象的替换算法FIFO(先进先出first in first out)
## LRU(最近最未使用算法,最久没有被访问的对象踢出)
## LFU(最少未被使用算法,考虑了对象的访问频率,踢出最近最少被访问的对象)
## 是windows自己的替换算法
清空缓存
一级缓存:session.clear();
二级缓存:sessionFactory.close();
集合映射
#
作用
集合包含于表类中,对应其一个属性,相当于该类对应表的一个子表
每种集合对应一张表,内容对应记录。
把java类中经常使用的数据结构对应到表中
使用
javaBean(User)中
private Set<String> telSet = new LinkedHashSet<String>();
private List<String> cityList = new ArrayList<String>();
private Map<String,String> telCityMap = new LinkedHashMap<String,String>();
xml文件中
<set name="telSet" table="TELS">
<key column="USERS_ID"/> # 外键列:集合所创建的表的外键列名
<element column="TEL" type="string"/> # 内容列:这里必需要有type
# set中也可以把<element>标签换成<one-to-many class="Order"/>标签来对应JaveBean作为值,这就是一对多的映射
<list name table>
<key column/>
<list-index column="IDX"/> # 索引列:表中的索引号列(对应在list中的索引)
<element column type/>
<map name table>
<key>
<map-key type column> # map对应key的列
<element column type>
dao中使用
user.getTelSet().add("131");
检索策略
#
hibernate检索的两种类型
立刻检索:session.get,query.list <class lazy="true">标签中类的检索策略,get方法与list都不遵循
延迟检索:session.load # 初始时是代理对象,使用时查询 只有load方法遵循<class lazy="true">标签中类的检索策略
检索方法是load时
lazy属性出现在<class>与<set>标签中,两个标签中lazy属性的含义是不同的,两个lazy属性都是对load方法执行时是否查询数据库进行设置。
# <class>标签中lazy的含义是执行load方法时是否懒于查询数据库中除了set集合之外的所有属性
## <set>标签中lazy的含义是执行load方法时是否懒于查询数据库中set集合的数据
## <class>中默认lazy属性的值为true
## <set>中默认lazy属性的值为true
true true 时 查类时没有查集合
false true 时 查类时没有查集合
false false 时 查类时查集合
true false 时 查类时没有查集合
经验
#
删除的两种方法
session.delete(session.get(Category.class,id)); # 先查询再删除,效率低
session.createQuery("delete Categroy c where c.id=:id").setInteger("id",id).executeUpdate();
# 执行hql语句,效率高
hibernate注解
hibernate3.6支持注解
javaee5不支持,默认关闭
javaee6支持,默认开启,此时不加载注解配置文件会报错,所以要关掉
hibernate.cfg.xml中
<property name="javax.persistence.validation.mode">none</property>
DB Browser反射编译表的生成映射文件和类的时候,会生成项目目录下hibernate.reveng.xml的临时配置文件,可以删掉
映射文件class属性
dynamic-update="true" # 动态更新,只有对相同的session有效,而且性能不好
## 用字段设置中的update="false"(对象中有字段值时更新,没有时不更新)属性来设置动态更新
映射文件set标签属性
Order-by="id" # set中级联对象按照"id"属性进行排序
c3p0
#
c3p0并不是hibernate默认的连接池(默认的是hibernate自带的连接池算法)
配置c3p0以后自动关闭Hibernate自带的连接池,而使用c3p0连接池
hibernate.cfg.xml文件中
<!-- 最大连接数 -->
<property name="hibernate.c3p0.max_size">20</property>
<!-- 最小连接数 -->
<property name="hibernate.c3p0.min_size">5</property>
<!-- 获得连接的超时时间,如果超过这个时间,会抛出异常,单位毫秒 -->
<property name="hibernate.c3p0.timeout">120</property>
<!-- 最大的PreparedStatement的数量 -->
<property name="hibernate.c3p0.max_statements">100</property>
<!-- 每隔120秒检查连接池里的空闲连接 ,单位是秒-->
<property name="hibernate.c3p0.idle_test_period">120</property>
<!-- 当连接池里面的连接用完的时候,C3P0一下获取的新的连接数 -->
<property name="hibernate.c3p0.acquire_increment">2</property>
<!-- 每次都验证连接是否可用 -->
<property name="hibernate.c3p0.validate">true</property>
hibernate.properties文件中
hibernate.c3p0.min_size=5
hibernate.c3p0.max_size=20
hibernate.c3p0.timeout=1800
hibernate.c3p0.max_statements=50
映射
#
hbm.xml
位置与名称:
domain.xx.java 文件同级目录 xx.hbm.xml
约束文件位置
hibernate3.jar/org/hibernate/hibernate-mapping-3.0.dtd
从其中复制约束头
源码中的案例文件
\project\tutorials\中搜索 hbm.xml
类-表映射的特点
1.映射JavaBean到表字段(动态占位符),可以使用面向对象的hql语名生成sql语句
2.session中保存类对象,缓存查询过的表的内容
3.在映射关系的xml文件中可以设置主键的改变方式(这样以后dao类中设置的主键内容被配置文件中的设置覆盖)
主键
表中的主键
自然主键:有业务逻辑含义的字段(如name)(多个自然主键:联合主键)
代理主键
hibernate中id的增加类型
increment 整型,不依赖数据库自增,多线程不安全
uuid 缺点:占空间
identity 整型,依赖数据库自增,线程安全
sequence 专用于oracle数据库,要用特定名字的序列,create sequence hibernate_sequence;线程安全
native(重点) 根据情况判断是identity或sequence
assigned 自然主键:<id name="name" column="name">,线程不安全
composite-id 多个自然主键,表的javaBean必须实现序列化(1.对象序列化到硬盘、数据库【其它JavaBean有id属性,hibernate自动实现序列化】2.线程间传递数据)
<composite-id><key-property name="firstname" column="firstname"/><key-property name="firstname" column="lastname"/>
持久化对象的两种类型
实体型:具有id属性的类,映射成一条含有id主键的完整记录
值类型或组件:与上面相反(被实体型包含),如
# 包含以后会把组件的属性添加到实体类属性的后面,一起当作一张表,仅此而已
# Address
province
city
area
映射组件型属性
1.类中引用组件:private Address address
2.映射 <component name="address" class="Address"><property name column/>
3.dao中 star.setAdrress(address);
内容
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="hibernate.domain">
<class name="Hero" table="heros" dynamic-insert="true">
# 设置动态插入为true:如果是null的值,不再插入
## 如果不设定动态插入,会插入数据库null值,数据库中设定的默认值不会起作用
<!-- hibernate通过自己内部的类型type="",来转换java类型与sql类型之间的转换,一般不必写,自动反射 -->
<!-- id 是指主键,property是属性 -->
<id name="id" column="id">
<!-- hibernate内部的主键生成器 -->
<generator class="increment"/>
</id>
<property name="name" column="name"></property>
<property name="gender" column="gender"></property>
<property name="age" column="age"></property>
<property name="birthday" column="birthday"></property>
<property name="des" column="des"></property>
</class>
</hibernate-mapping>
javaBean
实现序列化接口
在有名为id属性的JavaBean中,hibernate会自动实现序列化接口
没有名为id属性的JavaBean中,需要我们自己实现序列化接口
public class Hero implements java.io.Serializable{
private Integer id;
private String name;
private String gender;
private Integer age;
private Date birthday;
private String des;
}