使用Hibernate + Spring和3个事务数据库

时间:2017-02-11 15:56:02

标签: java spring hibernate spring-transactions

厄瓜多尔的问候:

目前我已经创建了一个项目,我必须在3个不同的数据库上执行操作。为此,我决定使用Hibernate ORM 5.2.7,Spring Framework 4.3.6和其他库来实现连接池等。为了实现Spring上下文的配置支持我的注释,我将在下面展示:

@Configuration
@ComponentScan("fttg.*")
@EnableTransactionManagement
@EnableScheduling
@PropertySources({
       @PropertySource("classpath:application.properties"),
       @PropertySource("classpath:schedule.properties")
})
public class ApplicationConfig {

      @Autowired
      private Environment environment;

@Bean(destroyMethod = "close")
public BasicDataSource dataSourceBitacora() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("postgres.jdbc.driver"));
    dataSource.setUrl(environment.getRequiredProperty("bitacora.jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("bitacora.jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("bitacora.jdbc.password"));
    dataSource.setPoolPreparedStatements(true);
    dataSource.setInitialSize(4);
    dataSource.setMaxTotal(4);
    dataSource.setMaxIdle(2);
    dataSource.setMinIdle(1);
    dataSource.setDefaultAutoCommit(Boolean.FALSE);
    return dataSource;
}

@Bean(destroyMethod = "close")
public BasicDataSource dataSourceFacturacion() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("postgres.jdbc.driver"));
    dataSource.setUrl(environment.getRequiredProperty("facturacion.jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("facturacion.jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("facturacion.jdbc.password"));
    dataSource.setPoolPreparedStatements(true);
    dataSource.setInitialSize(1);
    dataSource.setMaxTotal(4);
    dataSource.setDefaultAutoCommit(Boolean.FALSE);
    return dataSource;
}

@Bean(destroyMethod = "close")
public BasicDataSource dataSourceSietab() {
    BasicDataSource dataSource = new BasicDataSource();
    dataSource.setDriverClassName(environment.getRequiredProperty("postgres.jdbc.driver"));
    dataSource.setUrl(environment.getRequiredProperty("sietab.jdbc.url"));
    dataSource.setUsername(environment.getRequiredProperty("sietab.jdbc.username"));
    dataSource.setPassword(environment.getRequiredProperty("sietab.jdbc.password"));
    dataSource.setPoolPreparedStatements(true);
    dataSource.setInitialSize(1);
    dataSource.setMaxTotal(2);
    dataSource.setDefaultAutoCommit(Boolean.FALSE);
    return dataSource;
}

@Bean
public LocalSessionFactoryBean sessionFactoryBitacora() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSourceBitacora());
    sessionFactory.setPackagesToScan(environment.getRequiredProperty("bitacora.sessionFactory.packagesToScan"));
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("postgres.hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    sessionFactory.setHibernateProperties(properties);
    return sessionFactory;
}

@Bean
public LocalSessionFactoryBean sessionFactoryFacturacion() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSourceFacturacion());
    sessionFactory.setPackagesToScan(environment.getRequiredProperty("facturacion.sessionFactory.packagesToScan"));
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("postgres.hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    sessionFactory.setHibernateProperties(properties);
    return sessionFactory;
}

@Bean
public LocalSessionFactoryBean sessionFactorySietab() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSourceSietab());
    sessionFactory.setPackagesToScan(environment.getRequiredProperty("sietab.sessionFactory.packagesToScan"));
    Properties properties = new Properties();
    properties.put("hibernate.dialect", environment.getRequiredProperty("postgres.hibernate.dialect"));
    properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
    sessionFactory.setHibernateProperties(properties);
    return sessionFactory;
}

@Bean
public HibernateTransactionManager transactionManagerBitacora() {
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(sessionFactoryBitacora().getObject());
    return txManager;
}

@Bean
public HibernateTransactionManager transactionManagerFacturacion() {
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(sessionFactoryFacturacion().getObject());
    return txManager;
}

@Bean
public HibernateTransactionManager transactionManagerSietab() {
    HibernateTransactionManager txManager = new HibernateTransactionManager();
    txManager.setSessionFactory(sessionFactorySietab().getObject());
    return txManager;
}
}

DAOS配置对于数据库中的所有对象都是相同的:

@Repository
public class BitacoraFacturasDetalleDao extends GenericDaoImpl<BitacoraFacturasDetalle, Integer>{

private final static Logger LOGGER = Logger.getLogger(BitacoraFacturasDetalleDao.class);

@Qualifier("sessionFactoryBitacora")
@Autowired
private SessionFactory sessionFactory;

public BitacoraFacturasDetalleDao() {
    super(BitacoraFacturasDetalle.class);
}

public BitacoraFacturasDetalle findByEstablecimientoAndPuntoEmisionAndSecuencial(String establecimiento, String puntoEmision, String secuencial) {
    LOGGER.info("evento findByEstablecimientoAndPuntoEmisionAndSecuencial");
    BitacoraFacturasDetalle ret = (BitacoraFacturasDetalle) getCurrentSession().createNamedQuery("BitacoraFacturasDetalle.findByEstablecimientoAndPuntoEmisionAndSecuencial").setParameter("establecimiento", establecimiento).setParameter("puntoEmision", puntoEmision).setParameter("secuencial", secuencial).uniqueResult();
    return ret;
}

   @Override
   protected Session getCurrentSession() {
       return this.sessionFactory.getCurrentSession();
   }

}

交易对象实现如下:

@Service("facturasService")
@Transactional(value="transactionManagerFacturacion", readOnly = false)
public class FacturasServiceImpl implements FacturasService, Serializable {

private static final long serialVersionUID = 1L;
private final static Logger LOGGER =        Logger.getLogger(FacturasServiceImpl.class);

@Autowired
private FacturasCabeceraDao facturasCabeceraDao;

@Override
public boolean save(FacturasCabecera factura) {
    LOGGER.info("evento save");
    return facturasCabeceraDao.save(factura);
 }

}

@Service("bitacoraFacturasDetalleService")
@Transactional(readOnly = false, value = "transactionManagerBitacora")
public class BitacoraFacturasDetalleServiceImpl implements BitacoraFacturasDetalleService, Serializable {

private static final long serialVersionUID = 1L;
private final static Logger LOGGER = Logger.getLogger(BitacoraFacturasDetalleServiceImpl.class);

@Autowired
private BitacoraFacturasDetalleDao bitacoraFacturasDetalleDao;

@Override
public boolean save(BitacoraFacturasDetalle b) {
    LOGGER.info("evento save");
    return bitacoraFacturasDetalleDao.save(b);
}

@Override
public boolean edit(BitacoraFacturasDetalle b) {
    LOGGER.info("evento edit");
    return bitacoraFacturasDetalleDao.edit(b);
}

@Override
@Transactional(readOnly = true, value = "transactionManagerBitacora")
public BitacoraFacturasDetalle findByEstablecimientoAndPuntoEmisionAndSecuencial(String establecimiento, String puntoEmision, String secuencial) {
    LOGGER.info("evento findByEstablecimientoAndPuntoEmisionAndSecuencial");
    return   bitacoraFacturasDetalleDao.findByEstablecimientoAndPuntoEmisionAndSecuencial(establecimiento, puntoEmision, secuencial);
}

}

在实现Quartz的服务中,我调用了3种不同类型的服务: 我从数据库中检索信息,生成一些xmls,我在第二个数据库中插入bitacora的记录,如果这个动作是正确的,我更新从第一个基地检索到的记录的状态,然后我在生成的xmls如果正确执行此操作,我会在第二个数据库的记录中更改状态,并插入两个表类型master和第三个数据库的详细信息

然后是我进行调用的代码:

@Service
public class ScheduleService implements Serializable {
      @Autowired
      private LocalidadService localidadService;
      @Autowired
      private CooperativaService cooperativaService;
      @Autowired
      private BoletoTasaService boletoTasaService;
      @Autowired
      private BitacoraFacturasDetalleService bitacoraFacturasDetalleService;
      @Autowired
      private InformacionTributariaService informacionTributariaService;
      @Autowired
      private ClientesService clientesService;
      @Autowired
      private FacturasService facturasService;

      @Scheduled(cron = "${schedule.cronExpresion}")
      public void start() {
           if(XMLUtil.generarXML(factura, XML_GENERADO)) {
           LOGGER.info("XML para la factura " + SECUENCIAL_DOCUMENTO + " generado correctamente");
           //code that fills a javaBean
           //Execution of service that inserts in the database # 2
           if(bitacoraFacturasDetalleService.save(bitacoraFacturaDetalle)) {
                              LOGGER.info("Factura " + SECUENCIAL_DOCUMENTO + " registrada en bitacora correctamente");
               // object retrieved from database # 1 to be changed status not to be taken into account in future
               tasa.setStatusFacturacionElectronica("P");
               if(boletoTasaService.update(tasa)) {
               //Other post-upgrade operations

           }
      }
    }
}

这种情况是这个代码工作到一定数量的寄存器(大约700或800的数据库1),在插入或更新不同基础的下一个动作之后代码在很长一段时间后“休眠”再跑一次

对于在转换到生产之前执行的测试,制作3个数据库的副本,为了本场景的目的,这些数据库没有与它们交互的系统和/或接口的并发连接。

我不知道“问题”的原因是:所使用的编程代码,定义事务对象的策略(我已阅读并被建议使用JTA但是从我读过的这个机制只使用了一个事务性线程[控制数据库操作的服务])或者是否由于其他应用程序对不同数据库的表的精确性而产生这种不便

如果弹簧配置,事务服务的定义或您确实需要使用JTA来解决此问题,请提供帮助。

有可能表明以前我使用过这个方案,我有一个或几个数据库,我从中提取信息,只有我插入的数据库,因此我没有问题;另一方面,在给定的情况下写三个数据库

1 个答案:

答案 0 :(得分:0)

至于所描述的问题,很难确切地说出可能出现的问题。不过,我可以给你一些提示:

  1. 您根本没有使用任何连接池。尝试用HikariCP连接池替换BasicDataSource
  2. 而不是长时间运行的交易。尝试将其拆分成块。使用Spring Integration来构建管道。每个数据库事务一次只应处理一小部分数据。通过这种方式,VACUUM比您使用长时间运行的交易有更好的运行机会。