Hibernate的事务和并发
- 格式:doc
- 大小:224.00 KB
- 文档页数:51
hibernate的基本用法Hibernate是一个开源的Java框架,用于简化数据库操作。
它为开发人员提供了一个更加简单、直观的方式来管理数据库,同时也提高了应用程序的性能和可维护性。
本文将逐步介绍Hibernate的基本用法,包括配置、实体映射、数据操作等。
一、配置Hibernate1. 下载和安装Hibernate:首先,我们需要下载Hibernate的压缩包并解压。
然后将解压后的文件夹添加到Java项目的构建路径中。
2. 创建Hibernate配置文件:在解压后的文件夹中,可以找到一个名为"hibernate.cfg.xml"的文件。
这是Hibernate的主要配置文件,我们需要在其中指定数据库连接信息和其他相关配置。
3. 配置数据库连接:在"hibernate.cfg.xml"文件中,我们可以添加一个名为"hibernate.connection.url"的属性,用于指定数据库的连接URL。
除此之外,还需要指定数据库的用户名和密码等信息。
4. 配置实体映射:Hibernate使用对象关系映射(ORM)来将Java类映射到数据库表。
我们需要在配置文件中使用"mapping"元素来指定实体类的映射文件。
这个映射文件描述了实体类与数据库表之间的对应关系。
二、实体映射1. 创建实体类:我们需要创建一个Java类,用于表示数据库中的一行数据。
这个类的字段通常与数据库表的列对应。
同时,我们可以使用Hibernate提供的注解或XML文件来配置实体的映射关系。
2. 创建映射文件:可以根据个人喜好选择使用注解还是XML文件来配置实体类的映射关系。
如果使用XML文件,需要创建一个与实体类同名的XML文件,并在其中定义实体类与数据库表之间的映射关系。
3. 配置实体映射:在配置文件中,我们需要使用"mapping"元素来指定实体类的映射文件。
一、多选题1.在Hibernate 主配置文件(hibernate.cfg.xml)中,以下哪个元素()为它的根元素。
A.<hibernate-configuration>元素B.<session-factory>元素C.<property>元素D.<mapping>元素E.<hibernate-mapping>元素2.在Hibernate 主配置文件(hibernate.cfg.xml)中,是通过哪个元素()来配置映射文件的。
A.<hibernate-configuration>元素B.<session-factory>元素C.<property>元素D.<mapping>元素E.<hibernate-mapping>元素3.下面关于Hibernate 的映射文件说法正确的有哪些()。
A.Hibernate 是以xml 格式的文件来指定对象与关系数据之间的映射B.在hibernate.cfg.xml文件中可以配置<mapping>元素的resource属性来指定映射文件C.配置映射文件时,需要遵循它对应的DTD 文件格式D.在映射文件中,<class>元素的<id>子元素只能出现一次E.<id>元素的<generator>子元素用来设定标识符生成器4.在Hibernate 的映射文件中,<id>元素的<generator>子元素用来设定标识符生成器,以下对常用的标识符生成器的用法说法正确的是()。
A.increment:适用于代理主键。
用于为long, short 或者int 类型生成唯一标识B.identity:适用于代理主键。
由底层数据库生成标识符C.sequence:适用于代理主键。
Hibernate 根据底层数据库的序列来生成标识符D.hilo:使用一个高/低位算法高效的生成long、short 或者int 类型的标识符E.seqhilo:使用一个高/低位算法来高效的生成long、short 或者int 类型的标识符,给定一个数据库序列(sequence)的名字5.Hibernate 采用xml 文件来配置对象—关系映射有哪些好处()。
一. H ibern ate工作使用步骤?1.读取并解析配置文件2. 读取并解析映射信息,创建Ses sionF actor y3.打开Sess sion4. 创建事务Tran satio n5.持久化操作6. 提交事务7.关闭Sess ion 8. 关闭Se sstio nFact ory 二.Hib ernat e的查询方式有几种?(1)导航对象图检索方式。
根据已经加载的对象,导航到其他对象。
(2)OID查询方式。
根据对象的O ID来查询对象。
Se ssion的get()和loa d()方法。
(3)HQL查询方式。
HQ L是面向对象的查询语言,ses sion的find()方法用于执行HQL查询语句。
可以利用Q uery接口。
Q ueryquery = se ssion.crea teQue ry(“f rom C ustom er as c wh ere c.name=: c ustom erNam e”);quer y.set Strin g(“cu stome rName”,”张三”);Listresul tList = qu ery.l ist();(4)QBC查询方式。
这种API封装了基于字符串形式的查询语句。
Crit eriacrite ria = sess ion.c reate Crite ria(U ser.c lass);Cr iteri on cr iteri on1 = Expe ssion.like(“nam e”,”T%”);Crite rioncrite rion2 = Ex pessi on.eq(age,new I ntege r(30));cr iteri a =crite ria.a dd(cr iteri on1);crit eria = cr iteri a.add(crit erion2);L ist r esult List= cri teria.list();这种查询方式使用的较少,主要是在查询中需要用户输入一系列的查询条件,如果采用HQL查询代码会比较烦。
hibernate框架的工作原理Hibernate框架的工作原理Hibernate是一个开源的ORM(Object-Relational Mapping)框架,它将Java对象映射到关系型数据库中。
它提供了一种简单的方式来处理数据持久化,同时也提供了一些高级特性来优化性能和可维护性。
1. Hibernate框架的基本概念在开始讲解Hibernate框架的工作原理之前,需要先了解一些基本概念:Session:Session是Hibernate与数据库交互的核心接口,它代表了一个会话,可以用来执行各种数据库操作。
SessionFactory:SessionFactory是一个线程安全的对象,它用于创建Session对象。
通常情况下,应用程序只需要创建一个SessionFactory对象。
Transaction:Transaction是对数据库操作进行事务管理的接口。
在Hibernate中,所有对数据库的操作都应该在事务中进行。
Mapping文件:Mapping文件用于描述Java类与数据库表之间的映射关系。
它定义了Java类属性与数据库表字段之间的对应关系。
2. Hibernate框架的工作流程Hibernate框架主要分为两个部分:持久化层和业务逻辑层。
其中,持久化层负责将Java对象映射到数据库中,并提供数据访问接口;业务逻辑层则负责处理业务逻辑,并调用持久化层进行数据访问。
Hibernate框架的工作流程如下:2.1 创建SessionFactory对象在应用程序启动时,需要创建一个SessionFactory对象。
SessionFactory是一个线程安全的对象,通常情况下只需要创建一个即可。
2.2 创建Session对象在业务逻辑层需要进行数据访问时,需要先创建一个Session对象。
Session是Hibernate与数据库交互的核心接口,它代表了一个会话,可以用来执行各种数据库操作。
2.3 执行数据库操作在获取了Session对象之后,就可以执行各种数据库操作了。
Transaction用法什么是Transaction?Transaction(事务)是数据库管理系统中的一个重要概念,它指的是一组数据库操作语句的执行单元。
事务提供了一种机制,可以将多个操作看作一个整体,要么全部执行成功,要么全部回滚到初始状态。
在现实世界中,我们常常需要进行一系列相关的操作,并将它们作为一个不可分割的整体进行处理。
例如,在银行转账过程中,我们需要扣除转账账户的金额并增加接收账户的金额,这两个操作必须同时成功或同时失败。
如果其中一个操作失败了,那么整个转账过程都应该被回滚到初始状态。
事务的特性事务具有以下四个特性(通常称为ACID特性):1.原子性(Atomicity):事务是一个不可分割的操作序列,要么全部执行成功,要么全部回滚。
如果在事务执行过程中发生错误或异常,所有已经执行的操作都会被撤销。
2.一致性(Consistency):事务执行前后数据库从一个一致状态变为另一个一致状态。
这意味着在任何时刻都应该满足预定义的完整性约束。
3.隔离性(Isolation):并发执行的多个事务之间应该互相隔离,每个事务都应该感知不到其他事务的存在。
这样可以避免数据不一致和并发访问引起的问题。
4.持久性(Durability):一旦事务提交成功,其对数据库的影响应该是永久性的。
即使系统发生故障,数据也应该能够恢复到提交事务后的状态。
事务的使用场景事务广泛应用于各种数据库管理系统和应用程序中。
以下是一些常见的使用场景:1.银行系统:在银行系统中,转账、存款和取款等操作需要保证原子性和一致性。
如果一个操作失败了,整个交易都会被回滚。
2.航空订票系统:当用户预订机票时,需要同时更新座位信息和用户账户余额。
如果其中一个操作失败了,整个预订过程都会被撤销。
3.电子商务平台:在电子商务平台上下单、支付和库存管理等操作需要通过事务来保证数据的一致性和完整性。
4.在线游戏:在多人在线游戏中,对玩家之间进行交易、竞拍或共享资源等操作也需要使用事务来保证数据的正确性。
J2EE事务管理教程一个典型的企业应用程序在一个或多个数据库中访问和存储信息。
因为这些信息对于商业操作非常重要,它必须精确、实时、可靠。
如果允许多个程序同时更新相同的数据,就会破坏数据的完整性。
如果在一个商业交易处理过程中,部分数据被更新后系统崩溃也将破坏数据完整性。
事务通过预防以上情况的发生确保数据的完整性。
事务控制多个应用程序对数据库的并发操作。
如果发生系统崩溃,事务确保恢复的数据崩溃前将保持一致。
本章内容:什么是事务容器管理事务事务的属性回滚容器管理事务同步会话bean实例变量容器管理事务中不允许使用的方法Bean 管理事务JDBC事务JTA 事务非提交返回事务在Bean管理事务中不允许使用的方法企业Bean事务摘要事务超时隔离级别更新多个数据库Web 组件事务一.什么是事务模拟一个商业交易,应用程序需要完成几个步骤。
例如,一个财物应用程序,可能会将资金从经常性帐户(checking account)转到储蓄性账户(saving account),该交易的伪码表示如下:begin transactiondebit checking accountcredit savings accountupdate history logcommit transaction三个步骤要么全部完成,要么一个都不做。
否则数据完整性将被破坏。
因为事务中的所有步骤被看作一个统一的整体,所以事务一般被定义为一个不可分割的工作单元。
结束事务有两种方法:提交或者回滚。
当一个事务提交,数据修改被保存。
如果事务中有一个步骤失败,事务就回滚,这个事务中的已经执行的动作被撤销。
例如在上面的伪码中,如果在处理第二步的时候硬盘驱动器崩溃,事务的第一步将被撤销。
尽管事务失败,数据的完整性不会被破坏,因为帐目仍然保持平衡。
前面伪码中,begin和commit标明了事务的界限。
当设计一个企业Bean的时候,你要决定怎样通过容器管理或bean管理事务来指定事务界限。
Hibernate工作原理及为什么要用?一原理:1.读取并解析配置文件2.读取并解析映射信息,创建SessionFactory3.打开Sesssion4.创建事务Transaction5.持久化操作6.提交事务7.关闭Session。
8.关闭SessionFactory为什么要用:1. 对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
2. Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。
他很大程度的简化DAO层的编码工作3. hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
4. hibernate的性能非常好,因为它是个轻量级框架。
映射的灵活性很出色。
它支持各种关系数据库,从一对一到多对多的各种复杂关系。
二Hibernate 的核心接口及其作用1 Configuration类:配置Hibernate启动Hibernate创建SessionFactory对象2 SessionFactory:初始化Hibernate创建Session对象线程安全—同一实例被多个线程共享重量级:代表一个数据库内部维护一个连接池2.1 openSession():总是创建新的session,需要手动close()2.2 getCurrentSession() : 必须在hibernate.cfg.xml设置session 上下文事务自动提交并且自动关闭session.从上下文环境中获得session,如果当时环境中不存就创建新的.如果环境中存在就使用环境中的,而且每次得到的都是同一个session (在session提交之前,提交之后就是新的了) 应用在一个session中有多个不同DAO操作处于一个事务时3 Session:负责保存、更新、删除、加载和查询对象轻量级--可以经常创建或销毁3.1 Load与get方法的区别:简单理解:load是懒加载,get是立即加载.load方法当使用查出来的对象时并且session未关闭,才会向数据库发sql, get会立即向数据库发sql返回对象3.3 merge(); 合并对象更新前会先select 再更新3.4clear()清空缓存,flush()将session中的数据同步到数据库两者组合使用于批量数据处理3.4Transaction commit() rollback()JPA: java persistence API 提供了一组操作实体bean的注解和API规范SchemaExporthiberante的生成数据库表(及其他ddl)的工具类可以通过这个工具类完成一些ddl四Hibernate查询查询语言主要有:HQL 、QBC (Query By Criteria条件查询) 、 Native SQLHql:1、属性查询2、参数查询、命名参数查询3、关联查询4、分页查询5、统计函数五优化抓取策略连接抓取(Join fetching)使用 OUTER JOIN(外连接)来获得对象的关联实例或者关联集合查询抓取(Select fetching)另外发送一条 SELECT 语句抓取当前对象的关联实体或集合另外可以配置hibernate抓取数量限制批量抓取(Batch fetching)另外可以通过集合过滤来限制集合中的数据量使用session.createFilter(topic.getReplies(),queryString).list();检索策略延迟检索和立即检索(优先考虑延迟检索)N+1问题指hibernate在查询当前对象时查询相关联的对象查询一端时会查询关联的多端集合对象解决方案:延迟加载连接抓取策略二级缓存集合过滤 BatchSize限制记录数量映射建议使用双向一对多关联,不使用单向一对多灵活使用单向一对多关联不用一对一,用多对一取代配置对象缓存,不使用集合缓存一对多集合使用Bag,多对多集合使用Set继承类使用显式多态表字段要少,表关联不要怕多,有二级缓存撑腰Hibernbate缓存机制性能提升的主要手段Hibernate进行查询时总是先在缓存中进行查询,如缓存中没有所需数据才进行数据库的查询.Hibernbate缓存:一级缓存 (Session级别)二级缓存(SessionFactory级别)查询缓存 (基于二级缓存存储相同参数的sql查询结果集)一级缓存(session缓存)Session缓存可以理解为session中的一个map成员, key为OID ,value为持久化对象的引用在session关闭前,如果要获取记录,hiberntae先在session缓存中查找,找到后直接返回,缓存中没有才向数据库发送sql三种状态的区别在于:对象在内存、数据库、session缓存三者中是否有OID临时状态内存中的对象没有OID, 缓存中没有OID,数据库中也没有OID 执行new或delete()后持久化状态内存中的对象有OID, 缓存中有OID,数据库中有OIDsave() load() get() update() saveOrUpdate() Query对象返回的集合游离(脱管)状态内存中的对象有OID, 缓存中没有OID,数据库中可能有OIDflush() close()后使用session缓存涉及三个操作:1将数据放入缓存2从缓存中获取数据3缓存的数据清理4二级缓存SessionFactory级别SessionFactory级别的缓存,它允许多个Session间共享缓存一般需要使用第三方的缓存组件,如: Ehcache Oscache、JbossCache等二级缓存的工作原理:在执行各种条件查询时,如果所获得的结果集为实体对象的集合,那么就会把所有的数据对象根据OID放入到二级缓存中。
Hibernate的事务和并发Hibernate的事务和并发控制很容易掌握。
Hibernate直接使用JDBC连接和JTA资源,不添加任何附加锁定行为。
我们强烈推荐你花点时间了解JDBC编程,ANSI SQL查询语言和你使用的数据库系统的事务隔离规范。
Hibernate只添加自动版本管理,而不会锁定内存中的对象,也不会改变数据库事务的隔离级别。
基本上,使用Hibernate就好像直接使用JDBC(或者JTA/CMT)来访问你的数据库资源。
除了自动版本管理,针对行级悲观锁定,Hibernate也提供了辅助的API,它使用了S ELECT FOR UPDATE的SQL语法。
本章后面会讨论这个API。
我们从Configuration层、SessionFactory层, 和Session层开始讨论Hibernate的并行控制、数据库事务和应用程序的长事务。
12.1.Session和事务范围(transaction scopes)一个SessionFactory对象的创建代价很昂贵,它是线程安全的对象,它被设计成可以为所有的应用程序线程所共享。
它只创建一次,通常是在应用程序启动的时候,由一个Co nfiguraion的实例来创建。
一个Session的对象是轻型的,非线程安全的,对于单个业务进程,单个的工作单元而言,它只被使用一次,然后就丢弃。
只有在需要的时候,Session 才会获取一个JDBC 的Connection(或一个Datasource)对象。
所以你可以放心的打开和关闭Session,甚至当你并不确定一个特定的请求是否需要数据访问时,你也可以这样做。
(一旦你实现下面提到的使用了请求拦截的模式,这就变得很重要了。
此外我们还要考虑数据库事务。
数据库事务应该尽可能的短,降低数据库锁定造成的资源争用。
数据库长事务会导致你的应用程序无法扩展到高的并发负载。
一个操作单元(Unit of work)的范围是多大?单个的Hibernate Session能跨越多个数据库事务吗?还是一个Session的作用范围对应一个数据库事务的范围?应该何时打开Se ssion,何时关闭Session?,你又如何划分数据库事务的边界呢?12.1.1.操作单元(Unit of work)首先,别再用session-per-operation这种反模式了,也就是说,在单个线程中,不要因为一次简单的数据库调用,就打开和关闭一次Session!数据库事务也是如此。
应用程序中的数据库调用是按照计划好的次序,分组为原子的操作单元。
(注意,这也意味着,应用程序中,在单个的SQL语句发送之后,自动事务提交(auto-commit)模式失效了。
这种模式专门为SQL控制台操作设计的。
Hibernate禁止立即自动事务提交模式,或者期望应用服务器禁止立即自动事务提交模式。
)在多用户的client/server应用程序中,最常用的模式是每个请求一个会话(session-pe r-request)。
在这种模式下,来自客户端的请求被发送到服务器端(即Hibernate持久化层运行的地方),一个新的Hibernate Session被打开,并且执行这个操作单元中所有的数据库操作。
一旦操作完成(同时发送到客户端的响应也准备就绪),session被同步,然后关闭。
你也可以使用单个数据库事务来处理客户端请求,在你打开Session之后启动事务,在你关闭Session之前提交事务。
会话和请求之间的关系是一对一的关系,这种模式对于大多数应用程序来说是很棒的。
真正的挑战在于如何去实现这种模式:不仅Session和事务必须被正确的开始和结束,而且他们也必须能被数据访问操作访问。
用拦截器来实现操作单元的划分,该拦截器在客户端请求达到服务器端的时候开始,在服务器端发送响应(即,ServletFilter)之前结束。
我们推荐使用一个ThreadLocal 变量,把Session绑定到处理客户端请求的线程上去。
这种方式可以让运行在该线程上的所有程序代码轻松的访问Session(就像访问一个静态变量那样)。
你也可以在一个ThreadLocal 变量中保持事务上下文环境,不过这依赖于你所选择的数据库事务划分机制。
这种实现模式被称之为ThreadLocal Session和Open S ession in View。
你可以很容易的扩展本文前面章节展示的HibernateUtil 辅助类来实现这种模式。
当然,你必须找到一种实现拦截器的方法,并且可以把拦截器集成到你的应用环境中。
请参考Hibernate网站上面的提示和例子。
12.1.2.应用程序事务(Application transactions)session-per-request模式不仅仅是一个可以用来设计操作单元的有用概念。
很多业务处理流程都需要一系列完整的和用户之间的交互,即用户对数据库的交叉访问。
在基于w eb的应用和企业应用中,跨用户交互的数据库事务是无法接受的。
考虑下面的例子:在界面的第一屏,打开对话框,用户所看到的数据是被一个特定的Session 和数据库事务载入(load)的。
用户可以随意修改对话框中的数据对象。
5分钟后,用户点击“保存”,期望所做出的修改被持久化;同时他也期望自己是唯一修改这个信息的人,不会出现修改冲突。
从用户的角度来看,我们把这个操作单元称为应用程序长事务(application transactio n)。
在你的应用程序中,可以有很多种方法来实现它。
头一个幼稚的做法是,在用户思考的过程中,保持Session和数据库事务是打开的,保持数据库锁定,以阻止并发修改,从而保证数据库事务隔离级别和原子操作。
这种方式当然是一个反模式,因为数据库锁定的维持会导致应用程序无法扩展并发用户的数目。
很明显,我们必须使用多个数据库事务来实现一个应用程序事务。
在这个例子中,维护业务处理流程的事务隔离变成了应用程序层的部分责任。
单个应用程序事务通常跨越多个数据库事务。
如果仅仅只有一个数据库事务(最后的那个事务)保存更新过的数据,而所有其他事务只是单纯的读取数据(例如在一个跨越多个请求/响应周期的向导风格的对话框中),那么应用程序事务将保证其原子性。
这种方式比听起来还要容易实现,特别是当你使用了Hibernate的下述特性的时候:自动版本化- Hibernate能够自动进行乐观并发控制,如果在用户思考的过程中发生并发修改冲突,Hibernate能够自动检测到。
脱管对象(Detached Objects)- 如果你决定采用前面已经讨论过的session-per-reque st模式,所有载入的实例在用户思考的过程中都处于与Session脱离的状态。
Hibernate 允许你把与Session脱离的对象重新关联到Session 上,并且对修改进行持久化,这种模式被称为session-per-request-with-detached-objects。
自动版本化被用来隔离并发修改。
长生命周期的Session (Long Session)- Hibernate 的Session 可以在数据库事务提交之后和底层的JDBC连接断开,当一个新的客户端请求到来的时候,它又重新连接上底层的JDBC连接。
这种模式被称之为session-per-application-transaction,这种情况可能会造成不必要的Session和JDBC连接的重新关联。
自动版本化被用来隔离并发修改。
session-per-request-with-detached-objects 和session-per-application-transaction 各有优缺点,我们在本章后面乐观并发控制那部分再进行讨论。
12.1.3.关注对象标识(Considering object identity)应用程序可能在两个不同的Session中并发访问同一持久化状态,但是,一个持久化类的实例无法在两个Session中共享。
因此有两种不同的标识语义:数据库标识foo.getId().equals( bar.getId() )JVM 标识foo==bar对于那些关联到特定Session (也就是在单个Session的范围内)上的对象来说,这两种标识的语义是等价的,与数据库标识对应的JVM标识是由Hibernate来保证的。
不过,当应用程序在两个不同的session中并发访问具有同一持久化标识的业务对象实例的时候,这个业务对象的两个实例事实上是不相同的(从JVM识别来看)。
这种冲突可以通过在同步和提交的时候使用自动版本化和乐观锁定方法来解决。
这种方式把关于并发的头疼问题留给了Hibernate和数据库;由于在单个线程内,操作单元中的对象识别不需要代价昂贵的锁定或其他意义上的同步,因此它同时可以提供最好的可伸缩性。
只要在单个线程只持有一个Session,应用程序就不需要同步任何业务对象。
在S ession 的范围内,应用程序可以放心的使用==进行对象比较。
不过,应用程序在Session的外面使用==进行对象比较可能会导致无法预期的结果。
在一些无法预料的场合,例如,如果你把两个脱管对象实例放进同一个Set的时候,就可能发生。
这两个对象实例可能有同一个数据库标识(也就是说,他们代表了表的同一行数据),从JVM标识的定义上来说,对脱管的对象而言,Hibernate无法保证他们的的JVM 标识一致。
开发人员必须覆盖持久化类的equals()方法和hashCode() 方法,从而实现自定义的对象相等语义。
警告:不要使用数据库标识来实现对象相等,应该使用业务键值,由唯一的,通常不变的属性组成。
当一个瞬时对象被持久化的时候,它的数据库标识会发生改变。
如果一个瞬时对象(通常也包括脱管对象实例)被放入一个Set,改变它的hash code会导致与这个Set的关系中断。
虽然业务键值的属性不象数据库主键那样稳定不变,但是你只需要保证在同一个Set 中的对象属性的稳定性就足够了。
请到Hibernate网站去寻求这个问题更多的详细的讨论。
请注意,这不是一个有关Hibernate的问题,而仅仅是一个关于Java对象标识和判等行为如何实现的问题。
12.1.4.常见问题决不要使用反模式session-per-user-session或者session-per-application(当然,这个规定几乎没有例外)。
请注意,下述一些问题可能也会出现在我们推荐的模式中,在你作出某个设计决定之前,请务必理解该模式的应用前提。
Session 是一个非线程安全的类。
如果一个Session 实例允许共享的话,那些支持并发运行的东东,例如HTTP request,session beans,或者是Swing workers,将会导致出现资源争用(race condition)。