当前位置:文档之家› Hibernate的事务和并发

Hibernate的事务和并发

Hibernate的事务和并发
Hibernate的事务和并发

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)。如果在HttpSession中有Hibernate 的Session的话(稍后讨论),你应该考虑同步访问你的Http session。否则,只要用户足够快的点击浏览器的“刷新”,就会导致两个并发运行线程使用同一个Session。

一个由Hibernate抛出的异常意味着你必须立即回滚数据库事务,并立即关闭Session (稍后会展开讨论)。如果你的Session绑定到一个应用程序上,你必须停止该应用程序。回滚数据库事务并不会把你的业务对象退回到事务启动时候的状态。这意味着数据库状态和业务对象状态不同步。通常情况下,这不是什么问题,因为异常是不可恢复的,你必须在回滚之后重新开始执行。

Session 缓存了处于持久化状态的每个对象(Hibernate会监视和检查脏数据)。这意味着,如果你让Session打开很长一段时间,或是仅仅载入了过多的数据,Session占用的内存会一直增长,直到抛出OutOfMemoryException异常。这个问题的一个解决方法是调用clear() 和evict()来管理Session的缓存,但是如果你需要大批量数据操作的话,最好考虑使用存储过程。在第14章批量处理(Batch processing)中有一些解决方案。在用户会话期间一直保持Session打开也意味着出现脏数据的可能性很高。

12.2.数据库事务声明

数据库(或者系统)事务的声明总是必须的。在数据库事务之外,就无法和数据库通讯(这可能会让那些习惯于自动提交事务模式的开发人员感到迷惑)。永远使用清晰的事务声明,即使只读操作也是如此。进行显式的事务声明并不总是需要的,这取决于你的事务隔离级别和数据库的能力,但不管怎么说,声明事务总归有益无害。

一个Hibernate应用程序可以运行在非托管环境中(也就是独立运行的应用程序,简单Web应用程序,或者Swing图形桌面应用程序),也可以运行在托管的J2EE环境中。在一个非托管环境中,Hibernate 通常自己负责管理数据库连接池。应用程序开发人员必须手工设置事务声明,换句话说,就是手工启动,提交,或者回滚数据库事务。一个托管的环境通常提供了容器管理事务,例如事务装配通过可声明的方式定义在EJB session beans 的部署描述符中。可编程式事务声明不再需要,即使是Session 的同步也可以自动完成。

让持久层具备可移植性是人们的理想。Hibernate提供了一套称为Transaction的封装API,用来把你的部署环境中的本地事务管理系统转换到Hibernate事务上。这个API是可选的,但是我们强烈推荐你使用,除非你用CMT session bean。

通常情况下,结束Session 包含了四个不同的阶段:

同步session(flush,刷出到磁盘)

提交事务

关闭session

处理异常

session的同步(flush,刷出)前面已经讨论过了,我们现在进一步考察在托管和非托管环境下的事务声明和异常处理。

12.2.1.非托管环境

如果Hibernat持久层运行在一个非托管环境中,数据库连接通常由Hibernate的连接池机制来处理。

你不需要显式flush() Session - 对commit()的调用会自动触发session的同步。

调用close() 标志session的结束。close()方法重要的暗示是,session释放了JDB C连接。

这段Java代码是可移植的,可以在非托管环境和JTA环境中运行。

你很可能从未在一个标准的应用程序的业务代码中见过这样的用法;致命的(系统)异常应该总是在应用程序“顶层”被捕获。换句话说,执行Hibernate调用的代码(在持久层)和处理RuntimeException异常的代码(通常只能清理和退出应用程序)应该在不同的应用程序逻辑层。这对于你设计自己的软件系统来说是一个挑战,只要有可能,你就应该使用J2EE/EJB容器服务。异常处理将在本章稍后进行讨论。

请注意,你应该选择org.hibernate.transaction.JDBCTransactionFactory (这是默认选项).

12.2.2.使用JTA

如果你的持久层运行在一个应用服务器中(例如,在EJB session beans的后面),Hibernate获取的每个数据源连接将自动成为全局JTA事务的一部分。Hibernate提供了两种策略进行JTA集成。

如果你使用bean管理事务(BMT),可以通过使用Hibernate 的Transaction API来告诉应用服务器启动和结束BMT事务。因此,事务管理代码和在非托管环境下是一样的。

CMT方式下,事务声明是在session bean的部署描述符中,而不需要编程。除非你设置了属性hibernate.transaction.flush_before_completion和hibernate.transaction.a uto_close_session为true,否则你必须自己同步和关闭Session。Hibernate可以为你自动同步和关闭Session。你唯一要做的就是当发生异常时进行事务回滚。幸运的是,在一个CMT bean中,事务回滚甚至可以由容器自动进行,因为由session bean方法抛出的未处理的RuntimeException异常可以通知容器设置全局事务回滚。这意味着在CMT中,你完全无需使用Hibernate的Transaction API 。

请注意,当你配置Hibernate事务工厂的时候,在一个BMT session bean中,你应该选择org.hibernate.transaction.JTATransactionFactory,在一个CMT session bean中

选择org.hibernate.transaction.CMTTransactionFactory。记住,同时也要设置org.hibern ate.transaction.manager_lookup_class。

如果你使用CMT环境,并且让容器自动同步和关闭session,你可能也希望在你代码的不同部分使用同一个session。一般来说,在一个非托管环境中,你可以使用一个Thre adLocal 变量来持有这个session,但是单个EJB方法调用可能会在不同的线程中执行(举例来说,一个session bean调用另一个session bean)。如果你不想在应用代码中被传递Session对象实例的问题困扰的话,那么SessionFactory 提供的getCurrentSession()方法就很适合你,该方法返回一个绑定到JTA事务上下文环境中的session实例。这也是把Hibernate集成到一个应用程序中的最简单的方法!这个“当前的”session总是可以自动同步和自动关闭(不考虑上述的属性设置)。我们的session/transaction 管理代码减少到如下所示:

换句话来说,在一个托管环境下,你要做的所有的事情就是调用SessionFactory.get CurrentSession(),然后进行你的数据访问,把其余的工作交给容器来做。事务在你的se ssion bean的部署描述符中以可声明的方式来设置。session的生命周期完全由Hibernat e来管理。

对after_statement连接释放方式有一个警告。因为JTA规范的一个很愚蠢的限制,Hi bernate不可能自动清理任何未关闭的ScrollableResults 或者Iterator,它们是由scroll()或iterate()产生的。你must通过在finally块中,显式调用ScrollableResults.close()或者H ibernate.close(Iterator)方法来释放底层数据库游标。(当然,大部分程序完全可以很容易的避免在CMT代码中出现scroll()或iterate()。)

12.2.3.异常处理

如果Session 抛出异常(包括任何SQLException), 你应该立即回滚数据库事务,调用Session.close() ,丢弃该Session实例。Session的某些方法可能会导致session 处于不一致的状态。所有由Hibernate抛出的异常都视为不可以恢复的。确保在finally 代码块中调用close()方法,以关闭掉Session。

HibernateException是一个非检查期异常(这不同于Hibernate老的版本),它封装了Hibernate持久层可能出现的大多数错误。我们的观点是,不应该强迫应用程序开发人员在底层捕获无法恢复的异常。在大多数软件系统中,非检查期异常和致命异常都是在相应方法调用的堆栈的顶层被处理的(也就是说,在软件上面的逻辑层),并且提供一个错误信息给应用软件的用户(或者采取其他某些相应的操作)。请注意,Hibernate也有可能抛出其他并不属于HibernateException的非检查期异常。这些异常同样也是无法恢复的,应该采取某些相应的操作去处理。

在和数据库进行交互时,Hibernate把捕获的SQLException封装为Hibernate的JDBCEx ception。事实上,Hibernate尝试把异常转换为更有实际含义的JDBCException异常的子类。底层的SQLException可以通过JDBCException.getCause()来得到。Hibernate通过使用关联到SessionFactory上的SQLExceptionConverter来把SQLException转换为一个对应的JDBCException 异常的子类。默认情况下,SQLExceptionConverter可以通过配置dialect 选项指定;此外,也可以使用用户自定义的实现类(参考javadocs SQLExcepti onConverterFactory类来了解详情)。标准的JDBCException子类型是:JDBCConnectionException - 指明底层的JDBC通讯出现错误

SQLGrammarException - 指明发送的SQL语句的语法或者格式错误

ConstraintViolationException - 指明某种类型的约束违例错误

LockAcquisitionException - 指明了在执行请求操作时,获取所需的锁级别时出现的错误。

GenericJDBCException - 不属于任何其他种类的原生异常

12.3.乐观并发控制(Optimistic concurrency control)

唯一能够同时保持高并发和高可伸缩性的方法就是使用带版本化的乐观并发控制。版本检查使用版本号、或者时间戳来检测更新冲突(并且防止更新丢失)。Hibernate为使用乐观并发控制的代码提供了三种可能的方法,应用程序在编写这些代码时,可以采用它们。我们已经在前面应用程序长事务那部分展示了乐观并发控制的应用场景,此外,在单个数据库事务范围内,版本检查也提供了防止更新丢失的好处。

12.3.1.应用程序级别的版本检查(Application version checking)

未能充分利用Hibernate功能的实现代码中,每次和数据库交互都需要一个新的Sess ion,而且开发人员必须在显示数据之前从数据库中重新载入所有的持久化对象实例。这种方式迫使应用程序自己实现版本检查来确保应用程序事务的隔离,从数据访问的角度来说是最低效的。这种使用方式和entity EJB最相似。

// foo is an instance loaded by a previous Session session = factory.openSession();

Transaction t = session.beginTransaction();

int oldVersion = foo.getVersion();

session.load( foo, foo.getKey() ); // load the current state

if ( oldVersion!=foo.getVersion ) throw new StaleObjectStateException();

foo.setProperty("bar");

https://www.doczj.com/doc/145638883.html,mit();

session.close();

version 属性使用来映射,如果对象是脏数据,在同步的时候,Hibernate会自动增加版本号。

当然,如果你的应用是在一个低数据并发环境下,并不需要版本检查的话,你照样可以使用这种方式,只不过跳过版本检查就是了。在这种情况下,最晚提交生效(last comm it wins)就是你的应用程序长事务的默认处理策略。请记住这种策略可能会让应用软件的用户感到困惑,因为他们有可能会碰上更新丢失掉却没有出错信息,或者需要合并更改冲突的情况。

很明显,手工进行版本检查只适合于某些软件规模非常小的应用场景,对于大多数软件应用场景来说并不现实。通常情况下,不仅是单个对象实例需要进行版本检查,整个被修改过的关联对象图也都需要进行版本检查。作为标准设计范例,Hibernate使用长生命周期Session的方式,或者脱管对象实例的方式来提供自动版本检查。

12.3.2.长生命周期session和自动版本化

单个Session实例和它所关联的所有持久化对象实例都被用于整个应用程序事务。Hi bernate在同步的时候进行对象实例的版本检查,如果检测到并发修改则抛出异常。由开发人员来决定是否需要捕获和处理这个异常(通常的抉择是给用户提供一个合并更改,或者在无脏数据情况下重新进行业务操作的机会)。

在等待用户交互的时候,Session 断开底层的JDBC连接。这种方式以数据库访问的角度来说是最高效的方式。应用程序不需要关心版本检查或脱管对象实例的重新关联,在每个数据库事务中,应用程序也不需要载入读取对象实例。

foo 对象始终和载入它的Session相关联。Session.reconnect()获取一个新的数据库连接(或者你可以提供一个),并且继续当前的session。Session.disconnect() 方法把s ession与JDBC连接断开,把数据库连接返回到连接池(除非是你自己提供的数据库连接)。在Session重新连接上数据库连接之后,你可以对任何可能被其他事务更新过的对象调用Session.lock(),设置LockMode.READ 锁定模式,这样你就可以对那些你不准备更新的数据进行强制版本检查。此外,你并不需要锁定那些你准备更新的数据。

假若对disconnect()和reconnect()的显式调用发生得太频繁了,你可以使用hibernate. connection.release_mode来代替。

如果在用户思考的过程中,Session因为太大了而不能保存,那么这种模式是有问题的。举例来说,一个HttpSession应该尽可能的小。由于Session是一级缓存,并且保持了所有被载入过的对象,因此我们只应该在那些少量的request/response情况下使用这种策略。而且在这种情况下,Session 里面很快就会有脏数据出现,因此请牢牢记住这一建议。

此外,也请注意,你应该让与数据库连接断开的Session对持久层保持关闭状态。换句话说,使用有状态的EJB session bean来持有Session,而不要把它传递到web层(甚至把它序列化到一个单独的层),保存在HttpSession中。

12.3.3.脱管对象(deatched object)和自动版本化

这种方式下,与持久化存储的每次交互都发生在一个新的Session中。然而,同一持久化对象实例可以在多次与数据库的交互中重用。应用程序操纵脱管对象实例的状态,这个脱管对象实例最初是在另一个Session 中载入的,然后调用Session.update(),Sessi on.saveOrUpdate(), 或者Session.merge() 来重新关联该对象实例。

Hibernate会再一次在同步的时候检查对象实例的版本,如果发生更新冲突,就抛出异常。

如果你确信对象没有被修改过,你也可以调用lock() 来设置LockMode.READ(绕过所有的缓存,执行版本检查),从而取代update()操作。

12.3.4.定制自动版本化行为

对于特定的属性和集合,通过为它们设置映射属性optimistic-lock的值为false,来禁止Hibernate的版本自动增加。这样的话,如果该属性脏数据,Hibernate将不再增加版本号。

遗留系统的数据库Schema通常是静态的,不可修改的。或者,其他应用程序也可能访问同一数据库,根本无法得知如何处理版本号,甚至时间戳。在以上的所有场景中,实现版本化不能依靠数据库表的某个特定列。在的映射中设置optimistic-lock="all"可以在没有版本或者时间戳属性映射的情况下实现版本检查,此时Hibernate将比较一行记录的每个字段的状态。请注意,只有当Hibernate能够比较新旧状态的情况下,这种方式才能生效,也就是说,你必须使用单个长生命周期Session模式,而不能使用session-per-requ est-with-detached-objects模式。

有些情况下,只要更改不发生交错,并发修改也是允许的。当你在的映射中设置optimistic-lock="dirty",Hibernate在同步的时候将只比较有脏数据的字段。

在以上所有场景中,不管是专门设置一个版本/时间戳列,还是进行全部字段/脏数据字段比较,Hibernate都会针对每个实体对象发送一条UPDATE(带有相应的WHERE语句)的SQL语句来执行版本检查和数据更新。如果你对关联实体设置级联关系使用传播性持久化(transitive persistence),那么Hibernate可能会执行不必要的update语句。这通常不是个问题,但是数据库里面对on update点火的触发器可能在脱管对象没有任何更改的情况下被触发。因此,你可以在的映射中,通过设置select-before-update="true" 来定制这一行为,强制Hibernate SELECT这个对象实例,从而保证,在更新记录之前,对象的确是被修改过。

12.4.悲观锁定(Pessimistic Locking)

用户其实并不需要花很多精力去担心锁定策略的问题。通常情况下,只要为JDBC连接指定一下隔离级别,然后让数据库去搞定一切就够了。然而,高级用户有时候希望进行一个排它的悲观锁定,或者在一个新的事务启动的时候,重新进行锁定。

Hibernate总是使用数据库的锁定机制,从不在内存中锁定对象!

类LockMode 定义了Hibernate所需的不同的锁定级别。一个锁定可以通过以下的机制来设置:

当Hibernate更新或者插入一行记录的时候,锁定级别自动设置为LockMode.WRITE。

当用户显式的使用数据库支持的SQL格式SELECT ... FOR UPDATE 发送SQL的时候,锁定级别设置为LockMode.UPGRADE

当用户显式的使用Oracle数据库的SQL语句SELECT ... FOR UPDATE NOWAIT 的时候,锁定级别设置LockMode.UPGRADE_NOWAIT

当Hibernate在“可重复读”或者是“序列化”数据库隔离级别下读取数据的时候,锁定模式自动设置为LockMode.READ。这种模式也可以通过用户显式指定进行设置。

LockMode.NONE 代表无需锁定。在Transaction结束时,所有的对象都切换到该模式上来。与session相关联的对象通过调用update() 或者saveOrUpdate()脱离该模式。

"显式的用户指定"可以通过以下几种方式之一来表示:

调用Session.load()的时候指定锁定模式(LockMode)。

调用Session.lock()。

调用Query.setLockMode()。

如果在UPGRADE或者UPGRADE_NOWAIT锁定模式下调用Session.load(),并且要读取的对象尚未被session载入过,那么对象通过SELECT ... FOR UPDATE这样的SQL语句被载入。如果为一个对象调用load()方法时,该对象已经在另一个较少限制的锁定模式下被载入了,那么Hibernate就对该对象调用lock() 方法。

如果指定的锁定模式是READ, UPGRADE 或UPGRADE_NOWAIT,那么Session.l ock()就执行版本号检查。(在UPGRADE 或者UPGRADE_NOWAIT 锁定模式下,执行SELECT ... FOR UPDATE这样的SQL语句。)

如果数据库不支持用户设置的锁定模式,Hibernate将使用适当的替代模式(而不是扔出异常)。这一点可以确保应用程序的可移植性。

用Hibernate 和Spring 开发事务持久层

https://www.doczj.com/doc/145638883.html, 2008年09月05日社区交流

关键字:引擎设计O/R MAPPING VisAD对象结构模式UDDI4J MVC模式

当您自以为已经了解了所有开发工具时,肯定又会冒出一个新的工具。在本文中,developerWorks 的固定撰稿人Rick Hightower 用一个真实世界的例子向您介绍两个最激动人心的企业新技术。Hibernate 是一个对象关系映射工具,而Spring 是一个AOP 框架和IOC 容器。Rick 介绍了如何结合这两者,为企业应用程序构建一个事务持久层。

如果关心开发人员的最新热点,那么您可能听说过IOC (控制倒置,Inversion of C ontrol)容器和AOP (面向方面编程)。不过,像许多开发人员一样,您可能不清楚在自己的开发工作中如何使用这些技术。在本文中,通过具体介绍使用Hibernate 和Spring 在企业应用程序中构建一个事务持久层,您会认识到这些技术。

Hibernate 是Java 平台上的一种流行的、容易使用的开放源代码对象关系(OR)映射框架。Spring 是一个AOP 框架和IOC 容器。这两种技术一起提供了本文中介绍的开发工作的基础。将使用Hibernate 把一些持久性对象映射到关系数据库中,用Spring 使Hibernate 更容易使用并提供声明性事务支持。由于为示例类编写测试代码时使用了DbUn it,我还附带介绍了一点TDD (测试驱动的开发)的内容。

注意,本文假定读者熟悉Java 平台上的企业开发,包括JDBC、OR 映射内容、J2 EE 设计模式如DAO,以及声明性事务支持,如Enterprise JavaBean (EJB)技术所提供的事务支持。理解这里的讨论不需要成为这些技术的专家,也不需要熟悉AOP、IOC 或者TDD,因为在本文中对这三者都做了介绍。

我将首先介绍两种开发技术,然后分析例子。

Hibernate 简介

Hibernate 是Java 平台上的一种全功能的、开放源代码OR 映射框架。Hibernate 在许多方面类似于EJB CMP CMR (容器管理的持久性/容器管理的关系)和JDO(Jav a Data Objects)。与JDO 不同,Hibernate 完全着眼于关系数据库的OR 映射,并且包括比大多数商业产品更多的功能。大多数EJB CMP CMR 解决方案使用代码生成实现持久性代码,而JDO 使用字节码修饰。与之相反,Hibernate 使用反射和运行时字节码生

成,使它对于最终用户几乎是透明的(以前Hibernate 的实现只使用反射,它有助于调试,当前版本保留了这种选项)。

移植基于Hibernate 的应用程序

如果应用程序必须在多个RDBMS 系统上运行,那么基于Hibernate 的应用程序可以毫不费力地移植到IBM DB2、MySQL、PostgreSQL、Sybase、Oracle、HypersonicS QL 和许多其他数据库。我最近甚至将一个应用程序从MySQL 移植到Hibernate 没有很好支持的Firebird,而这种移植是很容易的。

Hibernate 可以模拟继承(有几种方式)、关联(一对一或者一对多、containment 和aggregation)和composition。我将在本文中讨论每种关系类型的几个例子。

Hibernate 提供了一种称为Hibernate Query Language (HQL)的查询语言,它类似于JDO 的JDOQL 和EJB 的EJB QL,尽管它更接近于前者。但是Hibernate 没有就此止步:它还可以进行直接的SQL 查询和/或使用object criteria 很容易地在运行时构成查询条件。在本文的例子中我将只使用HQL。

与EJB CMP CMR 不同,Hibernate 像JDO 一样可以在J2EE 容器内部或者外部工作,这可以让那些进行TDD 和敏捷开发的人受益。

Spring 简介

AOP 专家Nicholas Lesiecki 第一次向我解释AOP 时,他说的我一个词也没理解,我觉得就像第一次考虑使用IOC 容器的可能性时一样。每一种技术的概念基础本身就需要很好地消化,每一种技术所使用的各种各样的缩写让事情更糟了——特别是其中许多术语与我们已经使用的根本不一样了。

像许多技术一样,理解这两种技术的实际使用比学习理论更容易。经过自己对AOP

和IOC 容器实现(即XWork、PicoContainer 和Spring)的分析,我发现这些技术可以帮助我获得功能,而不会在多框架中添加基于代码的依赖性。它们都将成为我后面开发项目的一部分。

简单地说,AOP 让开发人员可以创建非行为性的关注点,称为横切关注点,并将它们插入到应用程序代码中。使用AOP 后,公共服务(比如日志、持久性、事务等)就可以分解成方面并应用到域对象上,同时不会增加域对象的对象模型的复杂性。

IOC 允许创建一个可以构造对象的应用环境,然后向这些对象传递它们的协作对象。正如单词倒置所表明的,IOC 就像反过来的JNDI。没有使用一堆抽象工厂、服务定位器、单元素(singleton)和直接构造(straight construction),每一个对象都是用其协作对象构造的。因此是由容器管理协作对象(collaborator)。

Spring 既是一个AOP 框架、也是一个IOC 容器。我记得Grady Booch 说过,对象最好的地方是可以替换它们,而Spring 最好的地方是它有助于您替换它们。有了Spri ng,只要用JavaBean 属性和配置文件加入依赖性(协作对象)。然后可以很容易地在需要时替换具有类似接口的协作对象。

Spring 为IOC 容器和AOP 提供了很好的入口(on-ramp)。因此,不需要熟悉A OP 就可以理解本文中的例子。所需要知道的就是将要用AOP 为示例应用程序声明式地添加事务支持,与使用EJB 技术时的方式基本相同。

具体到业务

在本文的其余部分,所有的讨论都将基于一个实际的例子。起点是一个企业应用程序,要为它实现一个事务持久层。持久层是一个对象关系数据库,它包括像User、User Grou p、Roles 和ContactInfo 这些熟悉的抽象。

在深入到数据库的要素——查询和事务管理——之前,需要建立它的基础:对象关系映射。我将用Hibernate 设置它,并只使用一点Spring。

用Hibernate 进行OR 映射

Hibernate 使用XML (*.hbm.xml) 文件将Java 类映射到表,将JavaBean 属性映射到数据库表。幸运的是,有一组XDoclet 标签支持Hibernate 开发,这使得创建所需要的*.hbm.xml 文件更容易了。清单1 中的代码将一个Java 类映射到数据库表。

实验15 事务与并发控制

实验十五事务与并发控制 【实验目的与要求】 1.掌握数据库事务的概念 2.熟悉数据库的四个特性 3.熟练掌握数据库事务的实现方法 【实验内容与步骤】 15.1.SQL Server数据库事务基础知识 1.事务的概念( Transaction ) 所谓事务是用户定义的一个数据库操作序列,这些操作要么都做,要么都不做,是一个不可分割的工作单位。 关系数据库中,事务可以是一条SQL语句、一组SQL语句。 在SQL语言中,定义事务的语句有三条: Begin Transaction 开始 Commit 结束 Rollback 回滚 2.事务开始:BEGIN TRANSACTION 标记一个显式本地事务的起始点。BEGIN TRANSACTION将@@TRANCOUNT 加1。 语法结构: BEGIN TRAN [ SACTION ] [ transaction_name | @tran_name_variable [ WITH MARK [ 'description' ] ] ] 参数说明: transaction_name:是给事务分配的名称。transaction_name 必须遵循标识符规则,但是不允许标识符多于32 个字符。仅在嵌套的https://www.doczj.com/doc/145638883.html,MIT 或BEGIN...ROLLBACK 语句的最外语句对上使用事务名。 @tran_name_variable:是用户定义的、含有有效事务名称的变量的名称。必须用char、varchar、nchar 或nvarchar 数据类型声明该变量。 WITH MARK ['description']:指定在日志中标记事务。Description 是描述该标记的字符串。 如果使用了WITH MARK,则必须指定事务名。WITH MARK 允许将事务日志还原到命名标记。 4.事务提交:COMMIT TRANSACTION 标志一个成功的隐性事务或用户定义事务的结束。如果@@TRANCOUNT 为1,COMMIT TRANSACTION 使得自从事务开始以来所执行的所有数据修改成为数据库的永

并发控制课后答案-简述并发控制

第八章并发控制 习题解答和解析 1. 1.在数据库中为什么要并发控制? 答:数据库是共享资源,通常有许多个事务同时在运行。当多个事务并发地存取数据库时就会产生同时读取和/或修改同一数据的情况。若对并发操作不加控制就可能会存取和存储不正确的数据,破坏数据库的一致性。所以数据库管理系统必须提供并发控制机制。 2. 2.并发操作可能会产生哪几类数据不一致?用什么方法能避免各种不一致的情况? 答:并发操作带来的数据不一致性包括三类:丢失修改、不可重复读和读"脏"数据。 (1)丢失修改(Lost Update)两个事务T1和T2读入同一数据并修改,T2提交的结果破坏了(覆盖了)T1提交的结果,导致T1的修改被丢失。 (2)不可重复读(Non -Repeatable Read)不可重复读是指事务T1读取数据后,事务T2 执行更新操作,使T1无法再现前一次读取结果。不可重复读包括三种情况:详见《概论》8.1(P266)。 (3)读"脏"数据(Dirty Read)读"脏"数据是指事务T1修改某一数据,并将其写回磁盘,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已修改过的数据恢复原值,T2读到的数据就与数据库中的数据不一致,则T2读到的数据就为"脏"数据,即不正确的数据。 避免不一致性的方法和技术就是并发控制。最常用的技术是封锁技术。也可以用其他技术,例如在分布式数据库系统中可以采用时间戳方法来进行并发控制。 3. 3.什么是封锁? 答:封锁就是事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其他的事务不能更新此数据对象。封锁是实现并发控制的一个非常重要的技术。 4. 4.基本的封锁类型有几种?试述它们的含义。 答:基本的封锁类型有两种:排它锁(Exclusive Locks, 简称 X 锁 )和共享锁(Share Locks,简称 S 锁)。 排它锁又称为写锁。若事务T对数据对象A加上X锁,则只允许T读取和修改A,其他任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。这就保证了其他事务在T释放A上的锁之前不能再读取和修改A。 共享锁又称为读锁。若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。 5.如何用封锁机制保证数据的一致性 ? 答:DBMS在对数据进行读、写操作之前首先对该数据执行封锁操作,例如下图中事务T1在对A进行修改之前先对A执行XLock(A),即对A加X锁。这样,当T2请求对A加X锁时就被拒绝,T2只能等待T1释放A上的锁后才能获得对A的X锁,这时它读到的A是T1更新后 的值,再按此新的A值进行运算。这样就不会丢失 T1的更新。

数据库实验报告:事务与并发控制

1.实验七:事务与并发控制 1.1.实验目的 1.掌握事务机制,学会创建事务。 2.理解事务并发操作所可能导致的数据不一致性问题,用实验展现四种数据不一致性 问题:丢失修改、读脏数据、不可重复读以及幻读现象。 3.理解锁机制,学会采用锁与事务隔离级别解决数据不一致的问题。 4.了解数据库的事务日志。 1.2.实验内容 假设学校允许学生将银行卡和校园卡进行绑定,在student数据库中有如下的基本表,其中校园卡编号cardid即为学生的学号: icbc_card(studcardid,icbcid,balance) //校园卡ID,工行卡ID,银行卡余额campus_card(studcardid,balance) //校园卡ID,校园卡余额 数据创建的代码: use student createtable campus_card ( studcardid Char(8), balance Decimal(10,2)) createtable icbc_card ( studcardid Char(8), icbcid Char(10), balance Decimal(10,2) )

insertinto campus_card values('20150031', 30) insertinto campus_card values('20150032', 50) insertinto campus_card values('20150033', 70) insertinto icbc_card values('20150031','2015003101', 1000) insertinto icbc_card values('20150032','2015003201', 1000) insertinto icbc_card values('20150033','2015003301', 1000) 针对以上数据库按照要求完成下列实验: 1.编写一个事务处理(begin tran)实现如下的操作:某学号为20150032的学生要从银 行卡中转账200元到校园卡中,若中间出现故障则进行rollback。(15分)settransactionisolationlevel repeatableread

事务调度与并发控制

四级数据库第八章-事务调度与并发控制8.1 并发控制概述 在第七章中己经讲到,事务是并发控制的基本单位,保证事务ACID特性是事务处理的重要任务,而事务ACID特性可能遭到破坏的原因之一是多个事务对数据库的并发操作造成的。为了保证事务的隔离性更一般,为了保证数据库的一致性,DBMS需要对并发操作进行正确调度。这些就是数据库管理系统中并发控制机制的责任。 下面先来看一个例子,说明并发操作带来的数据的不一致性问题。 考虑飞机订票系统中的一个活动序列: ①甲售票点(甲事务)读出某航班的机票余额A,设A=16; ②乙售票点(乙事务)读出同一航班的机票余额A,也为16; ③甲售票点卖出一张机票,修改余额A A-l,所以A为15,把A写回数据库; ④乙售票点也卖出一张机票,修改余额A A-l,所以A为15,把A写回数据库。结果明明卖出两张机票,数据库中机票余额只减少1。 这种情况称为数据库的不一致性。这种不一致性是由并发操作引起的。在并发操作情况下,对甲、乙两个事务的操作序列的调度是随机的。若按上面的调度序列执行,甲事务的修改就被丢失。这是由于第④步中乙事务修改A并写回后覆盖了甲事务的修改。 仔细分析并发操作带来的数据不一致性包括三类:丢失修改、不可重复读和读“脏”数据,如图8.1所示。 1.丢失修改(Lost Update) 两个事务T1和T2。读入同一数据并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失,如图8.1(a)所示。上面飞机订票例子就属此类。

图8.1 2.不可重复读(Non-Repeatable Read) 不可重复读是指事务T1读取数据后,重复T2执行更新操作,使T1无法再现前一次读 取结果。具体地讲,不可重复读包括三种情况: (1)事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时,得到与前一次不同的值。例如在图8.1(b)中,T1读取B=100进行运算,T2读取同一数据B对其进行修改后将B=200写回数据库。T1为了对读取值校对重读B,B己为200,与第1次读取值不一致。 (2)事务T1按一定条件从数据库中读取了某些数据记录后,事务T2删除了其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神秘地消失了。 (3)事务T1按一定条件从数据库中读取某些数据记录后,事务T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。 后两种不可重复读有时也称为幻影(Phantom Row)现象。

事务并发控制中的两段锁和可串行化冲突图的对比

文章编号:1000-2375(2005)01-0019-05 事务并发控制中的两段锁和 可串行化冲突图的对比 金 蓉,李跃新 (湖北大学数学与计算机科学学院,湖北武汉430062) 摘 要:数据库中并发操作一般分为数据级和事务级两种,由于资源的竞争可能引起数据级的冲突和事 务级的冲突,因此需要对并发执行的事务转化为某个可串行化调度,从而确保数据库的一致性.目前并发控制的方法有很多,从锁和非锁机制两个方面分析了两段锁和可串行化冲突图两种并发控制的规则和数据结构及分类,并从事务的冲突可串行化方面和结构上分析了各自的性能和优缺点. 关键词:锁;两段锁协议;可串行化冲突图 中图分类号:TP311 文献标志码:A 收稿日期:2004-03-25 作者简介:金 蓉(1979-  ),女,硕士生1 引 言 数据库中的并发操作一般分为数据级和事务级两种,一方面在微观数据级上有数据对象的读(Read )操作和写(Write )操作,另一方面在宏观事务级上有事务的操作原语:终止(Abort ),开始(Begin ),提交(C ommit ),结束(End ),实质上事务中包含着对一系列数据对象的操作,因为一个事务系统主要由3个部分构成:数据项集、对数据项集的操作和控制事务存取数据的管理器(我们称为事务管理器T M ).并发控制的作用是正确协调同一时间里多个事务对数据库的并发操作,解决资源竞争问题以保证数据库的一致性和完整性. 并发控制是通过调度来确保事务的并发执行的效果等同于没有并发执行时的执行效果,也就是使事务的并发执行调度等价于事务的某个可串行化调度,从而确保数据库的一致性.可串行化简单的说就是一个并发操作等效于某个串行执行的效果,也即有相同的输出结果,与串行操作对数据库有同样的效果. 冲突有数据级的冲突和事务级的冲突,数据间的冲突体现在数据库中同时对相同的数据对象操作,事务间的冲突是由事务的数据相关性及在共享数据对象上的交互作用而引起的,通常用事务的“冲突关系”来表示. 定义1 数据对象d 上的两个操作p 、q 是“冲突”的,记为CT (d ,p ,q ),当且仅当S (S (s ,p ),q )≠S (S (s ,q ),p )∨R (s ,p )≠R (S (s ,q ),p )∨R (s ,q )≠R (S (s ,p ),q ).其中,S (s ,p )和R (s ,p )分别表示操作p 对d 的给定状态s 所产生的结果状态和结果输出(返回). 由定义可知,两个或多个数据操作产生冲突的条件是1)它们属于不同的事务;2)都访问数据库中相同的数据对象;3)并且至少有一个是写操作否则就不会产生冲突. 定义2 两个事务t 1、t 2是“冲突”的,记为t 1CR t 2,是指它们包含了(至少)一对冲突操作.即对于任何t 1≠t 2,t 1CR t 2,当且仅当?d 、?p ,q (p (d )∈t 1∧q (d )∈t 2∧CT (d ,p ,q ). 事务间的冲突归根结底集中在数据操作的冲突上,因此解决冲突最初的方法是对数据对象采用锁机制,而锁可以分为读锁和写锁,当数据对象加了读锁后可以再加读锁但不能加写锁,因此读锁是共享的,当数据对象加了写锁后就不能加其他任何锁,因此写锁是排它的,显然读锁较写锁的并发度高. 第27卷第1期2005年3月湖北大学学报(自然科学版)Journal of Hubei University (Natural Science ) V ol.27 N o.1 Mar.,2005

数据库并发控制

数据库是一个共享资源,可以提供多个用户使用。这些用户程序可以一个一个地串行执行,每个时刻只有一个用户程序运行,执行对数据库的存取,其他用户程序必须等到这个用户程序结束以后方能对数据库存取。但是如果一个用户程序涉及大量数据的输入/输出交换,则数据库系统的大部分时间处于闲置状态。因此,为了充分利用数据库资源,发挥数据库共享资源的特点,应该允许多个用户并行地存取数据库。但这样就会产生多个用户程序并发存取同一数据的情况,若对并发操作不加控制就可能会存取和存储不正确的数据,破坏数据库的一致性,所以数据库管理系统必须提供并发控制机制。并发控制机制的好坏是衡量一个数据库管理系统性能的重要标志之一。 DM用封锁机制来解决并发问题。它可以保证任何时候都可以有多个正在运行的用户程序,但是所有用户程序都在彼此完全隔离的环境中运行。 一、并发控制的预备知识 (一) 并发控制概述 并发控制是以事务(transaction)为单位进行的。 1. 并发控制的单位――事务 事务是数据库的逻辑工作单位,它是用户定义的一组操作序列。一个事务可以是一组SQL 语句、一条SQL语句或整个程序。 事务的开始和结束都可以由用户显示的控制,如果用户没有显式地定义事务,则由数据库系统按缺省规定自动划分事务。 事务应该具有4种属性:原子性、一致性、隔离性和持久性。 (1)原子性 事务的原子性保证事务包含的一组更新操作是原子不可分的,也就是说这些操作是一个整体,对数据库而言全做或者全不做,不能部分的完成。这一性质即使在系统崩溃之后仍能得到保证,在系统崩溃之后将进行数据库恢复,用来恢复和撤销系统崩溃处于活动状态的事务对数据库的影响,从而保证事务的原子性。系统对磁盘上的任何实际数据的修改之前都会将修改操作信息本身的信息记录到磁盘上。当发生崩溃时,系统能根据这些操作记录当时该事

基于封锁的事务并发控制概述

基于封锁的事务并发控制概述 发表时间:2010-05-14T10:46:24.013Z 来源:《计算机光盘软件与应用》2010年第4期供稿作者:卢成浪,徐湖鹏 [导读] 叙述了关系型数据库管理系统中的事务管理和基于锁的事务并发控制方法。 卢成浪,徐湖鹏 (温州大学瓯江学院,温州 325035) 摘要:叙述了关系型数据库管理系统中的事务管理和基于锁的事务并发控制方法。详细介绍了事务的串行化调度方法中的锁技术和锁 协议,并深入讨论了锁的管理、死锁处理、幻影问题和其它加锁过程中可能出现的一些问题。 关键词:数据库管理系统;事务;并发控制;封锁 中图分类号:TP311.131 文献标识码:A 文章编号:1007-9599 (2010) 04-0000-03 Lock-Based Transaction Concurrency Control Overview Lu Chenglang,Xu Hupeng (Wenzhou University,Oujiang College,Wenzhou 325035,China) Abstract:An overview on the management of lock- based concurrency control of transactions is presented in this paper.The locking protocols and locking techniques of the locking are discussed in depth. Keywords:Database management systems;Transaction;Concurrency control;Lock 一、引言 事务是用户定义的一组数据库操作序列。事务的执行结果将使数据库从一个一致性状态转变到另一个一致性状态。为了提高吞吐量, 系统中常常是多个事务并发执行。这会产生多个事务同时存取同一数据的情况,从而破坏数据库的一致性。所以数据库管理系统 (Database Management System,DBMS)必须提供并发控制机制,使得并发的事务在冲突的时候被串行化执行。这种调度称为可串行化 调度。其中基于封锁的并发控制机制是一种被广泛应用于商业DBMS中的并发控制机制。 二、事务的特性和并发的数据不一致性 事务具有ACID特性:原子性(Atomicity),一致性(Consistency),隔离性(Isolation)和持续性(Durability)。原子性指:事 务包含的所有操作要么全部被执行,要么都不被执行;一致性指:事务的执行结果必须使数据库从一个一致性状态变到另一个一致性状 态;隔离性指:在事务被提交以前,其操作结果对于其他事务不可见;持续性指:一旦事务成功提交,其对数据库中数据的改变是永久 的。事务是并发控制的基本单位,保证事务的ACID特性是事务处理的重要任务。然而,事务的并发执行可能会破坏事务的ACID特性,而导 致数据的不一致性: (一)Write-Write冲突,丢失更新。它是由于事务之间的写冲突造成的。两个事务T1和T2同时读入同一数据并修改,T2的提交破坏 了T1的提交结果,导致T1的修改丢失。 (二)Read-Write冲突,也称不一致读。不一致读是指事务T1读取数据后,事务T2执行更新操作,使T1无法再现前一次读取结果。它 包括三种情况:1.T1读取某一数据后, T2对其做了修改,当T1再次读取该数据时,得到与前一次不同的值;2.T1按一定的条件从数据库 中读取了某些记录后,T2删除其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神秘的消失了;3.T1按一定的条件从数据库 中读取了某些记录后,T2插入了一些记录,当T1再次按相同条件读取数据时,发现多了一些记录。后两种情况也称幻影现象。 (三)Write-Read冲突,也称读脏数据。读脏数据指事务T1修改某数据,事务T2读取同一数据后,T1由于某种原因被撤销,这时T1已 修改过的数据恢复原值,T2读到的数据就与数据中的数据不一致,则称T2读到的数据就为脏数据。 三、基于封锁的事务并发控制机制 (一)锁的类型 封锁是实现并发控制的一个非常重要的技术。所谓封锁就是事务T在对某个数据对象例如表,记录等操作之前,先向系统发出请求,对 其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它之前,其他事务不能更新该数据对象。下面介绍DBMS涉及的锁: 1.互斥锁(Exclusive Lock):用于写操作,又称写锁或者排他锁,记做X锁。若事务T对数据对象A加上X锁,则只允许T读写A,其他 事务都不能对A加任何锁,直到T释放A上的锁。 2.共享锁(Shared Lock):用于读操作,又称读锁,记做S锁。若事务T对数据对象A加上S锁,则T可读A但不能写A,其他事务只能对 A加S锁,而不能加X锁,直到T释放锁。 3.更新锁(Update Lock):用于更新操作。等价于先加共享锁,在真正执行更新操作时,将共享锁升级为互斥锁。大部分DMBS 都 不使用这种锁。 4.增量锁(Increment Lock):用于增量操作,如果一个对象被上了增量锁,除增量操作以外任何读写操作都是被禁止的。即增量锁 之间不排斥。因同时对某一对象的数值进行加一或者减一操作时,其结果与操作先后顺序是无关的,可以交换。这种锁使用并不广泛。 5.意向锁(Intention Lock):它是因为引入多粒度对象而产生的,又可 细分为:意向共享锁,意向排他锁和共享意向排他锁。 在DBMS 中被广泛使用的是共享锁,互斥锁和意向锁。为了保证写操作的互 斥性,不同事务对同一数据对象加锁时需要进行冲突检测。检测可以借助锁的相 容矩阵来判断,如图1(a)所示。从中可以发现5种锁的强度偏序关系,如图1 (b)所示。 (二)加锁管理和锁转换 DBMS中处理事务加锁事宜的部分被称为锁管理器。锁管理器维护着一个锁 表,这是一个以数据对象标志为码的哈希表。DBMS也在事务表中维护着每个事务的描述信息项,该记录中包含一个指向事务拥有的锁列表 的指针。在请求锁之前要检查这个列表,以确定不会对同一个锁请求两次。 加锁表中的每一项针对某个数据对象(可以是一页,一条记录等等),它包括下面的信息:拥有数据对象锁的事务数目,锁的属性 (共享锁、互斥锁等)和一个指向加锁请求队列的指针。

Informix的事务、并发控制、锁机制、隔离级别

Informix的事务、并发控制、锁机制、隔离级别 1、事务 事务是指作为单个逻辑工作单元执行的一系列操作。事务处理可以确保除非事务性单元内的所有操作都成功完成,否则不会永久更新面向数据的资源。通过将一组相关操作组合为一个要么全部成功要么全部失败的单元,可以简化错误恢复并使应用程序更加可靠。数据库服务器保证在事务范围内执行的操作完整且正确地提交至磁盘,否则数据库会复原至事务启动之前的状态。 一个逻辑工作单元要成为事务,必须满足所谓的ACID属性。ACID的具体含义如下: 1)A(Atomicity):操作序列要么完整的执行,否则什么都不做; 2)C(Consistency):一致性,事务执行后,保证数据库从一个一致性状态到另外一个一致性状态; 3)I(Isolation):隔离,一个事务的中间状态对其他事务不可见,即每个用户都感觉他们在单独使用数据库。隔离级别用来定义多大程度的隔离多个不同的事务; 4)D(Durability):持久性,事务的有效性,不会应用硬件或软件的失败而丢失。 2、并发控制 1)相关概念 i)隔离(+一致性) => 并发控制; ii)多个事务可以访问或修改相同的资源; iii)只要多个进程共享资源,就需要对访问进程进行排队控制; iv)在进行并发控制时,数据库内部将生成多个并发事务访问资源的操作序列表,并且每一个事务内部的各个操作都需要序列化。 2)串行调度存在的问题 在串行调度中,采用操作序列,一个事务完成了再完成另外一个,即使两个事务T1、T2更新的是数据库中不同的对象。此种方式从并发和性能角度考虑,都不能很好的利用计算机资源。 为了改善性能,需要采用非串行调度,即允许事务并发执行,即一个事务内的操作可以在其他事务提交前开始执行。 3)并发调度的常见问题 i)脏读:事务T2读取到了事务T1没有提交的结果 例如如下的操作序列会导致脏读: 事务T1读取记录,然后更新记录; 事务T2读取了更新后的记录;

事务管理与并发控制学习笔记数据库的三种日志详解

6、事务管理与并发控制学习笔记——数据库的三种日志详解 6.1、概念:acid性质、共享锁、排它锁 6.1.1 事务的ACID特性 A:表示事务的原子性(Atomicity),即事务完全执行或完全不执行 –事务中包含的所有操作要么全做,要么全不做原子性由恢复机制实现 C:表示一致性(Consistency),所有数据库都有一致性约束,或关于数据之间联系的预期状态 –事务的隔离执行必须保证数据库的一致性。事务开始前,数据库处于一致性的状态;事务结束后,数据库必须仍处于一致性状态。 –数据库的一致性状态由用户来负责,由并发控制机制实现。如银行转帐,转帐前后两个帐户金额之和应保持不变 I:表示隔离(Isolation),即表面看起来,每个事务都是在没有其它事务同时执行的情况下执行的 –系统必须保证事务不受其它并发执行事务的影响。对任何一对事务T1,T2,在T1看来,T2要么在T1开始之前已经结束,要么在T1完成之后再开始执行 –隔离性通过并发控制机制实现 D:表示持久性(Durability),即一旦事务完成了,事务对数据库的影响就不会丢失 –一个事务一旦提交之后,它对数据库的影响必须是永久的 –系统发生故障不能改变事务的持久性。持久性通过恢复机制实现这里大家要知道,事务是我们对数据库操作的执行单位。我们要注意事务的整体性,即原子性,事务是绝对不能做一半的,否则很难保证数据库的一致性。而对于数据库来说,必须要保证一致性,因为一个数据库如果没有一致性,那么这个数据库是失败的!隔离性是数据库并发处理性能的体现,当然如果数据库没有很好的并发性那么你还是改用Excel吧,呵呵,开个玩笑而已。 6.2、三种日志例题 系统是很可能崩溃的,但是崩溃后我们不能坐以待毙,我们要保证事务的原子性,进而保证数据库的一致性和持久性。那么我们就应该考虑怎样建立一个合理的运行机制,让系统崩溃后能够通过一系列办法将那些不能确定是否真正写盘的事务回滚或者重做,哪怕数据库回到之前好久的状态。还好,高手们很有正事,他们研究出来一些针对故障的恢复机制!也就是我们下面要说到的日志系统!6.2.1 日志与故障恢复 数据库系统(例如Oracle)一般都有一个日志系统,它由日志管理服务和日志文件组成,这个如果大家有兴趣复习一下Oracle的体系架构,这里就不多说了。这个日志文件中存储的是一些文本行,当我们对一个数据库中的数据进行操作时,数据库系统首先按照一定的规则将你的操作命令和一些附加参数记录到这些日志文件中,(注意记录的只是命令语句、参数和一些标记等等)。然后再对数据库中的数据进行操作,最后完成所有操作后,再写一些标志到日志文件中。 根据对日志文件的管理规则的不同(对应的恢复机制也不同。),我们现在常用的是Undo、Redo还有Undo/Redo三种日志模式。 注意:在故障恢复里我们只对数据库的写操作感兴趣,因为读操作根本不会

基于封锁的事务并发控制概述

基于封锁的事务并发控制概述 摘要:叙述了关系型数据库管理系统中的事务管理和基于锁的事务并发控制方法。详细介绍了事务的串行化调度方法中的锁技术和锁协议,并深入讨论了锁的 管理、死锁处理、幻影问题和其它加锁过程中可能出现的一些问题。 关键词:数据库管理系统;事务;并发控制;封锁 中图分类号:TP311.131 文献标识码:A 文章编号:1007-9599 (2010) 04-0000-03 Lock-Based Transaction Concurrency Control Overview Lu Chenglang,Xu Hupeng (Wenzhou University,Oujiang College,Wenzhou 325035,China) Abstract:An overview on the management of lock- based concurrency control of transactions is presented in this paper.The locking protocols and locki ng techniques of the transaction concurrency control are investigated in detail, and the approach t o avoiding phantom problem as well as the way for handling dead-locking are discussed in depth. Keywords:Database management systems;Transaction;Concurrency control;Lock 一、引言 事务是用户定义的一组数据库操作序列。事务的执行结果将使数据库从一个一致性状 态转变到另一个一致性状态。为了提高吞吐量,系统中常常是多个事务并发执行。这会产生 多个事务同时存取同一数据的情况,从而破坏数据库的一致性。所以数据库管理系统(Database Management System,DBMS)必须提供并发控制机制,使得并发的事务在冲突的 时候被串行化执行。这种调度称为可串行化调度。其中基于封锁的并发控制机制是一种被广 泛应用于商业DBMS中的并发控制机制。 二、事务的特性和并发的数据不一致性 事务具有ACID特性:原子性(Atomicity),一致性(Consistency),隔离性(Isolation)和持续性(Durability)。原子性指:事务包含的所有操作要么全部被执行,要么都不被执行;一致性指:事务的执行结果必须使数据库从一个一致性状态变到另一个一致性状态;隔离性指:在事务被提交以前,其操作结果对于其他事务不可见;持续性指:一旦事务成功提交, 其对数据库中数据的改变是永久的。事务是并发控制的基本单位,保证事务的ACID特性是事务处理的重要任务。然而,事务的并发执行可能会破坏事务的ACID特性,而导致数据的不一致性: (一)Write-Write冲突,丢失更新。它是由于事务之间的写冲突造成的。两个事务 T1和T2同时读入同一数据并修改,T2的提交破坏了T1的提交结果,导致T1的修改丢失。 (二)Read-Write冲突,也称不一致读。不一致读是指事务T1读取数据后,事务T2 执行更新操作,使T1无法再现前一次读取结果。它包括三种情况:1.T1读取某一数据 后, T2对其做了修改,当T1再次读取该数据时,得到与前一次不同的值;2.T1按一定的条 件从数据库中读取了某些记录后,T2删除其中部分记录,当T1再次按相同条件读取数据时,发现某些记录神秘的消失了;3.T1按一定的条件从数据库中读取了某些记录后,T2插入了一 些记录,当T1再次按相同条件读取数据时,发现多了一些记录。后两种情况也称幻影现象。 (三)Write-Read冲突,也称读脏数据。读脏数据指事务T1修改某数据,事务T2读 取同一数据后,T1由于某种原因被撤销,这时T1已修改过的数据恢复原值,T2读到的数据 就与数据中的数据不一致,则称T2读到的数据就为脏数据。 三、基于封锁的事务并发控制机制

数据库实验报告记录:事务与并发控制

数据库实验报告记录:事务与并发控制

————————————————————————————————作者:————————————————————————————————日期:

《数据库原理》实验报告 题目:实验七 事务与并发控制 学号姓名班级日期2013302478 纪昌宇10011301 2015.11.14 1.实验七:事务与并发控制 1.1.实验目的 1.掌握事务机制,学会创建事务。 2.理解事务并发操作所可能导致的数据不一致性问题,用实验展现四种数据不一致性 问题:丢失修改、读脏数据、不可重复读以及幻读现象。 3.理解锁机制,学会采用锁与事务隔离级别解决数据不一致的问题。 4.了解数据库的事务日志。 1.2.实验内容 假设学校允许学生将银行卡和校园卡进行绑定,在student数据库中有如下的基本表,其中校园卡编号cardid即为学生的学号: icbc_card(studcardid,icbcid,balance) //校园卡ID,工行卡ID,银行卡余额 campus_card(studcardid,balance) //校园卡ID,校园卡余额 数据创建的代码: use student create table campus_card (studcardid Char(8) , balance Decimal(10,2)) create table icbc_card ( studcardid Char(8), icbcid Char(10), balance Decimal(10,2) )

insert into campus_card values('20150031', 30) insert into campus_card values('20150032', 50) insert into campus_card values('20150033', 70) insert into icbc_card values('20150031','2015003101', 1000) insert into icbc_card values('20150032','2015003201', 1000) insert into icbc_card values('20150033','2015003301', 1000) 针对以上数据库按照要求完成下列实验: 1.编写一个事务处理(begin tran)实现如下的操作:某学号为20150032的学生要从银 行卡中转账200元到校园卡中,若中间出现故障则进行rollback。(15分) set transaction isolation level repeatable read

第14章事务与MySQL的多用户并发控制

数据库系统原理及MySQL应用教程(第2版) 课后习题参考答案 第14章事务与MySQL的多用户并发控制 1、事务是DB的逻辑工作单位,由用户定义的一组操作序列组成,序列中的操作要么全做要么全不做。 2、InnoDB和BDB存储引擎支持事务。 3、每个事务的处理必须满足ACID原则,即原子性(A):原子性意味着每个事务都必须被认为是一个不可分割的单元。一致性(C):不管事务是完全成功完成还是中途失败,当事务使系统处于一致的状态时存在一致性。隔离性(I):隔离性是指每个事务在它自己的空间发生,和其他发生在系统中的事务隔离,而且事务的结果只有在它完全被执行时才能看到。持久性(D):持久性是指即使系统崩溃,一个提交的事务仍然存在。 4、MySQL中可以使用begin开始事务,使用commint结束事务。 5、每一个事务都有一个所谓的隔离级,它定义了用户彼此之间隔离和交互的程度。 MySQL提供了下面4种隔离级:序列化(serializable)、可重复读(repeatable read)、提交读(read committed)、未提交读(read uncommitted) 。 6、若对并发操作不加控制可能会存取和存储不正确的数据,就会出现数据的不一致问题。 (1)丢失更新(lost update) 问题 (2)脏读(dirty read)问题 (3)不可重复读( unrepeatableread) 问题 (4)幻读(phantom read) 问题 7、MySQL中可以使用begin开始事务,使用commint结束事务,中间可以使用rollback回滚事务。MySQL通过set autocommint 、start transaction 、

Oracle事务处理与并发控制

事物处理与并发控制 授课教师:李斌 目标: ●Oracle中的事务处理是什么 ●怎样控制Oracle中的事务处理 ●Oracle怎样在数据库中实现并发控制,让多个用户同时访问和修改相同的数据表 1 什么是事务 事务就是在数据库上完成的一个操作。要么全部执行并且存储需要的操作,要么全部撤销已经进行的操作,使得数据库恢复到没有改变之前的状态。 2 事务处理控制语句 Oracle中的一个重要的概念就是没有“开始事务处理”的语句。用户不能显式开始一个事务,事务结束时需要向数据库提交(Commit),或者回滚(Rollback)操作。 ●COMMIT ●ROLLBACK ●SA VEPOINT ●ROLLBACK TO SA VEPOINT ●SET TRANSACTION ●SET CONSTRAINTS 2.1 COMMIT处理 当提交时,我们需要处理三个任务: 1、为我们的事务处理生成SCN(系统改变号)。 2、将所有剩余的已经缓冲的重做日志表项写入磁盘,并且将SCN记录到在线重做日志文 件中。由LGWR执行处理。 3、释放我们的会话所锁定的资源。 LGWR会在下列情况之一发生时执行清理工作: ●每隔3秒 ●当SGA中的Redo Log Buffer Cache容量超过1/3的空间,或者包含了1MB或者更 多的已经缓冲数据

●进行任何事务处理提交 2.2 ROLLBACK处理 回滚是一项比较耗费资源的操作。当我们不需要存储所作出的修改时,就回滚我们的操作。回滚可以归结为异常处理范畴。 2.3 SA VEPOINT 和ROLLBACK TO SAVEPOINT SA VEPOINT可以在应用中建立保存点。它可以让用户将单独的大规模事务处理分割成一系列较小的部分。 2.4 SET TRANSACTION SET TRANSACTION必须是你的事务处理的第一条语句,用来设置事务之间的隔离级别。 ●规定事务处理的隔离级别 ●规定为用户事务处理所使用的特定回滚段 ●命名用户事务处理 SET TRANSACTION READ ONLY SET TRANSACTION READ WRITE SET TRANSACTION ISOLA TION LEVEL SERIALIZABLE SET TRANSACTION ISOLA TION LEVEL READ COMMITED 1、READ ONLY 命令SET TRANSACTION READ ONLY将会做两件事情。 首先而且最明显的是:它会确保你无法执行修改数据的DML操作。如果你要执行这样的操作,就会报错。 另外,READ ONLY可以使得我们把数据库视图冻结在某个时间点。 例如:我们需要获得上午10:00使,数据库中某个数据表中的数据,而这张表又与其它很多数据表之间存在复杂的关联关系。数据库的其它用户有可能继续对其它的一些表随时都在进行DML操作。我们如何获得10:00时我们需要的数据? 一种方法是:停止其它用户的所有活动,锁定相关的数据表。 好的方法是:用户可以使用SET TRANSACTION READ ONLY语句,冻结10:00的用户数据库视图。这样你会看到你需要的数据,而且不会影响其它用户的操作。

数据库系统原理与开发-并发控制-事务调度

5.3 并发控制——事务调度

【本节学习目标】 ?了解数据库并发事务控制目的 ?了解并发事务调度控制需要解决的问题?理解并发事务调度原理与策略

一、为什么需要并发控制 并发控制目的 ?支持并发事务处理,使更多用户并行操作,提高系统的并发访问能力。?保证一个事务工作不会对另一个事务工作产生不合理的影响。 当多个事务程序在DBMS系统中同时运行时,可能会出现对一些共享数据同时进行访问操作,如一些事务修改数据,另一些事务读取数据。这些并发的共享数据操作,如果在DBMS中没有一定的约束控制情况下,可能会带来数据不一致性或事务程序死锁问题。因此,在多个事务并发运行时,必须进行并发控制处理。

3 二、并发控制需解决的问题A=16读 读 A=A-1 A=A-1 A=15 A=16A=16 出售1出售1 事务T1事务T2 执行结果分析:剩余机票数A值为15,该数据有错,应为14。1.丢失更新数据 A=15售票点2 机票数量A 售票点1

错误分析: ?T1、T2两个事务并发执行,它们均对数据库共享数据A进行了非锁定资源的读写操作。 ?当事务T1和T2均读入该共享数据A并修改,T2提交的结果破坏了T1提交的结果,导致T1的修改被丢失。 4

5 2.不可重复读取 问题分析: 为什么出现不可重复读取? 事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时,得到与前一次不同的值。不可重复读取是指一个事务对一个共享数据重复多次读取,但前后读取的数据不一致。 假如A的初始数据为100 事务T1首次读取A的值为100 事务T1不知道其它事务修改A值 事务T1第2次读取A的值为200 因此,事务T1前后读取数据A的值不一致。

相关主题
文本预览
相关文档 最新文档