Hibernate一览

温故而知新,复习一下Hibernate5.x,个人笔记!!!

1、Hibernate 一级缓存

1、SessionFactory 初始化很慢,所以项目中一般只有一个sessionFactory.
2、Hibernate的二级缓存现在已经基本不适用,使用访问为sessionfactory范围,替代产品为redis等nosql
3、Hibernate的一级缓存默认就是打开的
4、Hibernate的一级缓存适用范围为session访问,即从session创建到session.close();
5、Hibernate的一级缓存,缓存的数据是持久态数据(验证方式为在一个session中执行两次session.get(User.class,1),
同样的id只会查询一次,后一次从缓存拿。如果配置show-sql=true ,将只会打印一次)


2、Hibernate主键生成策略
配置native--会自动根据数据库生成不同的主键生成策略。比如Mysql会自动用identity ,oracle会自动用sequence 

3、Hibernate持久化自动保存
User user = session.get(User.class,1);
user.setName("xxx");
可以不sessioin.update(user);
在session.close()的时候会发起update语句
(了解:一级缓存有副本区,如果值不同,才会更新不同的值到数据库,相同则不同步)

4、事务:
一个操作单元,要不全部成功,要不全部失败
不考虑隔离性
脏读
不可重复读
幻读
Mysql默认的事务隔离级别为:不可重复读(repeatable read)

5、Hibernate得到本地线程绑定session
(注意:如果用MyEclipse去配置Hibernate,会生成一个管理session的工具类,叫做HibernateUtil,实现原理就是用到了ThreadLocal)

现在通过配置的方式得到与线程绑定的session
<!-- 在hibernate配置文件中配置,其实内部实现就是用到了ThreadLocal -->
<property name="hibernate.current_session_context_class">thread</property>


如果我们加了这条配置,就可以通过这样来得到与线程绑定的session了

//提供返回与本地线程绑定的session方法
public static Session getSession(){
	return sessionFactory.getCurrentSession();  //如果用openSession()方法,要手动关闭
}
这样返回的session会与线程绑定(也就是:操作结束,线程结束,session结束),就不需要手动关闭了,
这时候在finally写了session.close(),如果没有session.isClose()判断,就会抛出session已关闭异常



6、单元测试:

如果是用main函数,或者junit测试功能,

最好每次都生成sessionFactory,Session session = sessionFactory.openSession()的方法

finally关闭sessionFactory,session,以防不关闭sessionFactory会造成内存溢出,

而在java ee 项目,就可以用上面线程绑定的session,finally不必关闭session

当前项目管理:每次直接调用HibernateUtil工具类getSession,用完之后closeSession

private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>();
public static Session getSession() throws HibernateException{
	Session session = threadLocal.get();
	if (session == null || !session.isOpen()){
		if (sessionFactory == null){
			rebuildSessionFactory();
		}
		session = (sessionFactory != null) ? sessionFactory.openSession() : null;
		threadLocal.set(session);
	}
	return session;
}

public static void closeSession() throws HibernateException{
	Session session = threadLocal.get();
	threadLocal.set(null);
	if (session != null){
		session.close();
	}
}

public static void rebuildSessionFactory(){
	try{
		configuration.configure(configFile);
		sessionFactory = configuration.buildSessionFactory();
	} catch (Exception e){
		System.err.println("%%%% Error Creating SessionFactory %%%%");
		e.printStackTrace();
	}
}


7、Hibernate查询--三个对象

Query对象(hql语句)--返回实体类对象列表
Criteria对象(不需要写语句,而是调用里面的方法)--返回实体类对象列表
SqlQuery对象(sql语句)--返回数组列表


小知识点:Arrays.toString(Object[])--把数组当做字符串输出

SqlQeury 如果不想接收全是数组列表,可以设置
SqlQuery sqlQuery = session.createSQLQuery("select * from user");
sqlQuery.addEntity(User.class);
List<User> list = sqlQuery.list();
这样就可以直接返回User对象列表


8、表与表之间的关系

表示一对多关系,在实体类中配置的是Set集合(特点:不重复,无序)
级联操作:
映射文件(当前项目中没有用外键,因为cascade="nono")
<set name="userAccounts" cascade="save-update,delete"> 
注意:现在我们项目没有使用外键,也就不存在级联操作

inverse属性:
hibernate是双向维护外键,用户User(一) -- > 用户账号UserAccount(多)
当在User的Set<UserAccount>添加元素时,修改User表会修改一次外键,修改UserAccount表又会修改一次外键,造成性能低下

解决方案:

在多的一方不维护外键字段。

也就是在<set> 配置中:inverse=true
true为放弃外键维护

<set name="accounts" table="user_accounts" inverse="true">
	<key column="USER_ID"></key>
	<one-to-many class="UserAccount" />    <!--所以配置hbm.xml写在一个xml中,所以class前没有包名-->
</set>

用户User.hbm.xml中配置set标签,说明用户有多个account

在UserAccount.hbm.xml中配置:
<many-to-one name="user" class="User" column="USER_ID"
	cascade="none" update="false" insert="false">
</many-to-one>

字段含义:
name:映射类属性的名字
column:关联的字段
class:关联类的名字
cascade:设置操作中的级联策略 可选值为 all所有操作情况均进行级联、none所有操作情况均不进行级联、save-update执行save和update操作时级联、delete执行删除操作时级联
fetch:设置抓取数据的策略 默认值为select序列选择抓取 可选值为join外连接抓取
update:进行update操作时是否包含此字段
insert:进行insert操作时是否包含此字段


9、Criteria查询
基本用法: Restrictions
Criteria criteria = session.createCriteria(User.class);
criteria.add(Restrictions.eq("name","dhh"));  //Restrictions含有eq.lg,gt like 等操作
criteria.add(Restrictions.like("description","%哈哈%"));
//分页
criteria.setFirstResult(0);
criteria.setMaxResults(10);
//排序
criteria.andOrder(Order.desc("id));

统计写法:

//统计行数
Criteria criteria = session.createCriteria(User.class);
//Projections统计类,max ,min avg等)
criteria.setProjection(Projections.rowCount());
Object obj = criteria.uniqueResult();

10、Hql多表查询
表格对应关系:一个Customer 有多个LinkMan (一个客户有多个联系人)
内连接(能查询出有关联关系的记录,linkMan表cid字段为空,或者customer中没有联系人,这些记录查不出):
1、select * from customer c , linkMan l where c.id = l.cid;
2、select * from customer c inner join linkMan on c.id = l.cid;

左外连接(显示左边表customer中所有记录,没有没有联系人的,字段为null):
select * from customer c left outer join linkMan on c.id = l.cid;

Hql 的写法:
内连接:

from customer c inner join c.likeManList

c.likeManList为实体bean中的Set<LinkMan>

所以列表为list为object[]

迫切内连接:(为了方便,做了封装)
1、迫切内连接和内连接底层实现是一样的
2、内连接返回的是object[],而迫切内连接返回的是对象集合

from customer c inner join fetch c.likeManList 

左连接和迫切左连接:
from customer c left outer join c.likeManList
from customer c left outer join fetch c.likeManList

右连接:(没有迫切右连接)


11、Hql特殊写法:
常用聚集函数:sum,min,max,count,avg.
如果查询出来是对象,就直接from 实体类

但是如果是查询聚集函数呢??

Query query = session.createQuery("select count(*) from User");   //注意哦,不是createSqlQuery()
Object obj = query.uniqueResult();


12、Hibernate检索策略(一般都不要修改,采用默认):

1、立即查询(get,一调用就立即发送sql语句去查询数据库)
2、延迟查询(load,不马上执行:要用里面的值时才会发送sql语句查询)

Customer c = session.get(Customer.class,1);  //打断点,一执行到这里,就会打印sql语句

//延迟加载
Customer c = sessio.load(Customer.class,2);  
syso(c.getId());  //不发起sql,因为id已经知道了,为2
syso(c.getName());  //发起sql,name值不知道

延迟查询氛围两类:
(1)类级别延迟,根据id查询返回实体对象,调用load方法不会马上发送sql发育
(2)关联级别延迟,查询某个实体类,再查询里面的Set<>集合时,是否需要延迟,这个过程为关联级别延迟。


默认采用懒加载,也就是lazy = true;
效果为:加载出了实体类(get,load),不会加载实体类中的Set集合,当用到的时候,才会加载
class Customer{
 id ,name;
 Set<LinkMan> linkManLists;
}

lazy: false  采用立即加载
lazy: true   采用延迟加载
lazy: extra  采用延迟加载(极其懒惰)
在Set标签中使用

true和extra的区别:
true为延迟加载Set集合,但用到还是会加载,是把Set集合都查询出来
而extra如果你用的时候只要linkManLists.size();即只要数量,则只会加载数量,sql语句为select count(*)
而不会把整个Set集合加载出来!


13、hibernate批量抓取应用场景:
class Customer{
 id ,name;
 Set<LinkMan> linkManLists;
}
当我们得到客户列表,遍历客户,再遍历里面的联系人,默认采用懒加载,这样出出现一个问题,就是性能非常低,
每次取联系人都要从数据库加载内容,这样会打印很多sql语句


如果在映射文件,Set标签配置batch-size="10" 值越大发送的sql次数越少,这样发出来的请求将会是
select * from linkMan where cid in ( **,**,**,**)
这样将减少很多sql请求,能提高性能!!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值