Reputation: 490
I am starting new project using Postgres and hibernate (5.5.7) as the ORM, however I have recently read the following wiki page:
https://wiki.postgresql.org/wiki/Don%27t_Do_This
Based on that I would like to change some of the default column mappings, specifically:
Reading through the hibernate code it appears that the length, precision and scale are hardcoded in the class: org.hibernate.mapping.Column, specifically:
public static final int DEFAULT_LENGTH = 255;
public static final int DEFAULT_PRECISION = 19;
public static final int DEFAULT_SCALE = 2;
For the 2nd and 3rd cases (varchar and numeric) I don't see any easy way to change the default (length, precision and scale), so the best option I have been able to come up with is to create a new custom "Dialect" extending from PostgreSQL95Dialect who's constructor redefines the mappings as follows:
registerColumnType(Types.TIMESTAMP, "timestamptz");
registerColumnType(Types.VARCHAR, "varchar");
registerColumnType(Types.NUMERIC, "numeric($p, 5)");
Using this overridden dialect I can generate a schema which includes the changes I am trying to achieve.
I am happy with the timestamp change since I don't see any use cases where I would need to store a timestamp without the timezone (I typically use Instant's (UTC time) in my model).
I can't foresee a problem with the varchar change since all validation occurs when data is sent into the system (Rest service).
However I have lost the capability to use the (@Column) scale attribute - I have to use an explicit "columnDefinition" if I want to specify a different scale.
This still leaves me with the following questions:
Upvotes: 1
Views: 994
Reputation: 16430
Well, if you really must do this, it's fine, but I wouldn't recommend you to do this. The default values usually come from the @Column
annotation. So I would recommend you simply set proper values everywhere in your model. IMO the only okish thing you did is the switch to timestamptz
but you didn't understand how the type works correctly. The type does not store the timezone, but instead will normalize to UTC.
The next problem IMO is that you switch to an unbounded varchar. It might be "discouraged" to use a length limit, but believe me, it will save you a lot of trouble in the long run. There was just recently a blog post about switching back to length limited varchar due to users saving way too big texts. So even if you believe that you validated the lengths, you probably won't get this right for all future uses. Increasing the limit is easy and doesn't require any expensive locks, so if you already define some limits on your REST API, it would IMO be stupid not to model this in the database as well. Or are you omitting foreign key constraints just because your REST API also validates that? No you are not, and every DBA will tell you that you should never omit such constraints. These constraints are valuable.
As for numerics, just bite the sour apply and apply the values on all @Column
annotations. You can use some kind of constant holder class to avoid inconsistencies:
public class MyConstants {
public static final int VARCHAR_SMALL = 1000;
public static final int VARCHAR_MEDIUM = 5000;
public static final int VARCHAR_LARGE = 10000;
public static final int PRICE_PRECISION = 19;
public static final int PRICE_SCALE = 5;
}
and use it like @Column(precision = MyConstants.PRICE_PRECISION, scale = MyConstants.PRICE_SCALE)
Upvotes: 1