Hibernate整理

来源:互联网 发布:城门失火 殃及池鱼知乎 编辑:程序博客网 时间:2024/06/05 17:18
Hibernate是一个开放源代码的对象关系映射框架(orm),它对JDBC进行了非常轻量级的对象封装,它将POJO数据库表建立映射关系,是一个全自动的orm框架.
orm:(Object Relational Mapping) 对象关系映射,orm主要解决面向对象与关系型数据库存在的概念不匹配问题
pojo:(Plain Old java Object) 也就是javaBean

配置hibernate:
1.jar包
2.配置文件 cfg.xml
<hibernate-configuration>
<session-factory>
//jdbc驱动 ;com.mysql.jdbc.Driver 需要导入jdbc jar包
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///数据库名</property>
<property name="hibernate.connection.username">mysql用户名</property>
<property name="hibernate.connection.password">mysql密码</property>
<!-- 显示底层生成的SQL语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 格式化显示底层生成的SQL语句 -->
<property name="hibernate.format_sql">true</property>
<!-- 添加映射文件,不写报错 -->
<property name="hibernate.current_session_context_class">thread</property>
方言
<!-- 方言 hibernate-release-5.2.10.Final\project\etc\hibernate.properties 里复制 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>

<!-- #hibernate.hbm2ddl.auto create-drop 无论是否存在表结构,每次执行都会创建表结 构,之后删除
#hibernate.hbm2ddl.auto create 无论是否存在表结构,每次都会创建表结构,数据丢失
#hibernate.hbm2ddl.auto update 如果数据库不存在该表结构,会自动创建
;如果存在该表结构,并且表结构与持久化类一样,不做修改
;如果存在该表结构,并且表结构与持久化类不一样,会修改表结构,保留原有字段
#hibernate.hbm2ddl.auto validate 不会自动创建表结构 ,也不会修改表结构,只对表结构进行验证 表验证 -->
<property name="hibernate.hbm2ddl.auto">update</property>

配置映射文件
<!-- 映射文件: 配置映射文件路径 包名之间斜杠隔开
class 配置全限定名(包名+类名)
packge 配置持久化类所在的包名 "Spring 集成项目的时候可以这么配置" (包名)
-->
<mapping resource="/bean/User.hbm.xml"/>

C3P0
<!-- 连接C3P0
连接池参数 hibernate.connection.provider_class
org.hibernate.connection.C3P0ConnectionProvider
需要自己去找 /hibrnate/lib/hibernate-c3p0-5.2.10.Final.jar
#hibernate.c3p0.max_size 2
#hibernate.c3p0.min_size 2
#hibernate.c3p0.timeout 5000
#hibernate.c3p0.max_statements 100
#hibernate.c3p0.idle_test_period 3000
#hibernate.c3p0.acquire_increment 2
#hibernate.c3p0.validate false -->
<property name="hibernate.connection.provider_class">
org.hibernate.c3p0.internal.C3P0ConnectionProvider
</property>
<property name="hibernate.c3p0.min_size">10</property>


二级缓存
<!-- 二级缓存 默认不开启
#hibernate.cache.use_second_level_cache false
-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- #hibernate.cache.region.factory_class 路径:org.hibernate.cache.ehcache-->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property>

<!-- 配置类缓存,集合缓存 -->
<class-cache usage="read-only" class="bean1.Customer"/>
<class-cache usage="read-only" class="bean1.T_Order"/>
<collection-cache usage="read-only" collection="bean1.Customer.orders"/>

3.核心代码
Configuration configuration=new Configuration().configure();
SessionFactory factory=configuration.buildSessionFactory();
Session session=factory.openSession();
或者得到当前session
// Session session=factory.getCurrentSession()
Transaction transaction = session.beginTransaction();
//创建对象
User user = new User();
user.setUsername("lining");
user.setPassword("123");
//存储user --save : 修改--update : 删除--delete saveorupdate --没有就存,有就不同修改
session.save(user);
//查询
/***
1.User user = session.get(User.class , id); id查询---相当于where id=?;
2.User user = session.load(User.class , id); 懒加载
3.Query query = session.createQuery("from User where id=5");
User user = (User) query.uniqueResult();
4.createCriteria()
5.session.createNativeQuery(“select* from user”):使用原生sql
6.Query query = session.createQuery("from User "); //偏移量查询:分页
query.setFirstResult(1);//偏移量
query.setMaxResults(3); //查询个数
List<User> list = query.list();//返回集合
*/
//提交
transaction.commit();
// 关闭
session.close();
transaction.close();

封装HibernateUtils;
private static SessionFactory factory;
static{
Configuration configuration=new Configuration().configure("hibernate.cfg.xml");
factory=configuration.buildSessionFactory();
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
factory.close();
}
}
)
);
}
public static Session openSession(){
return factory.openSession();
}
public static Session getCurrentSession(){
return factory.getCurrentSession();
}


持久化对象的唯一标识 OID
Hibernate使用OID来建立内存中的对象和数据库中记录的对应关系
结论:对象的OID和数据库的表的主键对应。为保证OID的唯一性,应该让Hibernate来为OID赋值
主键需要具备:不为空/不能重复/不能改变


hbm.xml 对象配置文件重点(*)
<!-- package:配置持久类所在包
之后在class等标签中,name属性直接写类名
<hibernate-mapping package="domain" > -->
<hibernate-mapping>
<!-- class:配置类与表的映射关系
name:类名
table:表名
dynamic-insert:动态插入 默认值 false
设置为true ,如果字段为null,不参与insert语句
dynamic-update:动态修改 默认值 false
设置为true ,没有做修改的属性不参与update语句
-->
<class name="bean.User" table="user">
<!-- 主键
id:主键
name:属性名
column:字段名
unsaved-value:指定某个值当null处理
比如0 当做null 但现在规定建议使用包装类
access:可以指定成员变量名称(强烈不建议使用)
配置access 当访问属性的时候 直接操作成员变量 不会访问 get set方法
-->
<id name="id" column="id" >
<!-- assigned 指定的 native 自增长的-->
<!-- 指定主键的生成策略
generator:生成器
native:主键自动增长
increment:数据库自己维护主键,自动生成,先从表中查最大id,在将id+1 作新的主键
identity:依赖于数据库主键自增功能 在创建表的时候应勾选主键自增
sequence:序列 Orcale维护住建自动生成方式
hilo:hibernate 自定义的维护主键的自增方式
native:(三选一)identity sequence hilo
assigned:手动设置自己维护主键(主键分为 自然 代理) 当主键是自然主键时候
uuid:生成32位字符串作主键
eg: 将id这只为32位字符串 注意修改持久化类的属性类型
-->
<generator class="native" />
</id>
<!-- 其他属性与主键的映射关系
name:属性名
column:字段名
type:类型(java,hibernate ,sql)
length:长度
precision:小数点后的位数 精度
scale:有效位数 salary (5,2) 有效数字5 小数点 2
not-null:非空
unique:唯一
insert:该属性是否参与插入语句 insert
update:该属性是否参与修改语句 update
-->
<property name="username" column="username"/>
<property name="password" column="password"/>
</class>
</hibernate-mapping>

状态介绍
 Hibernate对象有三种状态,session时候缓存对象(一级缓存),数据库中是否有记录判断状态
1.瞬时状态Trasient 缓存和数据库都没有值
2.持久状态Persistent缓存对象有值,数据库最终会有记录(事务尚未提交)
3.游离状态Detached 数据库有值, 缓存没有值

快照:
与一级缓存一样的存储位置,对一级缓存进行备份.保证数据库中的数据与一级缓存中的数据一致,如果一级缓存中数据进行了修改,当提交事务的时候,回自动刷新一级缓存,将数据同步到数据库
快照的产生:只有查询数据库才会发生,查询的数据一式两份,一份存在一级缓存中,一份存在快照中
 

一对一.一对多.多对多:
配置文件
1-1:

第一种形式:
Person表与IdCard表一对一
<!-- name:属性名称
class :属性的类型.全类名
property-ref="" 当前类一对一指向对方的属性名-->
<one-to-one name="idcard" class="bean2.Idcard" property-ref="person"/>
<!-- 使用外键 unique="true" 让多的一端 为一.就是一对一 -->
<many-to-one name="person" class="bean2.Person" column="pid" unique="true"/>

第二种形式:
Company表与Address表一对一
<!-- constrained="true" sql:外键约束--> 进行主键同步 native 自增 assigned 手动设置主键
<one-to-one name="company" class="bean2.Company" constrained="true" />
<one-to-one name="address" class="bean2.Address" />

1-多:
Customer表与T_Order表 一对多

Customer表
<!--
set:配置一对多关系
name:集合的属性名称
key:用来描述外键,
column:外键名称,cid
one-to-many:配置一对多
class:多的一端的全类名
inverse:反转,由谁来维护主键,默认值为false,不反转,由一的一端来维护
true:反转,由多的一端来维护 可以理解为反客为主
cascade="save-update" 联级逻辑.save-update同增改.当没有存储,有就修改.
delete 同删
delete-orphan 删除时.代表多的一端关联值为null时,将会被删除
-->
<set name="orders" inverse="false" cascade="save-update">
<key>
<column name="cid" />
</key>
<one-to-many class="bean1.T_Order" />
</set>


T_Order表
<!--
many-to-one:配置多对一关系
name:属性名
column:外键名称,两个外键名称要求一致
class:一的一端的全类名
-->
<many-to-one name="customer" class="bean1.Customer">
<column name="cid" />
</many-to-one>


多-多
Student表与Course表
需要建立三个表.中间表用来关联
<!-- inverse ;只能一端设置为true,不可同时设置true
table="t_student_course" 中间表名
<key column="cid"></key> 外键
-->
<set name="students" table="t_student_course" inverse="true">
<key column="cid"></key>
<many-to-many class="bean3.Student" column="sid"></many-to-many>
<!-- many-to-many:多对多 class:对方的全类名,集合中元素的全类名 ;
column:对方的外键名称 -->
</set>


类级别检索:
Get:立即加载
Load:延迟加载
<class name="bean3.Course" table="COURSE" lazy="true">
关联级别检索:
一对多:
Fetch:抓取策略,使用哪种查询语句
Join:连接查询
Select:普通查询语句
Subselect:子查询
Lazy:是否延迟加载
True:延迟加载
False:立即加载
Extra:极其懒惰,查询集合中元素个数时,发出查询个数的语句,count()
多对一:
Fetch:
Join:
select
Lazy:
False:立即加载
Proxy:需要取决于类级别检索策略,取决于customer
hql:(structured Query Language)
针对hibernate的sql语句; 语句比较多,可以上网查询. 但语句是重点.以后整理

连接查询:
交叉连接:
内连接:inner join   on
左外连接:left outer join
右外连接:right outer join
迫切左外连接:left outer join fetch

// 交叉连接
@Test
public void test01() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c,Order o");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//内连接,隐式内连接
@Test
public void test02() {
Session session = HibernateUtils.openSession();
session.beginTransaction();

Query query = session.createQuery("from Customer c,Order o"
+ " where c=o.customer");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//内联接,customer c inner join order o on c.id = o.cid
@Test
public void test03() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
//面向对象思想
Query query = session.createQuery("from Customer c inner join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
session.getTransaction().commit();
session.close();
}
//左外连接,left outer join
/*
* 将左表数据全部显示,
* 与右边没有关联的显示为null
*/
@Test
public void test04() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}
session.getTransaction().commit();
session.close();
}
//迫切左外连接,将Order数据封装到Customer中
@Test
public void test05() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer c left outer join fetch c.orders");
List<Customer> list = query.list();
for(Customer obj : list) {
System.out.println(obj);
}
session.getTransaction().commit();
session.close();
}
//右外连接
@Test
public void test06() {
Session session = HibernateUtils.openSession();
session.beginTransaction();

Query query = session.createQuery("from Customer c right outer join c.orders");
List<Object[]> list = query.list();
for(Object[] obj : list) {
System.out.println(Arrays.toString(obj));
}

session.getTransaction().commit();
session.close();
}
//迫切右连接
@Test
public void test07() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Query query = session.createQuery("from Order o right outer join fetch o.customer");
List<Object> list = query.list();
for(Object obj : list) {
System.out.println(obj);
}

session.getTransaction().commit();
session.close();
}
命名查询:
有的hql语句使用比较频繁,可以将hql语句存储到配置文件中,使用时提取hql语句即可
配置文件:
class里写局部变量
<query name="localQuery">
<!--[CDATA[ ]] 处理大于小于 > < 问题
[CDATA[ from Customer c where c.id>10 ]]-->
                           <![CDATA[ from Customer c ]]>
                  </query>
         </class>
class外协全局变量
         <query name="globalQuery">
                  <![CDATA[ from Customer c]]>
         </query>
java:
public void test01() {
                  Session session = HibernateUtils.openSession();
                  session.beginTransaction();
                  //获得全局命名查询的hql语句
                  // Query query = session.getNamedQuery("globalQuery");
  //获取局部命名查询
                  Query query = session.getNamedQuery("com.qf.domain.Customer.localQuery");
                  List<Customer> list = query.list();
                  for (Customer c : list) {
                           System.out.println(c);
                  }
                  session.getTransaction().commit();
                  session.close();
         }
qbc:
-------- Query by Criteria,标准查询
@Test
public void test01() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
List<Customer> list = session.createCriteria(Customer.class).list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

// 排序
@Test
public void test02() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
List<Customer> list = session.createCriteria(Customer.class)
.addOrder(Order.desc("id")).list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

// 查询条件
@Test
public void test03() {
Session session = HibernateUtils.openSession();
session.beginTransaction();
Criteria criteria = session.createCriteria(Customer.class);
// id>10
// criteria.add(Restrictions.gt("id", 10));
// 含有s
// criteria.add(Restrictions.like("name", "%s%"));
// id<5 or id>15
criteria.add(Restrictions.or(Restrictions.lt("id", 5),
Restrictions.gt("id", 15)));
List<Customer> list = criteria.list();
for (Customer c : list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}

离线查询:
DetachedCriteria,不需要使用session可以拼接条件
service层使用DetachedCriteria,拼接条件,之后将DetachedCriteria对象传到dao层进行查询
@Test
public void test01() {
//service层
DetachedCriteria dCriteria = DetachedCriteria.forClass(Customer.class);
dCriteria.add(Restrictions.ge("id", 16));
//dao,findByCriteria(DetachedCriteria dc); dao层
Session session = HibernateUtils.openSession();
session.beginTransaction();
Criteria criteria = dCriteria.getExecutableCriteria(session);
List<Customer> list = criteria.list();
for(Customer c:list) {
System.out.println(c);
}
session.getTransaction().commit();
session.close();
}
二级缓存:
/**
* 二级缓存 二级缓存的不是对象,是对象的散列(属性)
* 之后查询是,从二级缓存中获得属性,那那么在一级缓存中封装对象
*/
/**
* 类缓存/集合缓存
* 只输出一套查询..走第二缓存
* 配置
* <class-cache usage="read-only" class="bean1.Customer"/> 类缓存
* <class-cache usage="read-only" class="bean1.T_Order"/>
* <collection-cache usage="read-only" collection="bean1.Customer.orders"/> 集合缓存
*/
@Test
public void test(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Customer c=session.get(Customer.class, 1);
for(T_Order o:c.getOrders()){
System.out.println(o.getName());
}
session.clear();
Customer c2=session.get(Customer.class, 1);
for(T_Order o2:c.getOrders()){
System.out.println(o2.getName());
}
session.getTransaction().commit();
session.close();
}
/**
* 查询缓存 针对hql语句
* 配置:
* <property name="hibernate.cache.use_query_cache">true</property>
* select
customer0_.ID as ID1_3_,
customer0_.NAME as NAME2_3_
from
CUSTOMER customer0_
只打印了一回sql
在查询缓存中 ,保存id 根据类缓存中存储的id去查询数据库
*/


/**<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

<!-- 硬盘 -->
<diskStore path="java.io.tmpdir"/>
<!-- 二级缓存默认配置
eternal="false" 是否永久存储在内存
-->
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
maxElementsOnDisk="10000000"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU">
<!-- 清除原则 least recently used
栈:FILO
队列:FIFO
-->
<persistence strategy="localTempSwap"/>
</defaultCache>
</ehcache>
*/
@Test
public void test1(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Query query = session.createQuery("from Customer");
query.setCacheable(true);//二级缓存是否可用
List<Customer> list = query.list();
session.clear();
Query query1 = session.createQuery("select c from Customer c");
query.setCacheable(true);//二级缓存是否可用
List<Customer> list1 = query.list();
session.getTransaction().commit();
session.close();
}
/**
* 时间戳;对数据库操作的时间
* 用来判断相同语句的操作,防止缓存影响查询结果, 所以每次去查询都是新的查询
*
*/
@Test
public void test2(){
Session session = HibernateUtil.openSession();
session.beginTransaction();
Customer customer=session.get(Customer.class, 1);
session.createQuery("update Customer set name= :name"
+" where id= :id").setParameter("name", "huafei")
.setParameter("id", 11).executeUpdate();
session.clear();
Customer customer1=session.get(Customer.class, 1);
session.getTransaction().commit();
session.close();
}