问题
I have an application running with Spring 3.1.1 , Hibernate 3.6.0.Final and Hibernate Spatial 1.1.1 on Tomcat 8.0.20. Until now, we were using Oracle 11.2.0.4 , but we want to migrate to PostgreSQL 9.2-1002.jdbc4 / PostGIS 2.1.6.
We will migrate the database schemas on different phases, so at some stage, we will need some connections to be working with Oracle and some with PostGIS. In order to begin developing and testing this, I removed any Oracle Maven dependency and added the necessary ones to work with Postgres as described in Hibernate Spatial 1.1.1 Tutorial, mostly :
<dependency>
<groupId>org.hibernatespatial</groupId>
<artifactId>hibernate-spatial-postgis</artifactId>
<version>1.1.1</version>
</dependency>
In Tomcat context.xml I have configured one single connection by now :
<Resource accessToUnderlyingConnectionAllowed="true" auth="Container"
autoReconnect="true" driverClassName="org.postgresql.Driver"
logAbandoned="true" maxWait="5000" minEvictableIdleTimeMillis="60000"
name="jdbc/dbname" numTestsPerEvictionRun="3" password="xxx"
removeAbandoned="true" removeAbandonedTimeout="60" testOnBorrow="true"
testWhileIdle="true" timeBetweenEvictionRunsMillis="60000"
type="javax.sql.DataSource" url="jdbc:postgresql://servername:5432/dbname"
username="username" validationQuery="select 1" />
This works fine. I can insert a record into the database with an empty value in its Geometry field first, and then I will update it with a coordinate value for that point. The field is defined as :
@Type(type = "org.hibernatespatial.GeometryUserType")
@Column(name = "geom", columnDefinition="Geometry", nullable = true)
protected Geometry geom;
That works, no problem. The issue comes as soon as I include Maven dependency for Oracle :
<dependency>
<artifactId>hibernate-spatial-oracle</artifactId>
<groupId>org.hibernatespatial</groupId>
<version>1.1.1</version>
</dependency>
Even though I don't configure any additional connection nor change anything in my project in order to use Oracle, the record is inserted in Postgres as expected, but when it comes to update its Geometry field, I get the stacktrace pasted below, that is an unexpected "Problem finding Oracle Connection" even if the connection stays the same.
org.hibernatespatial.helper.FinderException: Couldn't get at the OracleSpatial Connection object from the PreparedStatement.
I can't understand why Hibernate would be able to insert the data into the database, but would look for an Oracle connection when trying to update spatial data, only when I add an Oracle Maven dependency which shouldn't be used, as I keep my connection configured for PostGIS.
Any idea about what I could be doing wrong?
Thanks in advance.
EDIT : It seems that when starting Tomcat and initializing GeometryUserType, the configure method is called with null as properties. So it defaults to a spatialDialect which will be the first it finds from the available. As there are two (Oracle and PostGIS) it will just pick the first one (which happens to be Oracle).
So I must be missing something in the configuration, but I thought it would be enough to go to the * persistence.xml * and declare that the persistence unit should use that dialect.
<persistence-unit name="pu_name" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>${jta.datasource.prefix}datasource_name</jta-data-source>
<class>com.myorganization.MyClass</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="hibernate.dialect" value="org.hibernatespatial.postgis.PostgisDialect" />
(...)
javax.persistence.PersistenceException: org.hibernate.HibernateException: Problem finding Oracle Connection
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1389)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1317)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1323)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:965)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
at com.sun.proxy.$Proxy62.flush(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240)
at com.sun.proxy.$Proxy45.flush(Unknown Source)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl$6.executeTransactionalCommand(ProcessorInnerStepsImpl.java:1056)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl$6.executeTransactionalCommand(ProcessorInnerStepsImpl.java:1)
at com.mapflow.geotagdata.common.transactions.TransactionalCommandExecutor.executeTxRequiresNew(TransactionalCommandExecutor.java:37)
at com.mapflow.geotagdata.common.transactions.TransactionalCommandExecutor$$FastClassByCGLIB$$7beb81b5.invoke(<generated>)
at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191)
at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at com.mapflow.geotagdata.common.transactions.TransactionalCommandExecutor$$EnhancerByCGLIB$$4c535b1b.executeTxRequiresNew(<generated>)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl.synchPendingTaggedBatchToDB(ProcessorInnerStepsImpl.java:1012)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl.access$0(ProcessorInnerStepsImpl.java:996)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl$5.call(ProcessorInnerStepsImpl.java:969)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl$5.call(ProcessorInnerStepsImpl.java:1)
at com.mapflow.geotagdata.common.processing.utility.RetryOnExceptionBuilder.execute(RetryOnExceptionBuilder.java:96)
at com.mapflow.geotagdata.common.processing.impl.ProcessorInnerStepsImpl.dataTaggingPhase(ProcessorInnerStepsImpl.java:964)
at com.mapflow.geotagdata.common.processing.impl.ProcessorOuterStepsImpl.doOuterStepLineByLineInnerSteps(ProcessorOuterStepsImpl.java:107)
at com.mapflow.geotagdata.common.processing.impl.ProcessorImpl.process(ProcessorImpl.java:149)
at com.mapflow.geotagdata.common.processing.impl.ProcessorImpl.processFile(ProcessorImpl.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:318)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:80)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.HibernateException: Problem finding Oracle Connection
at org.hibernatespatial.oracle.OracleJDBCTypeFactory.createStruct(OracleJDBCTypeFactory.java:38)
at org.hibernatespatial.oracle.SDOGeometry.store(SDOGeometry.java:154)
at org.hibernatespatial.oracle.SDOGeometryType.conv2DBGeometry(SDOGeometryType.java:88)
at org.hibernatespatial.oracle.SDOGeometryType.nullSafeSet(SDOGeometryType.java:77)
at org.hibernatespatial.GeometryUserType.nullSafeSet(GeometryUserType.java:201)
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:140)
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2184)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2559)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2495)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2822)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:113)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:185)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:962)
... 44 more
Caused by: org.hibernatespatial.helper.FinderException: Couldn't get at the OracleSpatial Connection object from the PreparedStatement.
at org.hibernatespatial.oracle.DefaultConnectionFinder.find(DefaultConnectionFinder.java:82)
at org.hibernatespatial.oracle.DefaultConnectionFinder.find(DefaultConnectionFinder.java:68)
at org.hibernatespatial.oracle.DefaultConnectionFinder.find(DefaultConnectionFinder.java:68)
at org.hibernatespatial.oracle.DefaultConnectionFinder.find(DefaultConnectionFinder.java:51)
at org.hibernatespatial.oracle.OracleJDBCTypeFactory.createStruct(OracleJDBCTypeFactory.java:36)
... 61 more
回答1:
As commented, it looked to me that Hibernate will default to a spatialDialect which will be the first it finds from the available, and in that case it was Oracle, despite whatever was specified in the persistence.xml.
The first workaround that I found was to annotate in the entity that for the GeometryUserType I would use Postgis dialect as in :
@TypeDefs({@TypeDef(name="org.hibernatespatial.GeometryUserType",
parameters={@org.hibernate.annotations.Parameter(name="dialect",value="org.hibernatespatial.postgis.PostgisDialect")},
typeClass=org.hibernatespatial.GeometryUserType.class)})
That would force Hibernate to use Postgis for that entity.
The second workaround, which worked better for me (I need to be able to configure this and use different dialects for one entity depending on the persistence unit and the environment) is to use a mapping file in the persistence unit.
<persistence-unit name="persistence_unit_name" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>jta_data_source_name</jta-data-source>
<mapping-file>${hibernate.mappingfile}</mapping-file>
<class>(...)</class>
In my pom file, I will make that mapping file to the one that I need, using Maven profiles and variables.
<hibernate.mappingfile>oracle.hbm.xml</hibernate.mappingfile>
Or :
<hibernate.mappingfile>postgis.hbm.xml</hibernate.mappingfile>
So I would have for example a postgis.hbm.xml
file :
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<typedef name="org.hibernatespatial.GeometryUserType" class="org.hibernatespatial.GeometryUserType" >
<param name="dialect">org.hibernatespatial.postgis.PostgisDialect</param>
</typedef>
</hibernate-mapping>
And an oracle.hbm.xml
:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<typedef name="org.hibernatespatial.GeometryUserType" class="org.hibernatespatial.GeometryUserType" >
<param name="dialect">org.hibernatespatial.oracle.OracleSpatial10gDialect</param>
</typedef>
</hibernate-mapping>
I wonder if there is a better way to do this, but none that I could find during these days, or that I was answered here. Hope that this helps to somebody.
来源:https://stackoverflow.com/questions/30106542/not-finding-oracle-connection-when-a-postgis-connection-is-defined