Не удается найти соединение Oracle, когда определено соединение PostGIS

У меня есть приложение, работающее с Spring 3.1.1, Hibernate 3.6.0.Final и Hibernate Spatial 1.1.1 на Tomcat 8.0.20. До сих пор мы использовали Oracle 11.2.0.4, но мы хотим перейти на PostgreSQL 9.2-1002.jdbc4 / PostGIS 2.1.6.

Мы будем переносить схемы базы данных на разных этапах, поэтому на каком-то этапе нам понадобятся некоторые соединения для работы с Oracle, а некоторые - с PostGIS. Чтобы начать разработку и тестирование, я удалил все зависимости от Oracle Maven и добавил необходимые для работы с Postgres, как описано в Учебном руководстве по Hibernate Spatial 1.1.1, в основном:

<dependency>
    <groupId>org.hibernatespatial</groupId>
    <artifactId>hibernate-spatial-postgis</artifactId>
    <version>1.1.1</version>
</dependency>

В Tomcat context.xml я уже настроил одно соединение:

<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" />

Это отлично работает. Сначала я могу вставить запись в базу данных с пустым значением в ее поле Geometry, а затем обновлю ее значением координаты для этой точки. Поле определяется как:

@Type(type = "org.hibernatespatial.GeometryUserType")
@Column(name = "geom", columnDefinition="Geometry", nullable = true) 
protected Geometry geom;

Это работает, нет проблем. Проблема возникает, как только я включаю зависимость Maven для Oracle:

<dependency>
            <artifactId>hibernate-spatial-oracle</artifactId>
            <groupId>org.hibernatespatial</groupId>
            <version>1.1.1</version>
        </dependency>

Несмотря на то, что я не настраиваю никаких дополнительных подключений и ничего не изменяю в своем проекте для использования Oracle, запись вставляется в Postgres, как и ожидалось, но когда дело доходит до обновления ее поля Geometry, я вставляю трассировку стека ниже, то есть неожиданная "Проблема с поиском Oracle Connection", даже если соединение остается прежним.

org.hibernatespatial.helper.FinderException: не удалось получить доступ к объекту OracleSpatial Connection из PreparedStatement.

Я не могу понять, почему Hibernate смог бы вставить данные в базу данных, но искал бы соединение Oracle при попытке обновить пространственные данные, только когда я добавляю зависимость Oracle Maven, которая не должна использоваться, поскольку я продолжаю мое соединение настроено для PostGIS.

Есть идеи о том, что я могу делать неправильно?

Заранее спасибо.

РЕДАКТИРОВАТЬ: Кажется, что при запуске Tomcat и инициализации GeometryUserType, метод настройки вызывается с нулем в качестве свойств. Таким образом, по умолчанию используется пространственный диалект, который будет первым из доступных. Поскольку их два (Oracle и PostGIS), он просто выберет первый (который является Oracle).

Так что я, должно быть, что-то упустил в конфигурации, но я подумал, что этого будет достаточно, чтобы перейти к * persistence.xml * и объявить, что модуль персистентности должен использовать этот диалект.

<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 ответ

Решение

Как отмечалось, мне показалось, что Hibernate по умолчанию будет использовать пространственный диалект, который будет первым, который он найдет из доступных, и в этом случае это был Oracle, несмотря на то, что было указано в файле persistence.xml.

Первый обходной путь, который я нашел, заключался в том, чтобы аннотировать в сущности, что для GeometryUserType я использовал бы диалект Postgis, как в:

@TypeDefs({@TypeDef(name="org.hibernatespatial.GeometryUserType", 
        parameters={@org.hibernate.annotations.Parameter(name="dialect",value="org.hibernatespatial.postgis.PostgisDialect")},
        typeClass=org.hibernatespatial.GeometryUserType.class)})

Это заставит Hibernate использовать Postgis для этой сущности.

Второй обходной путь, который работал лучше для меня (мне нужно иметь возможность настроить это и использовать разные диалекты для одной сущности в зависимости от единицы сохраняемости и среды), заключается в использовании файла сопоставления в единице постоянства.

<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>

В моем файле pom я сделаю тот файл сопоставления с тем, который мне нужен, используя профили и переменные Maven.

<hibernate.mappingfile>oracle.hbm.xml</hibernate.mappingfile>

Или же:

<hibernate.mappingfile>postgis.hbm.xml</hibernate.mappingfile>

Так что я бы, например, postgis.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.postgis.PostgisDialect</param>
    </typedef>
</hibernate-mapping>

И 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>

Интересно, есть ли лучший способ сделать это, но не тот, который я мог бы найти в эти дни, или мне ответили здесь. Надеюсь, что это кому-нибудь поможет.

Другие вопросы по тегам