HHH-11186 - Add examples for all Hibernate annotations
Document @Source and @RowId annotation
This commit is contained in:
parent
e2e48e4e07
commit
ec165296c6
|
@ -1139,7 +1139,7 @@ For instance, Oracle defines the https://docs.oracle.com/cd/B19306_01/server.102
|
|||
|
||||
According to Oracle documentation, `ROWID` is the fastest way to access a single row from a table.
|
||||
|
||||
//TODO: Add example
|
||||
See the <<chapters/domain/identifiers.adoc#identifiers-rowid, `@RowId` mapping>> section for more info.
|
||||
|
||||
[[annotations-hibernate-selectbeforeupdate]]
|
||||
==== `@SelectBeforeUpdate`
|
||||
|
@ -1178,7 +1178,7 @@ The `SourceType` offers two options:
|
|||
DB:: Get the timestamp from the database.
|
||||
VM:: Get the timestamp from the current JVM.
|
||||
|
||||
//TODO: Add example
|
||||
See the <<chapters/locking/Locking.adoc#locking-optimistic-version-timestamp-source-mapping-example, Database-generated version timestamp mapping>> section for more info.
|
||||
|
||||
[[annotations-hibernate-sqldelete]]
|
||||
==== `@SQLDelete`
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
SELECT
|
||||
p.id as id1_0_0_,
|
||||
p."name" as name2_0_0_,
|
||||
p."number" as number3_0_0_,
|
||||
p.ROWID as rowid_0_
|
||||
FROM
|
||||
Product p
|
||||
WHERE
|
||||
p.id = ?
|
||||
|
||||
-- binding parameter [1] as [BIGINT] - [1]
|
||||
|
||||
-- extracted value ([name2_0_0_] : [VARCHAR]) - [Mobile phone]
|
||||
-- extracted value ([number3_0_0_] : [VARCHAR]) - [123-456-7890]
|
||||
-- extracted ROWID value: AAAwkBAAEAAACP3AAA
|
||||
|
||||
UPDATE
|
||||
Product
|
||||
SET
|
||||
"name" = ?,
|
||||
"number" = ?
|
||||
WHERE
|
||||
ROWID = ?
|
||||
|
||||
-- binding parameter [1] as [VARCHAR] - [Smart phone]
|
||||
-- binding parameter [2] as [VARCHAR] - [123-456-7890]
|
||||
-- binding parameter [3] as ROWID - [AAAwkBAAEAAACP3AAA]
|
|
@ -469,4 +469,35 @@ include::{extrasdir}/id/CompositeIdAssociationPrimaryKeyJoinColumn.java[]
|
|||
[NOTE]
|
||||
====
|
||||
Unlike `@MapsId`, the application developer is responsible for ensuring that the identifier and the many-to-one (or one-to-one) association are in sync.
|
||||
====
|
||||
|
||||
[[identifiers-rowid]]
|
||||
==== @RowId
|
||||
|
||||
If you annotate a given entity with the `@RowId` annotation and the underlying database supports fetching a record by ROWID (e.g. Oracle),
|
||||
then Hibernate can use the `ROWID` pseudo-column for CRUD operations.
|
||||
|
||||
[[identifiers-rowid-mapping]]
|
||||
.`@RowId` entity maapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/RowIdTest.java[tag=identifiers-rowid-mapping]
|
||||
----
|
||||
====
|
||||
|
||||
Now, when fetching an entity and modifying it, Hibernate uses the `ROWID` pseudo-column for the UPDATE SQL statement.
|
||||
|
||||
[[identifiers-rowid-example]]
|
||||
.`@RowId` example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/RowIdTest.java[tag=identifiers-rowid-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/id/identifiers-rowid-example.sql[]
|
||||
----
|
||||
====
|
|
@ -82,7 +82,33 @@ Hibernate can retrieve the timestamp value from the database or the JVM, by read
|
|||
The value can be either `org.hibernate.annotations.SourceType.DB` or `org.hibernate.annotations.SourceType.VM`.
|
||||
The default behavior is to use the database, and is also used if you don't specify the annotation at all.
|
||||
|
||||
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 can also be generated by the database instead of Hibernate
|
||||
if you use the `@org.hibernate.annotations.Generated(GenerationTime.ALWAYS)` or the `@Source` annotation.
|
||||
|
||||
[[locking-optimistic-version-timestamp-source-mapping-example]]
|
||||
.Database-generated version timestamp mapping
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/VersionSourceTest.java[tags=locking-optimistic-version-timestamp-source-mapping-example]
|
||||
----
|
||||
====
|
||||
|
||||
Now, when persisting a `Person` entity, Hibernate calls the database-specific current timestamp retrieval function:
|
||||
|
||||
[[locking-optimistic-version-timestamp-source-persist-example]]
|
||||
.Database-generated version timestamp example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/VersionSourceTest.java[tags=locking-optimistic-version-timestamp-source-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/locking-optimistic-version-timestamp-source-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[locking-pessimistic]]
|
||||
=== Pessimistic
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
CALL current_timestamp()
|
||||
|
||||
INSERT INTO
|
||||
Person
|
||||
(firstName, lastName, version, id)
|
||||
VALUES
|
||||
(?, ?, ?, ?)
|
||||
|
||||
-- binding parameter [1] as [VARCHAR] - [John]
|
||||
-- binding parameter [2] as [VARCHAR] - [Doe]
|
||||
-- binding parameter [3] as [TIMESTAMP] - [2017-05-18 12:03:03.808]
|
||||
-- binding parameter [4] as [BIGINT] - [1]
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.locking;
|
||||
|
||||
import java.util.Date;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.annotations.Source;
|
||||
import org.hibernate.annotations.SourceType;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class VersionSourceTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::locking-optimistic-version-timestamp-source-persist-example[]
|
||||
Person person = new Person();
|
||||
person.setId( 1L );
|
||||
person.setFirstName( "John" );
|
||||
person.setLastName( "Doe" );
|
||||
assertNull( person.getVersion() );
|
||||
|
||||
entityManager.persist( person );
|
||||
assertNotNull( person.getVersion() );
|
||||
//end::locking-optimistic-version-timestamp-source-persist-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::locking-optimistic-version-timestamp-source-mapping-example[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
private String firstName;
|
||||
|
||||
private String lastName;
|
||||
|
||||
@Version
|
||||
@Source(value = SourceType.DB)
|
||||
private Date version;
|
||||
//end::locking-optimistic-version-timestamp-source-mapping-example[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public Date getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
//tag::locking-optimistic-version-timestamp-source-mapping-example[]
|
||||
}
|
||||
//end::locking-optimistic-version-timestamp-source-mapping-example[]
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.mapping.identifier;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.annotations.Formula;
|
||||
import org.hibernate.annotations.RowId;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(Oracle8iDialect.class)
|
||||
public class RowIdTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Product.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Product product = new Product();
|
||||
product.setId( 1L );
|
||||
product.setName( "Mobile phone" );
|
||||
product.setNumber( "123-456-7890" );
|
||||
entityManager.persist( product );
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
//tag::identifiers-rowid-example[]
|
||||
Product product = entityManager.find( Product.class, 1L );
|
||||
|
||||
product.setName( "Smart phone" );
|
||||
//end::identifiers-rowid-example[]
|
||||
} );
|
||||
}
|
||||
|
||||
//tag::identifiers-rowid-mapping[]
|
||||
@Entity(name = "Product")
|
||||
@RowId("ROWID")
|
||||
public static class Product {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
@Column(name = "`name`")
|
||||
private String name;
|
||||
|
||||
@Column(name = "`number`")
|
||||
private String number;
|
||||
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
//end::identifiers-rowid-mapping[]
|
||||
|
||||
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 String getNumber() {
|
||||
return number;
|
||||
}
|
||||
|
||||
public void setNumber(String number) {
|
||||
this.number = number;
|
||||
}
|
||||
|
||||
|
||||
//tag::identifiers-rowid-mapping[]
|
||||
}
|
||||
//end::identifiers-rowid-mapping[]
|
||||
}
|
|
@ -27,6 +27,8 @@ log4j.logger.org.hibernate.SQL=debug
|
|||
### log JDBC bind parameters ###
|
||||
log4j.logger.org.hibernate.type=trace
|
||||
log4j.logger.org.hibernate.type.descriptor.sql=trace
|
||||
log4j.logger.org.hibernate.persister.entity.AbstractEntityPersister=trace
|
||||
log4j.logger.org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl=trace
|
||||
|
||||
### log schema export/update ###
|
||||
log4j.logger.org.hibernate.tool.hbm2ddl=info
|
||||
|
|
|
@ -328,6 +328,13 @@ public class EntityReferenceInitializerImpl implements EntityReferenceInitialize
|
|||
rowId = concreteEntityPersister.hasRowId()
|
||||
? resultSet.getObject( entityReferenceAliases.getColumnAliases().getRowIdAlias() )
|
||||
: null;
|
||||
|
||||
if ( rowId != null && log.isTraceEnabled() ) {
|
||||
log.tracev(
|
||||
"extracted ROWID value: {0}",
|
||||
rowId
|
||||
);
|
||||
}
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw context.getSession().getFactory().getServiceRegistry().getService( JdbcServices.class ).getSqlExceptionHelper().convert(
|
||||
|
|
|
@ -2746,6 +2746,16 @@ public abstract class AbstractEntityPersister
|
|||
final SharedSessionContractImplementor session,
|
||||
int index) throws SQLException {
|
||||
if ( rowId != null ) {
|
||||
if ( LOG.isTraceEnabled() ) {
|
||||
LOG.tracev(
|
||||
String.format(
|
||||
"binding parameter [%s] as ROWID - [%s]",
|
||||
index,
|
||||
rowId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
ps.setObject( index, rowId );
|
||||
return 1;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue