I have an application that has to run with an Oracle or embedded H2 database depending on the environment. Up till now I used a MySQL database instead of the embedded H2 one, but decided to migrate.
I use Hibernate 3.3.1GA (and am restricted, so I cannot update). With both Oracle and MySQL everything works fine, but when I try to use the H2 database it keeps hanging. The problem appears to be a column with BLOBs (serialized java objects). Even when the table is empty, execution hangs.
SLF4J output (loglevel ALL):
TableMetadata.java:org.hibernate.tool.hbm2ddl.TableMetadata:<init>:62 INFO table found: DATABASE.PUBLIC.JAVA_OBJECTS
org.hibernate.tool.hbm2ddl.TableMetadata:<init>:63 INFO columns: [id, last_update, markdeleted, class, object]
org.hibernate.connection.DriverManagerConnectionProvider:closeConnection:152 TRACE returning connection to pool, pool size: 1
At this point the program seems to hang. Earlier log output seems normal and when this table is not used (removed from hibernate.cfg.xml) the program starts up fine.
hibernate.cfg.xml (excerpt)
<property name="hibernate.connection.driver_class">org.h2.Driver</property>
<property name="hibernate.connection.url">jdbc:h2:file:database</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.default_schema">PUBLIC</property>
<property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
<property name="connection.pool_size">1</property>
<property name="current_session_context_class">thread</property>
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
The table's create string:
CREATE TABLE java_objects (
id int(11) NOT NULL AUTO_INCREMENT,
class varchar(255) NOT NULL,
object blob NOT NULL,
last_update timestamp AS CURRENT_TIMESTAMP,
markDeleted tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (id)
) ;
and finally the entity xml
<hibernate-mapping>
<class name="server.DataBean" table="java_objects">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="type" column="class" />
<property name="object" not-null="true">
<column name="object" sql-type="BLOB" />
</property>
<property name="lastUpdate" column="last_update" type="timestamp" />
<property name="markDeleted" type="boolean" />
</class>
</hibernate-mapping>
Does anyone know what I'm doing wrong? What is h2 expecting differently when handling blobs?
Problem may have been with org.hibernate.dialect.H2Dialect
Changing to HSQLDialect works. Still, is there an underlying issue?
Related
When I try to run this query with hibernate in Java somethings go wrong and throws an error like
( 12002 ) Internal Service Error. Exception Message : Bad Sql Grammar Exception occurred [Hibernate operation: could not execute query; bad SQL grammar [SELECT COMDT_COM_STAT, COMDT_COM_REFNO, COMDT_COM_CCY
FROM COMDT
WHERE COMDT_COM_REFNO = ?
AND COMDT_COM_RDN BETWEEN ? AND ?
AND COMDT_COM_STAT = ?
GROUP BY COMDT_COM_STAT, COMDT_COM_REFNO, COMDT_COM_CCY
ORDER BY COMDT_COM_REFNO]; nested exception is java.sql.SQLException: Invalid Column Name]
But when I run the same query with proper inputs in PLSQL, everything works as I expected. I am working on this error for 2 days but nothing came up.
Thanks.
QUERY
<sql-query name="getCommissionBetweenDatesWithStat">
<return alias="xyz"
class="com.ykb.hmn.cms.commission.datamodel.IComDetail"/>
<![CDATA[
SELECT COMDT_COM_CCY AS {xyz.currency}, SUM(xyz.COMDT_COM_AMT1) AS {xyz.amount1}
FROM COMDT
WHERE COMDT_COM_REFNO = :refNo
AND COMDT_COM_RDN BETWEEN :startRdn AND :endRdn
AND COMDT_COM_STAT = :stat
GROUP BY COMDT_COM_STAT, COMDT_COM_REFNO, COMDT_COM_CCY
ORDER BY COMDT_COM_REFNO
]]>
</sql-query>
Entity
<class name="com.ykb.hmn.cms.commission.datamodel.IComDetail"
table="COMDT">
<tuplizer class="com.ykb.hmn.inf.core.datamodel.IntfEntityTuplizer"
entity-mode="pojo" />
<id name="oid" type="java.lang.Long">
<column length="17" name="COMDT_ID" />
</id>
<property name="refNo" type="long">
<column length="12" name="COMDT_COM_REFNO" />
</property>
<property name="stat" type="string">
<column length="1" name="COMDT_COM_STAT" />
</property>
<property name="relDay" type="int">
<column length="5" name="COMDT_COM_RDN" />
</property>
<property name="amount1" type="big_decimal">
<column precision="18" scale="2" name="COMDT_COM_AMT1" />
</property>
<property name="currency" type="string">
<column length="4" name="COMDT_COM_CCY" />
</property>
<class/>
Table Schema
COMDT_ID NUMBER(17)
COMDT_COM_REFNO NUMBER(12)
COMDT_COM_AMT1 NUMBER(18,2)
COMDT_COM_STAT VARCHAR2(1)
COMDT_COM_RDN NUMBER(5)
COMDT_COM_CCY VARCHAR2(4)
Thanks.
My guess, hibernate named query should be declared using the property name, not the column name. So instead of using column name in the named query, use the property name.
See this example for more details:
https://www.journaldev.com/3451/hibernate-named-query-example-namedquery
We have a column in a table whose hbm enrty is like
<property name="test" type="java.lang.String" update="true"
insert="true" column="test" length="60" not-null="true"
/>
However, while insertion it allow us to insert null value in test column.
Hiberate version : 3.5.4-Final
Please let me know if we are missing anything for restrict null value.
The following is my code for batch inserting to MySQL remote database.
Session session = db.setSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<e.getContents().size(); i++ ) {
Content content = e.getContents().get(i);
session.save(content);
if ( i % 40 == 0 ) {
session.flush();
session.clear();
}
}
tx.commit();
The mapping is defined in the following way:
class name="Database.Content" table="..." schema="" catalog="...">
<id name="id">
<column name="id" sql-type="int" not-null="true"/>
<generator class="identity"/>
</id>
<property name="week">
<column name="week" sql-type="int"/>
</property>
<property name="type">
<column name="type" sql-type="int" not-null="true"/>
</property>
<many-to-one name="group" class="Database.Group">
<column name="`group`"/>
</many-to-one>
<many-to-one name="table" class="Database.Table">
<column name="`table`" not-null="true"/>
</many-to-one>
</class>
I also set up some properties in hibernate.cfg.xml:
<property name="hibernate.jdbc.batch_size">40</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
Unfortunately, the insertion of 150 rows takes about 30 seconds, which is very slow. I have read that setting generator=identity may disable batch inserting completely. However, if I remove the generator line, I end up with getting Duplicate key error. I wonder if I could send null as my id, so MySQL will do the job.
What is the best way to optimise the query? Thanks.
As answered in this SO question identity will indeed not work for batch. For MySQL you end up either generating ids in an application (f.e. with generator assigned or uuid - Hibernate-specific) or employing JPA-compliant table generator.
Example of using table generator:
<table-generator name="EMP_GEN"
table="GENERATOR_TABLE"
pk-column-name="key"
value-column-name="hi"
pk-column-value="EMP"
allocation-size="20"/>
See details on http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#mapping-declaration-id. There is also a description of what parameter mean on Java EE page.
I have a mapping for a set with a composite-element where a property has the attribute insert="false" set. However, upon saving of the parent object, this attribute seems to be ignored as Hibernate tries to insert it anyway.
What am I missing here? How can I get this to work as expected?
<set name="deals" cascade="all,save-update" >
<subselect>
...some select statement...
</subselect>
<key column="user_id" />
<composite-element class="UserDeal">
<property name="dealId" column="deal_id" type="string" />
<property name="dealName" column="deal_name" type="string" update="false" insert="false" />
</composite-element>
</set>
In the example above, I don't want the INSERT statement to include the deal_name property, but it's still included for some reason.
I am trying to update the existing schema programmatically using SchemaUpdate. I changed the name of the existing field name in specific table and then,
I am creating the hibernate configuration object and adding the changed hbm.xml files into the configuration object.
But when I said SchemaUpdate.execute(true,true) it is creating the new field in the table instead of updating.
Here is my code:
Configuration hibConfiguration = new Configuration();
hibConfiguration.configure(configFileDoc);
hibConfiguration.addDocument(doc1);
hibConfiguration.addDocument(doc2);
hibConfiguration.buildMappings();
SchemaUpdate schemaUpdate = new SchemaUpdate(hibConfiguration);
schemaUpdate.execute(true, true);
following is my cfg.xml file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">passwrd</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhot:3306/testSchema</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="javax.persistence.validation.mode">none</property>
<property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<property name="hibernate.default_entity_mode">dynamic-map</property>
</session-factory>
</hibernate-configuration>
and this is my hbm.xml file for table to update:
<?xml version="1.0" encoding="UTF-8"?><hibernate-mapping>
<class entity-name="testTable2">
<id column="id" name="id" type="java.lang.Long">
<generator class="identity"/>
</id>
<property column="testTable1Id" length="20" name="testTable1Id" type="java.lang.Long"/>
<property column="doubleColumnj" length="20" name="doubleColumnj" type="java.lang.Double"/>
</class>
</hibernate-mapping>
Hibernate does not do version control on tables. It has no way of determining that the field was renamed. So when it compares the existing mapping to the database, all it is able to determine is there is a mapped column which did not exist before.
It also does not drop unmapped columns in order to be able to support legacy databases, or perhaps multiple hibernate entities providing different views of the same table.