I add to my Entity
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
and something strange happend. When i update, hibernate tells thath key already exists. How #version filed affect my Entity? I have no idea why it happend. When i remove this #version field everything works. I also use #Audited annotation.
My Entity:
private static final long serialVersionUID = 1636824190907788517L;
#Id
#NotNull
#Column(name = "id")
private UUID id;
#Version
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "version")
private Date version;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "user", nullable = false)
private User user;
#Column(name = "purpose", length = 100)
protected String comment;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id", nullable = false)
protected BasicEquipment equip;
#OneToOne(cascade = CascadeType.REMOVE)
#JoinColumn(name = "eq_id2", nullable = false)
protected BasicEquipment equip2;
Error:
Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement (...)
org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(Standaorg.hibernate.engine.jdbc.sporg.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatch
org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTra
Caused by: org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "pk_entity"
Did you try this solution?
http://www.byteslounge.com/tutorials/jpa-entity-versioning-version-and-optimistic-locking
Under some circumstances, problems may occur when versioned updates
are used together with batch updates. It has happened to me in the
past with a given version of Oracle 11g and Hibernate, for example.
The Oracle JDBC driver was not able to extract the correct number of
updated rows count in JDBC batch statements execution.
If you are also facing this problem, you may check if you have set the
Hibernate property hibernate.jdbc.batch_versioned_data to true. When
this setting is true, Hibernate will use batch updates even for
updates that are made against versioned data, ie. updates that need to
use the updated rows count in order to check for concurrent updates.
Since the JDBC driver may not return the correct updated rows count,
Hibernate will not be able to detect if concurrent updates actually
happened. The default value for this setting in Hibernate is false, so
it will not use batch updates when it detects that versioned data
updates are going to be executed in a given flush operation.
This is of course a specific scenario with Oracle 11g that is easily
worked around, as we have just seen.
Related
I'm currently a little blocked with this and I can't see it clearly.
So I hope one of you have good idea's to help me.
The important code at the moment :
#Entity
#Table(name = "T_NOTA_RECIPIENT")
public class NotaRecipient extends PersistentEntity {
#Id
#Column(name = "NOTA_RECIPIENT_SID")
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
#Column(name = "STATUS", insertable = true, updatable = true)
#Enumerated(EnumType.STRING)
private Status status = Status.NEW;
#ManyToOne
#JoinColumn(name = "NOTA_SID", referencedColumnName = "NOTA_SID", nullable = false)
private Nota nota;
#ManyToOne
#JoinColumn(name = "CREATOR_OFFICE_SID", referencedColumnName = "OFFICE_SID", nullable = false)
private Office creator;
#OneToMany(fetch = FetchType.EAGER, mappedBy = "notaRecipient")
private Set<FollowUp> followUps;
...
}
Now, actually I don't want to load all the FollowUp who are in the DB but just the one of the current user.
But the problem is that I want to include the FollowUp so I can do database paging query.
We use hibernate, Spring Data and Query DSL with BooleanBuilder to "refine" our search.
I was thinking of using #Formula but this need to be a constant String so I can't include current userId in that.
Second solution could be setting the FollowUp as #Transient and fetch it myself in the DB and set it in mine service.
Problem here is that I can't use it as filter then or ordering by it.
#Formula doesn't have so much documentation, so is it possible to make a #Transient user and use that in the #Formula?
I asked some colleagues but they couldn't help me.
So then it's the time for asking here.
I can get the current user in the API, so that's no problem.
Anybody have alternative solutions?
You can define a mapping with expression
#JoinColumnOrFormula(formula=#JoinFormula(value="(SELECT f.id
FROM follow_up_table f
WHERE f.nota_id=id
and f.user_id={USER_ID})",
referencedColumnName="...")
And then add hibernate interceptor (see the example) and change the SQL on fly replacing {USER_ID} with real value in the
/**
* Called when sql string is being prepared.
* #param sql sql to be prepared
* #return original or modified sql
*/
public String onPrepareStatement(String sql);
I'm having a hard time understanding this JPA behavior which to me doesn't seem to follow the specification.
I have 2 basic entities:
public class User {
#Id
#Column(name = "id", unique = true, nullable = false, length = 36)
#Access(AccessType.PROPERTY)
private ID id;
#OrderBy("sequence ASC")
#OneToMany(fetch = FetchType.LAZY, mappedBy = "user", cascade = { CascadeType.REMOVE })
private final Set<UserProfile> userprofiles = new HashSet<UserProfile>(0);
//Ommiting rest of fields since they aren't relevant
}
public class UserProfile {
#Id
#Column(name = "id", unique = true, nullable = false, length = 36)
#Access(AccessType.PROPERTY)
private ID id;
#NotNull
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "userID", nullable = false, foreignKey = #ForeignKey(name = "FK_UserProfile_User"))
private User user;
//Ommiting rest of fields since they aren't relevant
}
As you can see I only have cascading set to REMOVE, the behavior will be the same if I don't have cascade set at all.
Now if I call:
User user = new User();
user.setId(UUIDGenerator.generateId());
UserProfile userProfile = new UserProfile();
userProfile.setId(UUIDGenerator.generateId());
userProfile.setUser(user);
user.getUserProfiles().add(userProfile);
em.merge(user);
merge will throw an exception.
I see Hibernate is executing a SQL query against the UserProfile table:
select userprofil0_.userProfileID as userProf1_4_0_, userprofil0_.profileID as profileI3_4_0_, userprofil0_.sequence as sequence2_4_0_, userprofil0_.userID as userID4_4_0_ from UserProfile userprofil0_ where userprofil0_.userProfileID=?
And then it will throw an exception
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find com.mytest.domain.UserProfile with id 6aaab891-872d-41e6-8362-314601324847;
Why is this query even called?
Since I don't have cascade type set to MERGE in userprofiles my expectation would be that JPA/Hibernate would simply ignore the entities inside userprofiles set and only insert/update the user record, doesn't this go against the JPA specs?
If I change cascadetype to MERGE things will work as expected and both User and UserProfile will be added to the database, so no problem there. What puzzles me is why is Hibernate querying the database and erroring out about an entity that's not supposed to be merged at all since I don't have it set to cascade.
This is more of an academic scenario that I ran into, of course I could simply clear the userprofiles set and things would work, but I'm trying to understand why the above behavior happens since I'm probably missing some crucial piece of information about how merge works. It seems it will always try to attach all entities to the session regardless cascade type being set or not.
Why is this query even called?
It's because you are trying to merge the entity, in JPA merge() is used to make the entity managed/attached. To "merge" User, JPA needs to still maintian the references it holds(UserProfile). In your case its not trying to persist UserProfile its trying to get a reference to it to merge User. Read here
If you use persist rather than merge this should not happen.
I have an entity that is defined with JPA annotations (only a few fields of interest shown here)
#Entity
public class Rule implements Serializable, Cloneable
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO,
generator = "SEQ_STORE")
#Column(name = "RULE_ID",
nullable = false)
private final Long id = null;
#Column(name = "CODE",
length = 25,
nullable = false)
private String code;
#Column(name = "DESCRIPTION",
length = 250,
nullable = true)
private String description;
#Column(name = "VALIDATION_FIELDS",
length = 250,
nullable = true)
private String validationFields;
#ExportField("EXPRESSION")
#Lob
#Column(name = "EXPRESSION",
nullable = true)
private String expression;
#Lob
#Column(name = "ACTION",
nullable = true)
private String action;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "PARENT_ID",
nullable = true,
foreignKey = #ForeignKey(name = "FK_XTB_RULE_2_PARENT") )
private Rule parent;
#JsonIgnore
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "RULESET_ID",
nullable = false,
foreignKey = #ForeignKey(name = "FK_XTB_RULE_2_RULESET") )
private RuleSet ruleSet;
}
#Entity
public class RuleSet implements Serializable, Cloneable
{
private static final long serialVersionUID = 7982682149517239983L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO,
generator = "SEQ_STORE")
#ExportField("RULESET_ID")
#Column(name = "RULESET_ID",
nullable = false)
private final Long id = null;
#JsonIgnore
#OneToMany(mappedBy = "ruleSet",
fetch = FetchType.EAGER,
cascade = CascadeType.ALL)
#OrderBy("position")
private List<Rule> rules = new LinkedList<Rule>();
}
Then I have a method that generates a tree of these Rules (see the backreference) and puts all the rules into the List contained in the Ruleset entity.
The auto-generated DDL makes columns suitable for large expressions as the column is #Lob annotated
On Mysql and Oracle I can successfully run the code that populates the rules table (I run Bamboo tests that create DB from scratch every time). Hoever, when the testing is run oh HSQLDB, Hibernate's insert of the Ruleset object fails
2016-04-29 13:09:26,946 WARN [localhost-startStop-1] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - logExceptions - SQL Error: 3401, SQLState: 22001
2016-04-29 13:09:26,949 ERROR [localhost-startStop-1] org.hibernate.engine.jdbc.spi.SqlExceptionHelper - logExceptions - data exception: string data, right truncation; table: XTB_RULES column: EXPRESSION
2016-04-29 13:09:39,965 ERROR [localhost-startStop-1] it.phoenix.web.data.managers.spring.ModuleManagerImpl - init - could not execute statement
org.hibernate.exception.DataException: could not execute statement
...
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation; table: XTB_RULES column: EXPRESSION
...
Caused by: org.hsqldb.HsqlException: data exception: string data, right truncation
There is an expression long 353 character in my code, I have almost found the "guilty" object.
But the problem is that even with HSQLDB the following DDL is generated
create table XTB_RULE_FUNCTIONS (RULE_FUNCTION_ID bigint identity not null,
DESCRIPTION varchar(250),
ENABLED bit not null,
EXPRESSION varchar(MAX) not null,
NAME varchar(50) not null,
OBJECT_TYPE varchar(20) not null,
POSITION bigint not null,
primary key (RULE_FUNCTION_ID));
EXPRESSION is supposed to be VARCHAR(max), so it should accommodate any string.
But my insertion still fails. I have no mean to check the actual in-memory database at the moment
Other info on the application:
Is a web application running on Tomcat
I use Bamboo CI to run tests on different databases, each loading the Spring context instead of being run in a servlet container
Part of Spring initialization is to populate, along others, the Ruleset table if data does not exist. Since Bamboo recreates DB at every run (especially in-memory one), I always need to populate rules declared programmatically somewhere in a piece of code useless to paste here
I have read this but I have checked that DDL script declares VARCHAR(max) so I don't think that applies to me
Again and again, the same code works on other DBs
Still, I need to store data larger than 255 characters
Any idea on how to fix? In my unit testing I may still comment out one of the entities, but that is only a workaround.
Database: MySQL 5.1
JPA implementation: EclipseLink
Container: Glassfish 4
Java: JDK 7u55
I use a native query to get results from a table of orders. Each order has a date and I want to select only by year and date. The whole method has this body.
Query query = entityManager.createNativeQuery("SELECT COUNT(PLACED_ORDER.ID) as POCET_OBJEDNAVEK FROM PLACED_ORDER WHERE ORDERDATE IS NOT NULL AND EXTRACT(YEAR FROM ORDERDATE) = ?1 AND extract(DAY FROM ORDERDATE) = ?2");
query.setParameter(1, year);
query.setParameter(2, day);
return (Long) query.getSingleResult();
This query WORKS properly, but is very slow to execute. By slow, I mean a second or more for every method call. Transaction management is set do Required.
Named queries are executed within few milliseconds, measured from request to response. Calling this method alone is very slow. Is there something that can be done about it ?
EDIT - Reaction to comments:
When I query the database from command line or via MySQL WorkBench, the performance is normal (max a millisecond or a few under heavy load).
I should also metion that SECOND LEVEL CACHE is disabled on the project and there is nothing I can do about it.
MySQL Explain looks like this (there is no easy way for me to enable explain on EclipseLink).
Entity annotations used to determine data type and DB constraints.
#Entity(name = "PLACED_ORDER")
public class Order implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#ManyToOne
#JoinColumn(name = "CUSTOMER_ID")
private Customer customer;
#OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.MERGE, CascadeType.REMOVE, CascadeType.PERSIST}, orphanRemoval = true)
#JoinColumn(name = "PLACED_ORDER_ID")
private List<OrderItem> items;
#Temporal(TemporalType.TIMESTAMP)
private Date orderDate;
#Enumerated(EnumType.STRING)
#NotNull
private OrderState orderState = OrderState.SEMIFINISHED;
#OneToOne
private Transportation transportation;
#OneToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
private Address deliveryAddress;
#Enumerated(EnumType.STRING)
private TransportationType transportationType;
With technologies specified in the question and second level cache disabled, the solution was to write the native query as #NamedNativeQuery, instead of creating it every time method was called. This way, the performance significantly increased.
In my SQL Server 2000 database, I have a timestamp (in function not in data type) column of type DATETIME named lastTouched set to getdate() as its default value/binding.
I am using the Netbeans 6.5 generated JPA entity classes, and have this in my code
#Basic(optional = false)
#Column(name = "LastTouched")
#Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
However when I try to put the object into the database I get,
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.generic.Stuff.lastTouched
I've tried setting the #Basic to (optional = true), but that throws an exception saying the database doesn't allow null values for the TIMESTAMP column, which it doesn't by design.
ERROR JDBCExceptionReporter - Cannot insert the value NULL into column 'LastTouched', table 'DatabaseName.dbo.Stuff'; column does not allow nulls. INSERT fails.
I previously got this to work in pure Hibernate, but I have since switched over to JPA and have no idea how to tell it that this column is supposed to be generated on the database side. Note that I am still using Hibernate as my JPA persistence layer.
I fixed the issue by changing the code to
#Basic(optional = false)
#Column(name = "LastTouched", insertable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date lastTouched;
So the timestamp column is ignored when generating SQL inserts. Not sure if this is the best way to go about this. Feedback is welcome.
I realize this is a bit late, but I've had success with annotating a timestamp column with
#Column(name="timestamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
This should also work with CURRENT_DATE and CURRENT_TIME. I'm using JPA/Hibernate with Oracle, so YMMV.
#Column(nullable = false, updatable = false)
#CreationTimestamp
private Date created_at;
this worked for me.
more info
Add the #CreationTimestamp annotation:
#CreationTimestamp
#Column(name="timestamp", nullable = false, updatable = false, insertable = false)
private Timestamp timestamp;
If you are doing development in Java 8 and Hibernate 5 Or Spring Boot JPA then use following annotation directly
in your Entity class. Hibernate gets the current timestamp from the VM and will insert date and time in database.
public class YourEntity {
#Id
#GeneratedValue
private Long id;
private String name;
#CreationTimestamp
private LocalDateTime createdDateTime;
#UpdateTimestamp
private LocalDateTime updatedDateTime;
…
}
I do not think that every database has auto-update timestamps (e.g. Postgres). So I've decided to update this field manually everywhere in my code. This will work with every database:
thingy.setLastTouched(new Date());
HibernateUtil.save(thingy);
There are reasons to use triggers, but for most projects, this is not one of them. Triggers dig you even deeper into a specific database implementation.
MySQL 5.6.28 (Ubuntu 15.10, OpenJDK 64-Bit 1.8.0_66) seems to be very forgiving, not requiring anything beyond
#Column(name="LastTouched")
MySQL 5.7.9 (CentOS 6, OpenJDK 64-Bit 1.8.0_72) only works with
#Column(name="LastTouched", insertable=false, updatable=false)
not:
FAILED: removing #Temporal
FAILED: #Column(name="LastTouched", nullable=true)
FAILED: #Column(name="LastTouched", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
My other system info (identical in both environments)
hibernate-entitymanager 5.0.2
hibernate-validator 5.2.2
mysql-connector-java 5.1.38
I have this working well using JPA2.0 and MySQL 5.5.10, for cases where I only care about the last time the row was modified. MySQL will create a timestamp on first insertion, and every time UPDATE is called on the row. (NOTE: this will be problematic if I cared whether or not the UPDATE actually made a change).
The "timestamp" column in this example is like a "last-touched" column.x`
The code below uses a separate column "version" for optimistic locking.
private long version;
private Date timeStamp
#Version
public long getVersion() {
return version;
}
public void setVersion(long version) {
this.version = version;
}
// columnDefinition could simply be = "TIMESTAMP", as the other settings are the MySQL default
#Column(name="timeStamp", columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP")
#Temporal(TemporalType.TIMESTAMP)
public Date getTimeStamp() {
return timeStamp;
}
public void setTimeStamp(Date timeStamp) {
this.timeStamp = timeStamp;
}
(NOTE: #Version doesn't work on a MySQL "DATETIME" column, where the attribute type is "Date" in the Entity class. This was because Date was generating a value down to the millisecond, however MySQL was not storing the millisecond, so when it did a comparison between what was in the database, and the "attached" entity, it thought they had different version numbers)
From the MySQL manual regarding TIMESTAMP :
With neither DEFAULT nor ON UPDATE clauses, it is the same as DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP.
If you mark your entity with #DynamicInsert e.g.
#Entity
#DynamicInsert
#Table(name = "TABLE_NAME")
public class ClassName implements Serializable {
Hibernate will generate SQL without null values. Then the database will insert its own default value. This does have performance implications See [Dynamic Insert][1].
This also works for me:-
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "CREATE_DATE_TIME", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
public Date getCreateDateTime() {
return createDateTime;
}
public void setCreateDateTime(Date createDateTime) {
this.createDateTime = createDateTime;
}
I'm posting this for people searching for an answer when using MySQL and Java Spring Boot JPA, like #immanuelRocha says, only have too #CreationTimeStamp to the #Column in Spring, and in MySQL set the default value to "CURRENT_TIMESTAMP".
In Spring add just the line :
#Column(name = "insert_date")
#CreationTimestamp
private Timestamp insert_date;
#Column(name = "LastTouched", insertable = false, updatable = false, columnDefinition = "TIMESTAMP default getdate()")
#Temporal(TemporalType.TIMESTAMP)
private Date LastTouched;`enter code here`
This worked for me:
#Column(name = "transactionCreatedDate", nullable = false, updatable = false, insertable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP")