- 浏览: 386748 次
- 性别:
- 来自: 深圳
文章分类
- 全部博客 (269)
- FY_UML (3)
- FY_JAVA (12)
- FY_JavaScript脚本 (7)
- FY_JSP (3)
- FY_Tapestry框架 (12)
- FY_Spring框架 (3)
- FY_Manager (5)
- FY_Junit(单元测试) (3)
- SERVER (14)
- FY_Struts2框架 (3)
- FY_SVN (2)
- FY_NoSQL (2)
- FY_jquery_sir (13)
- FY_hibernate_sir (8)
- FY_设计模式_sir (6)
- FY_Extjs_sir (10)
- FY_CI_sir (5)
- FY_Oracle_sir (11)
- FY_MySql_sir (10)
- FY_Hadoop_sir (3)
- FY_SOA_sir (1)
- 中文分词技术 (1)
- FY_Android (52)
- FY_架构 (2)
- FY_PhoneGap (2)
- FY_Webstorm (5)
- FY_Sencha Touch (3)
- HTML5应用快速开发 (1)
- FY_python (0)
- HADOOP (1)
- AI (0)
最新评论
-
antao592:
楼主,HkDataSourceWrapper中的getCurr ...
结合spring jdbc 实现分表分库的数据库访问构思 -
bonait:
不错,看看我的这个怎么样www.zipin168.com
So Easy京东商城 -
chenzheng8975:
...
So Easy京东商城 -
yzhenxing:
我导入demo后少com.google.android.gms ...
google地图demo -
echoaiya:
非常感谢~~
google地图demo
java 代码
- 19.1. 抓取策略(Fetching strategies)
- 抓取策略(fetching strategy) 是指:当应用程序需要在(Hibernate实体对象图的)关联关系间进行导航的时候, Hibernate如何获取关联对象的策略。抓取策略可以在O/R映射的元数据中声明,也可以在特定的HQL 或条件查询(Criteria Query)中重载声明。
- Hibernate3 定义了如下几种抓取策略:
- 连接抓取(Join fetching) - Hibernate通过 在SELECT语句使用OUTER JOIN(外连接)来 获得对象的关联实例或者关联集合。
- 查询抓取(Select fetching) - 另外发送一条 SELECT 语句抓取当前对象的关联实体或集合。除非你显式的指定lazy="false"禁止 延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
- 子查询抓取(Subselect fetching) - 另外发送一条SELECT 语句抓取在前面查询到(或者抓取到)的所有实体对象的关联集合。除非你显式的指定lazy="false" 禁止延迟抓取(lazy fetching),否则只有当你真正访问关联关系的时候,才会执行第二条select语句。
- 批量抓取(Batch fetching) - 对查询抓取的优化方案, 通过指定一个主键或外键列表,Hibernate使用单条SELECT语句获取一批对象实例或集合。
- 默认情况下,Hibernate3使用延迟查询抓取,对于多数应用中绝大部分的实体或集合,这是最佳选择。 如果你设置了hibernate.default_batch_fetch_size, Hibernate将根据这个批量抓取优化设置来进行延迟抓取(可以在更小的粒度上进行优化设置)。
- 但是,需要注意一个问题:在一个Hibernate Session作用范围之外访问延迟加载的关联关系将导致异常。例如:
- s = sessions.openSession();
- Transaction tx = s.beginTransaction();
- User u = (User) s.createQuery("from User u where u.name=:userName")
- .setString("userName", userName).uniqueResult();
- Map permissions = u.getPermissions();
- tx.commit();
- s.close();
- Integer accessLevel = (Integer) permissions.get("accounts"); // Error!
- 在Session关闭后,permessions集合将是未实例化的、不再可用,因此无法正常载入其状态。 Hibernate对分离对象不支持延迟实例化. 这里的修改方法是:将permissions读取数据的代码 移到tx.commit()之前(当然还有更加高级的方法可以解决此问题,这将在后面进行讨论)。
- 当然,也可以使用非延迟的方式、或连接抓取方式(它本质上也是非延迟的)抓取关联数据。但是, 对绝大部分集合来说,更推荐使用延迟方式抓取数据,尤其是对于那些实体引用的集合。如果在你 的对象模型中定义了太多的非延迟关联,Hibernate最终几乎需要在每个事务中载入整个数据库到内存中。
- 但是,另一方面,在一些特殊的事务中,我们也经常需要使用到连接抓取(它本身上就是非延迟的),以代替查询抓取。 下面我们将会很快明白如何具体的定制Hibernate中的抓取策略。在Hibernate3中,具体选择哪种抓取策略的机制是和选择 单值关联或集合关联相一致的。
- 19.1.1. 调整抓取策略(Tuning fetch strategies)
- 查询抓取(默认的)在N+1查询的情况下是极其脆弱的,因此我们可能会要求在映射文档中定义使用连接抓取:
- <set name="permissions"
- fetch="join">
- <key column="userId"/>
- <one-to-many class="Permission"/>
- </set
- <many-to-one name="mother" class="Cat" fetch="join"/>
- 在映射文档中定义的抓取策略将会有产生以下影响:
- 通过get()或load()方法取得数据。
- 只有在关联之间进行导航时,才会隐式的取得数据(延迟抓取)。
- 条件查询
- 在映射文档中显式的声明 连接抓取做为抓取策略并不会影响到随后的HQL查询。
- 通常情况下,我们并不使用映射文档进行抓取策略的定制。更多的是,保持其默认值,然后在特定的事务中, 使用HQL的左连接抓取(left join fetch) 对其进行重载。这将通知 Hibernate在第一次查询中使用外部关联(outer join),直接得到其关联数据。 在条件查询 API中,应该调用 setFetchMode(FetchMode.JOIN)语句。
- 也许你喜欢仅仅通过条件查询,就可以改变get() 或 load()语句中的数据抓取策略。例如:
- User user = (User) session.createCriteria(User.class)
- .setFetchMode("permissions", FetchMode.JOIN)
- .add( Restrictions.idEq(userId) )
- .uniqueResult();
- (这就是其他ORM解决方案的“抓取计划(fetch plan)”在Hibernate中的等价物。)
- 对集合使用连接抓取会有一个限制:你只能为每个持久类配置一个集合角色、在一次外部连接中执行一次查询。 Hibernate尽可能的禁止类似笛卡儿积查询的情况,而在两个集合间进行的每个外部关联查询, 将会产生一次笛卡儿查询,这显然要比两次查询(无论是延迟查询、或非延迟查询)速度慢。 这里的对一次外部连接集合的限制同样对映射抓取策略和HQL/条件查询都适用。
- 如果你想超越此限制,你必须使用子查询抓取或者批量抓取策略,才能达到更为可接受的性能。 当你的应用中出现了一个树状的集合数据抓取时,通常都需要这样做。
- 对于单向关联来说,连接抓取并没有任何的限制。
- 截然不同的一种避免N+1次查询的方法是,使用二级缓存。
- 19.1.2. 单端关联代理(Single-ended association proxies)
- 在Hinerbate中,对集合的延迟抓取的采用了自己的实现方法。但是,对于单端关联的延迟抓取,则需要采用 其他不同的机制。单端关联的目标实体必须使用代理,Hihernate在运行期二进制级(通过优异的CGLIB库), 为持久对象实现了延迟载入代理。
- 默认的,Hibernate3将会为所有的持久对象产生代理(在启动阶段),然后使用他们实现 多对一(many-to-one)关联和一对一(one-to-one) 关联的延迟抓取。
- 在映射文件中,可以通过设置proxy属性为目标class声明一个接口供代理接口使用。 默认的,Hibernate将会使用该类的一个子类。 注意:被代理的类必须实现一个至少包可见的默认构造函数,我们建议所有的持久类都应拥有这样的构造函数
- 在如此方式定义一个多态类的时候,有许多值得注意的常见性的问题,例如:
- <class name="Cat" proxy="Cat">
- ......
- <subclass name="DomesticCat">
- .....
- </subclass>
- </class>
- 首先,Cat实例永远不可以被强制转换为DomesticCat, 即使它本身就是DomesticCat实例。
- Cat cat = (Cat) session.load(Cat.class, id); // instantiate a proxy (does not hit the db)
- if ( cat.isDomesticCat() ) { // hit the db to initialize the proxy
- DomesticCat dc = (DomesticCat) cat; // Error!
- ....
- }
- 其次,代理的“==”可能不再成立。
- Cat cat = (Cat) session.load(Cat.class, id); // instantiate a Cat proxy
- DomesticCat dc =
- (DomesticCat) session.load(DomesticCat.class, id); // acquire new DomesticCat proxy!
- System.out.println(cat==dc); // false
- 虽然如此,但实际情况并没有看上去那么糟糕。虽然我们现在有两个不同的引用,分别指向这两个不同的代理对象, 但实际上,其底层应该是同一个实例对象:
- cat.setWeight(11.0); // hit the db to initialize the proxy
- System.out.println( dc.getWeight() ); // 11.0
- 第三,你不能对“final类”或“具有final方法的类”使用CGLIB代理。
- 最后,如果你的持久化对象在实例化时需要某些资源(例如,在实例化方法、默认构造方法中), 那么代理对象也同样需要使用这些资源。实际上,代理类是持久化类的子类。
- 这些问题都源于Java的单根继承模型的天生限制。如果你希望避免这些问题,那么你的每个持久化类必须实现一个接口, 在此接口中已经声明了其业务方法。然后,你需要在映射文档中再指定这些接口。例如:
- <class name="CatImpl" proxy="Cat">
- ......
- <subclass name="DomesticCatImpl" proxy="DomesticCat">
- .....
- </subclass>
- </class>
- 这里CatImpl实现了Cat接口, DomesticCatImpl实现DomesticCat接口。 在load()、iterate()方法中就会返回 Cat和DomesticCat的代理对象。 (注意list()并不会返回代理对象。)
- Cat cat = (Cat) session.load(CatImpl.class, catid);
- Iterator iter = session.iterate("from CatImpl as cat where cat.name='fritz'");
- Cat fritz = (Cat) iter.next();
- 这里,对象之间的关系也将被延迟载入。这就意味着,你应该将属性声明为Cat,而不是CatImpl。
- 但是,在有些方法中是不需要使用代理的。例如:
- equals()方法,如果持久类没有重载equals()方法。
- hashCode()方法,如果持久类没有重载hashCode()方法。
- 标志符的getter方法。
- Hibernate将会识别出那些重载了equals()、或hashCode()方法的持久化类。
- 19.1.3. 实例化集合和代理(Initializing collections and proxies)
- 在Session范围之外访问未初始化的集合或代理,Hibernate将会抛出LazyInitializationException异常。 也就是说,在分离状态下,访问一个实体所拥有的集合,或者访问其指向代理的属性时,会引发此异常。
- 有时候我们需要保证某个代理或者集合在Session关闭前就已经被初始化了。 当然,我们可以通过强行调用cat.getSex()或者cat.getKittens().size()之类的方法来确保这一点。 但是这样的程序会造成读者的疑惑,也不符合通常的代码规范。
- 静态方法Hibernate.initialized() 为你的应用程序提供了一个便捷的途径来延迟加载集合或代理。 只要它的Session处于open状态,Hibernate.initialize(cat) 将会为cat强制对代理实例化。 同样,Hibernate.initialize( cat.getKittens() ) 对kittens的集合具有同样的功能。
- 还有另外一种选择,就是保持Session一直处于open状态,直到所有需要的集合或代理都被载入。 在某些应用架构中,特别是对于那些使用Hibernate进行数据访问的代码,以及那些在不同应用层和不同物理进程中使用Hibernate的代码。 在集合实例化时,如何保证Session处于open状态经常会是一个问题。有两种方法可以解决此问题:
- 在一个基于Web的应用中,可以利用servlet过滤器(filter),在用户请求(request)结束、页面生成 结束时关闭Session(这里使用了视图打开Seiion模式(Open Session in View)), 当然,这将依赖于应用框架中异常需要被正确的处理。在返回界面给用户之前,乃至在生成界面过程中发生异常的情况下, 正确关闭Session和结束事务将是非常重要的, Servlet过滤器必须如此访问Session,才能保证正确使用Session。 我们推荐使用ThreadLocal 变量保存当前的Session (可以参考第 1.4 节 “与Cat同乐”的例子实现)。
- 在一个拥有单独业务层的应用中,业务层必须在返回之前,为web层“准备”好其所需的数据集合。这就意味着 业务层应该载入所有表现层/web层所需的数据,并将这些已实例化完毕的数据返回。通常,应用程序应该 为web层所需的每个集合调用Hibernate.initialize()(这个调用必须发生咱session关闭之前); 或者使用带有FETCH从句,或FetchMode.JOIN的Hibernate查询, 事先取得所有的数据集合。如果你在应用中使用了Command模式,代替Session Facade , 那么这项任务将会变得简单的多。
- 你也可以通过merge()或lock()方法,在访问未实例化的集合(或代理)之前, 为先前载入的对象绑定一个新的Session。 显然,Hibernate将不会,也不应该自动完成这些任务,因为这将引入一个特殊的事务语义。
- 有时候,你并不需要完全实例化整个大的集合,仅需要了解它的部分信息(例如其大小)、或者集合的部分内容。
- 你可以使用集合过滤器得到其集合的大小,而不必实例化整个集合:
- ( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()
- 这里的createFilter()方法也可以被用来有效的抓取集合的部分内容,而无需实例化整个集合:
- s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();
- 19.1.4. 使用批量抓取(Using batch fetching)
- Hibernate可以充分有效的使用批量抓取,也就是说,如果仅一个访问代理(或集合),那么Hibernate将不载入其他未实例化的代理。 批量抓取是延迟查询抓取的优化方案,你可以在两种批量抓取方案之间进行选择:在类级别和集合级别。
- 类/实体级别的批量抓取很容易理解。假设你在运行时将需要面对下面的问题:你在一个Session中载入了25个 Cat实例,每个Cat实例都拥有一个引用成员owner, 其指向Person,而Person类是代理,同时lazy="true"。 如果你必须遍历整个cats集合,对每个元素调用getOwner()方法,Hibernate将会默认的执行25次SELECT查询, 得到其owner的代理对象。这时,你可以通过在映射文件的Person属性,显式声明batch-size,改变其行为:
- <class name="Person" batch-size="10">...</class>
- 随之,Hibernate将只需要执行三次查询,分别为10、10、 5。
- 你也可以在集合级别定义批量抓取。例如,如果每个Person都拥有一个延迟载入的Cats集合, 现在,Sesssion中载入了10个person对象,遍历person集合将会引起10次SELECT查询, 每次查询都会调用getCats()方法。如果你在Person的映射定义部分,允许对cats批量抓取, 那么,Hibernate将可以预先抓取整个集合。请看例子:
- <class name="Person">
- <set name="cats" batch-size="3">
- ...
- </set>
- </class>
- 如果整个的batch-size是3(笔误?),那么Hibernate将会分四次执行SELECT查询, 按照3、3、3、1的大小分别载入数据。这里的每次载入的数据量还具体依赖于当前Session中未实例化集合的个数。
- 如果你的模型中有嵌套的树状结构,例如典型的帐单-原料结构(bill-of-materials pattern),集合的批量抓取是非常有用的。 (尽管在更多情况下对树进行读取时,嵌套集合(nested set)或原料路径(materialized path)(××) 是更好的解决方法。)
- 19.1.5. 使用子查询抓取(Using subselect fetching)
- TODO 待续
- 19.1.6. 使用延迟属性抓取(Using lazy property fetching)
- Hibernate3对单独的属性支持延迟抓取,这项优化技术也被称为组抓取(fetch groups)。 请注意,该技术更多的属于市场特性。在实际应用中,优化行读取比优化列读取更重要。但是,仅载入类的部分属性在某些特定情况下会有用,例如在原有表中拥有几百列数据、数据模型无法改动的情况下。
- 可以在映射文件中对特定的属性设置lazy,定义该属性为延迟载入。
- <class name="Document">
- <id name="id">
- <generator class="native"/>
- </id>
- <property name="name" not-null="true" length="50"/>
- <property name="summary" not-null="true" length="200" lazy="true"/>
- <property name="text" not-null="true" length="2000" lazy="true"/>
- </class>
- 属性的延迟载入要求在其代码构建时加入二进制指示指令(bytecode instrumentation),如果你的持久类代码中未含有这些指令, Hibernate将会忽略这些属性的延迟设置,仍然将其直接载入。
- 你可以在Ant的Task中,进行如下定义,对持久类代码加入“二进制指令。”
- <target name="instrument" depends="compile">
- <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask">
- <classpath path="${jar.path}"/>
- <classpath path="${classes.dir}"/>
- <classpath refid="lib.class.path"/>
- </taskdef>
- <instrument verbose="true">
- <fileset dir="${testclasses.dir}/org/hibernate/auction/model">
- <include name="*.class"/>
- </fileset>
- </instrument>
- </target>
- 还有一种可以优化的方法,它使用HQL或条件查询的投影(projection)特性,可以避免读取非必要的列, 这一点至少对只读事务是非常有用的。它无需在代码构建时“二进制指令”处理,因此是一个更加值得选择的解决方法。
- 有时你需要在HQL中通过抓取所有属性,强行抓取所有内容。
- 19.2. 二级缓存(The Second Level Cache)
- Hibernate的Session在事务级别进行持久化数据的缓存操作。 当然,也有可能分别为每个类(或集合),配置集群、或JVM级别(SessionFactory级别)的缓存。 你甚至可以为之插入一个集群的缓存。注意,缓存永远不知道其他应用程序对持久化仓库(数据库)可能进行的修改 (即使可以将缓存数据设定为定期失效)。
- 默认情况下,Hibernate使用EHCache进行JVM级别的缓存(目前,Hibernate已经废弃了对JCS的支持,未来版本中将会去掉它)。 你可以通过设置hibernate.cache.provider_class属性,指定其他的缓存策略, 该缓存策略必须实现org.hibernate.cache.CacheProvider接口。
- 表 19.1. 缓存策略提供商(Cache Providers)
- Cache Provider class Type Cluster Safe Query Cache Supported
- Hashtable (not intended for production use) org.hibernate.cache.HashtableCacheProvider memory yes
- EHCache org.hibernate.cache.EhCacheProvider memory, disk yes
- OSCache org.hibernate.cache.OSCacheProvider memory, disk yes
- SwarmCache org.hibernate.cache.SwarmCacheProvider clustered (ip multicast) yes (clustered invalidation)
- JBoss TreeCache org.hibernate.cache.TreeCacheProvider clustered (ip multicast), transactional yes (replication) yes (clock sync req.)
- 19.2.1. 缓存映射(Cache mappings)
- 类或者集合映射的“<cache>元素”可以有下列形式:
- <cache
- usage="transactional|read-write|nonstrict-read-write|read-only" (1)
- />
- (1) usage说明了缓存的策略: transactional、 read-write、 nonstrict-read-write或 read-only。
- 另外(首选?), 你可以在hibernate.cfg.xml中指定<class-cache>和 <collection-cache> 元素。
- 这里的usage 属性指明了缓存并发策略(cache concurrency strategy)。
- 19.2.2. 策略:只读缓存(Strategy: read only)
- 如果你的应用程序只需读取一个持久化类的实例,而无需对其修改, 那么就可以对其进行只读 缓存。这是最简单,也是实用性最好的方法。甚至在集群中,它也能完美地运作。
- <class name="eg.Immutable" mutable="false">
- <cache usage="read-only"/>
- ....
- </class>
- 19.2.3. 策略:读/写缓存(Strategy: read/write)
- 如果应用程序需要更新数据,那么使用读/写缓存 比较合适。 如果应用程序要求“序列化事务”的隔离级别(serializable transaction isolation level),那么就决不能使用这种缓存策略。 如果在JTA环境中使用缓存,你必须指定hibernate.transaction.manager_lookup_class属性的值, 通过它,Hibernate才能知道该应用程序中JTA的TransactionManager的具体策略。 在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前, 整个事务已经结束。 如果你想在集群环境中使用此策略,你必须保证底层的缓存实现支持锁定(locking)。Hibernate内置的缓存策略并不支持锁定功能。
- <class name="eg.Cat" .... >
- <cache usage="read-write"/>
- ....
- <set name="kittens" ... >
- <cache usage="read-write"/>
- ....
- </set>
- </class>
- 19.2.4. 策略:非严格读/写缓存(Strategy: nonstrict read/write)
- 如果应用程序只偶尔需要更新数据(也就是说,两个事务同时更新同一记录的情况很不常见),也不需要十分严格的事务隔离, 那么比较适合使用非严格读/写缓存策略。如果在JTA环境中使用该策略, 你必须为其指定hibernate.transaction.manager_lookup_class属性的值, 在其它环境中,你必须保证在Session.close()、或Session.disconnect()调用前, 整个事务已经结束。
- 19.2.5. 策略:事务缓存(transactional)
- Hibernate的事务缓存策略提供了全事务的缓存支持, 例如对JBoss TreeCache的支持。这样的缓存只能用于JTA环境中,你必须指定 为其hibernate.transaction.manager_lookup_class属性。
- 没有一种缓存提供商能够支持上列的所有缓存并发策略。下表中列出了各种提供器、及其各自适用的并发策略。
- 表 19.2. 各种缓存提供商对缓存并发策略的支持情况(Cache Concurrency Strategy Support)
- Cache read-only nonstrict-read-write read-write transactional
- Hashtable (not intended for production use) yes yes yes
- EHCache yes yes yes
- OSCache yes yes yes
- SwarmCache yes yes
- JBoss TreeCache yes yes
- 19.3. 管理缓存(Managing the caches)
- 无论何时,当你给save()、update()或 saveOrUpdate()方法传递一个对象时,或使用load()、 get()、list()、iterate() 或scroll()方法获得一个对象时, 该对象都将被加入到Session的内部缓存中。
- 当随后flush()方法被调用时,对象的状态会和数据库取得同步。 如果你不希望此同步操作发生,或者你正处理大量对象、需要对有效管理内存时,你可以调用evict() 方法,从一级缓存中去掉这些对象及其集合。
- ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //a huge result set
- while ( cats.next() ) {
- Cat cat = (Cat) cats.get(0);
- doSomethingWithACat(cat);
- sess.evict(cat);
- }
- Session还提供了一个contains()方法,用来判断某个实例是否处于当前session的缓存中。
- 如若要把所有的对象从session缓存中彻底清除,则需要调用Session.clear()。
- 对于二级缓存来说,在SessionFactory中定义了许多方法, 清除缓存中实例、整个类、集合实例或者整个集合。
- sessionFactory.evict(Cat.class, catId); //evict a particular Cat
- sessionFactory.evict(Cat.class); //evict all Cats
- sessionFactory.evictCollection("Cat.kittens", catId); //evict a particular collection of kittens
- sessionFactory.evictCollection("Cat.kittens"); //evict all kitten collections
- CacheMode参数用于控制具体的Session如何与二级缓存进行交互。
- CacheMode.NORMAL - 从二级缓存中读、写数据。
- CacheMode.GET - 从二级缓存中读取数据,仅在数据更新时对二级缓存写数据。
- CacheMode.PUT - 仅向二级缓存写数据,但不从二级缓存中读数据。
- CacheMode.REFRESH - 仅向二级缓存写数据,但不从二级缓存中读数据。通过 hibernate.cache.use_minimal_puts的设置,强制二级缓存从数据库中读取数据,刷新缓存内容。
- 如若需要查看二级缓存或查询缓存区域的内容,你可以使用统计(Statistics) API。
- Map cacheEntries = sessionFactory.getStatistics()
- .getSecondLevelCacheStatistics(regionName)
- .getEntries();
- 此时,你必须手工打开统计选项。可选的,你可以让Hibernate更人工可读的方式维护缓存内容。
- hibernate.generate_statistics true
- hibernate.cache.use_structured_entries true
- 19.4. 查询缓存(The Query Cache)
- 查询的结果集也可以被缓存。只有当经常使用同样的参数进行查询时,这才会有些用处。 要使用查询缓存,首先你必须打开它:
- hibernate.cache.use_query_cache true
- 该设置将会创建两个缓存区域 - 一个用于保存查询结果集(org.hibernate.cache.StandardQueryCache); 另一个则用于保存最近查询的一系列表的时间戳(org.hibernate.cache.UpdateTimestampsCache)。 请注意:在查询缓存中,它并不缓存结果集中所包含的实体的确切状态;它只缓存这些实体的标识符属性的值、以及各值类型的结果。 所以查询缓存通常会和二级缓存一起使用。
- 绝大多数的查询并不能从查询缓存中受益,所以Hibernate默认是不进行查询缓存的。如若需要进行缓存,请调用 Query.setCacheable(true)方法。这个调用会让查询在执行过程中时先从缓存中查找结果, 并将自己的结果集放到缓存中去。
- 如果你要对查询缓存的失效政策进行精确的控制,你必须调用Query.setCacheRegion()方法, 为每个查询指定其命名的缓存区域。
- List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger")
- .setEntity("blogger", blogger)
- .setMaxResults(15)
- .setCacheable(true)
- .setCacheRegion("frontpages")
- .list();
- 如果查询需要强行刷新其查询缓存区域,那么你应该调用Query.setCacheMode(CacheMode.REFRESH)方法。 这对在其他进程中修改底层数据(例如,不通过Hibernate修改数据),或对那些需要选择性更新特定查询结果集的情况特别有用。 这是对SessionFactory.evictQueries()的更为有效的替代方案,同样可以清除查询缓存区域。
- 19.5. 理解集合性能(Understanding Collection performance)
- 前面我们已经对集合进行了足够的讨论。本段中,我们将着重讲述集合在运行时的事宜。
- 19.5.1. 分类(Taxonomy)
- Hibernate定义了三种基本类型的集合:
- 值数据集合
- 一对多关联
- 多对多关联
- 这个分类是区分了不同的表和外键关系类型,但是它没有告诉我们关系模型的所有内容。 要完全理解他们的关系结构和性能特点,我们必须同时考虑“用于Hibernate更新或删除集合行数据的主键的结构”。 因此得到了如下的分类:
- 有序集合类
- 集合(sets)
- 包(bags)
- 所有的有序集合类(maps, lists, arrays)都拥有一个由<key>和 <index>组成的主键。 这种情况下集合类的更新是非常高效的——主键已经被有效的索引,因此当Hibernate试图更新或删除一行时,可以迅速找到该行数据。
- 集合(sets)的主键由<key>和其他元素字段构成。 对于有些元素类型来说,这很低效,特别是组合元素或者大文本、大二进制字段; 数据库可能无法有效的对复杂的主键进行索引。 另一方面,对于一对多、多对多关联,特别是合成的标识符来说,集合也可以达到同样的高效性能。( 附注:如果你希望SchemaExport为你的<set>创建主键, 你必须把所有的字段都声明为not-null="true"。)
- <idbag>映射定义了代理键,因此它总是可以很高效的被更新。事实上, <idbag>拥有着最好的性能表现。
- Bag是最差的。因为bag允许重复的元素值,也没有索引字段,因此不可能定义主键。 Hibernate无法判断出重复的行。当这种集合被更改时,Hibernate将会先完整地移除 (通过一个(in a single DELETE))整个集合,然后再重新创建整个集合。 因此Bag是非常低效的。
- 请注意:对于一对多关联来说,“主键”很可能并不是数据库表的物理主键。 但就算在此情况下,上面的分类仍然是有用的。(它仍然反映了Hibernate在集合的各数据行中是如何进行“定位”的。)
- 19.5.2. Lists, maps 和sets用于更新效率最高
- 根据我们上面的讨论,显然有序集合类型和大多数set都可以在增加、删除、修改元素中拥有最好的性能。
- 可论证的是对于多对多关联、值数据集合而言,有序集合类比集合(set)有一个好处。因为Set的内在结构, 如果“改变”了一个元素,Hibernate并不会更新(UPDATE)这一行。 对于Set来说,只有在插入(INSERT)和删除(DELETE) 操作时“改变”才有效。再次强调:这段讨论对“一对多关联”并不适用。
- 注意到数组无法延迟载入,我们可以得出结论,list, map和idbags是最高效的(非反向)集合类型,set则紧随其后。 在Hibernate中,set应该时最通用的集合类型,这时因为“set”的语义在关系模型中是最自然的。
- 但是,在设计良好的Hibernate领域模型中,我们通常可以看到更多的集合事实上是带有inverse="true" 的一对多的关联。对于这些关联,更新操作将会在多对一的这一端进行处理。因此对于此类情况,无需考虑其集合的更新性能。
- 19.5.3. Bag和list是反向集合类中效率最高的
- 在把bag扔进水沟之前,你必须了解,在一种情况下,bag的性能(包括list)要比set高得多: 对于指明了inverse="true"的集合类(比如说,标准的双向的一对多关联), 我们可以在未初始化(fetch)包元素的情况下直接向bag或list添加新元素! 这是因为Collection.add())或者Collection.addAll() 方法 对bag或者List总是返回true(这点与与Set不同)。因此对于下面的相同代码来说,速度会快得多。
- Parent p = (Parent) sess.load(Parent.class, id);
- Child c = new Child();
- c.setParent(p);
- p.getChildren().add(c); //no need to fetch the collection!
- sess.flush();
- 19.5.4. 一次性删除(One shot delete)
- 偶尔的,逐个删除集合类中的元素是相当低效的。Hibernate并没那么笨, 如果你想要把整个集合都删除(比如说调用list.clear()),Hibernate只需要一个DELETE就搞定了。
- 假设我们在一个长度为20的集合类中新增加了一个元素,然后再删除两个。 Hibernate会安排一条INSERT语句和两条DELETE语句(除非集合类是一个bag)。 这当然是显而易见的。
- 但是,假设我们删除了18个数据,只剩下2个,然后新增3个。则有两种处理方式:
- 逐一的删除这18个数据,再新增三个;
- 删除整个集合类(只用一句DELETE语句),然后增加5个数据。
- Hibernate还没那么聪明,知道第二种选择可能会比较快。 (也许
相关推荐
多核程序设计技术 通过软件多线程提升性能
"深度学习提升性能的方法" 深度学习是机器学习领域中一个热门的研究方向,旨在通过构建深度神经网络来学习和表示复杂数据中的隐式信息。然而,深度学习模型的性能可能会受到多种因素的影响,如数据质量、模型设计、...
SQL(Structured Query Language)是关系数据库的标准查询语言,用于管理和操作数据库中的数据。然而,随着数据量的增长...希望这篇文章能够帮助你更好地理解和运用SQL查询优化技巧,为你的数据库应用提升性能和效率。
标题提到的"USB提升性能补丁"是为了改善USB2.0接口的传输效率和稳定性。补丁通常是软件开发者为了修复程序中的错误、提高性能或增加新功能而发布的更新。在这个案例中,补丁可能是针对Windows操作系统,特别是...
”然后我会列举一些我认为能够提升性能的方法。 为了避免重复罗列这些内容,我打算在本文中把它们都写出来。 这些想法不仅可以用于深度学习,事实上可以用在任何机器学习的算法上。 提升算法性能的想法 我把这个...
"(转)Log4j的AsyncAppender能否提升性能"这个标题涉及到Log4j的一个特性——AsyncAppender,它是Log4j为了提高日志处理性能而引入的一种异步日志写入机制。 AsyncAppender的主要工作原理是通过使用单独的线程池来...
MySQL查询优化:提升性能的几个关键步骤.md
标题中的“让你的CPU性能提升35%的好软件”指的是一个声称能显著提高计算机中央处理器(CPU)性能的程序。...最后,硬件升级,如增加RAM或更换更强大的CPU,是提升性能的另一种有效途径,特别是当软件优化达到极限时。
这些工具提供了强大的功能和机制,能够帮助我们实现系统的故障恢复、消息队列、缓存等关键功能,提升系统的可靠性和性能。 通过参加“高级Java工程师体系课2.0:深入剖析高可用、高性能分布式系统设计与实现”课程...
1. 提升性能与数据相关 策略:通过改变训练数据和问题定义,创造数据的新视角,以最好地暴露底层问题的结构给学习算法。这可能是最大的性能提升点。 具体技巧包括: - 获取更多数据:检查是否可以获取更多数据或者...
通过合理利用GCC编译器的优化选项,开发者可以显著提升C语言程序的性能和效率。在选择优化选项时,需要根据项目的具体需求和目标平台的特性来决定使用哪些优化。同时,结合代码层面的优化技巧,可以进一步优化程序的...
因此,优化数据库查询是提升性能的关键。 1. 数据库查询优化: - 单表查询:避免大规模的联表查询,尤其是针对千万级或亿级数据。可先进行单表查询,获取主要数据。 - 减少查询次数:每次循环中都进行数据库查询...
系统优化是提升性能的基础,它包括硬件配置的合理调整和软件设置的优化。首先,确保硬件设备如CPU、内存和硬盘驱动器运行在最佳状态。例如,定期清理硬盘垃圾文件,进行磁盘碎片整理,以及根据工作负载合理分配内存...
除了优化措施,为了持续提升性能,A31团队还构建了AHguI A31性能监控平台。这一平台能实时监控360手机卫士的各项性能指标,及时发现并解决潜在的问题。这种精细化管理和持续的性能优化,让360手机卫士能够为用户提供...
开启全双工模式也能提升性能。不同品牌和类型的交换机可能有各自的优化技术,应根据实际需求进行选择。路由器作为连接内外网络的关键设备,其性能和配置也至关重要。对于预算有限的中小企业,可以通过软件解决方案,...
- **查询优化器**:SQL Server的查询优化器通过选择最佳执行计划来提升性能。了解如何读取和解释执行计划,以及如何使用查询提示(如FORCE PLAN或NOEXPAND)可以影响优化器的选择。 - **存储过程和参数化查询**:...
明确这些要素有助于提升性能测试的针对性和有效性。 为了提升敏捷性能测试的效果,还需要进行架构评估。这一步骤要求团队深入理解软件架构的设计,以确保性能测试能够覆盖所有的性能热点和瓶颈,及时发现并解决问题...
通过使用Smart Array 5i RAID控制器,可以实现RAID 0、1、1+0和5的配置,选择128MB缓存的5312 RAID控制器能进一步提升性能。 在远程管理方面,DL740集成了Lights-Out(iLO)组件,提供文本控制台界面,便于管理人员...
The paper introduces Selective Attention, a ...研究表明选择性注意力能够使Transformer模型根据不同任务动态调整记忆量,在减少无关输入的同时提升性能和计算效率,尤其是在大规模语料训练过程中展现出巨大优势。