Good afternoon,
I need to ensure application continuity using ojdbc7 12.1.0.2 Oracle function. I have thousands of projects where I use Spring and Hibernate to access db for transaction management. To implement the application continuity function in my projects, I have to use this class oracle.jdbc.replay.ReplayableConnection . Therefore, I don't know how to instruct Spring (and Hibernate) to use this class to manage transactions using the @Transactional annotation .
Actually, I am doing this:
Data source declaration (this implementation has a ReplayableConnection class)
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource oracleDataSource() throws SQLException {
OracleDataSourceImpl oracleDataSource = new OracleDataSourceImpl();
oracleDataSource.setUser(datasourceUsername);
oracleDataSource.setPassword(datasourcePassword);
oracleDataSource.setURL(datasourceUrl);
oracleDataSource.setDataSourceName("OracleDataSourceImpl");
return oracleDataSource;
}
Release the data source where I need it
@Resource(name = "oracleDataSource")
private DataSource dataSource;
@Autowired
private BdtContRepository bdtContRepository;
@Override
public void updateRow() {
logger.info("updateRow -> finding all rows...");
Iterable<BdtCont> bdtConts = bdtContRepository.findAll();
try {
if (this.dataSource.getConnection() instanceof oracle.jdbc.replay.ReplayableConnection) {
((oracle.jdbc.replay.ReplayableConnection)this.dataSource.getConnection()).beginRequest();
logger.info("updateRow -> updating all rows...");
StreamSupport.stream(bdtConts.spliterator(), false)
...
});
logger.info("updateRow -> done");
((oracle.jdbc.replay.ReplayableConnection)this.dataSource.getConnection()).endRequest();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
, BeginRequest EndRequest. ; .
Spring ?
30/01/2018
Spring:
@Configuration
public class DatabaseConfig {
@Value("${spring.datasource.url}")
private String datasourceUrl;
@Value("${spring.datasource.username}")
private String datasourceUsername;
@Value("${spring.datasource.password}")
private String datasourcePassword;
@Value("${spring.datasource.driver-class-name}")
private String driverClassName;
@Value("${spring.jpa.database-platform}")
private String databasePlatform;
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource oracleDataSource() throws SQLException {
OracleDataSourceImpl oracleDataSource = new OracleDataSourceImpl();
oracleDataSource.setUser(datasourceUsername);
oracleDataSource.setPassword(datasourcePassword);
oracleDataSource.setURL(datasourceUrl);
oracleDataSource.setDataSourceName("OracleDataSourceImpl");
return oracleDataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws SQLException {
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
localContainerEntityManagerFactoryBean.setDataSource(oracleDataSource());
localContainerEntityManagerFactoryBean.setPackagesToScan("com.example.demotx.domain");
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
@Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabasePlatform(databasePlatform);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(true);
return jpaVendorAdapter;
}
@Bean
public PlatformTransactionManager jpaTransactionManager() throws SQLException {
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
jpaTransactionManager.setDataSource(oracleDataSource());
return jpaTransactionManager;
}
@Bean
public OracleTransactionCoordinator transactionCoordinator() throws SQLException {
return new OracleTransactionCoordinator(oracleDataSource(),jpaTransactionManager());
}
, node, : SQL 17410 .
( , node, )
31/01/2018
, , . , .
TransactionCoordinator,
@Component
public class OracleTransactionCoordinator {
private final static Logger LOG = LoggerFactory.getLogger(OracleTransactionCoordinator.class);
private final OracleDataSource oracleDataSource;
private final PlatformTransactionManager jpaTransactionManager;
@Autowired
public OracleTransactionCoordinator(OracleDataSource oracleDataSource, PlatformTransactionManager jpaTransactionManager) {
this.oracleDataSource = oracleDataSource;
this.jpaTransactionManager = jpaTransactionManager;
}
public final <R> R doInTransaction(final ExecutionContext<R> context) throws SQLException {
return doInTransaction(context, true);
}
public final <R> R doInTransaction(final ExecutionContext<R> context, final boolean propagate) throws SQLException {
TransactionTemplate tx = new TransactionTemplate(jpaTransactionManager);
Connection connection = oracleDataSource.getConnection();
try {
((OracleConnection) connection).beginRequest();
if (propagate) {
tx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
} else {
tx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
}
R result = tx.execute(new TransactionCallback<R>() {
@Override
public R doInTransaction(TransactionStatus status) {
context.setTransactionStatus(status);
R result = context.doInTransaction();
context.setRollback(status.isRollbackOnly());
return result;
}
});
context.close(null);
return result;
} catch (RuntimeException ex) {
LOG.error(ex.getMessage(), ex);
context.setRollback(true);
context.close(ex);
return null;
} catch (Exception ex) {
LOG.error(ex.getMessage(), ex);
context.setRollback(true);
context.close(new RuntimeException("Wrapper pool exception", ex));
return null;
} finally {
try {
if (tx != null) {
((OracleConnection) connection).endRequest();
}
} catch (Exception e) {
}
}
}
public abstract static class ExecutionContext<R> {
private final Queue<Runnable> afterCommitCommands = new LinkedList<Runnable>();
private final Queue<Runnable> afterRollbackCommands = new LinkedList<Runnable>();
private TransactionStatus transactionStatus = null;
private boolean rollback = false;
private boolean rethrow = true;
public void setTransactionStatus(TransactionStatus transactionStatus) {
this.transactionStatus = transactionStatus;
}
public void setRollback(boolean rollback) {
this.rollback = rollback;
}
public void setRethrow(boolean rethrow) {
this.rethrow = rethrow;
}
public void close(RuntimeException error) {
if (!rollback) {
for (Runnable command : afterCommitCommands) {
try {
command.run();
} catch (RuntimeException e) {
LOG.error("Attention an after commit command has gone in error!!! Please check it!", e);
}
}
afterCommitCommands.clear();
} else {
for (Runnable command : afterRollbackCommands) {
try {
command.run();
} catch (RuntimeException e) {
LOG.error("Attention an after rollback command has gone in error!!! Please check it!", e);
}
}
afterRollbackCommands.clear();
}
if (error != null && rethrow) {
throw error;
}
}
protected abstract R doInTransaction();
protected void doAfterCommit(Runnable command) {
afterCommitCommands.offer(command);
}
protected void doAfterRollback(Runnable command) {
afterRollbackCommands.offer(command);
}
protected void rollbackTransaction() {
transactionStatus.setRollbackOnly();
}
protected void flush() {
transactionStatus.flush();
}
}
private final static class TransactionTemplateFactory extends BasePoolableObjectFactory<TransactionTemplate> {
private final PlatformTransactionManager transactionManager;
public TransactionTemplateFactory(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
public TransactionTemplate makeObject() {
return new TransactionTemplate(transactionManager);
}
}
OracleTransactionCoordinator :
:
transactionCoordinator.doInTransaction(new OracleTransactionCoordinator.ExecutionContext<Object>() {
@Override
protected Object doInTransaction() {
instanceRepository.findAll().forEach(ins -> logger.info("instance name: "+ ins.toString()));
logger.info("do In Transaction... updating all");
bdtContRepository.updateAll();
instanceRepository.findAll().forEach(ins -> logger.info("instance name: "+ ins.toString()));
logger.info("FINISHED");
return null;
}
});
, , node, , :
2018-01-31 13:55:54.077 INFO 8114
Hibernate: select instance0_.INSTANCE_NAME as INSTANCE_NAME1_1_ from CURR_INST instance0_
2018-01-31 13:55:54.422 INFO 8114
2018-01-31 13:55:54.422 INFO 8114
Hibernate: update BDT_CONT set VAL=?
2018-01-31 13:55:55.602 WARN 8114
2018-01-31 13:55:55.602 ERROR 8114
2018-01-31 13:55:55.602 WARN 8114
2018-01-31 13:55:55.603 ERROR 8114
2018-01-31 13:55:55.626 ERROR 8114
org.springframework.dao.DataAccessResourceFailureException: could not execute statement; nested exception is org.hibernate.exception.JDBCConnectionException: c
ould not execute statement
, , " ", , .