Spring jdbctemplate - أدخل blob وإرجاع المفتاح الذي تم إنشاؤه

StackOverflow https://stackoverflow.com/questions/2770877

  •  03-10-2019
  •  | 
  •  

سؤال

من وثائق الربيع JDBC ، أعرف كيف أدخل نقطة باستخدام jdbctemplate

final File blobIn = new File("spring2004.jpg");
final InputStream blobIs = new FileInputStream(blobIn);
jdbcTemplate.execute(
  "INSERT INTO lob_table (id, a_blob) VALUES (?, ?)",
  new AbstractLobCreatingPreparedStatementCallback(lobhandler) {                         
      protected void setValues(PreparedStatement ps, LobCreator lobCreator) 
          throws SQLException {
        ps.setLong(1, 1L);
        lobCreator.setBlobAsBinaryStream(ps, 2, blobIs, (int)blobIn.length());           
      }
  }
);
blobIs.close();

وكذلك كيف استرجاع المفتاح الذي تم إنشاؤه للصف الذي تم إدراجه حديثًا:

KeyHolder keyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(
    new PreparedStatementCreator() {
        public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
            PreparedStatement ps =
                connection.prepareStatement(INSERT_SQL, new String[] {"id"});
            ps.setString(1, name);
            return ps;
        }
    },
    keyHolder);

// keyHolder.getKey() now contains the generated key

هل هناك طريقة يمكنني الجمع بين الاثنين؟

هل كانت مفيدة؟

المحلول

جئت إلى هنا بحثًا عن نفس الإجابة ، لكنني لم أكن راضيا عن ما تم قبوله. لذلك فعلت القليل من الحفر وتوصلت إلى هذا الحل الذي اختبرته في Oracle 10G و SPRING 3.0

public Long save(final byte[] blob) {
  KeyHolder keyHolder = new GeneratedKeyHolder();
  String sql = "insert into blobtest (myblob) values (?)"; //requires auto increment column based on triggers
  getSimpleJdbcTemplate().getJdbcOperations().update(new AbstractLobPreparedStatementCreator(lobHandler, sql, "ID") {
    @Override
    protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException, DataAccessException {
      lobCreator.setBlobAsBytes(ps, 1, blob);
    }
  }, keyHolder);

  Long newId = keyHolder.getKey().longValue();
  return newId;
}

يتطلب هذا أيضًا الفئة التجريدية التالية ، استنادًا جزئيًا إلى Spring AbstractLoBcreatingPrepedStatementCallback

public abstract class AbstractLobPreparedStatementCreator implements PreparedStatementCreator {
  private final LobHandler lobHandler;
  private final String sql;
  private final String keyColumn;
  public AbstractLobPreparedStatementCreator(LobHandler lobHandler, String sql, String keyColumn) {
    this.lobHandler = lobHandler;
    this.sql = sql;
    this.keyColumn = keyColumn;
  }
  public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
    PreparedStatement ps = con.prepareStatement(sql, new String[] { keyColumn });
    LobCreator lobCreator = this.lobHandler.getLobCreator();
    setValues(ps, lobCreator);
    return ps;
  }
  protected abstract void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException, DataAccessException;
}

أيضًا ، يجب أن يحتوي الجدول الذي تنشئه في Oracle على عمود تم تثبيته تلقائيًا للمعرف باستخدام تسلسل وجهاز تشغيل. يعد المشغل ضروريًا لأنه على خلاف ذلك ، يجب عليك استخدام spring pararameterjdbcoperations (للقيام بالتسلسل. nextval في SQL) الذي لا يبدو أن لديه دعمًا لـ KeyHolder (الذي أستخدمه لاسترداد معرف الجيل التلقائي). شاهد منشور المدونة هذا (وليس مدونتي) لمزيد من المعلومات: http://www.lifeaftercoffee.com/2006/02/17/how-to-create-auto-increment-in-oracle/

create table blobtest (
id number primary key,
myblob blob);

create sequence blobseq start with 1 increment by 1;

CREATE OR REPLACE TRIGGER blob_trigger
BEFORE INSERT
ON blobtest
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
SELECT blobseq.nextval INTO :NEW.ID FROM dual;
end;
/

نصائح أخرى

بدا كل هذا الأمر معقدًا جدًا بالنسبة لي. هذا يعمل وبسيط. يستخدم org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate

import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.support.SqlLobValue;
import org.springframework.jdbc.support.lob.DefaultLobHandler;


    public void setBlob(Long id, byte[] bytes) {
        try {
            jdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
            MapSqlParameterSource parameters = new MapSqlParameterSource();
            parameters.addValue("id", id);
            parameters.addValue("blob_field", new SqlLobValue(new ByteArrayInputStream(bytes), bytes.length, new DefaultLobHandler()), OracleTypes.BLOB);
            jdbcTemplate.update("update blob_table set blob_field=:blob_field where id=:id", parameters);
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

انتهى بي الأمر فقط لأداء استفسارين ، أحدهما لإنشاء الصف وواحد لتحديث النقطة.

int id = insertRow();
updateBlob(id, blob);

عند النظر إلى رمز مصدر الربيع واستخراج الأجزاء المطلوبة ، توصلت إلى هذا:

final KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
getJdbcTemplate().execute(
    "INSERT INTO lob_table (blob) VALUES (?)",
    new PreparedStatementCallback() {
        public Object doInPreparedStatement(PreparedStatement ps) throws SQLException {
            LobCreator lobCreator = lobHandler.getLobCreator();
            lobCreator.setBlobAsBinaryStream(ps, 2, blobIs, (int)blobIn.length());

            int rows = ps.executeUpdate();
            List generatedKeys = generatedKeyHolder.getKeyList();
            generatedKeys.clear();
            ResultSet keys = ps.getGeneratedKeys();
            if (keys != null) {
                try {
                    RowMapper rowMapper = new ColumnMapRowMapper();
                    RowMapperResultSetExtractor rse = new RowMapperResultSetExtractor(rowMapper, 1);
                    generatedKeys.addAll((List) rse.extractData(keys));
                }
                finally {
                    JdbcUtils.closeResultSet(keys);
                }
            }
            if (logger.isDebugEnabled()) {
                logger.debug("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
            }
            return new Integer(rows);
        }
    }
);

لا أستطيع أن أقول أنني أفهم تمامًا ما يجري هنا. لست متأكدًا مما إذا كانت الطريقة المعقدة لاستخراج المفتاح الذي تم إنشاؤه ضروريًا في هذه الحالة البسيطة ، ولست واضحًا تمامًا بشأن فائدة حتى استخدام JDBCtemplate عندما يحصل الرمز على هذا الشعر.

على أي حال ، لقد اختبرت الرمز أعلاه وهو يعمل. بالنسبة لحالتي ، قررت أن هذا سيؤدي إلى تعقيد الكود الخاص بي.

package com.technicalkeeda.dao;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.sql.Types;

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.support.SqlLobValue;
import org.springframework.jdbc.support.lob.DefaultLobHandler;
import org.springframework.jdbc.support.lob.LobHandler;

public class ImageDaoImpl implements ImageDao {

    private DataSource dataSource;

    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
        this.jdbcTemplate = new JdbcTemplate(this.dataSource);
    }

    @Override
    public void insertImage() {
        System.out.println("insertImage" + jdbcTemplate);

        try {
            final File image = new File("C:\\puppy.jpg");
            final InputStream imageIs = new FileInputStream(image);

            LobHandler lobHandler = new DefaultLobHandler(); 

            jdbcTemplate.update(
                     "INSERT INTO trn_imgs (img_title, img_data) VALUES (?, ?)",
                     new Object[] {
                       "Puppy",
                       new SqlLobValue(imageIs, (int)image.length(), lobHandler),
                     },
                     new int[] {Types.VARCHAR, Types.BLOB});


        } catch (DataAccessException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

    }
}

في عام 2012، SimpleJdbcTemplate تم إهماله. وهذا هو ما فعلته:

KeyHolder keyHolder = new GeneratedKeyHolder();

List<SqlParameter> declaredParams = new ArrayList<>();

declaredParams.add(new SqlParameter(Types.VARCHAR));
declaredParams.add(new SqlParameter(Types.BLOB));
declaredParams.add(new SqlParameter(Types.VARCHAR));
declaredParams.add(new SqlParameter(Types.INTEGER));
declaredParams.add(new SqlParameter(Types.INTEGER));

PreparedStatementCreatorFactory pscFactory = 
    new PreparedStatementCreatorFactory(SQL_CREATE_IMAGE, declaredParams);

pscFactory.setReturnGeneratedKeys(true);

getJdbcTemplate().update(
    pscFactory.newPreparedStatementCreator(
        new Object[] {
            image.getName(), 
            image.getBytes(), 
            image.getMimeType(), 
            image.getHeight(),
            image.getWidth() 
        }), keyHolder);

image.setId(keyHolder.getKey().intValue());

يبدو SQL هكذا:

INSERT INTO image (name, image_bytes, mime_type, height, width) VALUES (?, ?, ?, ?, ?)

في حال كانت قاعدة البيانات الأساسية الخاصة بك هي MySQL ، يمكنك تلقائي تلقائيًا مفتاحك الأساسي. ثم لإدراج سجل في DB الخاص بك ، يمكنك استخدام بناء الجملة التالي للإدراج:

INSERT INTO lob_table (a_blob) VALUES (?)

يتم اختبار هذا على MySQL فقط ولم يلصق الجزء ذي الصلة إلا. بعد تشغيل فئة الاختبار الخاصة بي ، يتم عرض النتيجة أدناه: "تم إضافة السجل عبر template.update (PSC ، KH): 1 تمت إضافته وحصل على مفتاح 36"

final byte[] bytes = "My Binary Content".getBytes();
final ByteArrayInputStream bais = new ByteArrayInputStream(bytes);        
PreparedStatementCreator psc = new PreparedStatementCreator() {
        PreparedStatement ps = null;
        public PreparedStatement createPreparedStatement(
                Connection connection) throws SQLException {
            dummy.setStringCode("dummy_jdbc_spring_createPS_withKey_lob");
            ps = connection
                    .prepareStatement(
                            "INSERT INTO DUMMY (dummy_code, dummy_double, dummy_date, dummy_binary) VALUES (?, ?, ?,?)",
                            Statement.RETURN_GENERATED_KEYS);
            ps.setString(1, dummy.getStringCode());
            ps.setDouble(2, dummy.getDoubleNumber());
            ps.setDate(3, dummy.getDate());
            new DefaultLobHandler().getLobCreator().setBlobAsBinaryStream(
                    ps, 4, bais, bytes.length);

            return ps;
        }
    };
KeyHolder holder = new GeneratedKeyHolder();
System.out.println("record added via template.update(psc,kh): "
            + template.update(psc, holder)+" added and got key " + holder.getKey());

حل آخر مع لامدا (وهو غير مطلوب):

jdbcTemplate.update(dbcon -> {
    PreparedStatement ps = dbcon.prepareStatement("INSERT INTO ...");
    ps.setString(1, yourfieldValue);
    ps.setBinaryStream(2, yourInputStream, yourInputStreamSizeAsInt));
    return ps;
});

NB. آسف هذا لا يشمل keygenerator.

حصلت على نفس المشكلة لتحديث بيانات Blob - بحاجة إلى تحديث الصورة في قاعدة البيانات. مما أجد بعض الحلول على النحو التالي. لمزيد من التفاصيل تحديث الصورة في قاعدة البيانات

 LobHandler lobHandler = new DefaultLobHandler();
 statusRes = jdbcTemplate.update("update  USERS set FILE_CONTENT = ?, FILE_NAME = ? WHERE lower(USER_ID) = ?",
               new Object[] {new SqlLobValue(image, lobHandler),fileName,userIdLower},
               new int[] {Types.BLOB,Types.VARCHAR,Types.VARCHAR});

ربما البعض مثل هذا:

public class JdbcActorDao implements ActorDao {
private SimpleJdbcTemplate simpleJdbcTemplate;
private SimpleJdbcInsert insertActor;

public void setDataSource(DataSource dataSource) {
    this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
    this.insertActor =
            new SimpleJdbcInsert(dataSource)
                    .withTableName("t_actor")
                    .usingGeneratedKeyColumns("id");
}

public void add(Actor actor) {
    Map<String, Object> parameters = new HashMap<String, Object>(2);
    parameters.put("first_name", actor.getFirstName());
    parameters.put("last_name", actor.getLastName());
    Number newId = insertActor.executeAndReturnKey(parameters);
    actor.setId(newId.longValue());
}

//  ... additional methods
}

يرجى استخدام:

addValue("p_file", noDataDmrDTO.getFile_data(), Types.BINARY)

noDataDmrDTO.getFile_data() is byte array.


{
 simpleJdbcCall =
          new SimpleJdbcCall(jdbcTemplate).withProcedureName("insert_uploaded_files").withCatalogName("wct_mydeq_stg_upld_pkg")
              .withSchemaName("WCT_SCHEMA");

 SqlParameterSource sqlParms =
        new MapSqlParameterSource().addValue("p_upload_idno", Integer.parseInt("143"))
            .addValue("p_file_type_idno", Integer.parseInt(noDataDmrDTO.getFile_type_idno())).addValue("p_file_name", noDataDmrDTO.getFile_name())
            .addValue("p_file", noDataDmrDTO.getFile_data(), Types.BINARY).addValue("p_comments", noDataDmrDTO.getComments())
            .addValue("p_userid", noDataDmrDTO.getUserid());


    simpleJdbcCallResult = simpleJdbcCall.execute(sqlParms);

}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top