Bir String> 4k'den oluşturulan yüklemde Oracle clob kullanın


11

Aşağıda bir Oracle SELECT yükleminde kullanılmak üzere 4000 dosya karakterleri (file_data bağlama değişkeninde sağlanan) bir dizeden bir clob oluşturmaya çalışıyorum:

myQuery=
select *
from dcr_mols
WHERE flexmatch(ctab,:file_data,'MATCH=ALL')=1;

TO_CLOB () yuvarlak file_data eklersem bir varchar için rezil Oracle 4k sınırını başarısız olur (<4k dizeleri için iyidir). Hata (SQL Developer'da):

ORA-01460: unimplemented or unreasonable conversion requested
01460. 00000 -  "unimplemented or unreasonable conversion requested"

FYI Esnek eşleşme işlevi molekülleri aramak için kullanılır ve burada açıklanmıştır: http://help.accelrysonline.com/ulm/onelab/1.0/content/ulm_pdfs/direct/developers/direct_2016_developersguide.pdf

Fonksiyonun kendisi biraz karmaşıktır ama özü 2. parametrenin bir clob olması gerekir. Yani benim sorum nasıl 4000 karakterden bind_variable bir Java String sql (veya Java) bir clob dönüştürmek olduğunu.

Java (Bahar önyükleme 2) kullanarak aşağıdaki yöntemi (clobs eklerken çalışır) denedim:

MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", fileDataStr,Types.CLOB);
jdbcNamedParameterTemplate.query(myQuery,parameters,…

Bu yöntem çalışmalıdır, ancak FYI olan dönüştürülmüş bir flexmatch hatasıyla başarısız olur:

SQL state [99999]; error code [29902]; ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100: 
MDL-0203: Unable to read from CLOB (csfrm=1, csid=873): 
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976: 
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n; nested exception is java.sql.SQLException: 
ORA-29902: error in executing ODCIIndexStart() routine\nORA-20100: MDL-0203: Unable to read from CLOB (csfrm=1, csid=873): 
ORA-22922: nonexistent LOB value\nMDL-0021: Unable to copy LOB to string\nMDL-1051: Molstructure search query is not a valid molecule\nMDL-0976: 
Molecule index search initialization failed\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 329\nORA-06512: at \"C$MDLICHEM80.MDL_MXIXMDL\", line 309\n"

Not SpringBoot 2 kullanıyorum ama (bile benim bahar NamedParametersJdbcTemplate nesneden elde edilen) bir OracleConnection kullanarak herhangi bir yöntem alamıyorum (hatta <4k clobs), bu yüzden aptalca bir şey yaptığından şüpheleniyorum. Denedim:

 @Autowired
 NamedParameterJdbcTemplate  jdbcNamedParameterTemplate;
OracleConnection conn =  this.jdbcNamedParameterTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);
Clob myClob =  conn.createClob();
myClob.setString( 1, fileDataStr);
MapSqlParameterSource parameters = new MapSqlParameterSource();
parameters.addValue("file_data", myClob,Types.CLOB);

application.properties:

spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}/${ORA_SID}
spring.datasource.username=${ORA_USER}
spring.datasource.password=${ORA_PASS}

Ben eski okula gidip bahar olmayan bir bağlantı artı bir setClob () yöntemi olan bir PreparedStatement kullanırsanız iyi çalışır unutmayın:

OracleDataSource ods = new OracleDataSource();
String url ="jdbc:oracle:thin:@//" + ORA_HOST +":"+ORA_PORT +"/"+ORA_SID;
ods.setURL(url);
ods.setUser(user);
ods.setPassword(passwd);
Connection conn = ods.getConnection();
Clob myClob=conn.createClob();
PreparedStatement ps = conn.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
myClob.setString(1,myMol);
ps.setClob(1,myClob);
ResultSet rs =ps.executeQuery();

Ancak Java veya Sql'de bir Spring 2 çözümünü tercih ederim. Herhangi bir yardım, öneri takdir.


Bu, bugüne kadar yaptığımdan farklı olarak, +1 iyi bir soru. flexmatch()İşlev için API belgelerine dikkat çekebilir misiniz? Bunun ihtiyacını görmek istiyorum. Dürüst olmak gerekirse, WHEREmaddede parametre olarak asla büyük değerler kullanmadım . Onları kullandım INSERTve kullanarak geri alıyorum SELECT. Sizin durumunuz farklı.
Impaler

@The_impaler sorudaki dokümanlara bir bağlantı var. Korkarım bir api değilim, ama sahip olduğumuz tek şey bu. Bu çok niş bir işlevdir. İhtiyacım, bir molekülün dijital sunumunu araştırıyorum ve bunu yapmak için uzman bir işleve ihtiyacınız var. yani dcr_mols tablosunda zaten var olduğum molekül var mı?
DS.

Hangi Oracle sürümünü kullanıyorsunuz?
areus

@areaus ojdbc6-11.2.1.0.1
DS.

Yanıtlar:


5

Akış. Büyük bir değeri bir SQL deyimine yapıştıramazsınız.

Yapmanız gerekenler:

  • INSERTİfadeye boş bir BLOB ekleyin (EMPTY_BLOB () kullanarak? ... hatırlamıyorum).
  • Boş damla için çıkış akışını alın.
  • Sonra dosyadan bir girdi akışı alın. Lütfen dosyanın tamamını belleğe yüklemeyin.
  • Daha sonra tamponları kullanarak blokları giriş akışından çıkış akışına aktarın. 16 KB'lık bir arabellek yapmalıdır.
  • Her iki akışı da kapatın.

Oracle'daki büyük verilerle baş etmenin standart yolu budur. Orada çok sayıda örnek var.

Büyük verileri ( BLOBve CLOBtürleri) almak aynı şekilde çalışır. Bu durumda yalnızca InputStreams kullanın.


@The_impaler Ben bir clob takmıyorum. Ben bir select
DS

1

"BIOVIA Direct" API'sinin belgelerini okurken, aşağıda gösterilen alıntıdan sayfa 27'de ilginç bir örnek var:

select ...
from ...
where flexmatch(
ctab,
(select ctab from nostruct_table),
'all'
)=1

Zaten yüklü bir CLOB kullanır . Bu nedenle, yeterince iyi bir çözüm CLOB'unuzu bir tablonuza yüklemek (veya önceden önceden yüklemek) ve sadece bunları kullanmak olacaktır.

Adım # 1 - CLOB'nizi bir tabloya yükleyin:

create table mol_file (
  id number(12) primary key not null,
  content clob
);

insert into mol_file (id, content) values (:id, :content);

Ve Java kodunuzu, başka bir yanıtta gösterildiği gibi CLOB eklentisini (muhtemelen akışları kullanarak) gerçekleştirmek için kullanın (İnternette çok sayıda örnek). Örneğin, mol veri içeriğinizi ID = ile ekleyin 123.

Adım # 2 - Yüklü mol dosyasını kullanarak sorgunuzu çalıştırın:

select *
from dcr_mols
WHERE flexmatch(
        ctab,
        (select content from mol_file where id = :id),
        'MATCH=ALL'
      ) = 1;

:idParametreyi, 123önceden yüklediğiniz dosyayı (veya başka bir dosyayı) kullanacak şekilde ayarlayabilirsiniz .


@The_impaler Teşekkürler, ama bu bir ceviz kırmak için biraz balyoz. Çalıştırılacak birçok sorgumuz var ve bu, kodu karmaşıklaştıracak ve işleri yavaşlatacaktır. Sorumu, daha iyi bir şey ortaya çıkmazsa isteksizce kullanacağım eski bir okul cevabı ile güncelledim.
DS.

1

Eski moda fonksiyonunuza böyle diyebilirsiniz. ResultSet'i işlemek için bir Sınıf oluşturma

 class MyPreparedStatementCallback implements PreparedStatementCallback {
    public Object doInPreparedStatement(PreparedStatement preparedStatement)
            throws SQLException, DataAccessException {
        ResultSet rs = preparedStatement.executeQuery();
        List result = new LinkedList();
        rs.close();
        return result;
    }
}

ve yönteminizde JdbcTemplate kullanarak sorgunuzu arayın

 jdbcTemplate.execute(new PreparedStatementCreator() {
        @Override
        public PreparedStatement createPreparedStatement(Connection connection)

                throws SQLException, DataAccessException {

            PreparedStatement ps = connection.prepareStatement("select dcr_number from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1");
            Clob myClob =  connection.createClob();
            myClob.setString( 1, fileDataStr);
            MapSqlParameterSource parameters = new MapSqlParameterSource();
            parameters.addValue("file_data", myClob, Types.CLOB);
            ps.setClob(1,myClob);
            return ps;

        };
    }, new MyPreparedStatementCallback());

1

Bir PreparedStatement kullanmaya geri dönmek zorunda kaldım, ancak Spring'den bağlantı alıp ResacheSet'i bir nesne listesine eşleştirmek için apache commons BeanListHandler kullanarak normal uygulamayı biraz geliştirdim.

import org.apache.commons.dbutils.ResultSetHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

@Autowired
NamedParameterJdbcTemplate  jdbcTemplate;

List<MyDao> myMethod(String fileData){
    String myQuery="select * from dcr_mols WHERE flexmatch(ctab,?,'MATCH=ALL')=1";

try {
    Connection conn =  this.jdbcTemplate.getJdbcTemplate().getDataSource().getConnection().unwrap(OracleConnection.class);   // Get connection from spring

    Clob myClob =  conn.createClob();   // Open a dB clob 
    myClob.setString( 1, fileData);     // add data to clob
    PreparedStatement ps = conn.prepareStatement(myQuery);
    ps.setClob(1,myClob);              // Add a clob into the PreparedStatement
    ResultSet rs =ps.executeQuery();   // Execute the prepared statement

    //ResultSetHandler<List<MyDao>> handler = new BeanListHandler<MyDao>(MyDao.class);   // Define the ResultSet handler
    ResultSetHandler<List<MyDao>> handler = new BeanListHandler<MyDao>(MyDao.class, new BasicRowProcessor(new GenerousBeanProcessor()));  // This is better than the above handler , because GenerousBeanProcessor removes the requirement for the column names to exactly match the java variables

    List<MyDao> myDaoList = handler.handle(rs);   // Map ResultSet to List of MyDao objects
    }catch (Exception e) {
        e.printStackTrace();
    }

return myDaoList;
}

0

Bağlantı olan con'u kullanarak fileDataStr dosyasını CLOB olarak bildirebilirsiniz

java.sql.Clob fileDataStr = oracle.sql.CLOB.createTemporary
(con, false, oracle.sql.CLOB.DURATION_SESSION);

ve sonra aşağıdaki gibi kullanın

 parameters.addValue("file_data", fileDataStr,Types.CLOB);

Ayrıca bağlantı dizenizde Hizmet adı yerine SID kullanıyorsanız özellik dosyanızı aşağıdaki gibi değiştirmeyi deneyin

spring.datasource.url=jdbc:oracle:thin:@//${ORA_HOST}:${ORA_PORT}:${ORA_SID}

Teşekkürler, ama bu çok garip. Veriler herhangi bir boyut olabilir, bu yüzden parçalar oluşturmak için dinamik sql kullanmak zorunda kalacaksınız, ayrıca, im gibi bölümlere bir clob kırmak emin değilim.
DS.

fileDataStr türü nedir
psaraj12

Bu bir Java Dizesi
DS.

CLOB olarak ilan edebilir ve java.sql.Clob dosyasını beğenir misinizDataStr = oracle.sql.CLOB.createTemporary (con, false, oracle.sql.CLOB.DURATION_SESSION);
psaraj12

con bağlantı olduğunu burada DataStr CLOB olarak bildirmek için yorumda benim örnek bakın
psaraj12
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.