I am using HSQL to run a number of unit tests on my java application. I am using Spring + Hibernate. I am having a problem when switching from MySQL to HSQL. The tests run perfectly on MySQL but whenever I change to HSQL I get the following exception:
Caused by: org.hsqldb.HsqlException: invalid schema name: LMS
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.error.Error.error(Unknown Source)
at org.hsqldb.SchemaManager.getSchemaHsqlName(Unknown Source)
at org.hsqldb.SchemaManager.getSchemaName(Unknown Source)
at org.hsqldb.Session.getSchemaName(Unknown Source)
at org.hsqldb.SchemaManager.getTable(Unknown Source)
at org.hsqldb.ParserDQL.readTableName(Unknown Source)
at org.hsqldb.ParserDQL.readSimpleRangeVariable(Unknown Source)
at org.hsqldb.ParserDML.compileInsertStatement(Unknown Source)
at org.hsqldb.ParserCommand.compilePart(Unknown Source)
at org.hsqldb.ParserCommand.compileStatement(Unknown Source)
at org.hsqldb.Session.compileStatement(Unknown Source)
at org.hsqldb.StatementManager.compile(Unknown Source)
at org.hsqldb.Session.execute(Unknown Source)
My Spring configuration is the following:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver" />
<property name="url" value="jdbc:hsqldb:file:lms" />
<property name="username" value="SA"/>
<property name="password" value=""/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list>
<value>com.dreamteam.lms.**.*</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<!--<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>-->
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.generate_statistics">true</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.SingletonEhCacheProvider</prop>
</props>
</property>
</bean>
Sample Annotation on one of my classes:
#Entity
#Table(name = "answer", catalog = "lms")
public class Answer implements Cloneable, Serializable, IPojoGenEntity, IAnswer {
.
.
Any insight would be appreciated.
Regards
Chris
make "create-schema.sql" file
CREATE SCHEMA lms;
add "dataSourceInitializer" bean
<bean id="dataSourceInitializer" class="org.springframework.jdbc.datasource.init.DataSourceInitializer">
<property name="dataSource" ref="dataSource" />
<property name="databasePopulator">
<bean class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator">
<property name="continueOnError" value="true" />
<property name="scripts">
<list>
<value>classpath:SQL/create-schema.sql</value>
</list>
</property>
</bean>
</property>
</bean>
set "depends-on" attribute to "sessionFactory" bean
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean" depends-on="dataSourceInitializer">
...
I use following bean to create schema during tests.
public class HSQLSchemaCreator {
private String schemaName;
private DataSource dataSource;
public HSQLSchemaCreator(String schemaName, DataSource dataSource) {
this.schemaName = schemaName;
this.dataSource = dataSource;
}
#PostConstruct
public void postConstruct() throws Exception {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.execute("CREATE SCHEMA " + schemaName + " AUTHORIZATION DBA");
}
}
spring configuration:
<bean id="hsqlSchemaCreator" class="....HSQLSchemaCreator">
<constructor-arg name="schemaName" value="..."/>
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- Override entityManagerFactory to depend on hsqlSchemaCreator for tests -->
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" depends-on="hsqlSchemaCreator">
and so on...
Just for the record I managed to solve this one by simply removing the 'catalog' attribute from my Hibernate entities. Hence,
#Entity
#Table(name = "answer", catalog = "lms")
became
#Entity
#Table(name = "answer")
Names for schemas, tables, columns, etc. are not (at least not by default) case sensitive in MySQL. HSQLDB is case sensitive, but it also converts all identifiers in query that are not quoted to the uppercase.
You can quickly test is this your problem by changing schema name to LMS everywhere (first in database). You can find more detailed story about HSQLDB and Hibernate from here: HSQLDB No such table Exception
I am not sure why this worked, but for me, at least, adding square brackets around the table names and schema did the trick for me:
#Table(name = "schema.tableName")
became
#Table(name = "[schema].[tableName]")
Related
I am trying to call on a stored procedure from a db2 database using hibernate's entity manager and return the results as an object. I am using the #NamedStoredProcedureQuery annotation which does not seem to be found by hibernate. I am getting the error: "No #NamedStoredProcedureQuery was found with that name : Create_Division". Any ideas would be great.
beans:
<bean id="entityManagerFactoryBean" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="demoJPAUnit" />
<property name="packagesToScan">
<list>
<value>com.merchantBoarding.db2.queryObjects</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.archive.autodetection">class,hbm</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.DB2Dialect</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryBean" />
</bean>
Query output object:
#NamedStoredProcedureQuery(
name="Create_Division",
procedureName="MD.PMDBD017",
resultClasses = {CreateDivisionResult.class},
parameters={
#StoredProcedureParameter(name="IN_ENTY",mode=ParameterMode.IN,type=Integer.class),
#StoredProcedureParameter(name="IN_PARNT_ENTY",mode=ParameterMode.IN,type=Integer.class),
#StoredProcedureParameter(name="IN_ACTION",mode=ParameterMode.IN,type=String.class),
#StoredProcedureParameter(name="IN_ENTY_XREF",mode=ParameterMode.IN,type=String.class),
#StoredProcedureParameter(name="OUT_ENTY",mode=ParameterMode.OUT,type=Integer.class),
#StoredProcedureParameter(name="OUT_ID",mode=ParameterMode.OUT,type=String.class),
#StoredProcedureParameter(name="OUT_ENTY_XREF",mode=ParameterMode.OUT,type=String.class),
#StoredProcedureParameter(name="OUT_SQLCODE",mode=ParameterMode.OUT,type=Integer.class),
#StoredProcedureParameter(name="OUT_STATUS",mode=ParameterMode.OUT,type=String.class),
#StoredProcedureParameter(name="OUT_ERRORTEXT",mode=ParameterMode.OUT,type=String.class),
}
)
public class CreateDivisionResult implements Serializable {
#Id
public String OUT_ENTY;
public String OUT_ID;
public String OUT_ENTY_XREF;
public String OUT_SQLCODE;
public String OUT_STATUS;
public String OUT_ERRORTEXT;
}
DAO code:
StoredProcedureQuery query = manager.createNamedStoredProcedureQuery("Create_Division");
query.setParameter("IN_ENTY", 111);
query.setParameter("IN_PARNT_ENTY", 11111);
query.setParameter("IN_ACTION", "CREATE");
query.setParameter("IN_ENTY_XREF", "ED");
List<CreateDivisionResult> results = query.getResultList();
EDIT:
So I added #Entity and that did fix the original error, but the output parameters still aren't mapping to the CreateDivisionResult object. I can only get each indiviual field with query.getOutputParameterValue. Is this just a restriction of JPA?
#NamedStoredProcedureQuery should be applied to Entity class or mapped class
Seems you are missing the #Entity in your 'CreateDivisionResult'
I was running my unit tests directly with the targetted Database which is : Oracle 10g and i was asked to run them under H2 Database.
So, after generating the differents SQL scripts and configured the H2 database (through XML config. with Spring), i realized that some of my tests failed whereas some of them passed...
I have the following view (a view of a view) which returns different columns :
CREATE OR REPLACE FORCE VIEW ##.VIEW_OLB_SAT_COVERAGE
(
SAT_CODE,
ORBITAL_POSITION,
COVERAGE_DOWN,
COVERAGE_UP
)
AS
SELECT DISTINCT sat_code,
orbital_position,
coverage_down,
coverage_up
FROM ##.VIEW_OLB_TXP_COVERAGE
ORDER BY sat_code ASC;
The view "VIEW_OLB_TXP_COVERAGE" is the following :
CREATE OR REPLACE FORCE VIEW ##.VIEW_OLB_TXP_COVERAGE
(
SAT_CODE,
ORBITAL_POSITION,
TXP_NO,
COVERAGE_DOWN,
COVERAGE_UP,
POLARIZATION_DOWN,
POLARIZATION_UP
)
AS
SELECT DISTINCT ##.OLB_AVAILABLE_TXP.SAT_CODE,
###.SAT_DEP.ORBIT_LOC / 3600 ORBITAL_POSITION,
##.OLB_AVAILABLE_TXP.TXP_NO,
###.TXP.CUR_DN_COVERAGE COVERAGE_DOWN,
###.TXP.CUR_UP_COVERAGE COVERAGE_UP,
###.TXP.TXP_DN_POL,
###.TXP.TXP_UP_POL
... The rest is omitted for clarity
The Hibernate entities are the following :
#Component(value = "viewOlbSatCoverage")
#Scope("prototype")
#Entity
#Table(name = "VIEW_OLB_SAT_COVERAGE", schema = "##")
public class ViewOlbSatCoverage implements Serializable {
private static final long serialVersionUID = -6728959649786852446L;
#Id
private ViewOlbSatCoverageId viewOlbSatCoverageId;
public ViewOlbSatCoverageId getViewOlbSatCoverageId() {
return viewOlbSatCoverageId;
}
public void setViewOlbSatCoverageId(ViewOlbSatCoverageId viewOlbSatCoverageId) {
this.viewOlbSatCoverageId = viewOlbSatCoverageId;
}
#Override
public String toString() {
return "ViewOlbSatCoverage : [viewOlbSatCoverageId=" + viewOlbSatCoverageId == null ? "null"
: viewOlbSatCoverageId.toString() + "]";
}
}
#Component(value = "viewOlbSatCoverageId")
#Scope("prototype")
#Embeddable
public class ViewOlbSatCoverageId implements Serializable {
private static final long serialVersionUID = 2822316442843031126L;
#Column(name = "COVERAGE_DOWN")
private String coverageDown;
#Column(name = "COVERAGE_UP")
private String coverageUp;
#Column(name = "SAT_CODE")
private String satCode;
#Column(name = "ORBITAL_POSITION")
private BigDecimal orbitalPosition;
public ViewOlbSatCoverageId() {
}
public ViewOlbSatCoverageId(String satCode, BigDecimal orbitalPosition, String coverageDown, String coverageUp) {
setSatCode(satCode);
setOrbitalPosition(orbitalPosition);
setCoverageDown(coverageDown);
setCoverageUp(coverageUp);
}
// Getters, setters omitted for clarity ...
}
As I mentionned, the targetted database is Oracle 10g and all works fine with it (when the app is running).
But when I run H2 database for unit testing purpose, the following method ( findDistinctAllOrbitalPositions) doesn't work :
#Repository
public class ViewOlbSatCoverageDaoImpl extends GenericDaoImpl<ViewOlbSatCoverage> implements ViewOlbSatCoverageDao {
public ViewOlbSatCoverageDaoImpl() {
setGenericClass(ViewOlbSatCoverage.class);
setDaoLogger(ViewOlbSatCoverageDaoImpl.class);
}
#Override
#SuppressWarnings("unchecked")
public List<BigDecimal> findDistinctAllOrbitalPositions() {
Query query = sessionFactory.getCurrentSession().createQuery(
"select distinct(viewOlbSatCoverageId.orbitalPosition) from " + genericClass.getSimpleName()
+ " order by viewOlbSatCoverageId.orbitalPosition asc"); // genericClass is ViewOlbSatCoverage
return query.list();
}
}
As you can see, i'm using HQL but also the Criteria API.
When i launch maven from command line :
mvn clean -Dtest=ViewOlbSatCoverageDaoImplTestCase test
It gives me the following :
Caused by: org.h2.jdbc.JdbcSQLException: Column "VIEWOLBSAT0_.ORBITAL_POSITION" not found; SQL state
ment:
select distinct viewolbsat0_.ORBITAL_POSITION as col_0_0_ from ##.VIEW_OLB_SAT_COVERAGE viewolbsat0_
order by viewolbsat0_.ORBITAL_POSITION asc [42122-190]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:345)
at org.h2.message.DbException.get(DbException.java:179)
at org.h2.message.DbException.get(DbException.java:155)
at org.h2.expression.ExpressionColumn.optimize(ExpressionColumn.java:147)
at org.h2.expression.Alias.optimize(Alias.java:51)
at org.h2.command.dml.Select.prepare(Select.java:835)
at org.h2.command.Parser.prepareCommand(Parser.java:246)
at org.h2.engine.Session.prepareLocal(Session.java:460)
at org.h2.engine.Session.prepareCommand(Session.java:402)
at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1188)
at org.h2.jdbc.JdbcPreparedStatement.<init>(JdbcPreparedStatement.java:72)
at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:276)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.hibernate.engine.jdbc.internal.proxy.ConnectionProxyHandler.continueInvocation(Connec
tionProxyHandler.java:138)
... 64 more
Here is a sample of my applicationContext-test.xml :
<jdbc:embedded-database id="h2TestDataSource" type="H2"/>
<jdbc:initialize-database data-source="h2TestDataSource">
<jdbc:script location="classpath:com/eutelsat/olb/sql/create/views/VIEW_OLB_SAT_COVERAGE.sql" />
<jdbc:script location="classpath:com/eutelsat/olb/sql/create/views/VIEW_OLB_TXP_COVERAGE.sql" />
<!-- Other .sql files omitted for clarity -->
</jdbc:initialize-database>
<!-- Connection pool -->
<bean id="pooledDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="org.h2.Driver" />
<property name="jdbcUrl" value="jdbc:h2:mem:h2TestDataSource;INIT=RUNSCRIPT FROM 'com/eutelsat/olb/sql/create/schemas/INIT.sql'" />
<property name="user" value="sa" />
<property name="password" value="" />
<property name="acquireIncrement" value="1" />
<property name="minPoolSize" value="1" />
<property name="maxPoolSize" value="5" />
<property name="maxIdleTime" value="30" />
<property name="maxIdleTimeExcessConnections" value="10" />
<property name="numHelperThreads" value="3" />
<property name="unreturnedConnectionTimeout" value="0" />
</bean>
<!-- Session factory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="h2TestDataSource" />
<property name="packagesToScan" value="com.eutelsat.olb.server.model" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">none</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.order_inserts">true</prop>
<prop key="hibernate.order_updates">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="format_sql">true</prop>
<prop key="hibernate.id.new_generator_mappings">true</prop>
</props>
</property>
</bean>
<!-- Transaction Manager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
I have read a lot of things but I can't find what the problem is (incorrect SQL script which needs to be adapted to fit in H2 database or maybe an H2 database config. with column alias matters ?).
NB : schemas have been obfuscated.
Thanks in advance for pointers.
I've found a solution to my problem.
The SQL scripts (some of them were omitted in the sample posted in SOF) which were declared in my "applicationContext-test.xml" file were not well ordered resulting in a view with a INVALID status.
-> Resulting in generated SQL query done by Hibernate complaining that some tables and / or columns were'nt found.
I've found the problem (and also the solution) thanks to the excellent H2 web server allowing me to view in memory data. In the SCHEMA_INFORMATION section, I saw VIEWS and when clicking on it, I saw STATUS = INVALID.
In order to add an H2 web server using Spring XML config, you can easily add this :
<bean id="h2Server" class="org.h2.tools.Server" factory-method="createTcpServer" init-method="start" destroy-method="stop" depends-on="h2WebServer">
<constructor-arg value="-tcp,-tcpAllowOthers,-tcpPort,9992"/>
</bean>
<bean id="h2WebServer" class="org.h2.tools.Server" factory-method="createWebServer" init-method="start" destroy-method="stop">
<constructor-arg value="-web,-webAllowOthers,-webPort,8882"/>
</bean>
Do not forget to add a depends-on attribute valued to "h2Server" (so : depends-on="h2Server") to you datasource bean, otherwise it will not work as expected !
First of all, I can't use Spring's #Transactional annotation. I have to use exactly JTA which in out EJB-container. Currecntly I'm using JBoss AS 7.0 Web-Profile. So what I need to do is configure Hibernate's session factory to correctly work with JTA-transaction inside the Spring's Envirnoment. My current configuration:
piece of the context.xml configuration:
<tx:annotation-driven/>
<tx:jta-transaction-manager />
<!-- Some other beans -->
<bean id="userTransaction" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/UserTransaction"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.badmitrii.db.entity.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransaction" ref="userTransaction"></property>
</bean>
DAO-method:
public Player getPlayerById(Integer id){
try {
userTransaction.begin();
} catch (Exception e) { }
//Here is obtaining a Criteria object and setting Restrictions
try {
userTransaction.commit();
} catch (Exception e) { }
return (Player) criteria.uniqueResult();
}
But, I got the following excpetion when I was trying to get Session in the DAO method:
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
org.springframework.orm.hibernate4.SpringSessionContext.currentSession(SpringSessionContext.java:134)
org.hibernate.internal.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:1024)
com.badmitrii.db.dao.EmployeeDAOImpl.getEmployeeById(EmployeeDAOImpl.java:34)
com.badmitrii.EmployeeListController.getEmployeeById(EmployeeListController.java:42)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:483)
org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
javax.servlet.http.HttpServlet.service(HttpServlet.java:734)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
How to configure it correctly?
First of all remove the declaration for JtaTransactionManager as that is already provided by <tx:jta-transaction-manager />.
Next there is no reason why you wouldn't be able to use #Transactional in a JTA environment that is the whole point of declarative tx management.
You should wire the configured jta transactionmanager to the LocalSessionFactoryBean to switch out the used CurrentSessionContext.
<tx:annotation-driven/>
<tx:jta-transaction-manager />
<!-- Some other beans -->
<bean id="userTransaction" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/UserTransaction"></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jtaTransactionManager" ref="transactionManager" />
<property name="annotatedClasses">
<list>
<value>com.badmitrii.db.entity.Employee</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
Then in your cod eyou can simply do something like this
#Transactional
public Player getPlayerById(Integer id){
//Here is obtaining a Criteria object and setting Restrictions
return (Player) criteria.uniqueResult();
}
Update:
For JBoss the <tx:jta-transaction-manager /> doesn't work due to fact that the TransactionManager for JTA is registered in JNDI under the name java:jboss/TransactionManager instead of one of the well-known names. You will need to declare the JtaTransactionManager bean yourself and remove the <tx:jta-transaction-manager /> element. For the lookup you need to specify the transactionManagerName or do a JNDI lookup yourself.
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManagerName" value="java:jboss/TransactionManager" />
</bean>
The UserTransaction is registered under the default name so you can omit the injection of it in the JtaTransactionManager as it will do the lookup itself.
i want to use Hikari CP in my Spring 4.0.3 context but seems i am missing something.
My bean configuration looks like:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="dataSource.driverClassName">${database.driver}</prop>
<prop key="dataSource.jdbcUrl">${database.database.jdbc.url}</prop>
<prop key="dataSource.port">${database.port}</prop>
<prop key="dataSource.databaseName">${database.name}</prop>
<prop key="dataSource.user">${database.user}</prop>
<prop key="dataSource.password">${database.password}</prop>
</props>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
but i get an exception:
Caused by: java.lang.IllegalArgumentException: one of either dataSource or dataSourceClassName must be specified
at com.zaxxer.hikari.HikariConfig.validate(HikariConfig.java:655)
at com.zaxxer.hikari.HikariDataSource.<init>(HikariDataSource.java:66)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:408)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
... 15 more
i have tried to configure dataSourceClassName using the HSQL org.hsqldb.jdbc.JDBCDataSource
that way:
<prop key="dataSourceClassName">org.hsqldb.jdbc.JDBCDataSource</prop>
also that way:
<prop key="dataSource.ClassName">org.hsqldb.jdbc.JDBCDataSource</prop>
both times i got the following exception:
Caused by: java.lang.RuntimeException: java.beans.IntrospectionException: Method not found: setPort
at com.zaxxer.hikari.util.PropertyBeanSetter.setProperty(PropertyBeanSetter.java:109)
at com.zaxxer.hikari.util.PropertyBeanSetter.setTargetFromProperties(PropertyBeanSetter.java:61)
at com.zaxxer.hikari.pool.HikariPool.initializeDataSource(HikariPool.java:497)
... 23 more
Caused by: java.beans.IntrospectionException: Method not found: setPort
at java.beans.PropertyDescriptor.<init>(PropertyDescriptor.java:110)
at com.zaxxer.hikari.util.PropertyBeanSetter.setProperty(PropertyBeanSetter.java:97)
... 25 more
Can someone show me a working Hikari CP Spring 4 bean configuration that works with a HSQL DB?
I am not interested in MySql, PG etc. because i know how to get them working. But i can't manage to get it done with HSQL.
Thanks,
Tech used: Java8, Spring 4.0.3, HSQL 2.3.2
one way to get the job done is to provide an instance of a DataSource object:
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<property name="dataSource">
<bean class="org.hsqldb.jdbc.JDBCDataSource">
<property name="url" value="${database.database.jdbc.url}"/>
<property name="databaseName" value="${database.name}"/>
<property name="user" value="${database.user}"/>
<property name="password" value="${database.password}"/>
</bean>
</property>
</bean>
</constructor-arg>
</bean>
for sure there are other solutions.
HTH,
Some of your properties in your example do not need the prefix 'dataSource' if you are using a driver-class.
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg>
<bean class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="driverClassName">${database.driver}</prop>
<prop key="jdbcUrl">${database.database.jdbc.url}</prop>
<prop key="username">${database.user}</prop>
<prop key="password">${database.password}</prop>
</props>
</constructor-arg>
</bean>
</constructor-arg>
</bean>
And port and databaseName can be included in the jdbcUrl.
For a pure Java-config solution, I've used the following (in a class with a #Configuration annotation and included in the component-scan-path):
...
#Bean
public DataSource dataSource() {
return new HikariDataSource(hikariConfig());
}
private HikariConfig hikariConfig() {
HikariConfig config = new HikariConfig();
config.setDriverClassName(driverClassName);
config.setJdbcUrl(jdbcUrl);
config.setUsername(username);
config.setPassword(password);
return config;
}
...
HTH
Tested under HikariCP 2.3.8 and Hibernate 4.3.8.Final:
<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">
<constructor-arg>
<props>
<prop key="dataSourceClassName">org.postgresql.ds.PGSimpleDataSource</prop>
<prop key="dataSource.user">${database.username}</prop>
<prop key="dataSource.password">${database.password}</prop>
<prop key="dataSource.databaseName">${database.databaseName}</prop>
<prop key="dataSource.serverName">${database.serverName}</prop>
<prop key="connectionTestQuery">SELECT 1</prop>
</props>
</constructor-arg>
</bean>
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
<constructor-arg ref="hikariConfig" />
</bean>
For the dataSourceClassName, looks at the popular datasource class names table.
ConnectionTestQuery is required for postgresql as per https://github.com/brettwooldridge/HikariCP/issues/225, shouldn't be needed when using a latest jdbc driver version.
we're using spring, hibernate and hsql to persist a simple user entity. We always get the error "table not found". Do you have any idea what this could be? It seems like the table is not generated or the hsql database is not running at all.
Regards,
G.
#Entity
#Table (name="USER")
public class User {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
#Column(name="ID")
private Long id;
#Column(name="NAME", length = 100, nullable = false)
private String name;
public User(){}
//getters and setters ...
by this dao class:
package de.hsrm.mediathek;
import java.util.List;
public class UserDao implements IUserDao{
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(final HibernateTemplate hibernateTemplate){
this.hibernateTemplate = hibernateTemplate;
}
#Transactional
public void store(final User user){
hibernateTemplate.saveOrUpdate(user);
}
#Transactional
public void delete(final Long userId){
final User user = (User) hibernateTemplate.get(User.class, userId);
hibernateTemplate.delete(user);
}
#Transactional(readOnly = true)
public User findById(final Long userId){
return (User) hibernateTemplate.get(User.class, userId);
}
#Transactional(readOnly = true)
public List<User> findAll(){
return hibernateTemplate.find("from User");
}
}
Configuration XML:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<tx:annotation-driven/>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:mediathekdb" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>de.hsrm.mediathek.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.hbm2dll.auto">create-drop</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.connection.pool_size">10</prop>
<prop
key="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider</prop>
</props>
</property>
</bean>
<bean id="hibernateTemplate"
class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDao" class="de.hsrm.mediathek.UserDao">
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Interceptor for hibernate calls to be able to create and close sessions
<bean id="hibernateInterceptor"
class="org.springframework.orm.hibernate3.HibernateInterceptor">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
-->
</beans>
Error LOG:
Caused by: java.sql.SQLException: Table not found in statement [insert into User (ID, NAME) values (null, ?)]
at org.hsqldb.jdbc.Util.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.<init>(Unknown Source)
at org.hsqldb.jdbc.jdbcConnection.prepareStatement(Unknown Source)
at org.hibernate.jdbc.AbstractBatcher.getPreparedStatement(AbstractBatcher.java:528)
at org.hibernate.jdbc.AbstractBatcher.prepareStatement(AbstractBatcher.java:95)
at org.hibernate.id.insert.AbstractSelectingDelegate.performInsert(AbstractSelectingDelegate.java:30)
... 63 more
The problem is that the property "hbm2dll" is wrongly spelled. It should be "hbm2ddl":
It is:
<prop key="hibernate.hbm2dll.auto">create-drop</prop>
It should be:
<prop key="hibernate.hbm2ddl.auto">create-drop</prop>
It's also better to keep an eye on logs for any other errors, as I had a similar problem and found out that create table statement was failing for HSQLDB's DDL generated by Hibernate and Hibernate was silently swallowing it
2011-06-09 10:48:30,722 [main] ERROR org.hibernate.tool.hbm2ddl.SchemaExport - Wrong data type: ALERT_ID in statement [create table ACCOUNT_ALERT (ALERT_ID numeric generated by default as identity (start with 1)]
Later when I changed the following
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="ALERT_ID")
private BigInteger alertId;
to
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
#Column(name="ALERT_ID")
private BigInteger alertId;
it worked perfectly.
I'd suggest trying to run HSQLDB in server mode using:
java -classpath hsqldb.jar org.hsqldb.server.Server
Check that it's running using Database manager:
java -classpath hsqldb.jar org.hsqldb.util.DatabaseManagerSwing
Next, change your Hibernate URL, so it uses server mode HSQLDB:
<property name="url" value="jdbc:hsqldb:mediathekdb" />
I've had success using this method. It's possible that create-drop doesn't work properly when using a memory only instance.