通过在表中及POJO中增加一个version字段来表示记录的版本,来达到多用户同时更改一条数据的冲突
数据库脚本:
create table studentVersion (id varchar (32 ),name varchar (32 ),ver int );
POJO
注解形式:
private int version; @Version @Column (name = "version" ) public int getVersion() { return version; } private void setVersion(int version) { this .version = version; }
private int version;
@Version
@Column(name = "version")
public int getVersion() {
return version;
}
private void setVersion(int version) {
this.version = version;
}
xml文件形式:
Student.hbm.xml
<? xml version="1.0" encoding="utf-8" ?> <!
DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" > <!--
Mapping file autogenerated by MyEclipse - Hibernate Tools --> < hibernate-mapping > < class name ="Version.Student" table ="studentVersion" > < id name ="id" unsaved-value ="null" > < generator class ="uuid.hex" ></ generator > </ id > <!-- version标签必须跟在id标签后面 --> < version name ="version" column ="ver" type ="int" ></ version > < property name ="name" type ="string" column ="name" ></ property > </ class > </ hibernate-mapping >
Hibernate.cfg.xml
<? xml version='1.0' encoding='UTF-8' ?> <!
DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd" > <!-- Generated by MyEclipse Hibernate Tools. --> < hibernate-configuration > < session-factory > < property name ="connection.username" > root</ property > < property name ="connection.url" > jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312& useUnicode=true </ property > < property name ="dialect" > org.hibernate.dialect.MySQLDialect </ property > < property name ="myeclipse.connection.profile" > mysql</ property > < property name ="connection.password" > 1234</ property > < property name ="connection.driver_class" > com.mysql.jdbc.Driver </ property > < property name ="hibernate.dialect" > org.hibernate.dialect.MySQLDialect </ property > < property name ="hibernate.show_sql" > true</ property > < property name ="current_session_context_class" > thread</ property > < property name ="jdbc.batch_size" > 15</ property > < mapping resource ="Version/Student.hbm.xml" /> </ session-factory > </ hibernate-configuration >
测试代码:
运行结果:
Hibernate: insert into studentVersion (ver, name, id) values (?, ?, ?) Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.name as name0_ from studentVersion student0_ where student0_.name='tom11' Hibernate: select student0_.id as id0_, student0_.ver as ver0_, student0_.name as name0_ from studentVersion student0_ where student0_.name='tom11' v1=0--v2=0 Hibernate: update studentVersion set ver=?, name=? where id=? and ver=? v1=1--v2=0 Hibernate: update studentVersion set ver=?, name=? where id=? and ver=? Exception in thread "main" org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Version.Student#4028818316cd6b460116cd6b50830001]
可以看到,第二个“用户”session2修改数据时候,记录的版本号已经被session1更新过了,所以抛出了红色的异常,我们可以在实际应用中处理这个异常,例如在处理中重新读取数据库中的数据,同时将目前的数据与数据库中的数据展示出来,让使用者有机会比较一下,或者设计程序自动读取新的数据
注意:如果手工设置stu.setVersion()自行更新版本以跳过检查,则这种乐观锁就会失效,应对方法可以将Student.java的setVersion设置成private