从Spring JDBC文档中,我知道如何insert a blob using 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();
以及如何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
有没有办法将两者结合起来?
答案 0 :(得分:15)
我来到这里寻找相同的答案,但对接受的内容并不满意。所以我做了一点挖掘,并提出了我在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的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 :(得分: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 :(得分:2)
我最后只执行了两个查询,一个用于创建行,另一个用于更新blob。
int id = insertRow();
updateBlob(id, blob);
查看Spring源代码并提取所需的部分,我想出了这个:
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的好处。
无论如何,我测试了上面的代码并且它有效。对于我的情况,我认为它会使我的代码太复杂。
答案 3 :(得分:2)
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();
}
}
}
答案 4 :(得分:1)
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 (?, ?, ?, ?, ?)
答案 5 :(得分:0)
如果底层数据库是mysql,您可以自动生成主键。然后,要将记录插入数据库,可以使用以下语法进行插入:
INSERT INTO lob_table (a_blob) VALUES (?)
答案 6 :(得分: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());
答案 7 :(得分:0)
使用lambda的另一种解决方案(不是必需的):
jdbcTemplate.update(dbcon -> {
PreparedStatement ps = dbcon.prepareStatement("INSERT INTO ...");
ps.setString(1, yourfieldValue);
ps.setBinaryStream(2, yourInputStream, yourInputStreamSizeAsInt));
return ps;
});
NB。对不起,这不包括KeyGenerator。
答案 8 :(得分:0)
更新blob数据时遇到了同样的问题-需要将映像更新到数据库中。比我发现一些解决方案如下。有关更多详细信息,update image into database
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});
答案 9 :(得分:-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
}
答案 10 :(得分:-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);
}