ORA-00942: table or view does not exist with Spring JDBC Template in Spring Boot

老子叫甜甜 提交于 2021-02-11 13:38:09

问题


I'm getting a weird ORA-00942: table or view does not exist exception while trying to execute database code via Spring JDBC template:

2019-12-26 22:01:36.863[0;39m [31mERROR[0;39m [35m12232[0;39m [2m---[0;39m [2m[ctor-http-nio-3][0;39m [36ma.w.r.e.AbstractErrorWebExceptionHandler[0;39m [2m:[0;39m [ca8305eb] 500 Server Error for HTTP GET "/exs/acs/accounts-links?limit=20&q=632626&showActive=false&systemName=IMMS"

org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [select a.FACCIN, a.FACCKEY, a.FACCSNAME, b.LNKSYSTEM, b.LNKLOANKEY, a.FACCSTATUS, a.FACCCOND from BNYMACS.ACCOUNT a left outer join BNYMACS.LINKS b on a.FACCIN = b.lnkacc where (upper(a.FACCKEY) like ? or upper(FACCSNAME) like ? or (b.LNKLOANKEY like ? )) and b.LNKSYSTEM =?  and rownum<=? order by 3 ]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist

    at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:235) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ? org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    |_ checkpoint ? HTTP GET "/exs/acs/accounts-links?limit=20&q=632626&showActive=false&systemName=IMMS" [ExceptionHandlingWebHandler]
Stack trace:
        at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:235) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]

. . . . . . .

Caused by: java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist

    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:509) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIoer11.processError(T4CTTIoer11.java:461) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4C8Oall.processError(T4C8Oall.java:1104) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIfun.receive(T4CTTIfun.java:550) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CTTIfun.doRPC(T4CTTIfun.java:268) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4C8Oall.doOALL(T4C8Oall.java:655) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:270) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:91) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatement.java:807) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java:983) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java:1168) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedStatement.java:3666) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.T4CPreparedStatement.executeInternal(T4CPreparedStatement.java:1426) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatement.executeQuery(OraclePreparedStatement.java:3713) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at oracle.jdbc.driver.OraclePreparedStatementWrapper.executeQuery(OraclePreparedStatementWrapper.java:1167) ~[ojdbc8-19.3.0.0.jar:19.3.0.0.0]
    at com.p6spy.engine.wrapper.PreparedStatementWrapper.executeQuery(PreparedStatementWrapper.java:78) ~[p6spy-3.8.2.jar:na]
    at org.springframework.jdbc.core.JdbcTemplate$1.doInPreparedStatement(JdbcTemplate.java:678) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:617) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:669) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:700) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:712) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]
    at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:763) ~[spring-jdbc-5.2.0.RELEASE.jar:5.2.0.RELEASE]

Since an Oracle driver is used, I cannot really debug into what's happening in oracle.jdbc.driver.OraclePreparedStatementWrapper as ojdbc8 source code is closed for developers.

The strange thing is that the query from Spring's JDBC template that goes into the Oracle driver, when extracted with its parameters during a debugging session and copied into an external SQL client as is works just fine there:

select a.FACCIN, a.FACCKEY, a.FACCSNAME, b.LNKSYSTEM, b.LNKLOANKEY, a.FACCSTATUS, a.FACCCOND from BNYMACS.ACCOUNT a left outer join BNYMACS.LINKS b on a.FACCIN = b.lnkacc where (upper(a.FACCKEY) like '632626%' or upper(FACCSNAME) like '632626%' or (b.LNKLOANKEY like '632626%' )) and b.LNKSYSTEM ='IMMS'  and rownum<=20 order by 3 ;

and produces several records of a result.

This is the Spring repository in question:

import static cwp.services.adhoc_processor.domain.acs.Account.*;
import static cwp.services.adhoc_processor.domain.acs.Links.*;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;


import cwp.services.adhoc_processor.domain.acs.AccountLinkDetail;
import cwp.services.adhoc_processor.domain.acs.AccountLinkDetail.AccountLinkDetailBuilder;

import cwp.services.adhoc_processor.domain.acs.AccountLinksList;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class AccountLinksRepositoryCustomImpl implements AccountLinksRepositoryCustom {

    private static final String TERMINATED = "TERMINATED";
    private static final String STOPPED = "STOPPED";

    private final static String STATIC_QUERY_PART = "select a.FACCIN, a.FACCKEY, a.FACCSNAME, b.LNKSYSTEM, b.LNKLOANKEY, a.FACCSTATUS, a.FACCCOND "
            + "from BNYMACS.ACCOUNT a left outer join BNYMACS.LINKS b "
            + "on a.FACCIN = b.lnkacc where (upper(a.FACCKEY) like ? or upper(FACCSNAME) like ? "
            + "or (b.LNKLOANKEY like ? )) and b.LNKSYSTEM =? ";

    private final static String activeSuffix = "and upper(a.FACCSTATUS) <> 'TERMINATED' and upper(a.FACCCOND) <> 'STOPPED' ";

    private final static String orderbyClause = " and rownum<=? order by 3 ";

    @Autowired
    @Qualifier("acsJdbcTemplate")
    private JdbcTemplate template;

    @Autowired
    public void setDataSource(DataSource dataSource) {
        this.template = new JdbcTemplate(dataSource);
    }

    @Override
    public AccountLinksList searchByAccountOrLinks(String searchTerm, int limit, boolean isActive, String systemName) {
        AccountLinksList accountLinksList = new AccountLinksList();

        try {
            String dynQuery = STATIC_QUERY_PART;

            if (isActive)
                dynQuery += activeSuffix;

            dynQuery += orderbyClause;

            List<AccountLinkDetail>  accountDetailsList = template.<AccountLinkDetail>query(
                    dynQuery,
                    new Object[] { searchTerm, searchTerm, searchTerm, systemName, limit }, 
                    new RowMapper<AccountLinkDetail>() {
                        @Override
                        public AccountLinkDetail mapRow(ResultSet rs, int currentRow) throws SQLException {
                            AccountLinkDetailBuilder accountDetails = AccountLinkDetail.builder();
                            accountDetails
                                    .accountId(rs.getLong(ID_COLUMN_NAME))
                                    .accountKey(rs.getString(ACCOUNT_KEY_COLUMN_NAME))
                                    .accountName(rs.getString(ACCOUNT_SHORT_NAME_COLUMN_NAME))
                                    .loanKey(rs.getString(LOAN_KEY_COLUMN_NAME))
                                    .systemName(rs.getString(LINK_SYSTEM_COLUMN_NAME));
                            if (rs.getString(CONDITION_COLUMN_NAME) != null
                                    && !rs.getString(CONDITION_COLUMN_NAME).equalsIgnoreCase(STOPPED)
                                    && rs.getString(STATUS_COLUMN_NAME) != null
                                    && !rs.getString(STATUS_COLUMN_NAME).equalsIgnoreCase(TERMINATED)) {
                                accountDetails.isActive(true);
                            }
                            return accountDetails.build();
                        }



                    });
            accountLinksList.setAccountLinkDetail(accountDetailsList);
        } catch (Exception e) {
            log.error("Technical Exception", e);
            throw e;
        }
        return accountLinksList;
    }

}

This is how DB is configured:

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(
        basePackages = {"cwp.services.adhoc_processor.repository.acs" }, 
        entityManagerFactoryRef = "acsEntityManagerFactory", 
        transactionManagerRef = "acsTransactionManager")

public class AcsDatasourceConfiguration {

    @Autowired
    private AcsDbProperties properties;

    @Validated
    @Component
    @ConfigurationProperties(prefix = "acs.read.datasource")
    public class AcsDbProperties extends HikariDBProperties {
    }

    @ConditionalOnBean(value = AcsDbProperties.class)
    @Bean(name = "acsDataSource", destroyMethod = "")
    public DataSource acsDataSource() {
        return new HikariDataSource(new HikariConfig(properties.getProperties()));
    }

    @Bean("acsJdbcTemplate")
    public JdbcTemplate pmtTemplate () throws Exception {
        return new JdbcTemplate(acsDataSource());
    }

    @Bean(name = "acsEntityManagerFactory")
    public LocalContainerEntityManagerFactoryBean acsEntityManagerFactory(EntityManagerFactoryBuilder builder) {
        return builder.dataSource(acsDataSource())
                .packages("cwp.services.adhoc_processor.domain.acs" )
                .persistenceUnit("acs")
                .build();
    }

    /*
     * Leaky requirement for the unsatisfied transaction manager bean stemming from nxn-workflow-services#NWFProcessEngineConfiguration.java dependency.
     * 
     * N.B. MUST BE CALLED THIS EXACT NAME, else will get 
     * org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.transaction.PlatformTransactionManager' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.springframework.beans.factory.annotation.Qualifier(value=transactionManager)}
     * 
     */
    @Bean("transactionManager") // <-- must be called `transactionManager`.
    public PlatformTransactionManager acsTransactionManager
            (
            @Qualifier("acsEntityManagerFactory")
            final  LocalContainerEntityManagerFactoryBean acsEntityManagerFactory
            ) {

                return new JpaTransactionManager(acsEntityManagerFactory.getObject());
    }


}

and this is the invocation of the use case:

curl --location --request GET 'http://localhost:7010/exs/acs/accounts-links?limit=20&q=632626&showActive=false&systemName=IMMS' \
--header 'Content-Type: application/json'

The table seems to be a synonym:

and the runtime user is WEBSVC_READ:

When querying DB directly, I'm using the same WEBSVC_READ schema and that works fine:

N.B.: The behavior seems to be related to the JDBC template only. The following JPA query runs fine:

"select  a from Account a, Links l where l.accountId = a.id and l.loanKey = :loanKey and l.linkSystem = :systemName and(upper(a.status) <> 'TERMINATED' or upper(a.condition) <>'STOPPED' )";

with the following present in the application.properties:

spring.jpa.properties.hibernate.default_schema=BNYMACS

and the entities configured like so (no explicit schema):

@Entity(name="Account")
@Table(name="ACCOUNT")
public class Account implements Serializable{...}


@Entity
@Table(name="LINKS")
@Data
public class Links implements Serializable{...}

What might be wrong here? Is this ORA-00942 a meaningful error or just a placeholder for something else? Perhaps someone can give me useful pointers on approaches of getting to the bottom of it.

Thanks in advance.


回答1:


The culprit was the following incorrect and unnecessary definition in my Repository:

@Autowired
public void setDataSource(DataSource dataSource) {
        this.template = new JdbcTemplate(dataSource);
    }

It is already defined in the Configuration class and its redefining was causing all the havoc.



来源:https://stackoverflow.com/questions/59495461/ora-00942-table-or-view-does-not-exist-with-spring-jdbc-template-in-spring-boot

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!