• Oracle Lock and Hibernage Lock


    http://orafaq.com/node/854
    ORACLE锁:
    Oracle uses locks to control concurrent access to data. A lock gives you temporary ownership of a database resource such as a table or row of data. Thus, data cannot be changed by other users until you finish with it. You need never explicitly lock a resource because default locking mechanisms protect Oracle data and structures. However, you can request data locks on tables or rows when it is to your advantage to override default locking. You can choose from several modes of locking such as row share and exclusive.

    LOCK
    To lock data is to temporarily restrict other users’ access to data. The restriction that is placed on such
    data is called “a lock.” Lock modes are SHARE, SHARE UPDATE, EXCLUSIVE, SHARE EXCLUSIVE,
    ROW SHARE, and ROW EXCLUSIVE. Not all locks can be acquired in all modes.

    ORACLE-LOCK
         Making Low-Impact DDL Changes
         If you only have one database available, you need to be careful when making changes to your
    tables and indexes. When you create or modify an object, you must first acquire a DDL lock on
    the object to prevent other types of access against the object. Because of this locking issue, you
    will need to avoid changing objects while users are accessing them. Furthermore, changing an
    object will invalidate the stored procedures that reference the object.
         Although you should ideally make changes to objects at times when users are not accessing
    them, your maintenance time windows may not be sufficiently large enough to support that
    requirement. You should always plan for enough time to make the change, test the change, and
    recompile any objects that the change impacts. In the following sections you will see methods
    for making changes in ways that minimize the size of the maintenance window needed.  

    DDL LOCK
    When a user executes a DDL command, Oracle locks the objects referred to in the command with DDL
    locks. A DDL lock locks objects in the data dictionary.

    DEADLOCK
    A deadlock is a rare situation in which two or more user processes of a database cannot complete their transactions, because each process is holding a resource that the other process requires (such as a row in a table) in order to complete. Although these situations occur rarely, Oracle detects and resolves
    deadlocks by rolling back the work of one of the processes.

    什么是死锁?
    A deadlock can occur when two or more users try to access the same schema object. For example, two
    users updating the same table might wait if each tries to update a row currently locked by the other. Because each user is waiting for resources held by another user, neither can continue until Oracle breaks the deadlock by signaling an error to the last participating transaction.
    死锁描述的是两个或多个线程由于相互等待而永远被阻塞的情况。导致死锁的原因有很多。线程分析器可检测由于不恰当使用互斥锁而导致的死锁。此类死锁通常发生在多线程应用程序中。
    满足以下所有条件时,包含两个或多个线程的进程可能会进入死锁状态:
    已持有锁的线程请求新锁
    同时发出对新锁的请求
    两个或多个线程形成一个循环链,其中每个线程都在等待链中下一个线程持有的锁
    以下是一个死锁情况的简单示例:
    线程 1 持有锁 A 并请求锁 B
    线程 2 持有锁 B 并请求锁 A
    死锁可分为两种类型:潜在死锁或实际死锁。潜在死锁不一定在给定的运行过程中发生,但可能发生在程序的任何执行过程中,具体取决于线程的调度情况以及线程进行锁请求的时间。实际死锁是在程序执行过程中发生的死锁。实际死锁会导致所涉及的线程挂起,但不一定会导致整个进程挂起。

    ---------------------------------------------------------------------------------------------

    (游标锁住记录)

         (当游标打开的时候,所有满足查询条件的语句都将被游标锁定,只有当进行COMMIT提交的时候,才会释放锁)All rows that meet the SELECT criteria are locked at the OPEN. COMMIT releases the locks, and
    no further FETCHing is permitted. This means you must FETCH and process all of the rows you wish
    to update before you issue a COMMIT.

    -----------------------------------------------------------------------------------------------

    Oracle-FOR UPDATE NOWAIT(以不等待的 FORUPDATE 锁定记录)

    索引地址:The Complete Reference - Mcgraw Hill Osborne:1268页

           column is a column in a table listed in the FROM clause. This cannot be an expression, but must
    be a real column name. NOWAIT means that a SELECT … FOR UPDATE attempt that encounters a
    locked row will terminate and return immediately to the user, rather than wait and attempt to update the row again in a few moments.(直接进行更新纪录,假如已经被锁定,则返回错误信息-资源正忙,正在以 FOR UPDATE NOWAITE打开,而不是等待资源的释放)
           (FOR UPDATE语句锁定所有的满足查询条件的记录)The FOR UPDATE OF clause puts locks on the rows that have been selected. SELECT … FOR UPDATE OF should be followed immediately by an UPDATE … WHERE command, or, if you decide not to update anything, by a COMMIT or ROLLBACK. The FOR UPDATE OF clause also includes the actions of INSERT and DELETE(FOR UPDATE也可以包含在DELETE 和 INSERT之中). Once you have locked a row, other users cannot update it until you free it with a COMMIT command (or AUTOCOMMIT) or ROLLBACK. SELECT … FOR UPDATE OFcannot include DISTINCT, GROUP BY, UNION, INTERSECT, MINUS, or any group function such
    as MIN, MAX, AVG, or COUNT(FOR UPDATE中不可以包含聚合函数和统计函数). The columns named have no effect and are present for compatibility with other dialects of SQL. Oracle will lock only the tables that appear in the FOR UPDATE clause(将会锁住出现在FOR UPDATE子句中的字段所属的表). If you don’t have an OF clause listing any tables, Oracle will lock all the tables in the FROM clause for update(如果FOR UPDATE后面没有字段,则锁住所以的表). All the tables must be on the same database, and if there are references to a LONG column or a sequence in the SELECT, the tables must be on the same database as the LONG or the sequence. If you are querying from a partitioned table, you can list the name of the partition you are querying
    as part of the FROM clause of the query. See Chapter 17.(The Complete Reference - Mcgraw Hill Osborne)
         The other individual clauses in the SELECT statement are all described under their own names
    elsewhere in this reference. The AS OF {TIMESTAMP|SCN} clause for flashback queries was introduced
    in Oracle9i Release 2. The VERSIONS BETWEEN clause for flashback version queries is available as of
    Oracle Database 10g.

    游标FOR UPDATE的语句格式:

    1 DECLARE
    2 CURSOR cursor (parameter datatype [,parameter datatype]...)
    3 IS select_statement
    4 [FOR UPDATE OF column [,column]...];

          DECLARE CURSOR names a cursor and declares that it IS (the result of) a certain select_statement. The select_statement is required, and may not contain an INTO clause.(不可以包含INTO子句) The cursor must be declared. It can then be OPENed, and rows can then be FETCHed into it. Finally, it can be CLOSEd.
         Variables cannot be used directly in the WHERE clause of the select_statement unless they’ve first
    been identified as parameters(变量不可以直接在WHERE 子句后面使用,只可以当作参数使用), in a list that precedes the select. Note that DECLARE CURSOR does not execute the SELECT statement, and the parameters have no values until they are assigned in an OPEN statement.(声明游标后,并没有立即执行,他的参数也没有值,只有当打开的时候,它才执行) Parameters have standard object names, and datatypes including VARCHAR2, CHAR,
    NUMBER, DATE, and BOOLEAN, all without size or scale, however.
    FOR UPDATE OF is required if you wish to affect the current row in the cursor using either UPDATE
    or DELETE commands with the CURRENT OFclause.(当想只影响打开的游标的记录,可以使用CURRENT OF子句)

    SELECT FOR UPDATE in Cursors(FOR UPDATE在游标中的使用)

    摘自网址:网址:http://docstore.mik.ua/orelly/oracle/prog2/ch06_11.htm

          When you issue a SELECT statement against the database to query some records, no locks are placed on the selected rows. In general, this is a wonderful feature because the number of records locked at any given time is (by default) kept to the absolute minimum: only those records which have been changed but not yet committed are locked. Even then, others will be able to read those records as they appeared before the change (the "before image" of the data).

          There are times, however, when you will want to lock a set of records even before you change them in your program. Oracle offers the FOR UPDATE clause of the SELECT statement to perform this locking.

           When you issue a SELECT...FOR UPDATE statement, the RDBMS automatically obtains exclusive row-level locks(获得执行的行级别的锁) on all the rows identified by the SELECT statement, holding the records "for your changes only" as you move through the rows retrieved by the cursor. No one else will be able to change any of these records until you perform a ROLLBACK or a COMMIT.

    Here are two examples of the FOR UPDATE clause used in a cursor:

    case 1:

    1 CURSOR toys_cur IS
    2 SELECT name, manufacturer, preference_level, sell_at_yardsale_flag
    3 FROM my_sons_collection
    4 WHERE hours_used = 0
    5 FOR UPDATE;

    case 2:

    1 CURSOR fall_jobs_cur IS
    2 SELECT task, expected_hours, tools_required, do_it_yourself_flag
    3 FROM winterize
    4 WHERE year = TO_CHAR (SYSDATE, 'YYYY')
    5 FOR UPDATE OF task;

          The first cursor uses the unqualified FOR UPDATE clause, while the second cursor qualifies the FOR UPDATE with a column name from the query. You can use the FOR UPDATE clause in a SELECT against multiple tables. In this case, rows in a table are locked only if the FOR UPDATE clause references a column in that table(只会锁住for update涉及的字段的表). In the following example the FOR UPDATE clause does not result in any locked rows in the winterize table:(如下的例子,将不会锁住winterize表)

    1 CURSOR FALL_JOBS_CUR IS
    2 SELECT W.TASK, W.EXPECTED_HOURS,
    3 W.TOOLS_REQUIRED, W.DO_IT_YOURSELF_FLAG
    4 FROM WINTERIZE W, HUSBAND_CONFIG HC
    5 WHERE YEAR = TO_CHAR (SYSDATE, 'YYYY')
    6 FOR UPDATE OF husband_config.max_procrastination_allowed;

         The FOR UPDATE OF clause only mentions the max_procrastination_allowed column; no columns in the winterize table are listed.
    --注意

         (of后面的字段并不是限制只可以修改of后面的这些字段,锁将会出现在所有的行上,of后面的列表只是给了一种更清晰的标注方法)
         The OF list of the FOR UPDATE clause does not restrict you to changing only those columns listed. Locks are still placed on all rows; the OF list just gives you a way to document more clearly what you intend to change. If you simply state FOR UPDATE in the query and do not include one or more columns after the OF keyword, then the database will then lock all identified rows across all tables listed in the FROM clause.

    Furthermore, you do not have to actually UPDATE or DELETE any records just because you issued a SELECT...FOR UPDATE -- that act simply states your intention to be able to do so.

    Finally, you can append the optional keyword NOWAIT to the FOR UPDATE clause to tell Oracle not to wait if the table has been locked by another user. In this case, control will be returned immediately to your program so that you can perform other work or simply wait for a period of time before trying again. Without the NOWAIT clause, your process will block until the table is available. There is no limit to the wait time unless the table is remote. For remote objects, the Oracle initialization parameter, DISTRIBUTED_LOCK_TIMEOUT, is used to set the limit.

    使用COMMIT进行锁的释放:

     Releasing Locks with COMMIT

         As soon as a cursor with a FOR UPDATE clause is OPENed, all rows identified in the result set of the cursor are locked and remain locked until your session issues either a COMMIT statement to save any changes or a ROLLBACK statement to cancel those changes. When either of these actions occurs, the locks on the rows are released. As a result, you cannot execute another FETCH against a FOR UPDATE cursor after you COMMIT or ROLLBACK. You will have lost your position in the cursor.

        ORA-01002: fetch out of sequence

         If you ever need to execute a COMMIT or ROLLBACK as you FETCH records from a SELECT FOR UPDATE cursor, you should include code (such as a loop EXIT or other conditional logic) to halt any further fetches from the cursor.

    The WHERE CURRENT OF Clause(CURRENT OF子句)

         PL/SQL provides the WHERE CURRENT OF clause for both UPDATE and DELETE statements inside a cursor in order to allow you to easily make changes to the most recently fetched row of data.  The general format for the WHERE CURRENT OF clause is as follows:

          语句格式:(update)

    1 UPDATE table_name
    2 SET set_clause
    3 WHERE CURRENT OF cursor_name;

          (delete):

    1 DELETE
    2 FROM table_name
    3 WHERE CURRENT OF cursor_name;

          Notice that the WHERE CURRENT OF clause references the cursor and not the record into which the next fetched row is deposited.(CURRENT OF引用的是游标的记录,而不是当前FETCH的记录)

          (current of最大的好处是,不需要在update或者delete的where条件重复在游标中定义的where条件)

          The most important advantage to using WHERE CURRENT OF where you need to change the row fetched last is that you do not have to code in two (or more) places the criteria used to uniquely identify a row in a table. Without WHERE CURRENT OF, you would need to repeat the WHERE clause of your cursor in the WHERE clause of the associated UPDATEs and DELETEs. As a result, if the table structure changes in a way that affects the construction of the primary key, you have to make sure that each SQL statement is upgraded to support this change. If you use WHERE CURRENT OF, on the other hand, you only have to modify the WHERE clause of the SELECT statement.

       未使用 CURRENT OF子句(当需要删除或者更新的时候,还需要WHERE条件的添加)

     1 DECLARE
    2 CURSOR FALL_JOBS_CUR IS
    3 SELECT TASK, EXPECTED_HOURS, TOOLS_REQUIRED, DO_IT_YOURSELF_FLAG
    4 FROM WINTERIZE
    5 WHERE YEAR = TO_CHAR(SYSDATE, 'YYYY')
    6 AND COMPLETED_FLAG = 'NOTYET'
    7 FOR UPDATE OF TASK;
    8 BEGIN
    9 FOR JOB_REC IN FALL_JOBS_CUR LOOP
    10 IF JOB_REC.DO_IT_YOURSELF_FLAG = 'YOUCANDOIT' THEN
    11 UPDATE WINTERIZE
    12 SET RESPONSIBLE = 'STEVEN'
    13 WHERE TASK = JOB_REC.TASK
    14 AND YEAR = TO_CHAR(SYSDATE, 'YYYY');--还需要进行where条件的添加
    15 COMMIT;
    16 END IF;
    17 END LOOP;
    18 END;

    使用了CURRENT OF子句,(不需要重复添加在定义CURSOR语句的where条件)

        This might seem like a relatively minor issue, but it is one of many areas in your code where you can leverage subtle features in PL/SQL to minimize code redundancies. Utilization of WHERE CURRENT OF, %TYPE, and %ROWTYPE declaration attributes, cursor FOR loops, local modularization, and other PL/SQL language constructs can have a big impact on reducing the pain you may experience when you maintain your Oracle-based applications.

     Let's see how this clause would improve the previous example. In the jobs cursor FOR loop above, I want to UPDATE the record that was currently FETCHed by the cursor. I do this in the UPDATE statement by repeating the same WHERE used in the cursor because (task, year) makes up the primary key of this table:

     测试例子:

     1 CREATE TABLE t1 (
    2 pname VARCHAR2(10),
    3 cases NUMBER(3));
    4
    5 INSERT INTO t1 VALUES ('Morgan',2);
    6 INSERT INTO t1 VALUES ('Dan',3);
    7 INSERT INTO t1 VALUES ('Jack',2);
    8 INSERT INTO t1 VALUES ('Helen',1);
    9 COMMIT;
    10
    11 SELECT * FROM t1;

    (使用CURRENT OF语句)

    1 DECLARE
    2 CURSOR CUR_T1 IS
    3 SELECT * FROM T1 T WHERE T.CASES IN (1, 3) FOR UPDATE NOWAIT;
    4 BEGIN
    5 FOR V_CUR_T1 IN CUR_T1 LOOP
    6 UPDATE T1 T SET T.PNAME = 'a' WHERE CURRENT OF CUR_T1;
    7 END LOOP;
    8 --COMMIT;
    9 END;

    结果,只更新了属于游标的两条记录:

    假如没有,current of子句,则需要在update的子句后面,手动的加上条件

    T.CASES IN (1, 3)

    --------------------------------------------------------------------------------------------

    --------------------------------------------------------------------------------------------

    --------------------------------------------------------------------------------------------

    在开发过程中遇到了乐观锁的问题,查询了资料,觉得以下这边文章不错,遂转载:

    原文地址:http://www.jili360.com/home-space-uid-1618-do-blog-id-569.html

    锁( locking  
    业务逻辑的实现过程中,往往需要保证数据访问的排他性。如在金融系统的日终结算 
    处理中,我们希望针对某个 cut-off 时间点的数据进行处理,而不希望在结算进行过程中 
    (可能是几秒种,也可能是几个小时),数据再发生变化。此时,我们就需要通过一些机 
    制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓 
        ,即给我们选定的目标数据上锁,使其无法被其他程序修改。 
    Hibernate
     支持两种锁机制:即通常所说的  悲观锁( Pessimistic Locking  
      乐观锁( Optimistic Locking    
    悲观锁( Pessimistic Locking  
    悲观锁,正如其名,它指的是对数据被外界(包括本系统当前的其他事务,以及来自 
    外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定 
    状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能 
    真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系 
    统不会修改数据)。 
    一个典型的倚赖数据库的悲观锁调用: 
    select * from account where name=”Erica” for update
    这条 sql 语句锁定了 account 表中所有符合检索条件( name=”Erica” )的记录。 
    本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。 
    Hibernate
     的悲观锁,也是基于数据库的锁机制实现。 
    下面的代码实现了对查询记录的加锁:

    String hqlStr =
    "from TUser as user where user.name='Erica'";
    Query query = session.createQuery(hqlStr);
    query.setLockMode("user",LockMode.UPGRADE); //
     加锁 
    List userList = query.list();//
     执行查询,获取数据 
    query.setLockMode
     对查询语句中,特定别名所对应的记录进行加锁(我们为 
    TUser
     类指定了一个别名 “user” ),这里也就是对返回的所有 user 记录进行加锁。 
    观察运行期 Hibernate 生成的 SQL 语句: 
    select tuser0_.id as id, tuser0_.name as name, tuser0_.group_id
    as group_id, tuser0_.user_type as user_type, tuser0_.sex as sex
    from t_user tuser0_ where (tuser0_.name='Erica' ) for update
    这里 Hibernate 通过使用数据库的 for update 子句实现了悲观锁机制。 
    Hibernate
     的加锁模式有: 
    Ø LockMode.NONE 
     无锁机制。 
    Ø LockMode.WRITE 
     Hibernate  Insert  Update 记录的时候会自动 
    获取。 
    Ø LockMode.READ 
     Hibernate 在读取记录的时候会自动获取。 
    以上这三种锁机制一般由 Hibernate 内部使用,如 Hibernate 为了保证 Update
    过程中对象不会被外界修改,会在 save 方法实现中自动为目标对象加上 WRITE 锁。 
    Ø LockMode.UPGRADE 
    :利用数据库的 for update 子句加锁。 
    Ø LockMode. UPGRADE_NOWAIT 
     Oracle 的特定实现,利用 Oracle  for
    update nowait
     子句实现加锁。 
    上面这两种锁机制是我们在应用层较为常用的,加锁一般通过以下方法实现: 
    Criteria.setLockMode
    Query.setLockMode
    Session.lock
    注意,只有在查询开始之前(也就是 Hiberate 生成 SQL 之前)设定加锁,才会 
    真正通过数据库的锁机制进行加锁处理,否则,数据已经通过不包含 for update
    子句的 Select SQL 加载进来,所谓数据库加锁也就无从谈起。 
    乐观锁( Optimistic Locking  
    相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。悲观锁大多数情况下依 
    靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库 
    性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。 
    如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进 
    行修改时(如更改用户帐户余额),如果采用悲观锁机制,也就意味着整个操作过 
    程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作 
    员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对几

    百上千个并发,这样的情况将导致怎样的后果。 
    乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本 
     Version )记录机制实现。何谓数据版本?即为数据增加一个版本标识,在基于 
    数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来 
    实现。 
    读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提 
    交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据 
    版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 
    对于上面修改用户帐户信息的例子而言,假设数据库中帐户信息表中有一个 
    version
     字段,当前值为 1 ;而当前帐户余额字段( balance )为 $100  
    操作员 此时将其读出( version=1 ),并从其帐户余额中扣除 $50
     $100-$50 )。 
    在操作员 A 操作的过程中,操作员 B 也读入此用户信息( version=1 ),并 
    从其帐户余额中扣除 $20  $100-$20 )。 
    操作员 A 完成了修改工作,将数据版本号加一( version=2 ),连同帐户扣 
    除后余额( balance=$50 ),提交至数据库更新,此时由于提交数据版本大 
    于数据库记录当前版本,数据被更新,数据库记录 version 更新为 2  
    操作员 B 完成了操作,也将版本号加一( version=2 )试图向数据库提交数 
    据( balance=$80 ),但此时比对数据库记录版本时发现,操作员 B 提交的 
    数据版本号为 2 ,数据库记录当前版本也为 2 ,不满足  提交版本必须大于记 
    录当前版本才能执行更新  的乐观锁策略,因此,操作员 的提交被驳回。 
    这样,就避免了操作员 用基于 version=1 的旧数据修改的结果覆盖操作 
     A 的操作结果的可能。 
    从上面的例子可以看出,乐观锁机制避免了长事务中的数据库加锁开销(操作员 A
    和操作员 B 操作过程中,都没有对数据库数据加锁),大大提升了大并发量下的系 
    统整体性能表现。 
    需要注意的是,乐观锁机制往往基于系统中的数据存储逻辑,因此也具备一定的局 
    限性,如在上例中,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户 
    余额更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。在 
    系统设计阶段,我们应该充分考虑到这些情况出现的可能性,并进行相应调整(如 
    将乐观锁策略在数据库存储过程中实现,对外只开放基于此存储过程的数据更新途 
    径,而不是将数据库表直接对外公开)。 
    Hibernate 
    在其数据访问引擎中内置了乐观锁实现。如果不用考虑外部系统对数 
    据库的更新操作,利用 Hibernate 提供的透明化乐观锁实现,将大大提升我们的 
    生产力。 
    Hibernate
     中可以通过 class 描述符的 optimistic-lock 属性结合 version
    描述符指定。 
    现在,我们为之前示例中的 TUser 加上乐观锁机制。

    1  首先为 TUser  class 描述符添加 optimistic-lock 属性: 
    <hibernate-mapping>
    <class
    name="org.hibernate.sample.TUser"
    table="t_user"
    dynamic-update="true"
    dynamic-insert="true"
    optimistic-lock="version"
    >
    ……
    </class>
    </hibernate-mapping>
    optimistic-lock
     属性有如下可选取值: 
    Ø none
    无乐观锁 
    Ø version
    通过版本机制实现乐观锁 
    Ø dirty
    通过检查发生变动过的属性实现乐观锁 
    Ø all
    通过检查所有属性实现乐观锁 
    其中通过 version 实现的乐观锁机制是 Hibernate 官方推荐的乐观锁实现,同时也 
     Hibernate 中,目前唯一在数据对象脱离 Session 发生修改的情况下依然有效的锁机 
    制。因此,一般情况下,我们都选择 version 方式作为 Hibernate 乐观锁实现机制。 
    2
      添加一个 Version 属性描述符 
    <hibernate-mapping>
    <class
    name="org.hibernate.sample.TUser"
    table="t_user"
    dynamic-update="true"
    dynamic-insert="true"
    optimistic-lock="version"
    >
    <id
    name="id"
    column="id"
    type="java.lang.Integer"
    >
    <generator class="native">

    </generator>
    </id>
    <version
    column="version"
    name="version"
    type="java.lang.Integer"
    />
    ……
    </class>
    </hibernate-mapping>
    注意 version 节点必须出现在 ID 节点之后。 
    这里我们声明了一个 version 属性,用于存放用户的版本信息,保存在 TUser 表的 
    version
     字段中。 
    此时如果我们尝试编写一段代码,更新 TUser 表中记录数据,如: 
    Criteria criteria = session.createCriteria(TUser.class);
    criteria.add(Expression.eq("name","Erica"));
    List userList = criteria.list();
    TUser user =(TUser)userList.get(0);
    Transaction tx = session.beginTransaction();
    user.setUserType(1); //
     更新 UserType 字段 
    tx.commit();
    每次对 TUser 进行更新的时候,我们可以发现,数据库中的 version 都在递增。 
    而如果我们尝试在 tx.commit 之前,启动另外一个 Session ,对名为 Erica 的用 
    户进行操作,以模拟并发更新时的情形: 
    Session session= getSession();
    Criteria criteria = session.createCriteria(TUser.class);
    criteria.add(Expression.eq("name","Erica"));
    Session session2 = getSession();
    Criteria criteria2 = session2.createCriteria(TUser.class);
    criteria2.add(Expression.eq("name","Erica"));
    List userList = criteria.list();
    List userList2 = criteria2.list();TUser user =(TUser)userList.get(0);
    TUser user2 =(TUser)userList2.get(0);
    Transaction tx = session.beginTransaction();
    Transaction tx2 = session2.beginTransaction();
    user2.setUserType(99);
    tx2.commit();
    user.setUserType(1);
    tx.commit();
    执行以上代码,代码将在 tx.commit() 处抛出 StaleObjectStateException  
    常,并指出版本检查失败,当前事务正在试图提交一个过期数据。通过捕捉这个异常,我 
    们就可以在乐观锁校验失败时进行相应处理

    I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。
  • 相关阅读:
    2017面试记录
    Bzoj1079:[SCOI2008]着色方案
    Bzoj1046: [HAOI2007]上升序列
    Luogu1121:环状最大两段子段和
    BZOJ 4698: [SDOI2008]Sandy的卡片
    [SPOJ]DISUBSTR:Distinct Substrings&[SPOJ]SUBST1:New Distinct Substrings
    HiHocoder1419 : 后缀数组四·重复旋律4&[SPOJ]REPEATS:Repeats
    Bzoj2946:[POI2000] 最长公共子串
    HiHocoder1415 : 后缀数组三·重复旋律3 & Poj2774:Long Long Message
    POJ3261:Milk Patterns
  • 原文地址:https://www.cnblogs.com/caroline/p/2388864.html
Copyright © 2020-2023  润新知