2010-05-05 49 views
14

從春天JDBC文檔,我知道如何insert a blob using JdbcTemplateSpring的JdbcTemplate - 插入BLOB,並返回生成的密鑰

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(); 

以及如何retrieve the generated key of a newly inserted row

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 

有沒有一種方法,我可以結合他們倆?

回答

14

我來到這裏尋找同樣的答案,但並不滿足於已被接受。所以,我做了一個小挖周圍,並用此解決方案,我在Oracle 10g和春天已經測試想出了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的AbstractLobCreatingPreparedStatementCallback

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中創建的表應該使用序列和觸發器爲ID自動遞增列。觸發器是必須的,否則你必須使用Spring的NamedParameterJdbcOperations(在你的SQL中執行sequence.nextval),這似乎沒有支持KeyHolder(我用它來檢索自動生成的id)。更多信息請參閱本博客文章(我的博客):http://www.lifeaftercoffee.com/2006/02/17/how-to-create-auto-increment-columns-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; 
/
+1

接受這個答案,因爲所有的upvotes。你應該用'getJdbcTemplate()'替換'getSimpleJdbcTemplate()。getJdbcOperations()',因爲現在棄用了SimpleJdbcTemplate。 – itsadok 2012-10-09 07:26:04

2

我最終只執行了兩個查詢,一個創建行,一個更新blob。在春源代碼

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的好處。

無論如何,我測試了上面的代碼,它的工作原理。對於我的情況,我決定這會使我的代碼複雜得太多。

0

如果您的底層數據庫是mysql,您可以自動生成主鍵。然後插入一條記錄到你的數據庫,你可以使用下面的語法插入:

INSERT INTO lob_table (a_blob) VALUES (?) 
-1

也許一些這樣的:

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 
} 
+0

blob在哪裏? – itsadok 2012-01-09 08:24:21

+0

是否actor.getLastName()不能是一個blob? – iMysak 2012-01-12 17:20:44

0

在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 (?, ?, ?, ?, ?) 
1
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(); 
     } 

    } 
} 
+1

您插入了一個BLOB,但沒有得到生成的密鑰。 – itsadok 2013-02-03 12:19:09

8

所有這一切都似乎太複雜了我。這工作,很簡單。它採用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(); 
     } 
    } 
+2

問題是關於**插入**一個新的**行與一個blob,並獲得新生成的密鑰。你的代碼**更新**現有的**行與blob。我可以假設你的意思只是插入沒有blob的行作爲第一步,然後做到這一點? – itsadok 2014-09-07 12:04:00

0

這是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()); 
-1

請使用:

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); 

} 
+0

介意解釋你的答案? – CinCout 2015-09-11 19:38:00

0

與拉姆達另一種解決方案(其中不需要):

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

NB。對不起,這不包括KeyGenerator。