天天看点

Hibernate之三:OBC,二级缓存,乐观锁,悲观锁1.QBC:条件查询2.二级缓存:整个应用程序共享一个会话工厂,共享一个二级缓存3.查询缓存面试题:请你解释以下的作用:4.那个查询性能最高5.事务级别6.锁(解决并发问题,多个线程访问同一个资源)

1.QBC:条件查询

HQL是面向对象的查询,查询的是对象和对象中的属性

注意:HQL中的关键字不区分大小写,但是类名和属性名区分大小写

2.查询全部

//条件查询对象

Criteria criteria = session.createCriteria(User.class);

//得到集合

List<User> list = criteria.list();

3.查询单个

4.条件查询(重点)

1)Restrictions该类中提供了大量的条件判断的方法

5.分页 设置max最大显示条数和setFierst每页显示条数

6.排序  

7.离线查询   

//在没有和数据库连接之前先设置查询条件,创建查询对象

DetachedCriteria forClass = DetachedCriteria.forClass(User.class);

//设置查询条件

DetachedCriteria add = forClass.add(Restrictions.like("id", 2));

Session session = HibernateUtil.getSessionFactory().getCurrentSession();

Transaction transaction = session.beginTransaction();

//拿到真真的criteria对象

Criteria criteria = forClass.getExecutableCriteria(session);

Object uniqueResult = criteria.uniqueResult();

System.out.println(uniqueResult);

2.二级缓存:整个应用程序共享一个会话工厂,共享一个二级缓存

1)内置缓存:使用一个Map,用于存放配置信息,预定义SQL语句等,提供给Hibernate框架自己使用,对外只读的。不能操作

2)外置缓存:使用另一个Map,用于存放用户自定义数据。默认不开启。外置缓存hibernate只提供规范(接口),需要第三方实现类。外置缓存有成为二级缓存3.Ehcache

1)导入jar包,

2)开启二级缓存,

<!--开启二级缓存  -->

<property name="hibernate.cache.use_second_level_cache">true</property>

3)确定二级缓存的供应商,

<!--确定二级缓存供应商  -->

<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>

4)确定要缓存的对象(一般是只读)

<!--设置要缓存的对象 

class:配置要缓存的对象

usage:缓存中的数据是否只读

-->

<class-cache usage="read-only" class="com.qf.entity.User"/>

<class-cache usage="read-only" class="com.qf.entity.Address"/>

5)在缓存集合时候把集合中装的对象也要缓存起来

<!-- 缓存一个集合把集合中对象也给缓存了 -->

<collection-cache usage="read-only" collection="com.qf.entity.User.addresses"/>

6)ehcache配置文件中的属性

1)maxElementsInMemory(正整数):

在内存中缓存的最大对象数量

2)maxElementsOnDisk(正整数):

在磁盘上缓存的最大对象数量,默认值为0,表示不限制。 

3)eternal:

设定缓存对象保存的永久属性,默认为 false 。当为 true 时 timeToIdleSeconds、timeToLiveSeconds 失效。 

4)timeToIdleSeconds(单位:秒):

对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。

5)timeToLiveSeconds(单位:秒):

对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。

6)overflowToDisk:

如果内存中数据超过内存限制,是否要缓存到磁盘上。 

 7)diskPersistent:

是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。 

 8)diskSpoolBufferSizeMB(单位:MB):

DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。

 9)memoryStoreEvictionPolicy:

如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。

适合放入缓存中数据:

a)经常被查询的

b)很少被修改的

不适合放入缓存中数据(安全>效率)

a)很重要的数据,不允许出现并发问题(安全)

3.查询缓存

针对HQL的查询

a)session

开启查询缓存,二级缓存,二级缓存供应商,打开开关

和下面一样的配置,只是不需要确定缓存对象,2个不同的session也可以缓存共享

b)sessionFactory

开启查询缓存,二级缓存,二级缓存供应商,确定缓存对象,打开开关

<!-- 开启查询缓存-->

<property name="hibernate.cache.use_query_cache">true</property>

<!-- 3.设置要缓存的对象 -->

<!--

class:配置要缓存的对象,一般都是read-only

usage:缓存中的数据是否只读

 -->

<!-- <class-cache usage="read-write" class="com.qf.entity.User"/>

<class-cache usage="read-only" class="com.qf.entity.Address"/> -->

Query query = session.createQuery("from User u where u.id=:id");

//打开开关

query.setCacheable(true);

query.setInteger("id", 2);

面试题:请你解释以下的作用:

save():把编写好的sql语句放入缓存区中,

flush():把缓存区中的数据刷到数据库中

commit:第一把事务提交

隐式调用flush()

关闭session()

close():关闭session,清空session缓存

clear();清空session缓存

Hibernate中有几种查询方式:

1)主键查询

a)get

b)load

2)HQL查询(用的多)

3)QBC查询

4)原生态sql查询

4.那个查询性能最高

一般来说最原始的jdbc的性能最高,hibernate框架可以帮我们提高开发效率,但是hibernate需要翻译语言,他的查询效率是比不上jdbc的

if (i % 100 == 0) {

session.flush();//刷新进入数据库

session.clear();//清空缓存区

}

prst.addBatch();

if (i % 100 ==0) {

prst.executeBatch();//把缓存区中数据刷入数据库

prst.clearBatch();//清空缓存区

}

5.Hibernate整合c3p0

1.导入jar包

<!--c3p0连接池的信息 -->

<property name="hibernate.c3p0.max_size">30</property>

<property name="hibernate.c3p0.min_size">5</property>

<property name="hibernate.c3p0.timeout">5000</property>

2.连接池原理

系统初始化时候就创建好一些数据库连接对象到连接池中(内存中),当用户需要访问数据库时候,不创建新的连接对象,而是从连接池中取出空闲的连接对象给用户使用,用户使用完了也不销毁,放回连接池中,给下一个用户使用.连接的创建和销毁都是由连接池来完成.

5.事务级别

数据库中的隔离级别:事务和事务之间的干扰的强度

1,2,4,8:mysql4,8最高

隔离级别不同会产生哪些问题:(发生在2个事务同时操作)

脏读:一个事务读到了另一个事务未提交的数据

不可重复读:一个事务在查询期间,另一个事务在修改,多次查询都得到不同的结果

幻读:T1事务在修改全部数据某个字段为一样的期间,T2事务新增了一行数据,T1事务看到了不一样的数据,就好像幻象一样

修改默认的隔离级别:

mysql,jdbc如何修改

,Hibernate修改

<!--设置数据库的隔离级别-->

<propertyname="hibernate.connection.isolation">4</property>

6.锁(解决并发问题,多个线程访问同一个资源)

悲观锁和乐观锁

悲观锁:修改数据时候总是认为别人也会修改,

原理:for update(数据库的锁机制)

缺点:开销大,对大并发量的的访问不友好

优点:避免了冲突的发生

乐观锁实现的原理:版本号实现

乐观锁:在修改数据时候总会认为别人不会修改

在提交的时候判断版本号是否一致:

如果一致就提交,并且版本号自增;

如果不一致,就不让提交,说明其它事务修改过了

优点:避免了长事务中数据库的加锁解锁开销,大并发量下提高了系统整体性能

缺点:乐观锁只有在提交事务时才能发现业务事务失败,如果系统的冲突非常多,而且一旦失败就要重写提交而造成较大代价,乐观锁也会造成很大问题

*乐观锁是如何保证检查版本,提交和修改版本是同一个原子操作呢?

也就是如何保证在检查版本的期间,没有其他事务对其进行操作? 

解决方案: 将比较,更新操作写入到同一条SQL语句中可以解决该问题

共享锁:多个事务对同一数据可以共享一把锁,都能访问到数据,但是只能读不能写

排它锁:称为写锁,一个事务获取了一行的排它锁,其它事务就不能再获取这行的任意锁,获取排它锁的事务可以进行修改和读取

MySQL常用存储引擎的锁机制

MyISAM和MEMORY采用表级锁(table-level locking)

BDB采用页面锁(page-level locking)或表级锁,默认为页面锁

InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁(基于索引)

死锁在操作系统中指的是两个或两个以上的进程在执行的过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或者系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

继续阅读