Hibernate with long text column with Oracle and PostgreSQL - java

I'm trying make an entity work with Oracle (11.2) and PostgreSQL(9.4) in a Spring Boot (1.4.4) application.
My entity contains a long text field (over 4000 characters).
The appropriate data type in Oracle is CLOB and the corresponding type in PostgreSQL is TEXT.
I'm able to make it work with PostgreSQL
#Column(name = "LONG_TEXT", columnDefinition="TEXT")
private String longText;
However it would fail with Oracle in hibernate validation stage since CLOB requires #Lob annotation.
The following code works with Oracle
#Lob
#Column(name = "LONG_TEXT")
private String longText;
However this time it fails when reading from PostgreSQL with the following exception:
PSQLException: Large Objects may not be used in auto-commit mode
Stack overflow suggests performing queries in transactions. Disregarding questionable requirement to invoke transaction in select queries, adding #Transactional to query methods didn't help.
Any thoughts are more than welcomed.

The solution we came to is to adopt the #Lob and #Transactional approach.
The main issue was with the placement of the #Transactional annotation, causing the PSQLException. Once fixed, we were able to work with both types of DBs.

Related

JPA/Hibernate Bulk/Batch Insert using Mysql with Database Generated ID's

Okay, I've searched forever and I can't seem to find a good way of accomplishing batch inserts with JPA/Hibernate and MySql.
I want to be able to save/insert many records at once using JPA, but by default batching behavior is disabled if you use GenerationType.IDENTITY. I'm aware that you can switch to GenerationType.SEQUENCE, but that isn't available on MySql and creating new tables and using GenerationType.TABLE is not an option in my scenario.
So in the end, I need an efficient way of doing batch/bulk inserts using JPA/Hibernate, MySQL, and database generated IDs. I know it's possible to do this efficiently because I can do it with a JDBC connection, but I'd really like to not have to write my own JDBC queries for each of my repositories.
Anyone know how to accomplish this?
I'm okay if I'm unable to get the updated entities with the IDs back (think void saveAll() instead of List<User> saveAll()). My main requirement is this happens in one/two big queries instead of saving iteratively each entity like it does now when I call saveAll.
I can include more if needed, but my entity looks like this:
#Entity
#Builder
#Getter
#Setter
#With
#AllArgsConstructor
#NoArgsConstructor
#EqualsAndHashCode(callSuper = false, exclude = "id")
#Table(name = "user")
#ToString(callSuper = true, onlyExplicitlyIncluded = true)
public class User {
#Id
#ToString.Include
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "uID")
private long id;
private String name;
}
There is no way to accomplish JDBC batching on insert with Hibernate when using the identity generation strategy, because for Hibernate, every entity must have a PK value assigned after a persist/insert.
You can use Hibernate SPIs to implement this yourself though. Take a look at how Hibernate implements inserts here org.hibernate.persister.entity.AbstractEntityPersister#insert(java.lang.Object, java.lang.Object[], java.lang.Object, org.hibernate.engine.spi.SharedSessionContractImplementor). You can reduce the complexity if you want to implement this only for a few known entities that only use a handful of features.
IDENTITY generator disables JDBC batch insert of hibernate and JPA. since the sequence is not supported in MySQL, there is no way to bulk/batch insert records using MySQL and spring data JPA. Please read my blog on that. This is not the end of the road. we can use the JDBC template or query DSL-SQL. To see how to implement using query DSL-SQL click here. For the JDBC template click here.
If you need type-safe, easy to code choose query DSL-SQL else choose JDBC template

Alter table from jpa annotations in Java

I have a definition for a column like that:
#Column
private String my_column;
And by default in Postgres database type for this field is character varying(255).
Now, I want to change the data type for this column.
How I can do this without entry in database and alter table?
I tried this:
#Lob
#Column
private String my_column;
And
#Column(columnDefinition = "TEXT")
private String my_column;
But, without results.
The thing is, that JPA does not handle Schema changes.
JPA maps your existing DB to Java Classes, it does not manage the database it self.
As for schema changes managment.
A common practice is to have a schema migration tool to handle that, for example Flyway and Liquibase are a popular solutions.
There you can write a SQL script, to change the DB column type to "text"
and it will apply those changes when you run the DB migration process.
Or you can always just access your DB and modify it manually.

Cassandra through java\hibernate

I started learning Cassandra using java, after completing hibernate. I am really surprised by the way in which data is inserted/pulled/deleted from cassandra through java while java is moving backwards these days. Because, hibernate gives a very easy way to communicate with the database, a java developer has no need to know the database query syntax,etc. It is mostly method based operations which are used to communicate with the database. But if i want to communicate with cassandra through java, everything is in an SQL format i mean they named it as CQL but i am really surprised by the way in which things are happening when i compare it to the hibernate.
My question here is, is there any way to communicate/do CRUD operations on cassandra through java in O-R mapping style or can hibernate supports cassandra connectivity?
Cassandra is not a relational database, using a relational mapper isn't going to be as straight forward. There are no joins and it does not support SQL.
The java drivers object mapper is probably closest to what your looking for though. For basic CRUD mappings on Cassandra tables.
See documentation here: https://docs.datastax.com/en/developer/java-driver/3.0/supplemental/manual/object_mapper
ie
#Table(name = "posts")
public static class Post {
private String title;
private String content;
private InetAddress device;
#ClusteringColumn
#Column(name = "post_id")
private UUID postId;
#PartitionKey
#Column(name = "user_id")
private UUID userId;
private Set<String> tags;
...
}
You can perform crud operation with Cassandra using Solr or Spark. Example
Now, do not compare Cassandra with any RDBMS. There is no concept of Relational in Cassandra. So, be careful. If you want to fetch data from Cassandra without much knowledge of Cassandra (similar to Hibernate), you may try Spark:
JavaRDD<Student> studentObj = CassandraJavaUtil.javaFunctions(sc).cassandraTable("schema", "student_table",CassandraJavaUtil.mapRowTo(Student.class)).where("id=1");
Remember, Spark is mainly for Analytics purpose.
I also found some new OGM tools that you may try:
http://hibernate.org/ogm/
https://github.com/impetus-opensource/Kundera
Yes Hibernate is supporting cassandra but it is still under experimental stage!!
so read the below notes carefully before you use it.
This implementation uses CQL3 over the native wire protocol with java-driver. The currently supported version is Cassandra 2.1.
To add the dependencies via Maven, add the following module:
<dependency>
<groupId>org.hibernate.ogm</groupId>
<artifactId>hibernate-ogm-cassandra</artifactId>
<version>5.0.4.Final</version>
To get started you will need to configure the following properties:
hibernate.ogm.datastore.provider
hibernate.ogm.datastore.host
hibernate.ogm.datastore.database
source

Spring Boot hibernate using different naming convention to session save

Similar to this problem:
ORA-00904: : invalid identifier Issue with Hibernate Dependent objects program
I'm trying to do batch inserts using hibernate. Whenever I try to do a session.save or session.saveOrUpdate, hibernate complains that I have an invalid identifier
Stack output
2015-11-20 14:17:37 ERROR : ORA-00904: "USERATTRID": invalid identifier
Entity
public class Attribute {
#Id
#GenericGenerator(name = "increment", strategy = "increment")
#GeneratedValue(generator = "increment", strategy = GenerationType.SEQUENCE)
private int USERAttrID;
private long userNumber;
private String attribute;
private String value;
private String description;
private LocalDateTime updatedDate;
private LocalDateTime createdDate;
The database looks like this after hibernate applies its improved naming convention
USER_ATTRID
ATTRIBUTE
USER_NUMBER
DESCRIPTION
VALUE
CREATED_DATE
UPDATED_DATE
If I use repository.save then the code works fine. The crud repository seems to know how to map my entity to the database, but hibernate's session does not.
I see a few solutions here:
1. Use hibernate's default default naming strategy. Tables get named things like USERATTRID. I'm not sure what implications this has other than making columns harder to read.
2. Combine hibernate with crudrepository using the tutorial here
http://frightanic.com/software-development/jpa-batch-inserts/
3. Figure out how to get hibernate's session.save to use the improvedNamingConvention mapper. Can anyone help me with this or provide me another suggestion?
4. I guess I can also manually map the columns :/. Ugh this is messy, you now have to manually do all the conversions on dates :/
It would be good to know how you are actually getting the session?The most likely cause that comes to mind is that when you using the hibernate session it is actually not built using the same configuration that was used to build the entity manager that CrudRepository uses underneath.
Ends up being more trouble than it's worth as you stop using hibernate jpa's defaults and all the things spring-data provides you out of the box
Stupid. The tutorial doesn't even use crudRepository
Same as 1
Same as 1
Instead I'm banging my head against a wall trying to get a simple batch process to insert

H2 + Hibernate with non nullable String stores empty string

I'm currently migrating some existing code from Hibernate 3.2 to Hibernate 3.6.10.Final
(and also from Spring 2.0 to Spring 3.1.2 by the way).
I have an issue with some integration tests running against H2 database, verifying that some fields are not nullable.
- I test that an attempt to insert a null String into a field marked as nullable=false ends with an Exception
- I checked that the schema is correctly created : the column is not nullable.
Using H2 (with MySQL mode), nullable constraint is ignored : an empty String is inserted in database.
I don't reproduce the case if I run my test against a MySQL database.
It worked before with Hibernate 3.2
For example, if I have a class Person :
#Entity
class Person {
#Id
#GeneratedValue
private Long id;
#Column(nullable=false)
private String name;
//getters and setters
}
And then I have a test (still using JUnit3, I'll migrate this later) :
#ExpectedException(value=DataIntegrityViolationException.class)
public void testPerson_NameCantBeNull() throws Exception {
// Given
Person person = new Person();
person.setName(null);
// When
getHibernateTemplate().persist(person);
//Flush and clear session
}
I could fix this by replacing nullable=false by #NotNull annotation but I don't want to replace it in my huge code base as I wouldn't expect the same Exception.
I had a quick look into H2Dialect class and JIRA issues in Hibernate but I didn't find anything.
Does anybody know where it comes from ?
EDIT :
Some additional informations, I added the TRACE level in Hibernate logs.
When I insert null and the field is marked with #Column(nullable=false), I have the following log :
2013-01-16 15:57:52 TRACE [BasicExtractor] found [] as column [NAME1_3_]
When I insert null and the field is not marked with #Column(nullable=false), I have the following log :
2013-01-16 15:57:52 TRACE [BasicExtractor] found [null] as column [NAME1_3_]
EDIT (22/01/13) :
I still didn't found where the problem exactly come from, but I found out that it is tied to MySQL mode with H2 : if I disable MySQL mode, Hibernate doesn't try anymore to replace my null Strings by empty Strings.
But I can't do this since some other pieces of code are tied to MySQL syntax.
Any idea ?
I didn't have enough time to digg in Hibernate and MySQL dialect, so I moved to Java Validation Framework, using #NotNull annotation.
It does the job and meets one of our other requirement : a part of our model is used in a Grails application and we want to use constraints to validate part of CRUD operations (not possible with pure javax.persistence annotations).

Categories

Resources