Best type for JPA version field for Optimistic locking - jpa

I have doubts about which is the best type for a field annotated with #Version for optimistic locking in JPA.
The API javadoc (http://docs.oracle.com/javaee/7/api/javax/persistence/Version.html) says:
"The following types are supported for version properties: int, Integer, short, Short, long, Long, java.sql.Timestamp."
In other page (http://en.wikibooks.org/wiki/Java_Persistence/Locking#Optimistic_Locking) says:
"JPA supports using an optimistic locking version field that gets updated on each update. The field can either be numeric or a timestamp value. A numeric value is recommended as a numeric value is more precise, portable, performant and easier to deal with than a timestamp."
"Timestamp locking is frequently used if the table already has a last updated timestamp column, and is also a convenient way to auto update a last updated column. The timestamp version value can be more useful than a numeric version, as it includes the relevant information on when the object was last updated."
The questions I have are:
Is better a Timestamp type if you are going to have a lastUpdated field or is better to have a numeric version field and the timestamp in other field?
Between numeric types (int, Integer, short, Short, long, Long) which is the best to choose (considering the length of each type)? I mean, I think the best is Long but it requires a lot of space for each row.
What happens when the version field gets to the last number of a numeric type (for example 32,767 in a Short field)? Will it start from 1 again in the next increment?

Just go with Long or Integer.
BUT don't go with int or long.
In opposite to other comment here, null value is expected when entity was never persisted yet.
Having int or long might make Hibernate to think that entity is already persisted and in detached state as version value will be 0 when unset.
Just finished debugging a FK violation where "int" was the cause, so save your time and just go with Long or Integer.

First, know that locking is used to managed concurrent transactions.
1.Separate your concerns. If lastupdated field is business model specific, it should be separate from your versioning field - which is for - versioning.
2.Primitives and objects are usually mapped to your db as the same type. Except for the fact that Boolean by default will be nullable and boolean will be 'not nullable'. However, enforce nullability explicitly. In this case you want to use a primitive as the version field can't be nullable.
Integer or long are better than timestamp. Hibernate recommends numeric versionig and they don't take that much space.
If you use long, you might not live to find out.
Use this and you should be fine.
private long version;
#Version
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}

Don't use a time value like Timestamp (or derivates like Instant or LocalDateTime etc...).
Especially if you have a Java < 15 application and hope to ever migrate to Java >= 15. They changed the precision of timestamps within Java to nano-seconds, but your database probably only stores up to microseconds, so it truncates the value, which will make you run into an OptimisticLockException all the time (1).
Neither use a primitive value, see the answer from #Piotr: The Version field must be null for new entities.
Just go with Long.

Related

What are Pros and Cons in using prefixes and suffixes in PostgreSQL dialect for timestamp columns

I have analysed several articles about naming conventions for Date/Time types in SQL data models.
Most of them suggest implementing a database design where a timestamp type is used for some registered even values only, literally timestamping the event case just when it happens. And naturally they suggest datetime type for any other time instanting needs. And they suggest to avoid using suffixes and prefixes which match known data types, like date and time, at all costs, to avoid confusion with data types where only the purpose of the column name is expected.
But PostgreSQL dialect does not have that datetime type at all, so there is only the timestamp type for all cases when just date and time are not enough for the column which is expected to store a value of past or future instant of time.
So, basically, what prefixes or suffixes if any would you suggest for PostgreSQL dialect columns, known that some of them would store past and present and future time instants? And why, for what benefits or because of what limitations?
Should we use timestamp and datetime as prefixes or suffixes to distinguish the purpose of different timestamp type columns by their names? Or would that be a bad practice since there is actually a data type named timestamp and no data type named datetime in PostgreSQL dialect?
Or should we maybe use something very neurtal like an instant noun as a prefix or suffix to denote the purpose of the column?

Save a java.util.Date in a MySQL DB with Millisecond precision

I would like to get millisecond precision in my MariaDB. After some research, I found that I needed to change the columnDefinition - so I did this in my entity:
#NotNull
#Column(name = "createdDate", columnDefinition = "DATETIME(3) NOT NULL")
#Temporal(TemporalType.TIMESTAMP)
private TimeStamp createdDate;
#PrePersist
void onPersist() {
createdDate = new Timestamp(new Date().getTime());
}
The resulting SQL to create the column is:
`createdDate` DATETIME(3) NOT NULL
Now, in the DB the value has indeed 3 decimals:
2016-09-12 16:57:44.000
... but they are always 000
What did I do wrong, or what did I forget ?
Edit: I tried without JAVA:
CREATE TABLE `test` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`createdDate` DATETIME(3) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='latin1_swedish_ci'
ENGINE=InnoDB
;
And then:
INSERT INTO test (createdDate)
VALUES(current_timestamp())
Result:
2016-09-13 13:57:44.000
I had the same problem with MariaDB and date types. I've tried org.joda.DateTime and java.util.time types. Both, the server and the client code supported milliseconds correctly.
The problem was that I was using MySQL Connector instead of MariaDB Connector/J JDBC driver.
Background
In most situations using MariaDB with MySQL Connector works out well, but I would never ever recommend this. When I was searching for the issue I was debugging through Hibernate and Connector code and saw many feature detections that were based on the server version number instead of a real feature detection. The version numbering of course differs between MySQL and MariaDB. So there's a big probability that there are far more compatibility issues that are quietly ignored.
Your problem most probably comes from the fact that you mix Dates and Timestamps. Changing the createdDate type to java.sql.Timestamp should solve your issue.
Also, if your version of MySQL is prior to 5.6.4, DateTime won't let you save time fractions.
EDIT after OP's edit :
you are still mixing the Date Java type with Timestamp when you do this :
createdDate = new Timestamp(new Date().getTime());
Can you try createdDate = new Timestamp(System.currentTimeInMilliseconds()); instead ?
Ideally you should use objects from a library like JodaTime to avoid such issues, but that's beyond the point of your question, just a tip :)
Ultimately, if this way of creating your Timestamp does not work, I would use the Timestamp type in DB instead of Datetime, but that's just trial and error as Datetime should work as well in your example.
Edit :
excerpt from Oracle's Date API :
Date()
Allocates a Date object and initializes it so that it represents the time at which it was allocated, measured to the nearest millisecond.
In which case using System.currentTimeInMilliseconds() shouldn't change the outcome - my bad.
To troubleshoot the problem, I'd start to create a date via SQL (without passing via Java objects) with CURRENT_TIMESTAMP to make sure that the field can indeed contain decimal time precision.. If it is OK, verify the value in the Java object with a debugger.. Might give you a lead. If both contain milliseconds, I'd look at the usage of the annotations or start from a working sample.
To do this using pure JPA :
#Column(name="STMP", columnDefinition = "TIMESTAMP (6)")
private Timestamp timestamp = Timestamp.from(Instant.now());

Is there a MAX_INT constant in Postgres?

In Java I can say Integer.MAX_VALUE to get the largest number that the int type can hold.
Is there a similar constant/function in Postgres? I'd like to avoid hard-coding the number.
Edit: the reason I am asking is this. There is a legacy table with an ID of type integer, backed by a sequence. There is a lot of incoming rows into this table. I want to calculate how much time before the integer runs out, so I need to know "how many IDs are left" divided by "how fast we are spending them".
There's no constant for this, but I think it's more reasonable to hard-code the number in Postgres than it is in Java.
In Java, the philosophical goal is for Integer to be an abstract value, so it makes sense that you'd want to behave as if you don't know what the max value is.
In Postgres, you're much closer to the bare metal and the definition of the integer type is that it is a 4-byte signed integer.
There is a legacy table with an ID of type integer, backed by a sequence.
In that case, you can get the max value of the sequence by:
select seqmax from pg_sequence where seqrelid = 'your_sequence_name'::regclass.
This might be better than getting the MAX_INT, because sequence may have been created/altered with a specific max value that is different from MAX_INT.

Does SQL Alchemy know the current Sequence value?

I'm using SQL Alchemy (1.0) ORM with a PostgreSQL database. Let's say I have a line in my class
serialid = Column(Integer, Sequence('journal_seq'), unique=True)
I realize that then there is a special "table" in my database, that holds the current value of the last one or next available integer for a serialid. Can I, from ORM, get the value of that integer (without incrementing it - otherwise I can just call next_value)? And is there a guarantee that the next serialid will have exactly that value?
I'd like to make an journal item with a serialid, and also make another item refering to that same serialid, but I'd like two of those to be committed (or rollbacked) together - and until I commit the journal item, I don't know what its serialid is. Maybe there is a cleaner way of doing it without knowing the current sequence value. A relationship would be great, but I don't know how to set it up.
(I know there is a question that asks the same thing when you control the SQL directly. I'd like to do the same from SQL Alchemy ORM.)

Jasper Report: unable to get value for field 'x' of class 'org.postgresql.util.PGmoney'

When I need to retrieve some information in Order table, jasper cannot cast from PGmoney to double. I searched google first, but no have result of this.
You know how to fix it?
Note: I use PostgreSQL database.
This is one of the several reasons the PostgreSQL money type was deprecated and should be avoided. Oddly newer versions of the same documentation don't show the deprecation warning but I and others disagree with that and think its use should be discouraged.
If at all possible, change your schema to use numeric instead, like numeric(17,2) if you only want to store whole-number cents, or something more precise for intermediate values. You'll have a nightmare of a time working with money in HQL, to the point where even Java's BigDecimal class (usually used to map numeric fields) is better despite the awfully clumsy syntax of itsw arithmetic.
I'd do an ALTER TABLE blah ALTER COLUMN blahcol TYPE numeric(17,2) USING ( regexp_replace(blahcol::text, '[$,]', '', 'g')::numeric ); and forget the money type existed if I were you.