Migrate User Guide Locking chapter extras to test folder and old xml mapping to the Legacy appendix

This commit is contained in:
vladmihalcea 2016-01-27 13:06:14 +02:00
parent f8e7799848
commit aeac516eeb
15 changed files with 206 additions and 94 deletions

View File

@ -28,6 +28,7 @@ include::chapters/envers/Envers.adoc[]
include::chapters/portability/Portability.adoc[]
include::appendices/Legacy_Bootstrap.adoc[]
include::appendices/Legacy_DomainModel.adoc[]
include::appendices/Legacy_Criteria.adoc[]
include::Bibliography.adoc[]

View File

@ -0,0 +1,49 @@
[[appendix-legacy-domain-model]]
== Legacy Domain Model
:sourcedir: extras
.Declaring a version property in `hbm.xml`
====
[source,xml]
----
include::{sourcedir}/version_property.xml[]
----
====
[cols=",",]
|=======================================================================
|column |The name of the column holding the version number. Optional, defaults to the property name.
|name |The name of a property of the persistent class.
|type |The type of the version number. Optional, defaults to `integer`.
|access |Hibernate's strategy for accessing the property value. Optional, defaults to `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 |Indicates that the version property value is generated by the database. Optional, defaults to `never`.
|insert |Whether or not to include the `version` column in SQL `insert` statements.
Defaults to `true`, but you can set it to `false` if the database column is defined with a default value of `0`.
|=======================================================================
.The timestamp element in `hbm.xml`
====
[source,xml]
----
include::{sourcedir}/timestamp_version.xml[]
----
====
[cols=",",]
|=======================================================================
|column |The name of the column which holds the timestamp. Optional, defaults to the property name
|name |The name of a JavaBeans style property of Java type `Date` or `Timestamp` of the persistent class.
|access |The strategy Hibernate uses to access the property value. Optional, defaults to `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 |Whether the timestamp property value is generated by the database. Optional, defaults to `never`.
|=======================================================================

View File

@ -1,6 +1,6 @@
[[locking]]
== Locking
:sourcedir: extras
:sourcedir: ../../../../../test/java/org/hibernate/userguide/locking
:extrasdir: extras
In a relational database, locking refers to actions taken to prevent data from changing between the time it is read and the time is used.
@ -40,15 +40,16 @@ especially useful if you use assigned identifiers or composite keys.
The version number mechanism for optimistic locking is provided through a `@Version` annotation.
[[locking-optimistic-version-number-example]]
.@Version annotation
====
[source,java]
[source, JAVA, indent=0]
----
include::{sourcedir}/version_annotation.java[]
include::{sourcedir}/OptimisticLockingTest.java[tags=locking-optimistic-version-number-example]
----
====
Here, the version property is mapped to the `OPTLOCK` column, and the entity manager uses it to detect conflicting updates,
Here, the version property is mapped to the `version` column, and the entity manager uses it to detect conflicting updates,
and prevent the loss of updates that would otherwise be overwritten by a last-commit-wins strategy.
The version column can be any kind of type, as long as you define and implement the appropriate `UserVersionType`.
@ -62,39 +63,18 @@ To artificially increase the version number, see the documentation for propertie
If the version number is generated by the database, such as a trigger, use the annotation `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` on the version attribute.
====
.Declaring a version property in `hbm.xml`
====
[source,xml]
----
include::{sourcedir}/version_property.xml[]
----
====
[cols=",",]
|=======================================================================
|column |The name of the column holding the version number. Optional, defaults to the property name.
|name |The name of a property of the persistent class.
|type |The type of the version number. Optional, defaults to `integer`.
|access |Hibernate's strategy for accessing the property value. Optional, defaults to `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 |Indicates that the version property value is generated by the database. Optional, defaults to `never`.
|insert |Whether or not to include the `version` column in SQL `insert` statements.
Defaults to `true`, but you can set it to `false` if the database column is defined with a default value of `0`.
|=======================================================================
[[locking-optimistic-timestamp]]
=== Timestamp
Timestamps are a less reliable way of optimistic locking than version numbers, but can be used by applications for other purposes as well.
Timestamping is automatically used if you the `@Version` annotation on a `Date` or `Calendar` property type.
[[locking-optimistic-version-timestamp-example]]
.Using timestamps for optimistic locking
====
[source,java]
[source, JAVA, indent=0]
----
include::{sourcedir}/timestamp_version.java[]
include::{sourcedir}/OptimisticLockingTest.java[tags=locking-optimistic-version-timestamp-example]
----
====
@ -104,30 +84,6 @@ The default behavior is to use the database, and is also used if you don't speci
The timestamp can also be generated by the database instead of Hibernate, if you use the `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` annotation.
.The timestamp element in `hbm.xml`
====
[source,xml]
----
include::{sourcedir}/timestamp_version.xml[]
----
====
[cols=",",]
|=======================================================================
|column |The name of the column which holds the timestamp. Optional, defaults to the property name
|name |The name of a JavaBeans style property of Java type `Date` or `Timestamp` of the persistent class.
|access |The strategy Hibernate uses to access the property value. Optional, defaults to `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 |Whether the timestamp property value is generated by the database. Optional, defaults to `never`.
|=======================================================================
[[locking-pessimistic]]
=== Pessimistic
@ -185,7 +141,7 @@ The scope can either be `NORMAL` (default value) or `EXTENDED`. The `EXTENDED` s
====
[source, JAVA, indent=0]
----
include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java[tags=locking-jpa-query-hints-timeout-example]
include::{sourcedir}/ExplicitLockingTest.java[tags=locking-jpa-query-hints-timeout-example]
----
[source, SQL, indent=0]
@ -218,7 +174,7 @@ The following example shows how to obtain shared database lock without waiting f
====
[source, JAVA, indent=0]
----
include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/locking/ExplicitLockingTest.java[tags=locking-buildLockRequest-example]
include::{sourcedir}/ExplicitLockingTest.java[tags=locking-buildLockRequest-example]
----
[source, SQL, indent=0]

View File

@ -1,8 +0,0 @@
@Entity
public class Flight implements Serializable {
...
@Version
public Date getLastUpdate() {...}
}

View File

@ -1,11 +0,0 @@
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
int updatedEntities = session.createQuery(
"update versioned Customer set name = :newName where name = :oldName" )
.setString( "newName",newName )
.setString( "oldName",oldName )
.executeUpdate();
tx.commit();
session.close();

View File

@ -1,9 +0,0 @@
@Entity
public class Flight implements Serializable {
...
@Version
@Column( name = "OPTLOCK" )
public Integer getVersion() {...}
}

View File

@ -27,8 +27,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
/**
* <code>AlwaysFlushTest</code> - Always Flush Test
*
* @author Vlad Mihalcea
*/
public class AlwaysFlushTest extends BaseEntityManagerFunctionalTestCase {

View File

@ -23,8 +23,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
/**
* <code>AlwaysFlushTest</code> - Always Flush Test
*
* @author Vlad Mihalcea
*/
public class AutoFlushTest extends BaseEntityManagerFunctionalTestCase {

View File

@ -27,8 +27,6 @@ import static org.junit.Assert.assertTrue;
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
/**
* <code>CommitFlushTest</code> - Commit Flush Test
*
* @author Vlad Mihalcea
*/
public class CommitFlushTest extends BaseEntityManagerFunctionalTestCase {

View File

@ -28,8 +28,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
import static org.junit.Assert.assertTrue;
/**
* <code>ManualFlushTest</code> - Manual Flush Test
*
* @author Vlad Mihalcea
*/
public class ManualFlushTest extends BaseEntityManagerFunctionalTestCase {

View File

@ -27,8 +27,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* <code>BuildLockRequestTest</code> - Build Lock Request Test
*
* @author Vlad Mihalcea
*/
public class ExplicitLockingTest extends BaseEntityManagerFunctionalTestCase {

View File

@ -0,0 +1,146 @@
package org.hibernate.userguide.locking;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Version;
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
import org.junit.Test;
import org.jboss.logging.Logger;
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
/**
* @author Vlad Mihalcea
*/
public class OptimisticLockingTest extends BaseEntityManagerFunctionalTestCase {
private static final Logger log = Logger.getLogger( OptimisticLockingTest.class );
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class<?>[] {
Person.class,
Phone.class
};
}
@Test
public void test() {
Phone _phone = doInJPA( this::entityManagerFactory, entityManager -> {
Person person = new Person( );
person.setName( "John Doe" );
entityManager.persist( person );
Phone phone = new Phone( );
phone.setNumber( "123-456-7890" );
phone.setPerson( person );
entityManager.persist( phone );
return phone;
} );
doInJPA( this::entityManagerFactory, entityManager -> {
Person person = entityManager.find( Person.class, _phone.getPerson().getId() );
person.setName( person.getName().toUpperCase() );
Phone phone = entityManager.find( Phone.class, _phone.getId() );
phone.setNumber( phone.getNumber().replace( "-", " ") );
} );
}
@Entity(name = "Person")
public static class Person {
@Id
@GeneratedValue
private Long id;
@Column(name = "`name`")
private String name;
//tag::locking-optimistic-version-number-example[]
@Version
private long version;
//end::locking-optimistic-version-number-example[]
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
}
@Entity(name = "Phone")
public static class Phone {
@Id
@GeneratedValue
private Long id;
private String number;
@ManyToOne
private Person person;
//tag::locking-optimistic-version-timestamp-example[]
@Version
private Date version;
//end::locking-optimistic-version-timestamp-example[]
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public Date getVersion() {
return version;
}
public void setVersion(Date version) {
this.version = version;
}
}
}

View File

@ -14,8 +14,6 @@ import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
import static org.junit.Assert.assertEquals;
/**
* <code>BulkTest</code> - Bulk JPQL Test
*
* @author Vlad Mihalcea
*/
public class BulkTest extends BaseEntityManagerFunctionalTestCase {