爱问 爱问共享资料 爱问分类
首页 > > > 07_transaction.pdf

07_transaction.pdf

07_transaction.pdf

上传者: 小公子
7次下载 0人收藏 暂无简介 简介 2011-06-21 举报

简介:Hibernate 讲义(孙卫琴)

数据库事务与并发n教学内容n数据库事务的概念n声明事务边界n并发问题n设置事务隔离级别n使用悲观锁解决并发问题n使用乐观锁解决并发问题PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库事务的概念n事务是指一组相互依赖的操作行为,如银行交易、股票交易或网上购物。事务的成功取决于这些相互依赖的操作行为是否都能执行成功,只要有一个操作行为失败,就意味着整个事务失败。例如,Tom到银行办理转账事务,把100元钱转到Jack的账号上,这个事务包含以下操作行为:n(1)从Tom的账户上减去100元。n(2)往Jack的账户上增加100元。n显然,以上两个操作必须作为一个不可分割的工作单元。假如仅仅第一步操作执行成功,使得Tom的账户上扣除了100元,但是第二步操作执行失败,Jack的账户上没有增加100元,那么整个事务失败。n数据库事务是对现实生活中事务的模拟,它由一组在业务逻辑上相互依赖的SQL语句组成。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库事务的生命周期PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cnMySQL数据库系统的客户程序PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn声明事务的边界n事务的开始边界。n事务的正常结束边界(COMMIT):提交事务,永久保存被事务更新后的数据库状态。n事务的异常结束边界(ROLLBACK):撤销事务,使数据库退回到执行事务前的初始状态。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在mysql.exe程序中声明事务n每启动一个mysql.exe程序,就会得到一个单独的数据库连接。每个数据库连接都有个全局变量@@autocommit,表示当前的事务模式,它有两个可选值:n0:表示手工提交模式。n1:默认值,表示自动提交模式。n如果要察看当前的事务模式,可使用如下SQL命令:nmysql>select@@autocommitn如果要把当前的事务模式改为手工提交模式,可使用如下SQL命令:nmysql>setautocommit=0;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在MySQL中创建支持事务的表n在MySQL中,数据库表分为三种类型:INNODB、BDB和MyISAM类型。其中InnoDB和BDB类型的表支持数据库事务,而MyISAM类型的表不支持事务。在MySQL中用createtable语句新建的表默认为MyISAM类型。如果希望创建INNODB类型的表,可以采用以下形式的DDL语句:createtableACCOUNTS(IDbigintnotnull,NAMEvarchar(15),BALANCEdecimal(10,2),primarykey(ID))type=INNODB;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在自动提交模式下运行事务n在自动提交模式下,每个SQL语句都是一个独立的事务。如果在一个mysql.exe程序中执行SQL语句:nmysql>insertintoACCOUNTSvalues(1,'Tom',1000);nMySQL会自动提交这个事务,这意味着向ACCOUNTS表中新插入的记录会永久保存在数据库中。此时在另一个mysql.exe程序中执行SQL语句:nmysql>select*fromACCOUNTS;n这条select语句会查询到ID为1的ACCOUNTS记录。这表明在第一个mysql.exe程序中插入的ACCOUNTS记录被永久保存,这体现了事务的ACID特性中的永久性。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在手工提交模式下运行事务n在手工提交模式下,必须显式指定事务开始边界和结束边界:n事务的开始边界:beginn提交事务:commitn撤销事务:rollbackPDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在手工提交模式下运行事务n(1)启动两个mysql.exe程序,在两个程序中都执行以下命令,以便设定手工提交事务模式:nmysql>setautocommit=0;n(2)在第一个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>insertintoACCOUNTSvalues(2,'Jack',1000);n(3)在第二个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>select*fromACCOUNTS;nmysql>commit;n以上select语句的查询结果中并不包含ID为2的ACCOUNTS记录,这是因为第一个mysql.exe程序还没有提交事务。n(4)在第一个mysql.exe程序中执行以下SQL语句,以便提交事务:nmysql>commit;n(5)在第二个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>select*fromACCOUNTS;nmysql>commit;n此时,select语句的查询结果中会包含ID为2的ACCOUNTS记录,这是因为第一个mysql.exe程序已经提交事务。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过JDBCAPI声明事务边界nConnection类提供了以下用于控制事务的方法:nsetAutoCommit(booleanautoCommit):设置是否自动提交事务ncommit():提交事务nrollback():撤销事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过JDBCAPI声明事务边界try{con=java.sql.DriverManager.getConnection(dbUrl,dbUser,dbPwd);//设置手工提交事务模式con.setAutoCommit(false);stmt=con.createStatement();//数据库更新操作1stmt.executeUpdate("updateACCOUNTSsetBALANCE=900whereID=1");//数据库更新操作2stmt.executeUpdate("updateACCOUNTSsetBALANCE=1000whereID=2");con.commit();//提交事务}catch(Exceptione){try{con.rollback();//操作不成功则撤销事务}catch(Exceptionex){//处理异常……}//处理异常……}finally{…}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过HibernateAPI声明事务边界n声明事务的开始边界:Transactiontx=session.beginTransaction();n提交事务:tx.commit();n撤销事务:tx.rollback();PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn多个事务并发运行时的并发问题n第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖。n脏读:一个事务读到另一事务未提交的更新数据。n虚读:一个事务读到另一事务已提交的新插入的数据。n不可重复读:一个事务读到另一事务已提交的更新数据。n第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn取款事务和支票转账事务n取款事务包含以下步骤:n(1)某银行客户在银行前台请求取款100元,出纳员先查询账户信息,得知存款余额为1000元。n(2)出纳员判断出存款额超过了取款额,就支付给客户100元,并将账户上的存款余额改为900元。n支票转账事务包含以下步骤:n(1)某出纳员处理一转帐支票,该支票向一帐户汇入100元。出纳员先查询账户信息,得知存款余额为900元。n(2)出纳员将存款余额改为1000元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn并发运行的两个事务导致脏读取款事务在T5时刻把存款余额改为900元,支票转账事务在T6时刻查询账户的存款余额为900元,取款事务在T7时刻被撤销,支票转账事务在T8时刻把存款余额改为1000元。由于支票转账事务查询到了取款事务未提交的更新数据,并且在这个查询结果的基础上进行更新操作,如果取款事务最后被撤销,会导致银行客户损失100元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn并发运行的两个事务导致第二类丢失更新取款事务在T5时刻根据在T3时刻的查询结果,把存款余额改为1000-100元,在T6时刻提交事务。支票转账事务在T7时刻根据在T4时刻的查询结果,把存款余额改为1000+100元。由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失100元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库的事务隔离级别PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn隔离级别与并发性能的关系PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn设定隔离级别的原则n隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。n对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为ReadCommitted,它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读、虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在mysql.exe程序中设置隔离级别n每启动一个mysql.exe程序,就会获得一个单独的数据库连接。每个数据库连接都有个全局变量@@tx_isolation,表示当前的事务隔离级别。MySQL默认的隔离级别为RepeatableRead。如果要察看当前的隔离级别,可使用如下SQL命令:nmysql>select@@tx_isolation;n如果要把当前mysql.exe程序的隔离级别改为ReadCommitted,可使用如下SQL命令:nmysql>settransactionisolationlevelreadcommitted;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在Hibernate中设置隔离级别n在Hibernate的配置文件中可以显式的设置隔离级别。每一种隔离级别都对应一个整数:n1:ReadUncommittedn2:ReadCommittedn4:RepeatableReadn8:Serializablen例如,以下代码把hibernate.properties文件中的隔离级别设为ReadCommitted:hibernate.connection.isolation=2对于从数据库连接池中获得的每个连接,Hibernate都会把它改为使用ReadCommitted隔离级别。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn使用悲观锁Accountaccount=(Account)session.get(Account.class,newLong(1),LockMode.UPGRADE);account.setBalance(account.getBalance()-100);Hibernate执行的select语句为:select*fromACCOUNTSwhereID=1forupdate;updateACCOUNTSsetBALANCE=900…PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用悲观锁协调并发运行的取款事务和支票转账事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn使用乐观锁n乐观锁是由应用程序提供的一种机制,这种机制既能保证多个事务并发访问数据,又能防止第二类丢失更新问题。n在应用程序中,可以利用Hibernate提供的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>元素都具有版本控制功能:n<version>元素利用一个递增的整数来跟踪数据库表中记录的版本n<timestamp>元素用时间戳来跟踪数据库表中记录的版本。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(1)在Account类中定义一个代表版本信息的属性:privateintversion;publicintgetVersion(){returnthis.version;}publicvoidsetVersion(intversion){this.version=version;}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(2)在ACCOUNTS表中定义一个代表版本信息的字段:createtableACCOUNTS(IDbigintnotnull,NAMEvarchar(15),BALANCEdecimal(10,2),VERSIONinteger,primarykey(ID))type=INNODB;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(3)在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射:<idname="id"type="long"column="ID"><generatorclass="increment"/></id><versionname="version"column="VERSION"/>……PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n当Hibernate更新一个Account对象时,会根据它的id与version属性到ACCOUNTS表中去定位匹配的记录,假定Account对象的version属性为0,那么在取款事务中Hibernate执行的update语句为:updateACCOUNTSsetNAME=’Tom’,BALANCE=900,VERSION=1whereID=1andVERSION=0;n如果存在匹配的记录,就更新这条记录,并且把VERSION字段的值加1。当支票转账事务接着执行以下update语句时:updateACCOUNTSsetNAME=’Tom’,BALANCE=1100,VERSION=1whereID=1andVERSION=0;n由于ID为1的ACCOUNTS记录的版本已经被取款事务修改,因此找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n在应用程序中应该捕获该异常,这种异常有两种处理方式:n方式一:自动撤销事务,通知用户账户信息已被其他事务修改,需要重新开始事务。n方式二:通知用户账户信息已被其他事务修改,显示最新存款余额信息,由用户决定如何继续事务,用户也可以决定立刻撤销事务。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制try{tx=session.beginTransaction();log.write("transferCheck():开始事务");Thread.sleep(500);Accountaccount=(Account)session.get(Account.class,newLong(1));log.write("transferCheck():查询到存款余额为:balance="+account.getBalance());Thread.sleep(500);account.setBalance(account.getBalance()+100);log.write("transferCheck():汇入100元,把存款余额改为:"+account.getBalance());tx.commit();//当Hibernate执行update语句时,可能会抛出StaleObjectExceptionlog.write("transferCheck():提交事务");Thread.sleep(500);}catch(StaleObjectStateExceptione){if(tx!=null){tx.rollback();}e.printStackTrace();System.out.println("账户信息已被其他事务修改,本事务被撤销,请重新开始支票转账事务");log.write("transferCheck():账户信息已被其他事务修改,本事务被撤销");}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用乐观锁协调并发的取款事务和支票转账事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn实现乐观锁的其他方法n如果应用程序是基于已有的数据库,而数据库表中不包含代表版本或时间戳的字段,Hibernate提供了其他实现乐观锁的办法。把<class>元素的optimistic-lock属性设为“all”:<classname="Account"table="ACCOUNTS"optimistic-lock="all"dynamic-update="true">nHibernate会在update语句的where子句中包含Account对象被加载时的所有属性:updateACCOUNTSsetBALANCE=900whereID=1andNAME='Tom'andBALANCE='1000';PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn

07_transaction.pdf

07_transaction.pdf

上传者: 小公子
7次下载 0人收藏 暂无简介 简介 2011-06-21 举报

简介:Hibernate 讲义(孙卫琴)

数据库事务与并发n教学内容n数据库事务的概念n声明事务边界n并发问题n设置事务隔离级别n使用悲观锁解决并发问题n使用乐观锁解决并发问题PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库事务的概念n事务是指一组相互依赖的操作行为,如银行交易、股票交易或网上购物。事务的成功取决于这些相互依赖的操作行为是否都能执行成功,只要有一个操作行为失败,就意味着整个事务失败。例如,Tom到银行办理转账事务,把100元钱转到Jack的账号上,这个事务包含以下操作行为:n(1)从Tom的账户上减去100元。n(2)往Jack的账户上增加100元。n显然,以上两个操作必须作为一个不可分割的工作单元。假如仅仅第一步操作执行成功,使得Tom的账户上扣除了100元,但是第二步操作执行失败,Jack的账户上没有增加100元,那么整个事务失败。n数据库事务是对现实生活中事务的模拟,它由一组在业务逻辑上相互依赖的SQL语句组成。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库事务的生命周期PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cnMySQL数据库系统的客户程序PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn声明事务的边界n事务的开始边界。n事务的正常结束边界(COMMIT):提交事务,永久保存被事务更新后的数据库状态。n事务的异常结束边界(ROLLBACK):撤销事务,使数据库退回到执行事务前的初始状态。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在mysql.exe程序中声明事务n每启动一个mysql.exe程序,就会得到一个单独的数据库连接。每个数据库连接都有个全局变量@@autocommit,表示当前的事务模式,它有两个可选值:n0:表示手工提交模式。n1:默认值,表示自动提交模式。n如果要察看当前的事务模式,可使用如下SQL命令:nmysql>select@@autocommitn如果要把当前的事务模式改为手工提交模式,可使用如下SQL命令:nmysql>setautocommit=0;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在MySQL中创建支持事务的表n在MySQL中,数据库表分为三种类型:INNODB、BDB和MyISAM类型。其中InnoDB和BDB类型的表支持数据库事务,而MyISAM类型的表不支持事务。在MySQL中用createtable语句新建的表默认为MyISAM类型。如果希望创建INNODB类型的表,可以采用以下形式的DDL语句:createtableACCOUNTS(IDbigintnotnull,NAMEvarchar(15),BALANCEdecimal(10,2),primarykey(ID))type=INNODB;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在自动提交模式下运行事务n在自动提交模式下,每个SQL语句都是一个独立的事务。如果在一个mysql.exe程序中执行SQL语句:nmysql>insertintoACCOUNTSvalues(1,'Tom',1000);nMySQL会自动提交这个事务,这意味着向ACCOUNTS表中新插入的记录会永久保存在数据库中。此时在另一个mysql.exe程序中执行SQL语句:nmysql>select*fromACCOUNTS;n这条select语句会查询到ID为1的ACCOUNTS记录。这表明在第一个mysql.exe程序中插入的ACCOUNTS记录被永久保存,这体现了事务的ACID特性中的永久性。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在手工提交模式下运行事务n在手工提交模式下,必须显式指定事务开始边界和结束边界:n事务的开始边界:beginn提交事务:commitn撤销事务:rollbackPDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在手工提交模式下运行事务n(1)启动两个mysql.exe程序,在两个程序中都执行以下命令,以便设定手工提交事务模式:nmysql>setautocommit=0;n(2)在第一个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>insertintoACCOUNTSvalues(2,'Jack',1000);n(3)在第二个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>select*fromACCOUNTS;nmysql>commit;n以上select语句的查询结果中并不包含ID为2的ACCOUNTS记录,这是因为第一个mysql.exe程序还没有提交事务。n(4)在第一个mysql.exe程序中执行以下SQL语句,以便提交事务:nmysql>commit;n(5)在第二个mysql.exe程序中执行SQL语句:nmysql>begin;nmysql>select*fromACCOUNTS;nmysql>commit;n此时,select语句的查询结果中会包含ID为2的ACCOUNTS记录,这是因为第一个mysql.exe程序已经提交事务。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过JDBCAPI声明事务边界nConnection类提供了以下用于控制事务的方法:nsetAutoCommit(booleanautoCommit):设置是否自动提交事务ncommit():提交事务nrollback():撤销事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过JDBCAPI声明事务边界try{con=java.sql.DriverManager.getConnection(dbUrl,dbUser,dbPwd);//设置手工提交事务模式con.setAutoCommit(false);stmt=con.createStatement();//数据库更新操作1stmt.executeUpdate("updateACCOUNTSsetBALANCE=900whereID=1");//数据库更新操作2stmt.executeUpdate("updateACCOUNTSsetBALANCE=1000whereID=2");con.commit();//提交事务}catch(Exceptione){try{con.rollback();//操作不成功则撤销事务}catch(Exceptionex){//处理异常……}//处理异常……}finally{…}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn通过HibernateAPI声明事务边界n声明事务的开始边界:Transactiontx=session.beginTransaction();n提交事务:tx.commit();n撤销事务:tx.rollback();PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn多个事务并发运行时的并发问题n第一类丢失更新:撤销一个事务时,把其他事务已提交的更新数据覆盖。n脏读:一个事务读到另一事务未提交的更新数据。n虚读:一个事务读到另一事务已提交的新插入的数据。n不可重复读:一个事务读到另一事务已提交的更新数据。n第二类丢失更新:这是不可重复读中的特例,一个事务覆盖另一事务已提交的更新数据。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn取款事务和支票转账事务n取款事务包含以下步骤:n(1)某银行客户在银行前台请求取款100元,出纳员先查询账户信息,得知存款余额为1000元。n(2)出纳员判断出存款额超过了取款额,就支付给客户100元,并将账户上的存款余额改为900元。n支票转账事务包含以下步骤:n(1)某出纳员处理一转帐支票,该支票向一帐户汇入100元。出纳员先查询账户信息,得知存款余额为900元。n(2)出纳员将存款余额改为1000元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn并发运行的两个事务导致脏读取款事务在T5时刻把存款余额改为900元,支票转账事务在T6时刻查询账户的存款余额为900元,取款事务在T7时刻被撤销,支票转账事务在T8时刻把存款余额改为1000元。由于支票转账事务查询到了取款事务未提交的更新数据,并且在这个查询结果的基础上进行更新操作,如果取款事务最后被撤销,会导致银行客户损失100元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn并发运行的两个事务导致第二类丢失更新取款事务在T5时刻根据在T3时刻的查询结果,把存款余额改为1000-100元,在T6时刻提交事务。支票转账事务在T7时刻根据在T4时刻的查询结果,把存款余额改为1000+100元。由于支票转账事务覆盖了取款事务对存款余额所做的更新,导致银行最后损失100元。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn数据库的事务隔离级别PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn隔离级别与并发性能的关系PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn设定隔离级别的原则n隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。n对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为ReadCommitted,它能够避免脏读,而且具有较好的并发性能。尽管它会导致不可重复读、虚读和第二类丢失更新这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在mysql.exe程序中设置隔离级别n每启动一个mysql.exe程序,就会获得一个单独的数据库连接。每个数据库连接都有个全局变量@@tx_isolation,表示当前的事务隔离级别。MySQL默认的隔离级别为RepeatableRead。如果要察看当前的隔离级别,可使用如下SQL命令:nmysql>select@@tx_isolation;n如果要把当前mysql.exe程序的隔离级别改为ReadCommitted,可使用如下SQL命令:nmysql>settransactionisolationlevelreadcommitted;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn在Hibernate中设置隔离级别n在Hibernate的配置文件中可以显式的设置隔离级别。每一种隔离级别都对应一个整数:n1:ReadUncommittedn2:ReadCommittedn4:RepeatableReadn8:Serializablen例如,以下代码把hibernate.properties文件中的隔离级别设为ReadCommitted:hibernate.connection.isolation=2对于从数据库连接池中获得的每个连接,Hibernate都会把它改为使用ReadCommitted隔离级别。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn使用悲观锁Accountaccount=(Account)session.get(Account.class,newLong(1),LockMode.UPGRADE);account.setBalance(account.getBalance()-100);Hibernate执行的select语句为:select*fromACCOUNTSwhereID=1forupdate;updateACCOUNTSsetBALANCE=900…PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用悲观锁协调并发运行的取款事务和支票转账事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn使用乐观锁n乐观锁是由应用程序提供的一种机制,这种机制既能保证多个事务并发访问数据,又能防止第二类丢失更新问题。n在应用程序中,可以利用Hibernate提供的版本控制功能来实现乐观锁。对象-关系映射文件中的<version>元素和<timestamp>元素都具有版本控制功能:n<version>元素利用一个递增的整数来跟踪数据库表中记录的版本n<timestamp>元素用时间戳来跟踪数据库表中记录的版本。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(1)在Account类中定义一个代表版本信息的属性:privateintversion;publicintgetVersion(){returnthis.version;}publicvoidsetVersion(intversion){this.version=version;}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(2)在ACCOUNTS表中定义一个代表版本信息的字段:createtableACCOUNTS(IDbigintnotnull,NAMEvarchar(15),BALANCEdecimal(10,2),VERSIONinteger,primarykey(ID))type=INNODB;PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n(3)在Account.hbm.xml文件中用<version>元素来建立Account类的version属性与ACCOUNTS表中VERSION字段的映射:<idname="id"type="long"column="ID"><generatorclass="increment"/></id><versionname="version"column="VERSION"/>……PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n当Hibernate更新一个Account对象时,会根据它的id与version属性到ACCOUNTS表中去定位匹配的记录,假定Account对象的version属性为0,那么在取款事务中Hibernate执行的update语句为:updateACCOUNTSsetNAME=’Tom’,BALANCE=900,VERSION=1whereID=1andVERSION=0;n如果存在匹配的记录,就更新这条记录,并且把VERSION字段的值加1。当支票转账事务接着执行以下update语句时:updateACCOUNTSsetNAME=’Tom’,BALANCE=1100,VERSION=1whereID=1andVERSION=0;n由于ID为1的ACCOUNTS记录的版本已经被取款事务修改,因此找不到匹配的记录,此时Hibernate会抛出StaleObjectStateException。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制n在应用程序中应该捕获该异常,这种异常有两种处理方式:n方式一:自动撤销事务,通知用户账户信息已被其他事务修改,需要重新开始事务。n方式二:通知用户账户信息已被其他事务修改,显示最新存款余额信息,由用户决定如何继续事务,用户也可以决定立刻撤销事务。PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用<version>元素对ACCOUNTS表中记录进行版本控制try{tx=session.beginTransaction();log.write("transferCheck():开始事务");Thread.sleep(500);Accountaccount=(Account)session.get(Account.class,newLong(1));log.write("transferCheck():查询到存款余额为:balance="+account.getBalance());Thread.sleep(500);account.setBalance(account.getBalance()+100);log.write("transferCheck():汇入100元,把存款余额改为:"+account.getBalance());tx.commit();//当Hibernate执行update语句时,可能会抛出StaleObjectExceptionlog.write("transferCheck():提交事务");Thread.sleep(500);}catch(StaleObjectStateExceptione){if(tx!=null){tx.rollback();}e.printStackTrace();System.out.println("账户信息已被其他事务修改,本事务被撤销,请重新开始支票转账事务");log.write("transferCheck():账户信息已被其他事务修改,本事务被撤销");}PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn利用乐观锁协调并发的取款事务和支票转账事务PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn实现乐观锁的其他方法n如果应用程序是基于已有的数据库,而数据库表中不包含代表版本或时间戳的字段,Hibernate提供了其他实现乐观锁的办法。把<class>元素的optimistic-lock属性设为“all”:<classname="Account"table="ACCOUNTS"optimistic-lock="all"dynamic-update="true">nHibernate会在update语句的where子句中包含Account对象被加载时的所有属性:updateACCOUNTSsetBALANCE=900whereID=1andNAME='Tom'andBALANCE='1000';PDF文件使用"pdfFactory"试用版本创建www.fineprint.com.cn
  • 相关资料
  • 该用户的其他资料
  • 名称/格式
  • 下载次数
  • 资料大小
  • 名称/格式
  • 下载次数
  • 资料大小

用户评论

0/200
暂无评论
上传我的资料
关闭

请选择举报的类型

关闭

提示

提交成功!

感谢您对爱问共享资料的支持,我们将尽快核实并处理您的举报信息。

关闭

提示

提交失败!

您的举报信息提交失败,请重试!

关闭

提示

重复举报!

亲爱的用户!感觉您对爱问共享资料的支持,请勿重复举报噢!

全屏 缩小 放大
收藏
资料评价:

/ 33
所需积分:1 立即下载
返回
顶部
举报
资料
关闭

温馨提示

感谢您对爱问共享资料的支持,精彩活动将尽快为您呈现,敬请期待!