<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>hibernate</title>
	<atom:link href="https://www.aitaocui.cn/tag/249822/feed" rel="self" type="application/rss+xml" />
	<link>https://www.aitaocui.cn</link>
	<description>翡翠玉石爱好者聚集地</description>
	<lastBuildDate>Sun, 27 Nov 2022 18:00:22 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.1.1</generator>

<image>
	<url>https://www.aitaocui.cn/wp-content/uploads/2022/11/taocui.png</url>
	<title>hibernate</title>
	<link>https://www.aitaocui.cn</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>hibernate(开放源代码的对象关系映射框架)</title>
		<link>https://www.aitaocui.cn/article/361832.html</link>
					<comments>https://www.aitaocui.cn/article/361832.html#respond</comments>
		
		<dc:creator><![CDATA[墨菲斯托]]></dc:creator>
		<pubDate>Sun, 27 Nov 2022 18:00:22 +0000</pubDate>
				<category><![CDATA[知识]]></category>
		<category><![CDATA[hibernate]]></category>
		<guid isPermaLink="false">https://www.aitaocui.cn/?p=361832</guid>

					<description><![CDATA[Hibernate是一个开放源代码的对象关系映射框架，它对JDBC进行了非常轻量级的对象封装，使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应...]]></description>
										<content:encoded><![CDATA[</p>
<article>
<p>Hibernate是一个开放源代码的对象关系映射框架，它对JDBC进行了非常轻量级的对象封装，使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。Hibernate可以应用在任何使用JDBC的场合，既可以在Java的客户端程序使用，也可以在Servlet/JSP的Web应用中使用，最具革命意义的是，Hibernate可以在应用EJB的J2EE架构中取代CMP，完成数据持久化的重任。</p>
</article>
<p><img decoding="async" src="https://www.aitaocui.cn/wp-content/uploads/2022/08/20220828_630b672feab89.jpg" /></p>
<article>
<h1>基本简介</h1>
<div></div>
<p>大多数应用程序都需要处理数据。Java应用程序运行时，往往把数据封装为相互连接的对象网络，但是当程序结束时，这些对象就会消失在一团逻辑中，所以需要有一些保存它们的方法。</p>
<p>有时候，甚至在编写应用程序之前，数据就已经存在了，所以需要有读入它们和将其表示为对象的方法。手动编写代码来执行这些任务不仅单调乏味、易于出错，而且会占用整个应用程序的很大一部分开发工作量。</p>
<p>优秀的面向对象开发人员厌倦了这种重复性的劳动，他们开始采用通常的“积极”偷懒做法，即创建工具，使整个过程自动化。对于关系数据库来说，这种努力的最大成果就是对象/关系映射(ORM)工具。</p>
<p>这类工具有很多，从昂贵的商业产品到内置于J2EE中的EJB标准。然而，在很多情况下，这些工具具有自身的复杂性，使得开发人员必须学习使用它们的详细规则，并修改组成应用程序的类以满足映射系统的需要。</p>
<p>由于这些工具为应付更加严格和复杂的企业需求而不断发展，于是在比较简单和常见的场景中，使用它们所面临的复杂性反而盖过了所能获得的好处。这引起了一场革命，促进了轻量级解决方案的出现，而Hibernate就是这样的一个例子。</p>
<h1>核心接口</h1>
<p>Hibernate的核心接口一共有5个，分别为：Session、SessionFactory、Transaction、Query和Configuration。这5个核心接口在任何开发中都会用到。通过这些接口，不仅可以对持久化对象进行存取，还能够进行事务控制。下面对这五的核心接口分别加以介绍。</p>
<h2 id="a-29e282ee">Session接口</h2>
<p>Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流，包含了很多常见的SQL语句。)。但需要注意的是Session对象是非线程安全的。</p>
<p>同时，Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时，其实指的是Hibernate中的session，而以后会将HttpSesion对象称为用户session。</p>
<h2 id="a-371535fd">SessionFactory接口</h2>
<p>SessionFactroy接口负责初始化Hibernate。它充当数据存储源的代理，并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的，因为一般情况下，一个项目通常只需要一个SessionFactory就够，当需要操作多个数据库时，可以为每个数据库指定一个SessionFactory。</p>
<h2 id="a-edd989af">Configuration接口</h2>
<p>Configuration接口负责配置并启动Hibernate，创建SessionFactory对象。在Hibernate的启动的过程中，Configuration类的实例首先定位映射文档位置、读取配置，然后创建SessionFactory对象。</p>
<h2 id="a-4a41f7ee">Transaction接口</h2>
<p>Transaction接口负责事务相关的操作。它是可选的，开发人员也可以设计编写自己的底层事务处理代码。</p>
<h2 id="a-7d38e9ce">Query和Criteria接口</h2>
<p>Query和Criteria接口负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。</p>
<h1>主键介绍</h1>
<h2 id="a-7b7ea712">Assigned</h2>
<p>Assigned：Assigned方式由程序生成主键值，并且要在save()之前指定否则会抛出异常。</p>
<p>特点：主键的生成值完全由用户决定，与底层数据库无关。用户需要维护主键值，在调用session.save()之前要指定主键值。</p>
<h2 id="a-e18d32b0">Hilo</h2>
<p>Hilo：Hilo使用高低位算法生成主键，高低位算法使用一个高位值和一个低位值，然后把算法得到的两个值拼接起来作为数据库中的唯一主键。Hilo方式需要额外的数据库表和字段提供高位值来源。默认请况下使用的表是hibernate_unique_key，默认字段叫作next_hi。next_hi必须有一条记录否则会出现错误。</p>
<p>特点：需要额外的数据库表的支持，能保证同一个数据库中主键的唯一性，但不能保证多个数据库之间主键的唯一性。Hilo主键生成方式由Hibernate维护，所以Hilo方式与底层数据库无关，但不应该手动修改hi/lo算法使用的表的值，否则会引起主键重复的异常。</p>
<h2 id="a-93c4652e">Increment</h2>
<p>Increment：Increment方式对主键值采取自动增长的方式生成新的主键值，但要求底层数据库的支持Sequence。如Oracle，DB2等。需要在映射文件xxx.hbm.xml中加入Increment标志符的设置。</p>
<p>特点：由Hibernate本身维护，适用于所有的数据库，不适合多进程并发更新数据库，适合单一进程访问数据库。不能用于群集环境。</p>
<h2 id="a-006d1d69">Identity</h2>
<p>Identity：Identity当时根据底层数据库，来支持自动增长，不同的数据库用不同的主键增长方式。</p>
<p>特点：与底层数据库有关，要求数据库支持Identity，如MySQl中是auto_increment，SQLServer中是Identity，支持的数据库有MySql、SQLServer、DB2、Sybase和HypersonicSQL。Identity无需Hibernate和用户的干涉，使用较为方便，但不便于在不同的数据库之间移植程序。</p>
<h2 id="a-a2a46ebf">Sequence</h2>
<p>Sequence：Sequence需要底层数据库支持Sequence方式，例如Oracle数据库等。</p>
<p>特点：需要底层数据库的支持序列，支持序列的数据库有DB2、PostgreSql、Qracle、SAPDb等在不同数据库之间移植程序，特别从支持序列的数据库移植到不支持序列的数据库需要修改配置文件。</p>
<h2 id="a-2afb72fc">Native</h2>
<p>Native：Native主键生成方式会根据不同的底层数据库自动选择Identity、Sequence、Hilo主键生成方式。</p>
<p>特点：根据不同的底层数据库采用不同的主键生成方式。由于Hibernate会根据底层数据库采用不同的映射方式，因此便于程序移植，项目中如果用到多个数据库时，可以使用这种方式。</p>
<h2 id="a-6a576da8">UUID</h2>
<p>UUID：UUID使用128位UUID算法生成主键，能够保证网络环境下的主键唯一性，也就能够保证在不同数据库及不同服务器下主键的唯一性。</p>
<p>特点：能够保证数据库中的主键唯一性，生成的主键占用比较多的存贮空间。</p>
<h2 id="a-db587b53">Foreign GUID</h2>
<p>Foreign GUID：Foreign用于一对一关系中。GUID主键生成方式使用了一种特殊算法，保证生成主键的唯一性，支持SQLServer和MySQL。</p>
<h1>源码对照</h1>
<p>net.sf.hibernate.</p>
<p>该包的类基本上都是接口类和异常类</p>
<p>net.sf.hibernate.cache.</p>
<p>JCS的实现类</p>
<p>net.sf.hibernate.cfg.</p>
<p>配置文件读取类</p>
<p>net.sf.hibernate.collection.</p>
<p>Hibernate集合接口实现类，例如List，Set，Bag等等，Hibernate之所以要自行编写集合接口实现类是为了支持lazyloading</p>
<p>net.sf.hibernate.connection.</p>
<p>几个数据库连接池的Provider</p>
<p>net.sf.hibernate.dialect.</p>
<p>支持多种数据库特性，每个Dialect实现类代表一种数据库，描述了该数据库支持的数据类型和其它特点，例如是否有AutoIncrement，是否有Sequence，是否有分页sql等等</p>
<p>net.sf.hibernate.eg.</p>
<p>Hibernate文档中用到的例子</p>
<p>net.sf.hibernate.engine.</p>
<p>这个包的类作用比较散</p>
<p>net.sf.hibernate.expression.</p>
<p>HQL支持的表达式</p>
<p>net.sf.hibernate.hq.</p>
<p>HQL实现</p>
<p>net.sf.hibernate.id.</p>
<p>ID生成器</p>
<p>net.sf.hibernate.impl.</p>
<p>最核心的包，一些重要接口的实现类，如果Session，SessionFactory，Query等</p>
<p>net.sf.hibernate.jca.</p>
<p>JCA支持，把Session包装为支持JCA的接口实现类</p>
<p>net.sf.hibernate.jmx.</p>
<p>我不懂JMX，只知道JMX是用来编写AppServer的管理程序的，大概是JMX部分接口的实现，使得AppServer可以通过JMX接口管理Hibernate</p>
<p>net.sf.hibernate.loader.</p>
<p>也是很核心的包，主要是生成sql语句的</p>
<p>net.sf.hibernate.lob.</p>
<p>Blob和Clob支持</p>
<p>net.sf.hibernate.mapping.</p>
<p>hbm文件的属性实现</p>
<p>net.sf.hibernate.metadata.</p>
<p>PO的Meta实现</p>
<p>net.sf.hibernate.odmg.</p>
<p>ODMG是一个ORM标准，这个包是ODMG标准的实现类</p>
<p>net.sf.hibernate.persister.</p>
<p>核心包，实现持久对象和表之间的映射</p>
<p>net.sf.hibernate.proxy.</p>
<p>Proxy和LazyLoading支持</p>
<p>net.sf.hibernate.ps.</p>
<p>该包是PreparedStatmentCache</p>
<p>net.sf.hibernate.sql.</p>
<p>生成JDBCsql语句的包</p>
<p>net.sf.hibernate.test.</p>
<p>测试类，你可以用junit来测试Hibernate</p>
<p>net.sf.hibernate.tool.hbm2ddl.</p>
<p>用hbm配置文件生成DDL</p>
<p>net.sf.hibernate.transaction.</p>
<p>HibernateTransaction实现类</p>
<p>net.sf.hibernate.type.</p>
<p>Hibernate中定义的持久对象的属性的数据类型</p>
<p>net.sf.hibernate.util.</p>
<p>一些工具类，作用比较散</p>
<p>net.sf.hibernate.xml.</p>
<p>XML数据绑定。</p>
<h1>类库简介</h1>
<p>antlr(必需)：Hibernate使用ANTLR来产生查询分析器，这个类库在运行环境下时也是必需的。</p>
<p>Dom4j(必需)：Hibernate使用dom4j解析XML配置文件和XML映射元文件。</p>
<p>cglib，asm(必需)：Hibernate在运行时使用这个代码生成库增强类（与JAVA反射机制联合使用）。</p>
<p>CommonsCollections，CommonsLogging(必需)：Hibernat使用ApacheJakartaCommons项目提供的多个工具类库。</p>
<p>ehcache(必需)：Hibernate可以使用不同cache缓存工具作为二级缓存。EHCache是缺省的cache缓存工具。</p>
<p>Log4j(可选)：Hibernate使用CommonsLoggingAPI，它也可以依次使用Log4j作为底层实施log的机制。如果上下文类目录中存在Log4j库，则CommonsLogging使用Log4j和并它在上下文类路径中寻找的log4j.properties文件。你可以使用在Hibernate发行包中包含中的那个示例Log4j的配置文件。这样，把log4j.jar和它的配置文件（位于src/目录中）拷贝到你的上下文类路径下，就可以在后台看到底程序如何运行的。</p>
<p>其他文件是不是必需的：请察看Hibernate发行包中的lib/README.txt文件，这是一个Hibernate发行包中附带的第三方类库的列表，他们总是保持最新的。你可以在那里找到所有必需或者可选的类库(注意：其中的&quot;buildtimerequired&quot;指的是编译Hibernate时所需要而非编译你自己的程序所必需的类库）。</p>
<h1>缓存管理</h1>
<h2 id="a-b8df8e52">一级缓存的管理</h2>
<p>当应用程序调用Session的save()、update()、savaeOrUpdate()、get()或load()，以及调用查询接口的list()、iterate()或filter()方法时，如果在Session缓存中还不存在相应的对象，Hibernate就会把该对象加入到第一级缓存中。当清理缓存时，Hibernate会根据缓存中对象的状态变化来同步更新数据库。Session为应用程序提供了两个管理缓存的方法：evict(Object obj)：从缓存中清除参数指定的持久化对象。clear()：清空缓存中所有持久化对象。</p>
<h2 id="a-77a2022d">二级缓存的管理</h2>
<p>Hibernate的二级缓存策略的一般过程如下：</p>
<p>1、条件查询的时候，总是发出一条select * from table_name where….（选择所有字段）这样的SQL语句查询数据库，一次获得所有的数据对象。</p>
<p>2、把获得的所有数据对象根据ID放入到第二级缓存中。</p>
<p>3、当Hibernate根据ID访问数据对象的时候，首先从Session一级缓存中查；查不到，如果配置了二级缓存，那么从二级缓存中查；查不到，再查询数据库，把结果按照ID放入到缓存。</p>
<p>4、删除、更新、增加数据的时候，同时更新缓存。</p>
<p>Hibernate的二级缓存策略，是针对于ID查询的缓存策略，对于条件查询则毫无作用。为此，Hibernate提供了针对条件查询的Query Cache。</p>
<p>什么样的数据适合存放到第二级缓存中？</p>
<p>1、很少被修改的数据。</p>
<p>2、不是很重要的数据，允许出现偶尔并发的数据</p>
<p>3、不会被并发访问的数据</p>
<p>4、参考数据,指的是供应用参考的常量数据，它的实例数目有限，它的实例会被许多其他类的实例引用，实例极少或者从来不会被修改。</p>
<p>不适合存放到第二级缓存的数据？</p>
<p>1、经常被修改的数据</p>
<p>2、财务数据，绝对不允许出现并发</p>
<p>3、与其他应用共享的数据。</p>
<p>常用的缓存插件Hibernater的二级缓存是一个插件，下面是几种常用的缓存插件：</p>
<p>1、EhCache：可作为进程范围的缓存，存放数据的物理介质可以是内存或硬盘，对Hibernate的查询缓存提供了支持。</p>
<p>2、OSCache：可作为进程范围的缓存，存放数据的物理介质可以是内存或硬盘，提供了丰富的缓存数据过期策略，对Hibernate的查询缓存提供了支持。</p>
<p>3、SwarmCache：可作为群集范围内的缓存，但不支持Hibernate的查询缓存。</p>
<p>4、JBossCache：可作为群集范围内的缓存，支持事务型并发访问策略，对Hibernate的查询缓存提供了支持。</p>
<h2 id="a-3676c2cf">配置二级缓存的主要步骤：</h2>
<p>1、选择需要使用二级缓存的持久化类，设置它的命名缓存的并发访问策略。这是最值得认真考虑的步骤。</p>
<p>2、选择合适的缓存插件，然后编辑该插件的配置文件。</p>
<h1>程序性能优化</h1>
<p>对于HIBERNATE性能调优的主要考虑点如下:</p>
<p>数据库设计调整</p>
<p>HQL优化</p>
<p>API的正确使用(如根据不同的业务类型选用不同的集合及查询API)</p>
<p>主配置参数(日志，查询缓存，fetch_size,batch_size等)</p>
<p>映射文件优化(ID生成策略，二级缓存，延迟加载，关联优化)</p>
<p>一级缓存的管理</p>
<p>针对二级缓存，还有许多特有的策略</p>
<p>事务控制策略：</p>
<p>1、数据库设计</p>
<p>a)降低关联的复杂性</p>
<p>b)尽量不使用联合主键</p>
<p>c)ID的生成机制，不同的数据库所提供的机制并不完全一样</p>
<p>d)适当的冗余数据，不过分追求高范式</p>
<p>2、HQL优化</p>
<p>HQL如果抛开它同HIBERNATE本身一些缓存机制的关联，HQL的优化技巧同普通的SQL优化技巧一样，可以很容易在网上找到一些经验之谈。</p>
<p>3、主配置</p>
<p>a)查询缓存，同下面讲的缓存不太一样，它是针对HQL语句的缓存，即完全一样的语句再次执行时可以利用缓存数据。但是，查询缓存在一个交易系统(数据变更频繁，查询条件相同的机率并不大)中可能会起反作用:它会白白耗费大量的系统资源但却难以派上用场。</p>
<p>b)fetch_size，同JDBC的相关参数作用类似，参数并不是越大越好，而应根据业务特征去设置</p>
<p>c)batch_size同上。</p>
<p>d)生产系统中，切记要关掉SQL语句打印。</p>
<p>4、缓存</p>
<p>a)数据库级缓存:这级缓存是最高效和安全的，但不同的数据库可管理的层次并不一样，比如，在Oracle中，可以在建表时指定将整个表置于缓存当中。</p>
<p>b)SESSION缓存:在一个Hibernate SESSION有效，这级缓存的可干预性不强，大多于HIBERNATE自动管理，但它提供清除缓存的方法，这在大批量增加/更新操作是有效的。比如，同时增加十万条记录，按常规方式进行，很可能会发现OutofMemeroy的异常，这时可能需要手动清除这一级缓存:Session.evict以及Session.clear</p>
<p>c)应用缓存:在一个SESSIONFACTORY中有效，因此也是优化的重中之重，因此，各类策略也考虑的较多，在将数据放入这一级缓存之前，需要考虑一些前提条件:</p>
<p>i、数据不会被第三方修改(比如，是否有另一个应用也在修改这些数据?)</p>
<p>ii、数据不会太大</p>
<p>iii、数据不会频繁更新(否则使用CACHE可能适得其反)</p>
<p>iv、数据会被频繁查询</p>
<p>v、数据不是关键数据(如涉及钱，安全等方面的问题)。</p>
<p>缓存有几种形式，可以在映射文件中配置:read-only(只读，适用于很少变更的静态数据/历史数据)，nonstrict-read-write，read-write(比较普遍的形式，效率一般)，transactional(JTA中，且支持的缓存产品较少)</p>
<p>d)分布式缓存:同c)的配置一样，只是缓存产品的选用不同，在目前的HIBERNATE中可供选择的不多，oscache,jboss cache，目前的大多数项目，对它们的用于集群的使用(特别是关键交易系统)都持保守态度。在集群环境中，只利用数据库级的缓存是最安全的。</p>
<p>5、延迟加载</p>
<p>a)实体延迟加载:通过使用动态代理实现</p>
<p>b)集合延迟加载:通过实现自有的SET/LIST，HIBERNATE提供了这方面的支持</p>
<p>c)属性延迟加载:</p>
<p>6、方法选用</p>
<p>a)完成同样一件事，Hibernate提供了可供选择的一些方式，但具体使用什么方式，可能用性能/代码都会有影响。显示，一次返回十万条记录(List/Set/Bag/Map等)进行处理，很可能导致内存不够的问题，而如果用基于游标(ScrollableResults)或Iterator的结果集，则不存在这样的问题。</p>
<p>b)Session的load/get方法，前者会使用二级缓存，而后者则不使用。</p>
<p>c)Query和list/iterator，如果去仔细研究一下它们，你可能会发现很多有意思的情况，二者主要区别(如果使用了Spring，在HibernateTemplate中对应find,iterator方法):</p>
<p>i、list只能利用查询缓存(但在交易系统中查询缓存作用不大)，无法利用二级缓存中的单个实体，但list查出的对象会写入二级缓存，但它一般只生成较少的执行SQL语句，很多情况就是一条(无关联)。</p>
<p>ii、iterator则可以利用二级缓存，对于一条查询语句，它会先从数据库中找出所有符合条件的记录的ID，再通过ID去缓存找，对于缓存中没有的记录，再构造语句从数据库中查出，因此很容易知道，如果缓存中没有任何符合条件的记录，使用iterator会产生N+1条SQL语句(N为符合条件的记录数)</p>
<p>iii、通过iterator，配合缓存管理API，在海量数据查询中可以很好的解决内存问题，如:</p>
<p>while(it.hasNext()){</p>
<p>YouObject object=(YouObject)it.next();</p>
<p>session.evict(youObject);</p>
<p>sessionFactory.evice(YouObject.class,youObject.getId());</p>
<p>}</p>
<p>如果用list方法，很可能就出OutofMemory错误了。</p>
<p>iv、通过上面的说明，我想你应该知道如何去使用这两个方法了。</p>
<p>7、集合的选用</p>
<p>在Hibernate 3.1文档的“19.5.Understanding Collection performance”中有详细的说明。</p>
<p>8、事务控制</p>
<p>事务方面对性能有影响的主要包括:事务方式的选用，事务隔离级别以及锁的选用</p>
<p>a)事务方式选用:如果不涉及多个事务管理器事务的话，不需要使用JTA，只有JDBC的事务控制就可以。</p>
<p>b)事务隔离级别:参见标准的SQL事务隔离级别</p>
<p>c)锁的选用:悲观锁(一般由具体的事务管理器实现)，对于长事务效率低，但安全。乐观锁(一般在应用级别实现)，如在HIBERNATE中可以定义VERSION字段，显然，如果有多个应用操作数据，且这些应用不是用同一种乐观锁机制，则乐观锁会失效。因此，针对不同的数据应有不同的策略，同前面许多情况一样，很多时候我们是在效率与安全/准确性上找一个平衡点，无论如何，优化都不是一个纯技术的问题，你应该对你的应用和业务特征有足够的了解。</p>
<p>9、批量操作</p>
<p>即使是使用JDBC，在进行大批数据更新时，BATCH与不使用BATCH有效率上也有很大的差别。我们可以通过设置batch_size来让其支持批量操作。</p>
<p>举个例子，要批量删除某表中的对象，如“delete Account”，打出来的语句，会发现HIBERNATE找出了所有ACCOUNT的ID，再进行删除，这主要是为了维护二级缓存，这样效率肯定高不了，在后续的版本中增加了bulk delete/update，但这也无法解决缓存的维护问题。</p>
</article>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
<div class="mt-3 mb-3" style="max-width: 770px;height: auto;">
                                    </div>
]]></content:encoded>
					
					<wfw:commentRss>https://www.aitaocui.cn/article/361832.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
