Gaps In the sequence values generated by JPA #GeneratedValue with PostgreSQL - java

For my desktop application I use JavaFX, Spring, JPA + Hibernate and PostgreSQL. Currently I have faced several issues.
Issue one: Violation of PRIMARY KEY constraint SQL Error
When I create Entity classes according to following manner (GenerationType as AUTO) it works fine. But when I create a new data base and add some Test data with sql script (as showing following picture) and try to insert some data with my application I have got 'Violation of PRIMARY KEY constraint' SQL Error. That mean it seems Hibernate try to generated PK values which are already available (allocated with my test data ex 1, 2, 3 etc). But after 5 attempts (exceed the test data maximum pk value) it was fine and start the data inserting with PK key value with 6.
Entity Class - GenerationType as AUTO
#Entity
#Table(name = "devicetype")
public class Devicetype implements Serializable {
#Id
#Basic(optional = false)
#Column(name = "id")
private Integer id;
}
Table with initial test data
EntityManager factory
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="packagesToScan" value="com.core.domain" />
<property name="jpaProperties">
<props>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgresPlusDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.use_sql_comments">false</prop>
<prop key="hibernate.temp.use_jdbc_metadata_defaults">false</prop>
</props>
</property>
</bean>
Issue Two: Gaps In the sequence value
For make resolve about error I have changed Entity class according to following manner (with GenerationType as SEQUENCE) and done the same steps (insert initial test data with sql script and try to insert data via application). Then data was inserted without any exception. Now my table contains records both inserted via script and application (as showing following picture). But newly add data (I have highlight on light blue color) via application had very higher PK value (started at 184 not from 6). That mean with "GenerationType as SEQUENCE" it seems hibernate not populate ID value in sequence manner (maintain some gaps). When I add further some data via application it seems it will stat to inserting data with another higher ID value (not start form 214). That mean is seems ID is not incrementing on sequence manner.
Entity Class - GenerationType as SEQUENCE
#Entity
#Table(name = "device_type")
public class DeviceType implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name="my_seq", sequenceName="MY_SEQ", allocationSize=1, initialValue=1)
#Basic(optional = false)
#Column(name = "ID")
private Integer id;
}
Table data with gaps (for sequence ID)

This is how sequences (and so the PostgreSQL SERIAL type) behave.
If you are manually inserting values then you will need to update the sequence accordingly. Or, more usually, don't manually insert the values and let the sequence do it.
Gaps are inevitable unless you want to lock the table on each insert and kill off any hope of concurrency. I'd recommend not caring.
Remember - the numbers don't mean anything, they are just a convenient identifier.
Spend a few minutes reading up on how this all works: CREATE SEQUENCE, ALTER SEQUENCE

Related

SQL sequence: Hibernate and Liquibase

I am quite new to development with databases, so maybe this question is not entirely spot on, but I'd appreciate if someone can make it a bit clearer to me... I've read all about sequences, and how they are preferred over identities. I have a hypothetical question. If I were to use a sequence to generate my PK along with Hibernate (data insertion) and Liquibase (schema creation), what would be the right spot to define sequence?
For example: Sequence generation on class level.
User.java
#Entity
#Table(name = "USER")
public class User {
#Id
#SequenceGenerator(name = "USER_SEQ", sequenceName = "USER_SEQ")
#GeneratedValue(strategy = SEQUENCE, generator = "USER_SEQ")
#Column(name = "ID")
private Long id;
// other fields
}
Or other example: Sequence generation on Schema level.
changelog.xml
<changeSet author="wesleyy">
<createSequence catalogName="cat"
cycle="true"
incrementBy="1"
maxValue="1000"
minValue="10"
ordered="true"
schemaName="public"
sequenceName="user_seq"
startValue="1"/>
</changeSet>
Is it required to define a sequence in both Liquibase and Hibernate? What exactly is the difference between the two?
By lines in class User
#SequenceGenerator(name = "USER_SEQ", sequenceName = "USER_SEQ")
#GeneratedValue(strategy = SEQUENCE, generator = "USER_SEQ")
you say to hibernate: for each object User inserted into database give new value for primary key from sequence named USER_SEQ.
By adding described changeSet to liquibase xml script you say to liquibase: next time create in database sequence named user_seq if this changeSet was not already applied to database.
In other words in liquibase script you create sequence and in code of class User you use it.
If what you wish for is the id primary key to be auto generated then this can be simply done as follows using a JPA implementation such as Hibernate or others:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
The Id primary key will be auto generated and managed for you.
Using liquibase, in your base changelog xml file, you can do the following as long as your database supports auto generated id's (many do this but check if unsure):
<changeSet author="name" id="auto increment example">
<createTable tableName="users">
<column autoIncrement="true" name="id" type="SERIAL">
<constraints primaryKey="true" primaryKeyName="users_pkey"/>
</column>
<column name="some_other_column" type="VARCHAR(255)"/>
<column name="another_column" type="VARCHAR(255)"/>
</createTable>
</changeSet>
Your question is a bit misleading because it is related to two different things:
generation of entity identifiers (behavior of your application) and
definition of the underlying database schema.
"If I were to use a sequence to generate my PK along with Hibernate (data insertion) and Liquibase (schema creation), what would be the right spot to define sequence?"
You could define a sequence in many different ways. It always ends with SQL statement, but sometimes you may prefer to use Liquibase, Flyway or Hibernate to DDL auto export (Hibernate hbm2ddl.auto possible values and what they do?).
My personal preference is to rely on Hibernate automatic schema export during initial development and later on use some of the mentioned version-based DB migration tools.

Executing Oracle Stored Procedure with Hibernate

I have been trying to execute an Oracle Stored Procedure using Hibernate. This is not for production - but for a Java source parsing project, that I'm pursuing. To put it in simple terms, I'm not able to return a value from an Oracle Stored Proc.
I have searched and read all relevant links from SO, Hibernate community/documentation(Native SQL chapter) links and tried out the suggestions, but somehow couldn't get them to work. Below are my sources - I'm including only the relevant parts.
My Entity Class. I have reserved the first parameter for a PL/SQL OUT parameter.
Login.java
#NamedNativeQuery(
name = "getLoginDet",
query = "call GET_LOGIN_DET(?,:userId)",
resultClass = Login.class)
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {
Oracle Stored Proc : GET_LOGIN_DET.sql. The first parameter is OUT REFCURSOR as per Hibernate Spec
create or replace PROCEDURE GET_LOGIN_DET(listLogin OUT SYS_REFCURSOR,userId IN VARCHAR2)
AS
BEGIN
OPEN listLogin FOR
SELECT *
FROM T_LOGIN_DET
WHERE USER_ID = userId;
END GET_LOGIN_DET;
My DAO Class : I'm binding only the named parameter, ignoring the first ? in the named Query.
Session session = sessionFactory.openSession();
List results = session.getNamedQuery("getLoginDet").setParameter("userId", u.getUserId()).list();
My Hibernate Config
<bean id="mysessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="annotatedClasses">
<list>
<value>com.cogn.gto.sea.employee.entity.Employee</value>
<value>com.cogn.gto.sea.employee.entity.Department</value>
<value>com.cogn.gto.sea.login.entity.User</value>
<value>com.cogn.gto.sea.login.entity.Login</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">update</prop> -->
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
However, I always end up with Hibernate QueryException / Java SQLException
Expected positional parameter count: 1, actual parameters: [] [{call GET_LOGIN_DET(?,:userId)}]
I have tried variations of {? = call GET_LOGIN_DET(:userId)} , call GET_LOGIN_DET(?,:userId) to no avail. My requirement is to call the procedure that I have listed and get the result back in the DAO class. Can someone lead me to what exactly I'm missing here ?
I believe you have incorrectly declared call to stored procedure (curly brackets missing), try this:
#NamedNativeQuery(
name = "getLoginDet",
query = "{call GET_LOGIN_DET(?,:userId)}",
resultClass = Login.class
hints = {#QueryHint(name = "org.hibernate.callable", value = "true")})
#Entity
#Table(name = "T_LOGIN_DET")
public class Login {

How do I use Hibernate's second level cache with JPA?

I am implementing an Entity Attribute Value based persistence mechanism. All DB access is done via Hibernate.
I have a table that contains paths for nodes, it is extremely simple, just an id, and a path (string) The paths would be small in number, around a few thousand.
The main table has millions of rows, and rather than repeating the paths, I've normalized the paths to their own table. The following is the behaviour I want, when inserting into main table
1) Check if the path exists in paths table (query via entity manager, using path value as parameter)
2) if it does not exist, insert, and get id (persist via entity manager)
3) put id as foreign key value to main table row, and insert this into main table.
This is going to happen thousands of times for a set of domain objects, which correspond to lots of rows in main table and some other tables. So the steps above are repeated using a single transaction like this:
EntityTransaction t = entityManager.getTransaction();
t.begin();
//perform steps given above, check, and then persist etc..
t.commit();
When I perform step 2, it introduces a huge performance drop to the total operation. It is begging for caching, because after a while that table will be at most 10-20k entries with very rare new inserts. I've tried to do this with Hibernate, and lost almost 2 days.
I'm using Hibernate 4.1, with JPA annotations and ECache. I've tried to enable query caching, even using the same query object throughout the inserts, as shown below:
Query call = entityManager.createQuery("select pt from NodePath pt " +
"where pt.path = :pathStr)");
call.setHint("org.hibernate.cacheable", true);
call.setParameter("pathStr", pPath);
List<NodePath> paths = call.getResultList();
if(paths.size() > 1)
throw new Exception("path table should have unique paths");
else if (paths.size() == 1){
NodePath path = paths.get(0);
return path.getId();
}
else {//paths null or has zero size
NodePath newPath = new NodePath();
newPath.setPath(pPath);
entityManager.persist(newPath);
return newPath.getId();
}
The NodePath entity is annotated as follows:
#Entity
#Cacheable
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
#Table(name = "node_path", schema = "public")
public class NodePath implements java.io.Serializable {
The query cache is being used, as far as I can see from the statistics, but no use for second level cache is reported:
queries executed to database=1
query cache puts=1
query cache hits=689
query cache misses=1
....
second level cache puts=0
second level cache hits=0
second level cache misses=0
entities loaded=1
....
A simple, hand written hashtable as a cache, works as expected, cutting down total time drastically. I guess I'm failing to trigger Hibernate's caching due to nature of my operations.
How do I use hibernate's second level cache with this setup? For the record, this is my persistence xml:
http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>...</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
<properties>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
<property name="hibernate.connection.password" value="zyx" />
<property name="hibernate.connection.url" value="jdbc:postgresql://192.168.0.194:5432/testdbforml" />
<property name="hibernate.connection.username" value="postgres"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.search.autoregister_listeners" value="false"/>
<property name="hibernate.jdbc.batch_size" value="200"/>
<property name="hibernate.connection.autocommit" value="false"/>
<property name="hibernate.generate_statistics" value="true"/>
<property name="hibernate.cache.use_structured_entries" value="true"/>
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="true"/>
<property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory"/>
</properties>
Ok, I found it.
My problem was that, cached query was keeping only Ids of query results in the cache, and it was (probably) going back to db to get the actual values, rather than getting them from the second level cache.
The problem is of course, the query did not put those values to second level cache, since they were not selected by primary id. So the solution is to use a method that will put values to second level cache, and with hibernate 4.1, I've manage to do this with natural id. Here is the function that either inserts or returns the value from cache, just in case it helps anybody else:
private UUID persistPath(String pPath) throws Exception{
org.hibernate.Session session = (Session) entityManager.getDelegate();
NodePath np = (NodePath) session.byNaturalId(NodePath.class).using("path", pPath).load();
if(np != null)
return np.getId();
else {//no such path entry, so let's create one
NodePath newPath = new NodePath();
newPath.setPath(pPath);
entityManager.persist(newPath);
return newPath.getId();
}
}

org.hibernate.ObjectNotFoundException: No row with the given identifier exists, but it DOES

I've got a hibernate problem that I can't fix.
The setup: Java EE, web app, Hibernate 3.2, Tomcat 6, Struts 2.
Basically, I persist an object with my server logic (a struts action), then try and pull that data out for the next page and display it.
I check the database after I save the object, and sure enough, I can see the row there with all the data.
But when I try and retrieve it I get this:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [msc.model.Picture#73]
To make things even muddier, when I restart Tomcat and try and access the same object, I don't get the error - Hibernate finds the row just fine.
Hibernate will also be able to see the row if I do some other operations - maybe add a row here and there to the database, not even on the same table.
From all this I suspect a Hibernate bug, but I'm a Hibernate newbie so I am probably wrong. Please help! I've googled and googled to no avail.
Here is my Hibernate config:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/msc</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">-------</property>
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">80</property>
<property name="current_session_context_class">thread</property>
<!-- Echo all executed SQL to stdout -->
<property name="show_sql">true</property>
<mapping resource="msc/model/Picture.hbm.xml"/>
<mapping resource="msc/model/Comment.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Here are my two mapping files:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="msc.model.Picture" table="PICTURE">
<id column="PICTURE_ID" name="id">
<generator class="native"/>
</id>
<property name="story"/>
<property name="email"/>
<property name="category"/>
<property name="state"/>
<property name="ratings"/>
<property name="views"/>
<property name="timestamp"/>
<property name="title"/>
<property lazy="true" name="image" type="blob">
<column name="IMAGE"/>
</property>
<property lazy="true" name="refinedImage" type="blob">
<column name="REFINEDIMAGE"/>
</property>
<property lazy="true" name="thumbnail" type="blob">
<column name="THUMBNAIL"/>
</property>
<bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
<key column="PICTURE"/>
<one-to-many class="msc.model.Comment"/>
</bag>
</class>
</hibernate-mapping>
and
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="msc.model.User" table="USER">
<id column="USER_ID" name="id">
<generator class="native"/>
</id>
<property name="username"/>
<property name="email"/>
<bag cascade="save-update" lazy="true" name="pictures" table="PICTURE">
<key column="USER"/>
<one-to-many class="msc.model.Picture"/>
</bag>
<bag cascade="save-update" lazy="true" name="comments" table="COMMENT">
<key column="USER"/>
<one-to-many class="msc.model.Comment"/>
</bag>
</class>
</hibernate-mapping>
Please let me know if you need more info, I'm happy to oblige.
(note: this is not a duplicate of this question, the scenario is not the same "No row with the given identifier exists" although it DOES exist)
EDIT: as requested, posting Java code:
Code to save object
Session hib_ses = HibernateUtil.getSessionFactory().getCurrentSession();
hib_ses.beginTransaction();
hib_ses.save(user);
hib_ses.getTransaction().commit();
Code to display data (an image in this case)
public class ImageAction extends ActionSupport implements ServletResponseAware, SessionAware {
private HttpServletResponse response;
Map session;
private Long id;
private int thumbnail;
private InputStream inputStream;
#Override
public String execute() throws Exception {
response.setContentType("image/jpeg");
Session hib_session = HibernateUtil.getSessionFactory().getCurrentSession();
hib_session.beginTransaction();
//what is the ID now?
Picture pic = (Picture) hib_session.load(Picture.class, getId());
if (thumbnail == 1) {
inputStream = (ByteArrayInputStream) pic.getThumbnail().getBinaryStream();
} else {
inputStream = (ByteArrayInputStream) pic.getRefinedImage().getBinaryStream();
}
hib_session.close();
return SUCCESS;
}
This happens because you have inserted something which is meant to be a foreign key but do not reference anything.
Check out you database whether that key exist or not(even though it is in database in other tables).
Check all your mappings and database settings. It may be possible you are setting some not-null="true" in foreign key relations when your database says nullable="true". The first causes an INNER JOIN and the second causes LEFT JOIN.
Set log level to TRACE to see all steps and look for generated SQL when retrieving the objects.
In many to one relationship you need to tell Hibernate what needs to be done if the mapped row is not found. You can configure it in the following ways:
Annotation:
#NotFound(action = NotFoundAction.IGNORE)
Mapping XML:
<many-to-one name="user" column="user_id" class="com.xyz.User" cascade="save-update, evict" not-found="ignore"/>
Just check your database whether id 73 is available or not in your particular table
Okay, I am going to throw out a theory here. Could it be that you are trying to load the picture the first time before the transaction has been committed?
Since the transaction is not yet committed, the row is not visible to the transaction you are using for reading the picture (depends on what transaction isolation level you have).
Then, since hib_session.close() is not inside a finally block, it will not be executed, and the thread-bound session will still have an open transaction. The subsequent request gets the same Hibernate session, with the same open transaction, and you get the same result from the select it issues (again, dependent on transaction isolation level - see documentation here, in particular for REPEATABLE_READ).
This could also explain why flush() makes it slightly better, because if the flush() occurs earlier than the commit(), there's a smaller chance for the race condition to occur.
I suggest you try closing the session in a finally block and see if the behavior changes for subsequent requests.
I Faced this issue and here is What happened and How i resolved it. You most probably have the same thing going on too.
I had POST and USER objects. They are in a OneToMany relationship(A user can have many posts). Making it bidirectional they are in a ManyToOne relationship too (one post belongs to only one user).
Post class looks
#Entity
#Table(name="Post")
public class Post {
#Id
#GeneratedValue(strategy=GenerationType.TABLE)
private long postId;
private String title;
private String body;
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "postUserId")
private AutoUser autoUser;
// getter and setters
User class is
#Entity
#Table(name = "AUTO_USER")
public class AutoUser implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long autoUserId;
#Column(name = "USERNAME")
private String username;
#OneToMany
private List<Post> postList = new ArrayList<>();
// getter and setters
The first table names were Post and AUTO_USER I had 3 users persisted to a AUTO_USER table(with id 1, 2, 3).. And 3 entry to the Post table 1 for each user.
(the join columns or foreign key were 1, 2, 3)
Then I changed only the table name for the user object only and named it #Table(name = "AUTO_USER2").
and I had only one user in this table with id 1.
In my code I iterate over each post and identify which post belongs to which user and display them those belonging to the current logged in user.
After changing the post table name I got this exception
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#2
Which is telling me that the user object with id 2 is not available in the new user Table.
then I registered one more user with id 2 and later I got this
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.tadtab.core.authentication.AutoUser#3
This time it could not find user with id 3
Finally registered a third user and had not exception.
As you can see, the foreign key exists in the post table but since I changed the user table, there could not be a match for them and that is the reason I was facing this issue.
To avoid that situation I created new table names for both objects and started fresh
Hope this will help
I don't see any real problems pertaining to the exception in the code, you might wanna try:
Checking that the transaction is flushed or calling flush() manually after committing;
Checking whether the ID is passed to load() and whether the right ID is passed to it via debugger
Enabling Hibernate to print the generated SQL and/or enabling logging
I have a similar problem with hibernate 3.6.10, while I'm just searching and selecting (if exist).
Annotation:
#Entity
public class Familiares {
#OneToMany(mappedBy = "familiares")
private List<FamiliaresBaja> bajas;
#Entity
#Table(name = "familiares_baja")
public class FamiliaresBaja implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#JoinColumn(name = "familiares_id")
#ManyToOne(optional = false)
private Familiares familiares;
then i retrieve a List and with these looking in FamiliaresBaja if there is at least one.
createQuery("from FamiliaresBaja where familiares.id="+ id).uniqueResult() // should return a single result or null not throw a Exception
This must be a Hibernate bug
Please check the value of lower_case_table_names of your mysql server. If its value is 0, check the SQL generated by hibernate, make sure the table name's case is consistent with the actual table name in mysql.
Check triggers, if you have a before insert trigger, and having NEXTVAL in the sequence, cause that error.
You may have a one-to-one relationship in the entity you are looking for with a different ID, try to load the entity with the ID in the mapped table rather then the identity column.
The correct way to solve this problem is to use session.get() method. Get method will return null if entity is not found.
Caused by: org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.emmanuel.Entity.Classe#17]
at org.hibernate.boot.internal.StandardEntityNotFoundDelegate.handleEntityNotFound(StandardEntityNotFoundDelegate.java:28)
at org.hibernate.event.internal.DefaultLoadEventListener.load(DefaultLoadEventListener.java:216)
at org.hibernate.event.internal.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:327)
at org.hibernate.event.internal.DefaultLoadEventListener.doOnLoad(DefaultLoadEventListener.java:108)
at org.hibernate.event.internal.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:74)
at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118)
at org.hibernate.internal.SessionImpl.fireLoadNoChecks(SessionImpl.java:1215)
at org.hibernate.internal.SessionImpl.internalLoad(SessionImpl.java:1080)
at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:697)
at org.hibernate.type.EntityType.resolve(EntityType.java:464)
at org.hibernate.type.ManyToOneType.resolve(ManyToOneType.java:240)
at org.hibernate.engine.internal.TwoPhaseLoad$EntityResolver.lambda$static$0(TwoPhaseLoad.java:576)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntityEntryLoadedState(TwoPhaseLoad.java:221)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:155)
at org.hibernate.engine.internal.TwoPhaseLoad.initializeEntity(TwoPhaseLoad.java:126)
at org.hibernate.loader.Loader.initializeEntitiesAndCollections(Loader.java:1201)
at org.hibernate.loader.Loader.processResultSet(Loader.java:1009)
at org.hibernate.loader.Loader.doQuery(Loader.java:967)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:357)
at org.hibernate.loader.Loader.doList(Loader.java:2868)
at org.hibernate.loader.Loader.doList(Loader.java:2850)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2682)
at org.hibernate.loader.Loader.list(Loader.java:2677)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:109)
at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1906)
at org.hibernate.internal.CriteriaImpl.list(CriteriaImpl.java:370)
I had this same problem, I had previously deleted an object which was referenced in another table and when I loaded the objects I had a foreign key in the table which did not refer to anything hence this exception.
[com.emmanuel.Entity.Classe#17] specifies that the object which is referenced with id 17 in the table whose objects I want to load does not exist.
My issue was that the child in the relation had a FK which didn't map to the PK of the parent so I had to change the JoinColumn to include referencedColumnName
#Entity
#Table(name = "child")
class Child {
#ManyToOne
#JoinColumn(name = "child_id", referencedColumnName = "non_pk_parent_id")
var iabCategory: IabCategory
}
Note that this caused another issue because of a bug in Hibernate. Here's a stackoverflow post on it:
Jpa Repository got error cannot not serializable when get data from database
and the link to the Hibernate bug: https://hibernate.atlassian.net/browse/HHH-7668
This bug forced me to mark the parent Serializable
#Entity
#Table(name = "parent")
class Parent : Serializable {
}
The bug would cause a ClassCastException to be thrown if the parent didn't implement Serializable

Issue with hibernate/Spring transaction management

I am facing a problem with Spring Transaction management. I am using hibernate as ORM framework. And below is my spring for transaction management.
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="abstractDao"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
<property name="postInterceptors">
<list>
<ref bean="finderIntroductionAdvisor"/>
</list>
</property>
</bean>
<bean id="abstractService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true" lazy-init="true">
<property name="transactionManager">
<ref bean="transactionManager"/>
</property>
<property name="transactionAttributeSource">
<ref bean="transactionAttributeSource"/>
</property>
</bean>
I am basically following genericDao approach as mentioned here so My DaoObject are used to fetch the Domain objects and service classes have DAO objects to maipulate them.
issue i am facing : i am querying a large dataset and loading the result in a list inside the service class. i have marked service class as #transactional(readonly ="true").
to handle some reuirement i have changed all the getters of boxed primitive to
#Column(name = "students")
public Long getStudents() {
if(students== null){
return 0l;
}
return this.students;
}
whenever i load all the dataset via a named query. multiple update queries are fired subsequently to update the dataset.
I debugged that and came to know that this is occuring because of transaction.commit. as hibernate is treating my entities as dirty.
is there a way i can avoid this . i know Flushmode.never could be of help but in my application seesion object is not exposed so i do not have access to it. is there any other way or some mapping change which can help me ?
In addition to Xavi López's answer, another option is to separate persistent property handled by Hibernate from the transient property that conform to your requirement. For example, as follows:
#Column(name = "students")
public Long getStudentsInternal() {
return students;
}
#Transient
public Long getStudents() {
if (students == null) {
return 0l;
}
return students;
}
You can also configure Hibernate to use fields instead of properties by moving annotations to them, it will solve your problem as well (note that the placement of annotations should be consitent for all fields of the entity, or you can use #Access to configure an exclusion):
#Column(name = "students")
private Long students;
public Long getStudents() {
if (students == null) {
return 0l;
}
return students;
}
The issue is with
if(students== null){
return 0l;
}
When Hibernate fetches your entities, they all have null value on the studentsfield. At commit time, when checking if they are dirty, getStudents() returns 0, which is different from the value stored in the database. So, Hibernate sees them as dirty, and proceeds to the update.
If it is suitable to your requirement, changing the type of the studentfield to the primitive type long instead of Long would probably help. Note that this would lead to updating all null's in that column to 0 in the long term.
Maybe you should handle that requirement somewhere else, and free the getter from that concern.

Categories

Resources