在设置新环境时,我们的Jackrabbit(v2.6.1)系统有时无法在Oracle数据库中自动创建DATASTORE_DATASTORE
表。在这种情况下,我们在应用程序日志文件中看到以下错误:
DbDataStore - Can not insert new record
java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:447)
at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:396)
at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:951)
at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:513)
at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:227)
at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:531)
at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:208)
at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:886)
at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:1175)
at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1296)
at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3613)
at oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.java:3714)
at oracle.jdbc.driver.OraclePreparedStatementWrapper.execute(OraclePreparedStatementWrapper.java:1378)
at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
at org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPreparedStatement.java:172)
at org.apache.jackrabbit.core.util.db.ConnectionHelper.execute(ConnectionHelper.java:516)
at org.apache.jackrabbit.core.util.db.ConnectionHelper.reallyExec(ConnectionHelper.java:404)
at org.apache.jackrabbit.core.util.db.ConnectionHelper$3.call(ConnectionHelper.java:379)
at org.apache.jackrabbit.core.util.db.ConnectionHelper$3.call(ConnectionHelper.java:375)
at org.apache.jackrabbit.core.util.db.ConnectionHelper$RetryManager.doTry(ConnectionHelper.java:557)
at org.apache.jackrabbit.core.util.db.ConnectionHelper.exec(ConnectionHelper.java:375)
at org.apache.jackrabbit.core.util.db.ConnectionHelper.query(ConnectionHelper.java:359)
at org.apache.jackrabbit.core.data.db.DbDataStore.addRecord(DbDataStore.java:321)
at org.apache.jackrabbit.core.value.BLOBInDataStore.getInstance(BLOBInDataStore.java:121)
at org.apache.jackrabbit.core.value.InternalValue.getBLOBFileValue(InternalValue.java:626)
at org.apache.jackrabbit.core.value.InternalValue.create(InternalValue.java:381)
at org.apache.jackrabbit.core.value.InternalValueFactory.create(InternalValueFactory.java:108)
at org.apache.jackrabbit.core.value.ValueFactoryImpl.createBinary(ValueFactoryImpl.java:77)
我们对DataStore的Jackrabbit配置如下所示:
<DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">
<param name="url" value="jdbc:oracle:thin:@//db:1521/SID" />
<param name="user" value="foo" />
<param name="password" value="foo" />
<param name="databaseType" value="oracle" />
<param name="driver" value="oracle.jdbc.OracleDriver" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="" />
<param name="schemaObjectPrefix" value="datastore_"/>
</DataStore>
当我们在同一个数据库实例上有多个Jackrabbit实例时,似乎只会发生这种情况,每个Jackrabbit实例都在自己的数据库模式/用户中。问题只发生在DATASTORE_DATASTORE
表中 - 所有其他Jackrabbit表在这种情况下都能正常工作。
可能导致此问题的原因是什么?
答案 0 :(得分:0)
问:当我使用数据库数据存储时,我收到消息:&#39;表或视图不存在&#39;。答:也许数据存储表已经存在于另一个模式中。启动存储库时,数据库数据存储检查表是否已存在(使用数据库元数据调用),如果不存在则将创建表。如果表存在但位于另一个模式中,则表不会创建,但访问它可能会失败(如果其他模式不在此用户的模式搜索路径中)。
事实证明,对于DataStore(所有其他表使用不同的方式检查表的存在),Jackrabbit使用数据库的元数据来检查DATASTORE_DATASTORE
表的存在并且这是以默认不考虑用户的数据库模式的方式完成的。这意味着如果在同一个Oracle实例上有另一个Jackrabbit模式已经有一个名为DATASTORE_DATASTORE
的表,那么Jackrabbit会认为该表已经存在并且不会尝试在用户中创建它。架构。
在tablePrefix
配置中设置推荐的DataStore
属性不起作用:
<DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">
<param name="url" value="jdbc:oracle:thin:@//db:1521/SID" />
<param name="user" value="foo" />
<param name="password" value="foo" />
<param name="databaseType" value="oracle" />
<param name="driver" value="oracle.jdbc.OracleDriver" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="foo." />
<param name="schemaObjectPrefix" value="datastore_"/>
</DataStore>
执行此操作(tablePrefix
末尾的句号)将导致Jackrabbit永远不会找到该表,并且会导致更多错误,因为Jackrabbit每次都不会尝试创建表申请开始。
永久修复此方法有两种方法:
此修复程序需要操作tablePrefix
或schemaObjectPrefix
值,以便表的名称在整个数据库中是唯一的。例如,对于第一个Jackrabbit实例,请使用:
<DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">
<param name="url" value="jdbc:oracle:thin:@//db:1521/SID" />
<param name="user" value="foo1" />
<param name="password" value="foo1" />
<param name="databaseType" value="oracle" />
<param name="driver" value="oracle.jdbc.OracleDriver" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="" />
<param name="schemaObjectPrefix" value="FOO1_"/>
</DataStore>
这会导致此用户名为FOO1_DATASTORE
的表格。然后,同一数据库中的第二个Jackrabbit实例可以使用这样的配置来确保唯一的表名:
<DataStore class="org.apache.jackrabbit.core.data.db.DbDataStore">
<param name="url" value="jdbc:oracle:thin:@//db:1521/SID" />
<param name="user" value="foo2" />
<param name="password" value="foo2" />
<param name="databaseType" value="oracle" />
<param name="driver" value="oracle.jdbc.OracleDriver" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="" />
<param name="schemaObjectPrefix" value="foo2_"/>
</DataStore>
这会导致此架构的表被称为FOO2_DATASTORE
。
虽然这有效,但它有点难看且容易出错,因为它需要更改容易错过的配置 - 并且与所有其他Jackrabbit表不同,这些表在没有这个黑客的情况下工作正常。
另一个解决方案是在Jackrabbit的代码中解决这个问题。原始问题源于Jackrabbit通过其ConnectionHelper.tableExists
方法(http://grepcode.com/file/repo1.maven.org/maven2/org.apache.jackrabbit/jackrabbit-core/2.6.1/org/apache/jackrabbit/core/util/db/ConnectionHelper.java?av=f#201)检查数据库中是否存在表的方式,该方法检查名为checkTablesWithUserName
的标记,该标记已设置默认情况下为false
,导致整个数据库进行全局检查(错误!):
要将该标志设置为true
,需要调用一个单独的构造函数,以允许将标志设置为true
。为了使这项工作,我们需要创建自己的UserCheckDbDataStore
类 - 它需要与ConnectionHelper
类在同一个包中才能使用替代构造函数:
package org.apache.jackrabbit.core.util.db;
import javax.sql.DataSource;
import org.apache.jackrabbit.core.data.db.DbDataStore;
import org.apache.jackrabbit.core.util.db.ConnectionHelper;
public class UserCheckDbDataStore extends DbDataStore {
@Override
protected ConnectionHelper createConnectionHelper(DataSource dataSrc) throws Exception {
// Provide "true" as the second parameter to check in the user's schema
return new ConnectionHelper(dataSrc, true, false);
}
}
在类路径中使用此类,以下Jackrabbit配置在我在Oracle和MySQL上测试的场景中运行良好:
<DataStore class="org.apache.jackrabbit.core.util.db.UserCheckDbDataStore">
<param name="url" value="jdbc:oracle:thin:@//db:1521/SID" />
<param name="user" value="foo" />
<param name="password" value="foo" />
<param name="databaseType" value="oracle" />
<param name="driver" value="oracle.jdbc.OracleDriver" />
<param name="minRecordLength" value="1024" />
<param name="maxConnections" value="3" />
<param name="copyWhenReading" value="true" />
<param name="tablePrefix" value="" />
<param name="schemaObjectPrefix" value="datastore_"/>
</DataStore>
理想情况下,应该在Jackrabbit错误跟踪器中报告此错误/功能,但我不确定它是否会被修复/合并,因为过去几乎没有进展的类似请求。