I have the following entity:
#Entity
#Table(name = "full_address")
public class FullAddress {
#Id
#Column(name = "guid")
private String id;
#Column(name = "address")
private String address;
//getters and setters omitted
}
Also I create materialized view as follows:
CREATE TABLE address_table (
-- address fields,
aoid VARCHAR(36),
CONSTRAINT address_pk PRIMARY KEY (aoid)
);
CREATE MATERIALIZED VIEW full_address AS
SELECT buildFullAddressById(addrobj.aoid) AS address, addrobj.aoid AS guid FROM address_table AS addrobj;
-- buildFullAddressById is an sql function which is not important here
When I launch Tomcat application, i always get
org.hibernate.HibernateException: Missing table: full_address
Why is this happening? How to fix it?
UPD: looks like a bug in hibernate: https://hibernate.atlassian.net/browse/HHH-9602
I have had the same bug for several past days. As this answer said, it is possible to disable hibernate.hbm2ddl.auto property in your persistence.xml, but it is not a good idea if your project is rapidly developing.
TL;DR: set property hibernate.hbm2dll.extra_physical_table_types to MATERIALIZED VIEW.
Or add -Dhibernate.hbm2dll.extra_physical_table_types="MATERIALIZED VIEW" to VM options. But it is better to such options to configuration file.
Right now, we are using PostgreSQL 9.6 and Hibernate 5.2.12.Final. Somewhy, all materialized views validations were failing with the following exception:
Caused by: org.hibernate.tool.schema.spi.SchemaManagementException:
Schema-validation: missing table [our_project_schema.mv_one_of_views]
All entities that successfully passed validation were either simple tables or views.
It seems like it is a default behaviour for generic databases. In sources here on lines 79-81 they add only these types:
final List<String> tableTypesList = new ArrayList<>();
tableTypesList.add( "TABLE" );
tableTypesList.add( "VIEW" );
Lines 85-87 tell us that there is a possibility to extend these hardcoded values with custom ones:
if ( extraPhysicalTableTypes != null ) {
Collections.addAll( tableTypesList, extraPhysicalTableTypes );
}
On line 56 it is declared private String[] extraPhysicalTableTypes;,
and on lines 71-77 there are some more values added into this array:
if ( !"".equals( extraPhysycalTableTypesConfig.trim() ) ) {
this.extraPhysicalTableTypes = StringHelper.splitTrimmingTokens(
",;",
extraPhysycalTableTypesConfig,
false
);
}
They come from lines 66-70, encoded as String under key EXTRA_PHYSICAL_TABLE_TYPES with empty default value:
final String extraPhysycalTableTypesConfig = configService.getSetting(
AvailableSettings.EXTRA_PHYSICAL_TABLE_TYPES,
StandardConverters.STRING,
""
);
And here on line 1545 is the declaration of that key:
/**
* Identifies a comma-separate list of values to specify extra table types,
* other than the default "TABLE" value, to recognize as defining a physical table
* by schema update, creation and validation.
*
* #since 5.0
*/
String EXTRA_PHYSICAL_TABLE_TYPES = "hibernate.hbm2dll.extra_physical_table_types";
So, adding this property will add another entry to tableTypesList that is used for filtering of many other entities in database, such as sequences, indices, temporary tables and others, that may have name similar to yours materialized view.
This is how my persistence.xml looks like, if you are interested:
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
version="2.1">
<persistence-unit name="project-pu">
<jta-data-source>java:jboss/datasources/project-pu</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.hbm2dll.extra_physical_table_types" value="MATERIALIZED VIEW"/>
<property name="hibernate.show_sql" value="false"/>
<property name="hibernate.format_sql" value="false"/>
<property name="hibernate.use_sql_comments" value="false"/>
<property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/mgt"/>
<property name="hibernate.connection.driver_class" value="org.postgresql.Driver"/>
</properties>
</persistence-unit>
</persistence>
P.S. I know it is a very old post, but I fought with this problem for a few days. I failed finding an answer, so I decided to put it somewhere in the Internet. And this somewhere became here. :)
It's definitely a bug of Hibernate and was described here: https://hibernate.atlassian.net/browse/HHH-9602
So, I recommend removing hibernate.hbm2ddl.auto property as a workaround.
I found out the most simple solution (assuming you still want to use Hibernate to validate the schema) is to add a subselect to the table definition.
Using hbm.xml
<hibernate-mapping>
<class name="com.initech.MvObject" table="MV_OBJ">
<!-- This is necessary when using older Hibernate versions because of
Hibernate bugs. See
https://hibernate.atlassian.net/browse/HHH-1329
https://hibernate.atlassian.net/browse/HHH-9602
-->
<subselect>select * from MV_OBJ</subselect>
Using annotations
import org.hibernate.annotations.Subselect;
import javax.persistence.Entity;
#Entity
#Subselect("select * from MV_OBJ")
public class MvObj{
}
Related
I'm developing an application using:
Java 1.7
JPA (included in javaee-api 7.0)
Hibernate 4.3.8.Final
PostgreSQL-JDBC 9.4-1200-jdbc41
PostgreSQL 9.3.6
And I would like to use the PostgreSQL text datatype for some String attributes. As far as I know, in JPA this should be the correct annotation, to use text in PostgreSQL:
#Entity
public class Product{
...
#Lob
private String description;
....
}
When I annotate my entity like this, I run into errors which look like this:
http://www.shredzone.de/cilla/page/299/string-lobs-on-postgresql-with-hibernate-36.html
In short: It seems that hibernate and jdbc go not hand in hand for clob/text-types.
The solution described is working:
#Entity
public class Product{
...
#Lob
#Type(type = "org.hibernate.type.TextType")
private String description;
...
}
But this has a significant downside: The source code needs hibernate at compile time, which should be unnecessary (That's one reason for using JPA in the first place).
Another way is to use the column annotation like this:
#Entity
public class Product{
...
#Column(columnDefinition = "text")
private String description;
...
}
Which works nicely, BUT:
Now I'm stuck with databases which have a text type (and is also called text ;) ) and if another database will be used in the future the annotations can be overlooked easily. Thus the possible error can be hard to find, because the datatype is defined in a String and therefore can not be found before runtime.
Is there a solution, which is so easy, I just don't see it? I'm very sure that I'm not the only one using JPA in combination with Hibernate and PostgreSQL. So I'm a little confused that I can't find more questions like this.
Just to complete the question, the persistence.xml looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="entityManager">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.app.model.Product</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" />
<property name="javax.persistence.jdbc.url"
value="jdbc:postgresql://localhost:5432/awesomedb" />
<property name="javax.persistence.jdbc.user" value="usr" />
<property name="javax.persistence.jdbc.password" value="pwd" />
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
<property name="hibernate.jdbc.use_streams_for_binary" value="false" />
<property name="hibernate.hbm2ddl.auto" value="create-drop" />
<property name="show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
UPDATE:
This problem is more or less equivalent with this question, the picked answer is the second way to do it described in this question, which I don't like due to the hibernate runtime dependency:
store strings of arbitrary length in Postgresql
This seems to be kind of related to: https://hibernate.atlassian.net/browse/JPA-48
Since the text type is not a part of the SQL standard there is no official JPA way I guess.
However, the text type is quite similar to varchar, but without the length limit. You can hint the JPA implementation with the length property of #Column:
#Column(length=10485760)
private String description;
Update: 10 MiB seems to be the maximum length for varchar in postgresql. The text is almost unlimited, according the documentation:
In any case, the longest possible character string that can be stored
is about 1 GB.
I just had to add this annotation:
#Column(columnDefinition="TEXT")
It did not work on its own. I had to recreate the table in the database.
DROP TABLE yourtable or just alter column type to text with ALTER TABLE statement
If you want to use plain JPA you could just remap the used CLOB type on the Dialect like this:
public class PGSQLMapDialect extends PostgreSQL9Dialect {
#Override
public SqlTypeDescriptor remapSqlTypeDescriptor(SqlTypeDescriptor sqlTypeDescriptor) {
if (Types.CLOB == sqlTypeDescriptor.getSqlType()) {
return LongVarcharTypeDescriptor.INSTANCE;
}
return super.remapSqlTypeDescriptor(sqlTypeDescriptor);
}
}
So it won't use the CLOB mapping from the JDBC driver which uses a OID for the column and stores/loads the text via large object handling.
This would just result in setString and getString calls on the createt text column on the Postgres JDBC Driver via the VarcharTypeDescriptor class.
I would go with simple private String description;. The column type is only a problem if you are generating the database from your code, because it will be generated as varchar instead of text.
It is great to code in database agnostic way, and without any JPA vendor specific things, but there are cases where this just isn't possible. If the reality is that you will have to support multiple database types with all their specifics, then you have to account for those specifics somewhere. One option is to use columnDefinition for defining column type. Another is to leave the code as it is, and just change the column type in the database. I prefer the second one.
I have a small hibernate application as above:
BankAccount class is as follows:
package in.co.way2learn;
import java.util.Set;
public class BankAccount {
private int accountNumber;
private String accountHoldersName;
private int balance;
private Address address;
private Set<String> emails;
//setters and getters
}
Address class is as below:
package in.co.way2learn;
public class Address {
private String addressLine1;
private String addressLine2;
private String city;
private String country;
private int pinCode;
//setters and getters
}
BankAccount.hbm.xml file is as below:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Jul 2, 2014 3:59:34 PM by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="in.co.way2learn">
<class name="BankAccount">
<id name="accountNumber" type="integer">
<generator class="assigned"/>
</id>
<property name="accountHoldersName" type="string"/>
<property name="balance" type="integer"/>
<component name="address" class="Address" lazy="true">
<property name="addressLine1"/>
<property name="addressLine2"/>
<property name="city"/>
<property name="country"/>
<property name="pinCode"/>
</component>
<set name="emails" order-by="email asc" table="bankaccount_emails">
<key column="SNo"/>
<element column="email" type="string"/>
</set>
</class>
</hibernate-mapping>
hibernate.cfg.xml file is as below:
<?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.connection.driver_class">
org.gjt.mm.mysql.Driver
</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/way2learnDB
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">
org.hibernate.dialect.MySQLInnoDBDialect
</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">true</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="in/co/way2learn/BankAccount.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Now my question is in BankAccount.hbm.xml file in the component tag I am using using lazy="true", when ever I am firing select query on BankAccount class using session.get(BankAccount.class, 1235); It is loading address details also from database, the code I used to fire select query is below:
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
BankAccount bankAccount=(BankAccount)session.get(BankAccount.class, 1235);
transaction.commit();
session.close();
The query fired is
Hibernate:
select
bankaccoun0_.accountNumber as accountN1_0_0_,
bankaccoun0_.accountHoldersName as accountH2_0_0_,
bankaccoun0_.balance as balance3_0_0_,
bankaccoun0_.addressLine1 as addressL4_0_0_,
bankaccoun0_.addressLine2 as addressL5_0_0_,
bankaccoun0_.city as city6_0_0_,
bankaccoun0_.country as country7_0_0_,
bankaccoun0_.pinCode as pinCode8_0_0_
from
BankAccount bankaccoun0_
where
bankaccoun0_.accountNumber=?
But I am expecting address details will be loaded lazily from database when ever I used bankAccount.getAddress() method only?
Now can any one please explain why hibernate is loading address details eagerly, and how to load then lazily?
Take an example from below code:-
class B {
private C cee;
public C getCee() {
return cee;
}
public void setCee(C cee) {
this.cee = cee;
}
}
class C {
// Not important really
}
Right after loading B, you may call getCee() to obtain C. But look, getCee() is a method of your class and Hibernate has no control over it. Hibernate does not know when someone is going to call getCee(). That means Hibernate must put an appropriate value into "cee" property at the moment it loads B from database.
If proxy is enabled for C, Hibernate can put a C-proxy object which is not loaded yet, but will be loaded when someone uses it. This gives lazy loading for one-to-one.
But now imagine your B object may or may not have associated C (constrained="false"). What should getCee() return when specific B does not have C? Null. But remember, Hibernate must set correct value of "cee" at the moment it set B (because it does no know when someone will call getCee()). Proxy does not help here because proxy itself in already non-null object.
If your B->C mapping is mandatory (constrained=true), Hibernate will use proxy for C resulting in lazy initialization. But if you allow B without C, Hibernate just HAS TO check presence of C at the moment it loads B. But a SELECT to check presence is just inefficient because the same SELECT may not just check presence, but load entire object. So lazy loading goes away.
Workaround1 : - Just add annotation or entry in hdm file for #JoinColumn for reference private Address address;.
Workaround2 :- add optional=false in OneToOne relationship
Other solutions for this problem:
The simplest one is to fake one-to-many relationship. This will work because lazy loading of collection is much easier then lazy loading of single nullable property but generally this solution is very inconvenient if you use complex JPQL/HQL queries.
The other one is to use build time bytecode instrumentation. For more details please read Hibernate documentation: 19.1.7. Using lazy property fetching. Remember that in this case you have to add #LazyToOne(LazyToOneOption.NO_PROXY) annotation to one-to-one relationship to make it lazy. Setting fetch to LAZY is not enough.
The last solution is to use runtime bytecode instrumentation but it will work only for those who use Hibernate as JPA provider in full-blown Java EE environment (in such case setting "hibernate.ejb.use_class_enhancer" to true should do the trick: Entity Manager Configuration) or use Hibernate with Spring configured to do runtime weaving (this might be hard to achieve on some older application servers). In this case #LazyToOne(LazyToOneOption.NO_PROXY) annotation is also required.
This will work for you.
Hibernate does not create proxies for components, that's why lazy loading does not work for them.
Solutions:
Use bytecode instrumentation to enable lazy loading of non-entity fields. It has its own pitfalls and is not widely adopted.
Use two different classes for BankAccount, one containing the Address component (as it is now), and one without it, and map them to the same table. Then, use the one without address in contexts in which you don't need addresses.
Use fake one-to-one association between BankAccount and Address by making Address component an entity and mapping it to the same table. The drawback here is that you must not insert the Address instances (because you'll end up trying to insert a separate row in the table), but rather you have to read and update it after you insert the corresponding BankAccount entity instance.
Change the db schema and move the component to its own separate table. Then simply promote the component to an entity and map it to the new table.
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();
}
}
I have an old application that worked fine in JBOss 5, JPA and Derby. I am now porting it to JBoss 6, only to find that system is unable to insert the entity with error message:
Column 'ID' cannot accept a NULL value.
Where, ID is an identity column:
#Entity
public class Customer {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
int id;
...
}
I checked the generated schema and it looks good:
CREATE TABLE "APP"."CUSTOMER" (
"ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
"EMAIL" VARCHAR(255),
"NAME" VARCHAR(255),
"PHONE" VARCHAR(255));
You can look at the code of the application in the link below. Any help is appreciated.
https://docs.google.com/open?id=0B_lXBrNTL1s-R3NHb2hYZlJ1Znc
Raj
Well, I got things to work. Basically, when you use JPA to generate the schema in Derby, it creates the tables just fine, but then has problem inserting rows with identity column. The solution was not to generate schema from JPA. I manually created the schema and commented out the schema generation option.
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="ContactsPU" transaction-type="JTA">
<jta-data-source>java:DerbyDS</jta-data-source>
<class>com.webage.contacts.Customer</class>
<!--
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
</properties>
-->
</persistence-unit>
</persistence>
You can fix this without having to create the scheme yourself.
Simply change from GenerationType.IDENTITY to GenerationType.TABLE.
#GeneratedValue(strategy=GenerationType.TABLE)
I was having the same problem in derby and this solved it.
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