Migrate User Guide Locking chapter extras to test folder and old xml mapping to the Legacy appendix
This commit is contained in:
parent
f8e7799848
commit
aeac516eeb
|
@ -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[]
|
||||
|
|
|
@ -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`.
|
||||
|=======================================================================
|
|
@ -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]
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
@Entity
|
||||
public class Flight implements Serializable {
|
||||
|
||||
...
|
||||
|
||||
@Version
|
||||
public Date getLastUpdate() {...}
|
||||
}
|
|
@ -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();
|
|
@ -1,9 +0,0 @@
|
|||
@Entity
|
||||
public class Flight implements Serializable {
|
||||
|
||||
...
|
||||
|
||||
@Version
|
||||
@Column( name = "OPTLOCK" )
|
||||
public Integer getVersion() {...}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue