Spring和Hibernate的应用程序连续性

时间:2018-01-29 08:46:06

标签: java spring oracle hibernate jdbc

美好的一天,

我需要使用Oracle ojdbc7 12.1.0.2中的功能确保应用程序的连续性。我有成千上万的项目,我使用Spring和Hibernate访问数据库管理事务。 要在我的项目中实现应用程序连续性功能,我必须使用此类 oracle.jdbc.replay.ReplayableConnection 。所以实际上我不知道如何指示Spring(和Hibernate)使用这个类来使用 @Transactional 注释来管理事务。

实际上,我在做的是:

  1. 声明数据源(此实现具有ReplayableConnection类)

    @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;
    }
    
  2. 自动装配我需要的数据源

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

    }

  3. 如您所见,我使用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());
    }
    

    如果我使用当前配置启动应用程序,当我关闭oracle节点时,它会说:SQL异常17410没有更多数据要从套接字读取。 (实际上我有两个节点,我关闭它连接的节点)

    更新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;
    }
    
    /**
     * Execute a portion of code in transaction, with transaction behaviour {@link org.springframework.transaction.TransactionDefinition} PROPAGATION_REQUIRED.
     *
     * @param context a callback support instance.
     * @param <R>     type of result.
     * @return typed result of callback.
     */
    public final <R> R doInTransaction(final ExecutionContext<R> context) throws SQLException {
        return doInTransaction(context, true);
    }
    
    /**
     * Execute a portion of code in transaction.
     *
     * @param context   a callback support instance.
     * @param propagate true to use PROPAGATION_REQUIRED, false to use PROPAGATION_REQUIRES_NEW.
     * @param <R>       type of result.
     * @return typed result of callback.
     */
    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) {
                // ignored
            }
        }
    }
    
    /**
     * Transactional callback support class.
     *
     * @param <R> result type.
     */
    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;
                }
            });
    

    Acually,如果我启动它并关闭它所连接的oracle节点,则说:

    2018-01-31 13:55:54.077  INFO 8114 --- [ost-startStop-1] o.h.h.i.QueryTranslatorFactoryInitiator  : HHH000397: Using ASTQueryTranslatorFactory
    Hibernate: select instance0_.INSTANCE_NAME as INSTANCE_NAME1_1_ from CURR_INST instance0_
    2018-01-31 13:55:54.422  INFO 8114 --- [ost-startStop-1] com.example.demotx.DemoTxApplication     : instance name: Instance{instanceName='LABLAR2'}
    2018-01-31 13:55:54.422  INFO 8114 --- [ost-startStop-1] com.example.demotx.DemoTxApplication     : do In Transaction... updating all
    Hibernate: update BDT_CONT set VAL=?
    2018-01-31 13:55:55.602  WARN 8114 --- [ost-startStop-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 17410, SQLState: 08000
    2018-01-31 13:55:55.602 ERROR 8114 --- [ost-startStop-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : No more data to read from socket
    2018-01-31 13:55:55.602  WARN 8114 --- [ost-startStop-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : SQL Error: 17370, SQLState: 99999
    2018-01-31 13:55:55.603 ERROR 8114 --- [ost-startStop-1] o.h.engine.jdbc.spi.SqlExceptionHelper   : Replay disabled:
    2018-01-31 13:55:55.626 ERROR 8114 --- [ost-startStop-1] o.s.t.support.TransactionTemplate        : Application exception overridden by rollback exception
    
    org.springframework.dao.DataAccessResourceFailureException: could not execute statement; nested exception is org.hibernate.exception.JDBCConnectionException: c
    ould not execute statement
    

    正如你所看到的那样,“禁止重播”,我无法弄清楚原因。

0 个答案:

没有答案