Hibernate
面向对象操作模型数据库->阻抗不匹配
ORM(Object Relation Mapping->对象关系映射)->完成对象与关系之间的转换
主流ORM框架:Hibernate Toplink OJB
(一)
简单使用步骤:
详见:http://blog.csdn.net/qq_28796345/article/details/52513814
(1)创建项目
(2)导入jar包
(3)创建实体对象Usre
(4)创建User.hbm.xml映射文件(于相应包下)
(5)创建配置文件于src下(hibernate.cfg.xml)
(6)创建测试类(初始化hibernate)
hibernate.cfg.xml:
<!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="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- 所用数据库 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- 数据库url -->
<property name="connection.url">jdbc:mysql:///hibernate</property>
<!-- 数据库用户名 -->
<property name="connection.username">root</property>
<!-- 用户密码 -->
<property name="connection.password">0707</property>
<!-- 创建表 -->
<property name="hbm2ddl.auto">create</property>
<!-- 映射文件位置 -->
<mapping resource="com/sw/hibernate/domain/User.hbm.xml"/>
</session-factory>
</hibernate-configuration>
User.hbm.xml:
<?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.sw.hibernate.domain">
<class name="User" table="user">
<!-- 数据库表主键 column指定字段名 -->
<id name="id" column="id">
<generator class="native"/>
</id>
<!-- property为属性 -->
<property name="name" column="name"/>
<property name="birthday"/>
</class>
</hibernate-mapping>
工具类
初始化:
/*
*@Author swxctx
*@time 2016年9月12日
*/
package com.sw.util;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public final class HibernateUtil {
//工具类 用于初始化hibernate(一次初始化)
private static SessionFactory sessionFactory;
private HibernateUtil(){
}
static{
//需要进行一次初始化
Configuration cfg=new Configuration();
cfg.configure();//读取配置文件
//初始化后得到sessionfactory
sessionFactory = cfg.buildSessionFactory();//类似于DriverManager
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession(){
return sessionFactory.openSession();
}
}
执行方法封装:
/*
*@Author swxctx
*@time 2016年9月12日
*/
package com.sw.util;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.sw.hibernate.domain.User;
public class Tooladd {
static void addUser(User user){
Session s=null;
Transaction tx=null;
try {
//初始化
s=HibernateUtil.getSession();
//操作数据
tx=s.beginTransaction();
//保存对象
s.save(user);
//提交
tx.commit();
} catch (HibernateException he) {
// TODO: handle exception
if(tx!=null){
tx.rollback();//回滚
throw he;//抛出异常
}
}finally{
if(s!=null){
s.close();//关闭
s=null;
}
}
}
static void addUser1(User user){
Session s=null;
Transaction tx=null;
try {
//初始化
s=HibernateUtil.getSession();
//操作数据
tx=s.beginTransaction();
//保存对象
s.save(user);
//提交
tx.commit();
} finally{
if(s!=null){
s.close();//关闭
s=null;
}
}
}
}
Session接口:
get(查询)、load(更新)、persist(保存)方法
实体对象的三种状态与saveOrUpdate(根据id的值来确定使用save还是update方法)方法
(1)瞬时-数据库没有数据与之对应,超过作用域会被jvm垃圾回收。
(2)持久-数据库没有记录,并且session并没有关闭,与session有关
(3)脱管-与session没有关系,与数据库表有对应
HQL与Criteria
1、Hql
实例:
//查询
static void query(String name){
Session s=null;
try {
//初始化
s=HibernateUtil.getSession();
String hql="from User as user where user.name=?";
Query query=s.createQuery(hql);
query.setString(0, name);
List<User> list=query.list();
// Object ob=query.uniqueResult();//返回object类型
for(User user:list){
System.out.println(user.getName());
}
}finally{
if(s!=null){
s.close();//关闭
s=null;
}
}
}
注:在hbm.xml文件中,应该避免属性名与数据库关键字冲突,若冲突,则在前加上反引号即可。
hql的命名参数与Query接口的分页查询:
from User as user where user.name=?
如上语句,如果在字段过多时则不会适用。
解决办法:使用命名参数(为用户定义名字)
from User as user where user.name=:name
query.string("name",name);
Query
分页:
Query query=s.createQuery(hql);
//从第一页开始取结果,每页取十条
query.setFirstResult(0);//实现分页 第一条
query.setMaxResults(10);//每页十条
2、Criteria(条件查询)
实例:
static void cri(String name){
Session s=null;
try {
//初始化
s=HibernateUtil.getSession();
Criteria c=s.createCriteria(User.class);
//查找name对应的数据
c.add(Restrictions.eq("name", name));//传入的参数(约束条件)
c.setFirstResult(0);//分页
c.setMaxResults(10);
List<User> list=c.list();
User u=(User)c.uniqueResult();
for(User user:list){
System.out.println(user.getName());
}
}finally{
if(s!=null){
s.close();//关闭
s=null;
}
}
}
(二)
关联
详见:点击打开链接
多对一关联关系的映射与原理
一对多
多对一
一对一
多对多(使用中间表)->执行速率较慢,不常用
多对多关联关系的检索
两个组件(对象)关联
级联操作-对相应的对象进行统一的操作(保存时都保存、删除时将其数据都删除等)
<set name="em" cascade="save-update">
<key column="depart_id"></key>
<one-to-many class="Employee"/>
</set>
inverse属性(有序集合不能出现,不会放弃关系维护)
用于一对多中->一放弃维护与多个的关联关系
放弃维护关系->不再更新外键
<list name=" " inverse="true">
(四)
继承映射
<?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.sw.hibernate.domain">
<class name="Employee" table="Employee" discriminator-value="0">
<!-- 数据库表主键 column指定字段名 -->
<id name="id" column="id">
<generator class="native"/>
</id>
<discriminator column="type" type="int"/>
<!-- property为属性 -->
<property name="name" column="name"/>
<!-- Department 多对一-->
<!-- depart_id 外键 对应于department的id-->
<many-to-one name="depart" column="depart_id" property-ref="id"/>
<!-- 对象映射 -->
<subclass name="Skiller" discriminator-value="1">
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<property name="sell"/>
</subclass>
</class>
</hibernate-mapping>
每个子类映射到一张表(效率低,结构清晰)
<!-- 每个子类对应一张表 -->
<joined-subclass name="Skiller" table="skiller">
<key column="emp_id"/>
<property name="skill"/>
</joined-subclass>
<joined-subclass name="Sales" table="sales">
<key column="emp_id"/>
<property name="sell"/>
</joined-subclass>
继承映射->1、一个类继承体系一张表 2、每个子类各一张表
<union-subclass>->将每个表都保存完整的信息(每个子类一张表)
(五)
懒加载:Hibernate.initialize(对象)->Domain非final;
通过asm.jar与cglib.jar两个包实现懒加载。
一对一懒加载(默认情况下hibernate会使用懒加载)->查询主对象时不会进行懒加载
查询重对象时,会启用懒加载
除多对一以外,尽量不要禁用懒加载,如果禁用会产生一些意想不到的错误。
懒加载并不能区分空集合,当与数据表结构冲突时(数据为空),则会出现问题。
能够懒加载的对象都是被改写过的代理对象,当相关联的session没有关闭时,访问这些懒加载
对象(代理对象)的属性(getId和getClass除外)。hibername会初始化这些代理,或用hibernate
.initialize(proxy)来初始化代理对象;当相关联的session关闭后,再访问懒加载的对象将
出现异常。
属性亦可进行懒加载。
(六)
1、一级缓存
缓存->第一次读取时将其存放到内存中,第二次直接从内存读取,提高了性能。
(1)将数据放入缓存中->使用map map.put(key,user);
(2)从缓存中取出数据
(3)删除无效数据 map.remove(key);
Session存在缓存,随着session的关闭而消失。
第一次get(获取)时,将数据放入缓存。
session.evict(user);//将user对象从session缓存中清除
session.clear();//清除所有缓存
使用一级缓存需要防止数据溢出(并不会限制放置的个数,直到内存溢出)
一级缓存的存在时间较短(一个请求内),所以会导致数据失效等问题,使用二级缓存可以解决这一问题。
2、二级缓存(SessionFactory级共享)
交给第三方框架处理。
通过配置文件hibernate.cfg.xml进行处理:
<!-- 打开二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 打开查询缓存 -->
<property name="cache.use_query_cache">true</property>
<!-- 所使用的缓存机制 -->
<property name="cache.provider_class">org.hibernate.cache.OSCacheProvider</property>
<!-- 指定需要缓存的类 -->
<class-cache usage="read-only" class="cn/itcast/hibernate/domain/User"/>
指定需要缓存的类,除了在这里指定外,亦可在映射文件中进行配置指定:
<cache usge="read-only"/><!--放置于class内部-->
hibernate寻找数据步骤->先到以及缓存寻找,如果以及缓存不存在该数据,则到二级缓存进行寻找,
若二级缓存仍然不存在,则到数据库中进行寻找。
分布式缓存与中央缓存:
使用缓存的条件:
(1)读取次数大于修改
(2)数据量不能超过内存量
(3)对数据要有独享的控制
(4)可以容忍出现无效数据
(七)
事务
JDBC Transaction(单步事务,使用一个库)
JTA Transaction(分布式事务处理,使用多个库)->跨数据库的事务,由应用JTA容器实现。
openSession()->
getCurrentSession()->获取当前session
ThreadLocal
OpenSessionInView
Hibernate-Mapping->多种属性(隐藏属性的使用)->schema
使用class类可以定义一个持久化类。
鉴别器
property属性亦具有懒加载功能。
Hibernate映射类型。
Session是非线程安全的,生命周期较短,一般不会超过一个请求。代表一个和数据库的连接。
SessionFactory是线程安全的,声明周期较长,一般在整个系统内都是有效的。
保存着喝数据库连接的相关信息。
批量更新
1、flush使一级缓存与数据库同步。
Session.flush();
当数据量较大时,在调用clear之前先调用flush。
2、StatelessSession接口
不和一二级缓存交互,也不触发任何事件。
N+1次查询与懒加载。
N条记录会出现N+1此查询记录。
拦截器
监听器
本地sql查询与命名查询