column lengths and LOBs
This commit is contained in:
parent
e1160fec91
commit
6edefe6f4d
|
@ -226,6 +226,7 @@ With rare exception, the default behavior of every one of these settings was car
|
|||
The properties you really do need to get started are these three:
|
||||
|
||||
.JDBC connection settings
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
@ -255,6 +256,7 @@ This pool is not meant for use in production, and later, when we discuss perform
|
|||
Alternatively, in a container environment, you'll need at least one of these properties:
|
||||
|
||||
.Transaction management settings
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
@ -276,7 +278,7 @@ initialization time by specifying one or more of the following configuration
|
|||
properties:
|
||||
|
||||
.Schema management settings
|
||||
[cols="1,1"]
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
@ -339,6 +341,7 @@ logger.hibernate.level = debug
|
|||
You can make the logged SQL more readable by enabling one or both of the following settings:
|
||||
|
||||
.Setting for SQL logging to the console
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
@ -353,6 +356,7 @@ These settings can really help when troubleshooting SQL.
|
|||
The following properties are very useful for minimizing the amount of information you'll need to explicitly specify in `@Table` and `@Column` annotations, which we'll discuss below in <<mapping-entity-classes>>:
|
||||
|
||||
.Settings for minimizing explicit mapping information
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
@ -376,7 +380,8 @@ Please refer to the Javadoc for these interfaces for more information about the
|
|||
|
||||
_By default,_ SQL Server's `char` and `varchar` types don't accommodate Unicode data. So, if you're working with SQL Server, you might need to force Hibernate to use the `nchar` and `nvarchar` types.
|
||||
|
||||
.Setting the use of nationalized charcter data
|
||||
.Setting the use of nationalized character data
|
||||
[cols=",2"]
|
||||
|===
|
||||
| Configuration property name | Purpose
|
||||
|
||||
|
|
|
@ -208,6 +208,7 @@ On the other hand, if, as is more common, you're working with a pre-existing dat
|
|||
JPA defines the following strategies for generating ids, which are enumerated by `GenerationType`:
|
||||
|
||||
.Standard id generation strategies
|
||||
[cols="3,2,6"]
|
||||
|===
|
||||
| Strategy | Java type | Implementation
|
||||
|
||||
|
@ -215,7 +216,7 @@ JPA defines the following strategies for generating ids, which are enumerated by
|
|||
| `GenerationType.IDENTITY` | `Long` or `Integer` | An identity or autoincrement column.
|
||||
| `GenerationType.SEQUENCE` | `Long` or `Integer` | A database sequence.
|
||||
| `GenerationType.TABLE` | `Long` or `Integer` | A database table.
|
||||
| `GenerationType.AUTO` | `Long` or `Integer` | Selects `SEQUENCE` `TABLE`, or `UUID` based on the identifier type and capabilities of the database.
|
||||
| `GenerationType.AUTO` | `Long` or `Integer` | Selects `SEQUENCE`, `TABLE`, or `UUID` based on the identifier type and capabilities of the database.
|
||||
|===
|
||||
|
||||
For example, the following id maps to a SQL `identity`, `auto_increment`, or `bigserial` column:
|
||||
|
@ -447,6 +448,7 @@ A _basic_ attribute of an entity is a field or property which maps to a single c
|
|||
The JPA specification defines a quite limited set of basic types:
|
||||
|
||||
.JPA-standard basic attribute types
|
||||
[cols="3,2,6"]
|
||||
|====
|
||||
| Classification | Package | Types
|
||||
|
||||
|
@ -476,6 +478,17 @@ Serializing a Java object and storing its binary representation in the database
|
|||
As we'll soon see in <<embeddable-objects>>, Hibernate has much better ways to handle complex Java objects.
|
||||
====
|
||||
|
||||
Hibernate slightly extends this list with the following types:
|
||||
|
||||
.Additional basic attribute types in Hibernate
|
||||
[cols="3,2,6"]
|
||||
|====
|
||||
| Classification | Package | Types
|
||||
|
||||
| Date/time types | `java.time` | `Duration`, `ZoneId`, `ZoneOffset`, `ZonedDateTime`, `Year`
|
||||
| Miscellaneous | `java.util` | `Currency`, `URL`
|
||||
|====
|
||||
|
||||
The `@Basic` annotation explicitly specifies that an attribute is basic, but it's often not needed, since attributes are assumed basic by default.
|
||||
On the other hand, if an attribute cannot be null, use of `@Basic(optional=false)` is highly recommended.
|
||||
|
||||
|
@ -1203,18 +1216,18 @@ Let's pause to remember the annotations we've met so far.
|
|||
|===
|
||||
|
||||
.Declaring basic attributes
|
||||
[cols="2,4,1"]
|
||||
[cols="2,4,2,1"]
|
||||
|===
|
||||
| Annotation | Purpose | JPA-standard
|
||||
| Annotation | Purpose | Required | JPA-standard
|
||||
|
||||
| `@Id` | Declare a basic-typed identifier attribute | ✓
|
||||
| `@Version` | Declare a version attribute | ✓
|
||||
| `@Basic` | (Optional) Declare a basic attribute | ✓
|
||||
| `@EmbeddedId` | Declare an embeddable-typed identifier attribute | ✓
|
||||
| `@Embedded` | (Optional) Declare an embeddable-typed attribute | ✓
|
||||
| `@Enumerated` | (Optional) Declare an `enum`-typed attribute and specify how it is encoded | ✓
|
||||
| `@Array` | (Optional) Declare that an attribute maps to a SQL `ARRAY`, and specify the length | ✗
|
||||
| `@ElementCollection` | Declare that a collection is mapped to a dedicated table | ✓
|
||||
| `@Id` | Declare a basic-typed identifier attribute | Yes | ✓
|
||||
| `@Version` | Declare a version attribute | Yes | ✓
|
||||
| `@Basic` | Declare a basic attribute | No | ✓
|
||||
| `@EmbeddedId` | Declare an embeddable-typed identifier attribute | Yes | ✓
|
||||
| `@Embedded` | Declare an embeddable-typed attribute | No | ✓
|
||||
| `@Enumerated` | Declare an `enum`-typed attribute and specify how it is encoded | No | ✓
|
||||
| `@Array` | Declare that an attribute maps to a SQL `ARRAY`, and specify the length | No | ✗
|
||||
| `@ElementCollection` | Declare that a collection is mapped to a dedicated table | Yes | ✓
|
||||
|===
|
||||
|
||||
.Converters and compositional basic types
|
||||
|
|
|
@ -156,6 +156,7 @@ is a bad idea, since it's impossible to create a foreign key constraint that tar
|
|||
The following annotations specify exactly how elements of the domain model map to tables of the relational model:
|
||||
|
||||
.Annotations for mapping tables
|
||||
[cols=",5"]
|
||||
|===
|
||||
| Annotation | Purpose
|
||||
|
||||
|
@ -187,6 +188,7 @@ class Book { ... }
|
|||
The `@Table` annotation can do more than just specify a name:
|
||||
|
||||
.`@Table` annotation members
|
||||
[cols=",8"]
|
||||
|===
|
||||
| Annotation member | Purpose
|
||||
|
||||
|
@ -208,6 +210,7 @@ It's usually better to set the configuration properties `hibernate.default_schem
|
|||
The `@SecondaryTable` annotation is even more interesting:
|
||||
|
||||
.`@SecondaryTable` annotation members
|
||||
[cols=",8"]
|
||||
|===
|
||||
| Annotation member | Purpose
|
||||
|
||||
|
@ -228,6 +231,7 @@ To understand this annotation better, we must first discuss column mappings in g
|
|||
These annotations specify how elements of the domain model map to columns of tables in the relational model:
|
||||
|
||||
.Annotations for mapping columns
|
||||
[cols=",5"]
|
||||
|===
|
||||
| Annotation | Purpose
|
||||
|
||||
|
@ -246,6 +250,7 @@ We use the `@Column` annotation to map basic attributes.
|
|||
The `@Column` annotation is not only useful for specifying the column name.
|
||||
|
||||
.`@Column` annotation members
|
||||
[cols=",8"]
|
||||
|===
|
||||
| Annotation member | Purpose
|
||||
|
||||
|
@ -299,6 +304,7 @@ We don't use `@Column` to map associations.
|
|||
The `@JoinColumn` annotation is used to customize a foreign key column.
|
||||
|
||||
.`@JoinColumn` annotation members
|
||||
[cols=",8"]
|
||||
|===
|
||||
| Annotation member | Purpose
|
||||
|
||||
|
@ -346,6 +352,7 @@ The `@PrimaryKeyJoinColumn` is a special-purpose annotation for mapping:
|
|||
- the primary key column of the primary table mapped by a subclass in a `JOINED` inheritance hierarchy—which is also a foreign key referencing the primary table mapped by the root entity.
|
||||
|
||||
.`@PrimaryKeyJoinColumn` annotation members
|
||||
[cols=",8"]
|
||||
|===
|
||||
| Annotation member | Purpose
|
||||
|
||||
|
@ -387,3 +394,73 @@ class Book {
|
|||
}
|
||||
----
|
||||
|
||||
[[column-lengths]]
|
||||
=== Column lengths and adaptive column types
|
||||
|
||||
Hibernate automatically adjusts the column type used in generated DDL based on the column length specified by the `@Column` annotation.
|
||||
So we don't usually need to explicitly specify that a column should be of type `TEXT` or `CLOB`—or worry about the parade of `TINYTEXT`, `MEDIUMTEXT`, `TEXT`, `LONGTEXT` types on MySQL—because Hibernate will automatically select one of those types if required to accommodate a string of the `length` we specify.
|
||||
|
||||
The constant values defined in the class `org.hibernate.Length` are very helpful here:
|
||||
|
||||
.Predefined column lengths
|
||||
[cols=",,8"]
|
||||
|===
|
||||
| Constant | Value | Description
|
||||
|
||||
| `DEFAULT` | 255 | The default length of a `VARCHAR` or `VARBINARY` column when none is explicitly specified
|
||||
| `LONG` | 32600 | The largest column length for a `VARCHAR` or `VARBINARY` that is allowed on every database Hibernate supports
|
||||
| `LONG16` | 32767 | The maximum length that can be represented using 16 bits (but this length is too large for a `VARCHAR` or `VARBINARY` column on for some database)
|
||||
| `LONG32` | 2147483647 | The maximum length for a Java string
|
||||
|===
|
||||
|
||||
We can use these constants in the `@Column` annotation:
|
||||
|
||||
[source,java]
|
||||
----
|
||||
@Column(length=LONG)
|
||||
String text;
|
||||
|
||||
@Column(length=LONG32)
|
||||
byte[] binaryData;
|
||||
----
|
||||
|
||||
This is usually all you need to do to make use of large object types in Hibernate.
|
||||
|
||||
[[lobs]]
|
||||
=== LOBs
|
||||
|
||||
JPA provides a `@Lob` annotation which specifies that a field should be persisted as a `BLOB` or `CLOB`.
|
||||
|
||||
[NOTE]
|
||||
.Semantics of the `@Lob` amnotation
|
||||
====
|
||||
What the spec actually says is that the field should be persisted
|
||||
|
||||
> as a large object to a database-supported large object type.
|
||||
|
||||
It's quite unclear what this means, and the spec goes on to say that
|
||||
|
||||
> the treatment of the `Lob` annotation is provider-dependent
|
||||
|
||||
which doesn't help much.
|
||||
====
|
||||
|
||||
Hibernate interprets this annotation in what we think is the most reasonable way.
|
||||
In Hibernate, an attribute annotated `@Lob` will be written to JDBC using the `setClob()` or `setBlob()` method of `PreparedStatement`, and will be read from JDBC using the `getClob()` or `getBlob()` method of `ResultSet`.
|
||||
|
||||
Now, the use of these JDBC methods is usually unnecessary!
|
||||
JDBC drivers are perfectly capable of converting between `String` and `CLOB` or between `byte[]` and `BLOB`.
|
||||
So unless you specifically need to use these JDBC LOB APIs, you _don't_ need the `@Lob` annotation.
|
||||
|
||||
Instead, as we just saw in <<column-lengths>>, all you need is to specify a large enough column `length` to accommodate the data you plan to write to that column.
|
||||
|
||||
[WARNING]
|
||||
.PostgreSQL `BYTEA` and `TEXT`
|
||||
====
|
||||
Unfortunately, the driver for PostgreSQL does not allow `BYTEA` or `TEXT` columns to be read via the JDBC LOB APIs.
|
||||
|
||||
This limitation of the Postgres driver has resulted in a whole cottage industry of bloggers and stackoverflow question-answerers recommending convoluted ways to hack the Hibernate `Dialect` for Postgres to allow an attribute annotated `@Lob` to be written using `setString()` and read using `getString()`.
|
||||
|
||||
But _simply removing the `@Lob` annotation has exactly the same effect!_
|
||||
====
|
||||
|
||||
|
|
Loading…
Reference in New Issue