Java hibernate如何解析最初验证到Teradata数据库的模式?
环境: Java/Spring应用程序,使用JPA/Hibernate进行持久化,并连接到通过JNDI访问的应用程序容器(Tomcat)中配置的Teradata数据源 我正在使用的版本:Java hibernate如何解析最初验证到Teradata数据库的模式?,java,spring,hibernate,jpa,teradata,Java,Spring,Hibernate,Jpa,Teradata,环境: Java/Spring应用程序,使用JPA/Hibernate进行持久化,并连接到通过JNDI访问的应用程序容器(Tomcat)中配置的Teradata数据源 我正在使用的版本: java: 6 spring: 3.2.4.RELEASE hibernate.core: 4.2.4.Final hibernate.entitymanager: 4.2.4.Final hibernate.validator: 5.0.1.Final springdata: 1.3.4.RELEASE ja
java: 6
spring: 3.2.4.RELEASE
hibernate.core: 4.2.4.Final
hibernate.entitymanager: 4.2.4.Final
hibernate.validator: 5.0.1.Final
springdata: 1.3.4.RELEASE
javax.validation: 1.1.0.Final
问题:
同一服务器中有两个Teradata数据库具有相同的命名表,但列不同:
DatDe001.SFITEM
Columns: [iipcst, iidesc, iivend, updated_at, iisku#, created_at, item_expdt, item_effdt]
DEV_DIG_UMT.SFITEM
Columns: [iipcst, iidesc, iivend, row_updt_tms, iisku#, row_insrt_tms, item_expdt, item_effdt]
如您所见,不同的列在->行updt\U tms更新,并在->行insrt\U tms创建
我正在使用JNDI数据源,该数据源使用以下jdbc url配置:
jdbc:teradata://<server_ip>/DATABASE=DEV_DIG_UMT,DBS_PORT=1025,COP=OFF,CHARSET=UTF8,TMODE=ANSI
因此,由于我的JPA实体(请参阅下文中的实体)没有这些列,hibernate验证会抛出一个异常(请参阅摘要堆栈跟踪):
我启动了应用程序,并成功加载了它。现在日志看起来不错,而不是显示异常:
...
2013-08-15 14:42:52,056 INFO localhost-startStop-1 org.hibernate.tool.hbm2ddl.TableMetadata - HHH000261: Table found: DatDe001.SFITEM
2013-08-15 14:42:52,056 INFO localhost-startStop-1 org.hibernate.tool.hbm2ddl.TableMetadata - HHH000037: Columns: [iipcst, iidesc, iivend, updated_at, iisku#, created_at, item_expdt, item_effdt]
2013-08-15 14:42:52,061 DEBUG localhost-startStop-1 org.hibernate.internal.SessionFactoryImpl - Checking 0 named HQL queries
2013-08-15 14:42:52,061 DEBUG localhost-startStop-1 org.hibernate.internal.SessionFactoryImpl - Checking 0 named SQL queries
2013-08-15 14:42:52,063 TRACE localhost-startStop-1 org.hibernate.service.internal.AbstractServiceRegistryImpl - Initializing service [role=org.hibernate.service.config.spi.ConfigurationService]
2013-08-15 14:42:52,113 TRACE localhost-startStop-1 org.hibernate.service.internal.AbstractServiceRegistryImpl - Initializing service [role=org.hibernate.stat.spi.StatisticsImplementor]
...
我试图对该表执行查询,但意外地发现Hibernate这次指向的是正确的数据库/架构:DEV\u DIG\u UMT,查询失败,因为该实体现在有另一个数据库的列:DatDe001,请参阅日志:
2013-08-15 14:50:05,731 TRACE tomcat-http--4 org.hibernate.engine.query.spi.QueryPlanCache - Located HQL query plan in cache (SELECT o FROM Sfitem o WHERE o.id.iisku = :iisku AND o.id.itemEffdt <= :date AND coalesce(o.itemExpdt, cast('9999-12-31' as date)) >= :date)
2013-08-15 14:50:05,766 TRACE tomcat-http--4 org.hibernate.engine.query.spi.QueryPlanCache - Located HQL query plan in cache (SELECT o FROM Sfitem o WHERE o.id.iisku = :iisku AND o.id.itemEffdt <= :date AND coalesce(o.itemExpdt, cast('9999-12-31' as date)) >= :date)
2013-08-15 14:50:05,768 TRACE tomcat-http--4 org.hibernate.engine.query.spi.HQLQueryPlan - Find: SELECT o FROM Sfitem o WHERE o.id.iisku = :iisku AND o.id.itemEffdt <= :date AND coalesce(o.itemExpdt, cast('9999-12-31' as date)) >= :date
2013-08-15 14:50:05,772 TRACE tomcat-http--4 org.hibernate.engine.spi.QueryParameters - Named parameters: {iisku=387671, date=2013-08-08}
2013-08-15 14:50:05,810 DEBUG tomcat-http--4 org.hibernate.SQL - select sfitem0_."iisku#" as iisku1_0_, sfitem0_."item_effdt" as item_eff2_0_, sfitem0_."created_at" as created_3_0_, sfitem0_."iidesc" as iidesc4_0_, sfitem0_."iipcst" as iipcst5_0_, sfitem0_."iivend" as iivend6_0_, sfitem0_."item_expdt" as item_exp7_0_ from sfitem sfitem0_ where sfitem0_."iisku#"=? and sfitem0_."item_effdt"<=? and coalesce(sfitem0_."item_expdt", cast('9999-12-31' as DATE))>=?
2013-08-15 14:50:05,832 DEBUG tomcat-http--4 org.hibernate.engine.jdbc.spi.SqlExceptionHelper - could not prepare statement [select sfitem0_."iisku#" as iisku1_0_, sfitem0_."item_effdt" as item_eff2_0_, sfitem0_."created_at" as created_3_0_, sfitem0_."iidesc" as iidesc4_0_, sfitem0_."iipcst" as iipcst5_0_, sfitem0_."iivend" as iivend6_0_, sfitem0_."item_expdt" as item_exp7_0_ from sfitem sfitem0_ where sfitem0_."iisku#"=? and sfitem0_."item_effdt"<=? and coalesce(sfitem0_."item_expdt", cast('9999-12-31' as DATE))>=?]
com.teradata.jdbc.jdbc_4.util.JDBCException: [Teradata Database] [TeraJDBC 14.00.00.21] [Error 3810] [SQLState 42S22] Column/Parameter 'DEV_DIG_UMT.sfitem0_.created_at' does not exist.
at com.teradata.jdbc.jdbc_4.util.ErrorFactory.makeDatabaseSQLException(ErrorFactory.java:307)
at com.teradata.jdbc.jdbc_4.statemachine.ReceiveInitSubState.action(ReceiveInitSubState.java:102)
at com.teradata.jdbc.jdbc_4.statemachine.StatementReceiveState.subStateMachine(StatementReceiveState.java:320)
at com.teradata.jdbc.jdbc_4.statemachine.StatementReceiveState.action(StatementReceiveState.java:201)
at com.teradata.jdbc.jdbc_4.statemachine.StatementController.runBody(StatementController.java:121)
at com.teradata.jdbc.jdbc_4.statemachine.StatementController.run(StatementController.java:112)
...
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$5.doPrepare(StatementPreparerImpl.java:161)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl$StatementPreparationTemplate.prepareStatement(StatementPreparerImpl.java:182)
at org.hibernate.engine.jdbc.internal.StatementPreparerImpl.prepareQueryStatement(StatementPreparerImpl.java:159)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1859)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1836)
at org.hibernate.loader.Loader.executeQueryStatement(Loader.java:1816)
at org.hibernate.loader.Loader.doQuery(Loader.java:900)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:342)
at org.hibernate.loader.Loader.doList(Loader.java:2526)
at org.hibernate.loader.Loader.doList(Loader.java:2512)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2342)
at org.hibernate.loader.Loader.list(Loader.java:2337)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:495)
Persistence.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.TeradataDialect"/>
<!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<!-- Uncomment the following two properties for JBoss only -->
<!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
<!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
</properties>
</persistence-unit>
</persistence>
org.hibernate.ejb.HibernatePersistence
数据源和实体管理器bean:
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiName}"/>
<property name="lookupOnStartup" value="true"/>
<property name="resourceRef" value="true" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
这是错误还是配置问题?有人面临过同样的问题吗
我不想在持久化单元或实体中配置默认模式,因为我们所采用的方法是通过使用容器上下文中定义的JNDI数据源,将数据源配置保持在应用程序外部和单个位置。这样,在部署到不同的环境(开发、质量保证、产品等)时,我们就不必担心了。您可能需要在提交给Teradata的SELECT查询中完全限定表名
select sfitem0_."iisku#" as iisku1_0_, sfitem0_."item_effdt" as item_eff2_0_,
sfitem0_."created_at" as created_3_0_, sfitem0_."iidesc" as iidesc4_0_,
sfitem0_."iipcst" as iipcst5_0_, sfitem0_."iivend" as iivend6_0_,
sfitem0_."item_expdt" as item_exp7_0_
from DatDe001.SFITEM sfitem0_ /* Notice database name is included here */
where sfitem0_."iisku#"=?
and sfitem0_."item_effdt"<=?
and coalesce(sfitem0_."item_expdt", cast('9999-12-31' as DATE))>=?
然后可能使用一个参数来提供该值,就像您是WHERE
子句的值一样
编辑2
只能为给定的连接字符串指定单个数据库参数。如果您的要求是为支持应用程序前端的数据库提供不同的名称,则需要为应用程序需要在后端与之通信的每个数据库参数化连接字符串 是的,这是指向正确数据库的方法之一,但正如我在文章中提到的,我希望将数据源配置保留在应用程序之外,因为这是一个部署在多个环境中的企业应用程序,每个环境中的数据库名称都不同,并且可以在整个开发阶段更改。其思想是,Hibernate按照预期从URL提取数据库名称,但在运行模式验证程序时,它没有这样做。感谢Rob,是的,可以以某种方式参数化模式名称,然后直接将其提供给持久化单元、实体或查询。但这将再次将数据源的配置附加到应用程序端。我要寻找的是一种告诉Hibernate验证器从jdbc url中提取模式/数据库名称的方法:jdbc:teradata:///DATABASE=DEV_DIG_UMT... 正如运行querySee编辑2时所做的那样。我想不出别的办法来完成你想做的事。也许其他人有更好的主意。嗨,罗布,关于你的第二次编辑。实际上,应用程序只连接到一个DB,我在连接JDBCURL字符串中指定它,如问题帖子中所述。问题是hibernate模式验证没有使用该数据库,而是使用服务器中包含具有该名称的表的第一个数据库,因为该数据库包含不同的版本,因此无法验证该表。
@Entity
public class Sfitem implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private SfitemPK id;
@Column(name="\"iidesc\"")
private String iidesc;
@Column(name="\"iipcst\"")
private BigDecimal iipcst;
@Column(name="\"iivend\"")
private BigDecimal iivend;
@Column(name="\"item_expdt\"")
private Date itemExpdt;
@Column(name="\"row_insrt_tms\"")
private Timestamp rowInsrtTms;
@Column(name="\"row_updt_tms\"")
private Timestamp rowUpdtTms;
...
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.0" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="persistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.TeradataDialect"/>
<!-- value="create" to build a new database on each run; value="update" to modify an existing database; value="create-drop" means the same as "create" but also drops tables when Hibernate closes; value="validate" makes no changes to the database -->
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.ejb.naming_strategy" value="org.hibernate.cfg.ImprovedNamingStrategy"/>
<property name="hibernate.connection.charSet" value="UTF-8"/>
<!-- Uncomment the following two properties for JBoss only -->
<!-- property name="hibernate.validator.apply_to_ddl" value="false" /-->
<!-- property name="hibernate.validator.autoregister_listeners" value="false" /-->
</properties>
</persistence-unit>
</persistence>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="${datasource.jndiName}"/>
<property name="lookupOnStartup" value="true"/>
<property name="resourceRef" value="true" />
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>
<bean class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" id="entityManagerFactory">
<property name="persistenceUnitName" value="persistenceUnit"/>
<property name="dataSource" ref="dataSource"/>
</bean>
select sfitem0_."iisku#" as iisku1_0_, sfitem0_."item_effdt" as item_eff2_0_,
sfitem0_."created_at" as created_3_0_, sfitem0_."iidesc" as iidesc4_0_,
sfitem0_."iipcst" as iipcst5_0_, sfitem0_."iivend" as iivend6_0_,
sfitem0_."item_expdt" as item_exp7_0_
from DatDe001.SFITEM sfitem0_ /* Notice database name is included here */
where sfitem0_."iisku#"=?
and sfitem0_."item_effdt"<=?
and coalesce(sfitem0_."item_expdt", cast('9999-12-31' as DATE))>=?
DATABASE=?