Hibernate Community Documentation 之 Chapter 5. Locking 锁(翻译)

私人翻译,如有错误请大胆指出,我相信不会有人转载:)

原文见https://docs.jboss.org/hibernate/orm/4.0/devguide/en-US/html/ch05.html

所谓“锁”是指用来在关系型数据库中防止在数据读取(read)到数据使用(used)之间其内容发生变化的操作。

锁的实现分为两种,分别是乐观(Optimistic)与悲观(Pessimestic)。

锁策略

乐观锁

乐观锁假设多组事务(transaction)能够互不干涉地并发完成,因此这些事务执行时不需要将他们影响到的数据加锁。在事务提交(commit)前,每个事务都会校验以确保它的数据没有被别人改动过。如果校验的结果是已有修改冲突(conflicting modifications),整个事务就会回滚(rollback)。

悲观锁

悲观锁假设事务之间会相互冲突,因此要求在数据读取时上锁,直至数据使用完毕后才释放锁。

 

Hibernate为以上两种锁策略都提供了支持。

5.1 乐观锁 Optimistic

如果你的应用使用了长事务或是由许多数据库事务组成的会话(conversation),你可以通过存储版本(version)数据使得当一个实体(entity)被两个会话更新时,最后一个提交更改的会话会被告知出现冲突,并且此时不会影响到前一个会话进行的更改。该方法保证了一定的隔离性,扩展性好且特别适用于常读取、少写入(Read-Often Write-Sometimes)的场景。

5.1.1 专用版本号 Dedicated version number

实现乐观锁的版本号机制是通过 @Version 注释来实现的

此处,Version属性被映射到OPTLOCK列,实体管理器(the entity manager)通过这个注释来检测有冲突的更新,借此防止数据更新被最后一个写入提交操作给覆盖(last-commit-wins)。

Version列可以是任意类型的,只要你定义并且实现一个自定义的UserVersionType即可。

Hibernate禁止你的应用手动变更版本号(version number)。如需手动增加版本号,请查看下列相关文档:

LockModeType.OPTIMISTIC_FORCE_INCREMENT 或 LockModeType.PESSIMISTIC_FORCE_INCREMENTcheck。

如果版本号是由数据库通过注入triggert自动生成的,需使用注释

@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)

column 存储版本号的列名. 可选,默认是属性名.
name 需要持久化的类名
type 版本号存储类型. 可选,默认是 integer.
access Hibernate访问属性时使用的方式. 可选, 默认是 property.
unsaved-value Indicates that an instance is newly instantiated and thus unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value,undefined, indicates that the identifier property value should be used. Optional.
generated 表明这是由数据库生成的版本号. 可选,默认是never.
insert 是否在SQL insert 语句中加入版本号. 默认是 true, 但如果你的版本号列有默认值0的话,可以设置成false.

5.1.2 时间戳 Timestamp

与版本号相比,时间戳在实现锁时稍显不可靠一些,但如果应用想要借此实现一些其他功能,还是有用的。如果 @Version 注释应用在Date或Calendar对象上时,会自动采用时间戳实现。

如果你用注释 @org.hibernate.annotations.Source 特别指定,Hibernate可以从数据库或者JVM中撷取时间戳的值:可以是org.hibernate.annotations.SourceType.DB或者是org.hibernate.annotations.SourceType.VM,如果不特别指定,默认值是使用数据库的时间戳。

如果指定了 @org.hibernate.annotations.Generated(GenerationTime.ALWAYS) 注释,时间戳的值可以借由数据库直接生成,而不是Hibernate。

column 存放时间戳的列名。可选,默认值为属性名。
name The name of a JavaBeans style property of Java type Date or Timestamp of the persistent class.
access Hibernate用于访问属性的策略。可选,默认为property。
unsaved-value A version property which indicates than instance is newly instantiated, and unsaved. This distinguishes it from detached instances that were saved or loaded in a previous session. The default value of undefined indicates that Hibernate uses the identifier property value.
source Whether Hibernate retrieves the timestamp from the database or the current JVM. Database-based timestamps incur an overhead because Hibernate needs to query the database each time to determine the incremental next value. However, database-derived timestamps are safer to use in a clustered environment. Not all database dialects are known to support the retrieval of the database’s current timestamp. Others may also be unsafe for locking, because of lack of precision.
generated 是否由数据库内部自动生成时间戳的值。可选,默认值是never。

5.2 悲观锁 Pessimistic

通常情况下,你只需要指明一个JDBC的隔离等级(lsolation level),把锁的问题交给数据库处理就行了。如果你确实需要获得独占锁(exclusive locks)或是在事务开始时重新得到(re-obtain)锁,Hibernate会提供给你需要的方法。

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

5.2.1 LockMode类

LockMode类指定了Hibernate能取得的各种锁级别。

LockMode.WRITE 在Hibernate执行update或insert行时自动获取
LockMode.UPGRADE 在用户显式地使用 SELECT ... FOR UPDATE 语句时(仅当数据库支持该语法)
LockMode.UPGRADE_NOWAIT 在用户对Oracle数据库显式地使用SELECT ... FOR UPDATE NOWAIT 语句时.
LockMode.READ 在Hibernate以Repeatable Read或是Serializable隔离级别读取时自动获取,亦可由用户显式地获取
LockMode.NONE 不启用锁。在事物结束后,所有的对象将会切换到这一状态。通过调用update()或saveOrUpdate()方法与会话(session)关联的对象亦以这种锁模式启动。

 

 

附注:有关锁的其他参考文章

MYSQL获取自增ID

参考:
http://flandycheng.blog.51cto.com/855176/280224
http://www.cnblogs.com/badtree/articles/2143103.html
http://my.oschina.net/fz04003/blog/63327

比较简单的方法是:

insert/select…等操作

然后直接下一条语句:

LAST_INSERT_ID 是与table无关的,如果向表a插入数据后,再向表b插入数据,LAST_INSERT_ID会改变。

看参考文献中说,多用户的情况下这个方法不能用。不过在php环境下,单用户用足够的。

 

MySQL 引擎选择 MyISAM 还是 InnoDB?

建表的时候会选择数据库引擎,常用的有MyISAM和InnoDB,到底选哪个呢?

参考文献:

什么是MyISAM?

MyISAM是MySQL关系数据库管理系统的默认储存引擎。这种MySQL表存储结构从旧的ISAM代码扩展出许多有用的功能。在新版本的MySQL中,InnoDB引擎由于其对事务,参照完整性,以及更高的并发性等优点开始广泛的取代MyISAM。

每一个MyISAM表都对应于硬盘上的三个文件。这三个文件有一样的文件名,但是有不同的扩展名以指示其类型用途:.frm文件保存表的定义,但是这个文件并不是MyISAM引擎的一部,而是服务器的一部分;.MYD保存表的数据;.MYI是表的索引文件。

什么是InnoDB?

InnoDB是MySQL的另一个存储引擎,正成为目前MySQL AB所发行新版的标准,被包含在所有二进制安装包里。较之于其它的存储引擎它的优点是它支持兼容ACID的事务(类似于PostgreSQL),以及参数完整性(即对外键的支持)。

Oracle公司与2005年10月收购了Innobase。Innobase采用双认证授权。它使用GNU发行,也允许其它想将InnoDB结合到商业软件的团体获得授权。

MyISAM vs Innodb – Quick comparison Table | 快速比较表:

MyISAM Innodb
Not *ACID compliant and non-transactional *ACID compliant and hence fully transactional with ROLLBACK and COMMIT and support for Foreign Keys
MySQL 5.0 Default Engine Rackspace Cloud Default Engine
Offers Compression Offers Compression
Requires full repair/rebuild of indexes/tables Auto recovery from crash via replay of logs
Changed Db pages written to disk instantly Dirty pages converted from random to sequential before commit and flush to disk
No ordering in storage of data Row data stored in pages in PK order
Table level locking Row level locking

在StackOverflow上的小总结:

InnoDB的设计目标是处理大容量数据库系统,它的CPU利用率是其它基于磁盘的关系数据库引擎所不能比的。

phpMyAdmin中设置外键Foreign Key

恩~最近在倒腾百度云,因为建表什么的不想输入命令,所以用了phpMyAdmin的界面~

创建好之后发现找不到怎么设外键的,于是谷歌了一下~

http://stackoverflow.com/questions/459312/setting-up-foreign-keys-in-phpmyadmin

这里有详尽的解释~另外看了几篇中文的~

总归是

  • 数据库类型貌似要设置成InnoDb才行(我也不知道是真是假)
  • 搞定之后在需要有外键的库底下找到Relation View,然后设置

外键的其他必要条件就不叨叨了~