Hi habr! In this article there will be no in-depth analysis of the json type in PostgreSQL or the next
useless attempts to compare this PostgreSQL feature with NoSQL databases like MongoDB. I'll just talk about how to use Hibernate and PostgreSQL json. I think someone this may be useful.
Object inside an entity
Suppose you have a relational data model. A situation may well arise that for some of the entities it is necessary to store an object (a document, if you wish). Of course, you can extend the data model for this object with a single (or maybe several) entity, or simply store this object as an array of bytes. But for PostgreSQL, a
json data type capable of storing a json object in accordance with
RFC 4627 has appeared for quite some time. It became interesting how it can be used, and what opportunities it can provide. When I first accessed
google, I found several unstructured posts and Q & A that explained something, but did not give a complete picture. Having poked around a bit and figured out what was happening, I came to the conclusion that using these fields is very convenient, and decided to create a
small library that will simplify the use of json types. Below I will tell you how to use it, well, a little more comparison with the first alternatives that come to mind.
Dialect
Of course, there is no talk of any support for this type in the standard dialect. I would very much like hibernate to recognize the type itself and validate / update the schema. Therefore, the library contains a JsonPostgreSQLDialect dialect extending PostgreSQL9Dialect. Just use this dialect in your persistance.xml.
Storage facility
You can store the json field in both object and Map. If you want to store an object, then it is enough to inherit the class that you are going to store PGJsonObject
public class CacheObject extends PGJsonObject { ... }
and use annotations to define the type in your Entity:
@Entity @TypeDefs({@TypeDef( name= "JsonObject", typeClass = CacheObject.class)}) public class Product { ... @Type(type = "JsonObject") public CacheObject getCache() { return cache; } }
If this breaks your inheritance scheme, you can create a class separate from your class for storage that is responsible for the type. It will inherit the same PGJsonObject, and must override the returnedClass () method, which will return the class of the object you want to store. This class will then need to be used in your Entity to determine the type.
public class JsonCustomType extends PGJsonObject { @Override public Class returnedClass() { return Custom.class; } }
Then the type definition in Entity will look like this:
@Entity @TypeDefs({@TypeDef( name= "JsonObject", typeClass = JsonCustomType.class)}) public class Product { ... @Type(type = "JsonObject") public Custom getCustom() { return custom; } }
If you are going to store the Map, then simply use the type JsonMapType already available in the library.
')
Recommendations
- Be careful with changing object data. If the object that you are storing is not immutable, then any changes that you make in it will be saved to the database (of course, if the transaction does not roll back), so if you do not want to save the changes, make a copy
- Check your native requests. Make sure your Entity is listed.
Benefits of JSON Fields
Immediately comes to mind 2 alternative implementations
- Expand the database schema for the object
- store byte array
The first option can greatly complicate your data model, if the object has a deep hierarchy. If an object stores a large array, such as an array of points, then a table with points can have a huge number of records, which can slow down the selection. Also, with this option, the application should know everything about the data schema in order to pull them out of the table.
In the second variant, no schema extension is required, but the information stored in this field is absolutely not representative and not indexable. And as in the previous case, the application should be aware of the structure of the stored data, only this time for proper deserialization.
When using json fields, all information in the database is presented in a readable form. Also in
jar functions in PostgreSQL, you can write convenient native query for selection on certain fields of a json object. And thanks to
expression indexes, you can hang the index on any field of your json object.
Also, using json fields can be a great help in integration tasks. By saving an object in one json field, in another you can drag a Map out of it, and vice versa. If you know only a part of the object structure, you can deserialize only the part of the json object that you need and know into a java-object, and either ignore the rest or deserialize it again into a Map.
The source code of the project can be found on
github . So far, the project is raw. I hope in the future to simplify use, enter annotations.