खोज…


परिचय

यह बताता है कि कैसे अपने डेटाबेस में एक संग्रहीत प्रक्रिया के साथ SimpleJdbcCall का उपयोग करके एक SqlRowSet को सीधे प्राप्त किया जाए जिसमें कर्सर आउटपुट पैरामीटर है ,

मैं एक ओरेकल डेटाबेस के साथ काम कर रहा हूं, मैंने एक उदाहरण बनाने का प्रयास किया है जो अन्य डेटाबेस के लिए काम करना चाहिए, मेरा ओरेकल उदाहरण ओरेकल के साथ मुद्दों का विवरण देता है।

SimpleJdbcCall निर्माण

आमतौर पर, आप अपने SimpleJdbcCalls को एक सेवा में बनाना चाहेंगे।

यह उदाहरण मानता है कि आपकी प्रक्रिया में एक एकल आउटपुट पैरामीटर है जो एक कर्सर है; आपको अपनी प्रक्रिया से मेल खाने के लिए अपने घोषणापत्र को समायोजित करने की आवश्यकता होगी।

@Service
public class MyService() {

@Autowired
    private DataSource dataSource;
    
    // Autowire your configuration, for example
    @Value("${db.procedure.schema}")
    String schema;
    
    private SimpleJdbcCall myProcCall;
    
    // create SimpleJdbcCall after properties are configured
    @PostConstruct
    void initialize() {
        this.myProcCall = new SimpleJdbcCall(dataSource)
                        .withProcedureName("my_procedure_name")
                        .withCatalogName("my_package")
                        .withSchemaName(schema)
                        .declareParameters(new SqlOutParameter(
                            "out_param_name",
                            Types.REF_CURSOR, 
                            new SqlRowSetResultSetExtractor()));
    }

    public SqlRowSet myProc() {
        Map<String, Object> out = this.myProcCall.execute();
        return (SqlRowSet) out.get("out_param_name");
    }

}

कई विकल्प हैं जिनका आप यहां उपयोग कर सकते हैं:

  • यदि आपके पास प्रक्रिया के नाम ओवरलोड हैं या डेटाबेस के विरुद्ध सत्यापन करने के लिए SimpleJdbcCall नहीं चाहते हैं तो बिना ProProcedureColumnMetaDataAccess () की आवश्यकता है।
  • withReturnValue () यदि प्रक्रिया का रिटर्न मान है। घोषित करने के लिए दिया गया पहला मूल्यपार्टी रिटर्न रिटर्न को परिभाषित करता है। साथ ही, यदि आपकी प्रक्रिया एक फ़ंक्शन है, तो निष्पादित करते समय FFunctionName और executeFunction का उपयोग करें।
  • withNamedBinding () यदि आप स्थिति के बजाय नामों का उपयोग करके तर्क देना चाहते हैं।
  • useInParameterNames () तर्क क्रम को परिभाषित करता है। मुझे लगता है कि यह आवश्यक हो सकता है यदि आप अपने तर्कों को एक सूची के रूप में मानने के लिए तर्क नाम के नक्शे के बजाय पास करते हैं। हालांकि यह केवल आवश्यक हो सकता है यदि आप बिनाProProcedureColumnMetaDataAccess () का उपयोग करें

Oracle डेटाबेस

ओरेकल के साथ कई समस्याएं हैं। उन्हें हल करने का तरीका यहां बताया गया है।

मान लें कि आपकी प्रक्रिया आउटपुट पैरामीटर ref cursor , तो आपको यह अपवाद मिलेगा।

java.sql.SQLException: अमान्य स्तंभ प्रकार: 2012

इसलिए Types.REF_CURSOR को OracleTypes.CURSOR में बदलें simpleJdbcCall.declareParameters ()


OracleTypes का समर्थन

यदि आपके डेटा में कुछ कॉलम टाइप हैं, तो आपको केवल ऐसा करने की आवश्यकता हो सकती है।

अगला मुद्दा मैंने देखा कि मालिकाना प्रकार जैसे oracle.sql.TIMESTAMPTZ कारण oracle.sql.TIMESTAMPTZ यह त्रुटि हुई:

स्तंभ के लिए अमान्य SQL प्रकार; नेस्टेड अपवाद java.sql.SQLException: कॉलम के लिए अमान्य SQL प्रकार है

तो हम एक ResultSetExtractor कि Oracle प्रकार का समर्थन करता बनाना होगा।
मैं इस कोड के बाद पासवर्ड का कारण बताऊंगा।

package com.boost.oracle;

import oracle.jdbc.rowset.OracleCachedRowSet;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet;
import org.springframework.jdbc.support.rowset.SqlRowSet;

import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * OracleTypes can cause {@link org.springframework.jdbc.core.SqlRowSetResultSetExtractor}
 * to fail due to a Oracle SQL type that is not in the standard {@link java.sql.Types}.
 *
 * Also, types such as {@link oracle.sql.TIMESTAMPTZ} require a Connection when processing
 * the ResultSet; {@link OracleCachedRowSet#getConnectionInternal()} requires a JNDI
 * DataSource name or the username and password to be set.
 *
 * For now I decided to just set the password since changing SpringBoot to a JNDI DataSource
 * configuration is a bit complicated.
 *
 * Created by Arlo White on 2/23/17.
 */
public class OracleSqlRowSetResultSetExtractor implements ResultSetExtractor<SqlRowSet> {

    private String oraclePassword;

    public OracleSqlRowSetResultSetExtractor(String oraclePassword) {
        this.oraclePassword = oraclePassword;
    }

    @Override
    public SqlRowSet extractData(ResultSet rs) throws SQLException, DataAccessException {
        OracleCachedRowSet cachedRowSet = new OracleCachedRowSet();
        // allows getConnectionInternal to get a Connection for TIMESTAMPTZ
        cachedRowSet.setPassword(oraclePassword);
        cachedRowSet.populate(rs);
        return new ResultSetWrappingSqlRowSet(cachedRowSet);
    }

}

कुछ ओरेकल प्रकारों को रिजल्टसेट से कॉलम मान प्राप्त करने के लिए एक कनेक्शन की आवश्यकता होती है। TIMESTAMPTZ इन प्रकारों में से एक है। इसलिए जब rowSet.getTimestamp(colIndex) कहा जाता है, तो आपको यह अपवाद मिलेगा:

इसके कारण: java.sql.SQLException: oracle.jdbc.rowset.OracleCachedRowSet.getConnectionInternal (OracleCachedRowSet.java )60 पर oracle.jdbc.rowset.Occle अंकल अंकल के सेट पर एक या अधिक प्रमाणित रोसेट गुण नहीं। : 3717) org.springframework.jdbc.support.rowset.ResultSetWrappingSqlRowSet.getTimestamp

यदि आप इस कोड में खुदाई करते हैं, तो आप देखेंगे कि OracleCachedRowSet को कनेक्शन प्राप्त करने के लिए पासवर्ड या JNDI डेटा स्रोत नाम की आवश्यकता है। यदि आप JNDI लुकअप पसंद करते हैं, तो बस सत्यापित करें कि OracleCachedRowSet में DataSourceName सेट है।

इसलिए मेरी सेवा में, मैं पासवर्ड में ऑटोवॉयर करता हूं और आउटपुट पैरामीटर को इस तरह घोषित करता हूं:

new SqlOutParameter("cursor_param_name", OracleTypes.CURSOR, new OracleSqlRowSetResultSetExtractor(oraclePassword))


Modified text is an extract of the original Stack Overflow Documentation
के तहत लाइसेंस प्राप्त है CC BY-SA 3.0
से संबद्ध नहीं है Stack Overflow