hibernate若干问题及解决方案

使用悲观锁(Pessimistic Locking)解决事务并发问题

悲观锁:正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。 

Hibernate使用悲观锁十分容易,但实际应用中悲观锁是很少被使用的,因为它大大限制了并发性。

用乐观锁(Optimistic Locking)解决事务并发问题

相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。

乐观锁,大多是基于数据版本(Version)记录机制实现。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。

乐观锁的工作原理:读取出数据时,将此版本号一同读出,并在更新数据时比较版本号与数据库表中的版本号,如果等于数据库表中的版本号则予以更新,并递增版本号,如果小于数据库表中的版本号就抛出异常。

Hibernate为乐观锁提供了3中实现:

1. 基于version

配置基于version的乐观锁:

<?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>

    <class name="com.suxiaolei.hibernate.pojos.People" table="people">

        <id name="id" type="string">

            <column name="id"></column>

            <generator class="uuid"></generator>

        </id>

        <!-- version标签用于指定表示版本号的字段信息 -->

        <version name="version" column="version" type="integer"></version>

        <property name="name" column="name" type="string"></property>

    </class>

</hibernate-mapping>

2. 基于timestamp

配置基于timestamp的乐观锁:

<?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>

    <class name="com.suxiaolei.hibernate.pojos.People" table="people">

        <id name="id" type="string">

            <column name="id"></column>

            <generator class="uuid"></generator>

        </id>

        <!-- timestamp标签用于指定表示版本号的字段信息 -->

        <timestamp name="updateDate" column="updateDate"></timestamp>

        <property name="name" column="name" type="string"></property>

    </class>

</hibernate-mapping>

3. 为遗留项目添加乐观锁 :

遗留项目,由于各种原因无法为原有的数据库添加"version"或"timestamp"字段,这时不可以使用上面两种方式配置乐观锁,Hibernate为这种情况提供了一个"optimisitic-lock"属性,它位于<class>标签上

<?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>

    <class name="com.suxiaolei.hibernate.pojos.People" table="people" optimistic-lock="all">

        <id name="id" type="string">

            <column name="id"></column>

            <generator class="uuid"></generator>

        </id>

        <property name="name" column="name" type="string"></property>

    </class>

</hibernate-mapping>

将该属性的值设置为all,让该记录所有的字段都为版本控制信息。

 

Hibernate n+1的问题:

select语句的数目太多,需要频繁的访问数据库,会影响检索性能.

加载的对象完全是多余的操作,这些多余的对象白白浪费了许多内存空间。

为了解决以上问题,Hibernate提供了两种检索策略:延迟检索策略和迫切左外连接检索策略

1、延迟检索策略能避免多余加载应用程序不需要访问的关联对象,

hibernate3开始已经默认是lazy=true了;lazy=true时不会立刻查询关联对象,只有当需要关联对象(访问其属性)时才会发生查询动作。

2、迫切左外连接检索策略则充分利用了SQL的外连接查询功能,能够减少select语句的数目。

可以在映射文件中定义连接抓取方式。

<set name=”orders” fetch=”join”>

<key column=”customer_id”>

<one-to-many class="com.hibernate.mappings.Order"/>

</set>

或者使用HQL的LEFT OUTER JOIN.

或者在条件查询中使用setFetchMode(FetchMode.JOIN)如:

Customer ctm = (Customer)session.createCriteria(Customer.class)

                    .setFetchMode(“Order”.JOIN)

                    .add(Restrictions.idEq(customer_id));

 

Hibernate load()方法:

使用load()时如果在session关闭之后再查询此对象,会报异常:could not initialize proxy - no Session。处理办法:在session关闭之前初始化一下查询出来的对象:Hibernate.initialize(user);

使用load()可以提高效率,因为刚开始的时候并没有查询数据库。但很少使用。

 

Hibernate缓存:

Hibernate缓存包括两大类:

Hibernate一级缓存:事务范围的缓存

Hibernate二级缓存:进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory不会启用这个插件。

什么样的数据适合存放到第二级缓存中?
1 很少被修改的数据
2 不是很重要的数据,允许出现偶尔并发的数据
3 不会被并发访问的数据
4 常量数据
不适合存放到第二级缓存的数据?
1经常被修改的数据
2 .绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
3 与其他应用共享的数据。

hibernate配置文件中相关配置:

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

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

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

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

<!-- 二级缓存区域名的前缀 -->

<!--<property name="hibernate.cache.region_prefix">h3test</property>-->

<!-- 高速缓存提供程序 -->

<property name="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</property>

<!-- 指定缓存配置文件位置 -->

<property name="hibernate.cache.provider_configuration_file_resource_path">

ehcache.xml

</property>

<!-- 强制Hibernate以更人性化的格式将数据存入二级缓存 -->

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

<!-- Hibernate将收集有助于性能调节的统计数据 -->

<property name="hibernate.generate_statistics">true</property>

启用第三方缓存产品 (可改变,上面eache是hibernate官方默认的第三方缓存产品)

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

转载于:https://my.oschina.net/huoyun/blog/692605

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值