вторник, 27 января 2009 г.

Транзакции и ORACLE LOB вручную в spring

Недавно столкнулся с необходимостью сохранения LOB-объектов в базу Oracle из Spring приложения. Проблема была в записи кусков более 32k (Меньшие в CLOB пишутся через String, без мучений).
Пример использования транзакций без аннотаций:


Application Context:

<bean id="reportDao" class="***">
<property name="dataSource" ref="dataSource"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="lobHandler" ref="${reportDao.lobHandler}"/>
</bean>

<!-- Transaction manager for DataSource -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>

<!-- LobHandler for Oracle JDBC drivers -->
<!-- (refers to the NativeJdbcExtractor above to get access to native OracleConnections) -->

<bean id="oracleLobHandler" class="org.springframework.jdbc.support.lob.OracleLobHandler" lazy-init="true">
<property name="nativeJdbcExtractor" ref="nativeJdbcExtractor"/>
</bean>


DAO implements:

private DataSourceTransactionManager transactionManager;
public void setReport(int numRep, String code) {
TransactionTemplate txTemplate = new TransactionTemplate(transactionManager);
MyTransaction transaction = new MyTransaction(numRep, code);
try {
txTemplate.execute(transaction);
} catch (Exception e) {
log.warn("TRANSACTION EXCEPTION! " +e, e);
}
}

private class MyTransaction extends TransactionCallbackWithoutResult {
/** Logger for this class and subclasses */
protected final Log log = LogFactory.getLog(getClass());

private String clobData;
private int numRep;

public MyTransaction(int numRep, String clobData) {
this.clobData = clobData;
this.numRep = numRep;
}

public void doInTransactionWithoutResult(TransactionStatus status) {
JdbcTemplate jdbcTemplate = getJdbcTemplate();

Integer id = numRep; //obtain ID for new record
CLOB clob = null;

try {
clob = CLOB.empty_lob();

jdbcTemplate.update(
"update Report set report_text=? where id = ? ",
new Object[] { clob, id },
new int[] { Types.CLOB, Types.INTEGER });

List packetList = jdbcTemplate.query(
"select report_text from Report where id=? for update",
new Object[]{ id },
new int[] { Types.INTEGER },
new RowMapper() {
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
return rs.getClob("report_text");
}
});

if (packetList.size() == 1) {
Writer os = ((CLOB)packetList.get(0)).getCharacterOutputStream();
os.write(clobData);
os.flush();
os.close();
} else {
//handle - this shouldn't happen
}
} catch (SQLException e) {
log.warn(e,e);
} catch (IOException e) {
log.warn(e,e);
}
}
}

Всё просто.
Увы, не помню линк, окуда вытащил пример.

Комментариев нет: