1

I'm new to springboot and has been working on a project. I'm using Springboot with hibernate, JPA and hikariCP for mysql DB operations. Currently i have two datasources in which i could not rollback a transaction which i written inside a service. I tried everything i could find, but i couldn't find out what am i missing. Any help would be appreciated and pardon my mistakes and i'm very open to suggestions. Thank you.

@SpringBootApplication
public class AdminModuleApplication {
public static void main(String[] args) 
    {
        SpringApplication.run(AdminModuleApplication.class, args);
    }   
}
@Configuration
@PropertySource({ "classpath:acc_payDB_properties.properties" })
@EnableJpaRepositories(
    basePackages = "com.pinnacle.accpay.dao", 
    entityManagerFactoryRef = "accpayEntityManager", 
    transactionManagerRef = "accpayTransactionManager"
)
public class acc_payDBConfig 
{
    @Autowired
    private Environment env;

    @Bean
    public LocalContainerEntityManagerFactoryBean accpayEntityManager() 
    {
        String packageList[]= {"com.pinnacle.accpay.model","com.pinnacle.admin.model"};
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(accpayDataSource());
        em.setPackagesToScan(packageList);
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        Properties jpaProperties = new Properties();
        jpaProperties.setProperty("hibernate.hbm2ddl.auto", "none");
        Properties jpaProperties2 = new Properties();
        jpaProperties2.setProperty("connection.provider_class","org.hibernate.hikaricp.internal.HikariCPConnectionProvider");
        em.setJpaProperties(jpaProperties2);
        return em;
    }


    @Bean
    public DataSource accpayDataSource() 
    {

        HikariDataSource dataSource = new HikariDataSource(); 
        dataSource.setDriverClassName(env.getProperty("jdbc.driver-class-name"));
        dataSource.setJdbcUrl(env.getProperty("jdbc.url"));
        dataSource.setUsername(env.getProperty("jdbc.username"));
        dataSource.setPassword(env.getProperty("jdbc.password"));
        dataSource.setCatalog("acc_pay");
        //HikariCP specific properties. Remove if you move to other connection pooling library.
        dataSource.setConnectionTimeout(20000);
        dataSource.setMaximumPoolSize(20);
        dataSource.setMinimumIdle(10);
        dataSource.setIdleTimeout(20000);
        dataSource.setMaxLifetime(40000);
        dataSource.setAutoCommit(false);
        dataSource.addDataSourceProperty("cachePrepStmts", true);
        dataSource.addDataSourceProperty("prepStmtCacheSize", 25000);
        dataSource.addDataSourceProperty("prepStmtCacheSqlLimit", 20048);
        dataSource.addDataSourceProperty("useServerPrepStmts", true);
        dataSource.addDataSourceProperty("initializationFailFast", true);
        dataSource.setPoolName("ACCPAY DB_HIKARICP_CONNECTION_POOL");
        dataSource.addDataSourceProperty("useLocalTransactionState", false);
        return new HikariDataSource(dataSource);

    }

    @Bean
    public PlatformTransactionManager accpayTransactionManager() 
    {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(accpayEntityManager().getObject());
        return transactionManager;
    }
}


@Service
public class TranscationReceptionService {
    @Autowired
    PO_TXN_MasterBeanRepository po_TXN_MasterBeanRepository;

    @Autowired
    GRN_TXN_MasterBeanRepository grn_TXN_MasterBeanRepository;

    @Autowired
    Invoice_TXN_MasterBeanRepository invoice_TXN_MasterBeanRepository;

    @Autowired
    POEventLogRepository poEventLogRepository;

    @Autowired
    InvoiceEventLogRepository invoiceEventLogRepository;

    @Autowired
    GRNEventlogRepository grnEventlogRepository;

    @Autowired
    PO_GRN_INVBeanRepository po_GRN_INVBeanRepository;

    @Autowired
    LinkEventLogBeanRepository linkEventLogBeanRepository;

    @Autowired
    ScheduledJob scheudledJob;

    @Autowired
    acc_payDBConfig acc_paydbConfig;

    @Value("${in_process_status}")
    private String in_process_status;


    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateMatchStatus(Long poId, Long invoiceId, String poStatus, String invoiceStatus)
    {
        try
        {

        po_TXN_MasterBeanRepository.setPOStatusAfterMatching(poStatus, poId, invoiceId);

        POEventLogBean poEventLogBean = new POEventLogBean();
        poEventLogBean.setPo_id(poId); poEventLogBean.setEvent_time(LocalDateTime.now().toString());
        poEventLogBean.setStatus(poStatus); 
        poEventLogRepository.save(poEventLogBean);

        po_GRN_INVBeanRepository.setInvoiceNumber(poId, invoiceId);

        Long linkId = po_GRN_INVBeanRepository.getLinkIdfromPONumber(poId);

        LinkEventLogBean linkEventLogBean=new LinkEventLogBean();
        linkEventLogBean.setLink_id(linkId); 
        linkEventLogBean.setEvent_time(LocalDateTime.now().toString());
        linkEventLogBean.setStatus("");
        linkEventLogBeanRepository.save(linkEventLogBean);

        invoice_TXN_MasterBeanRepository.setInvoiceStatusAfterMatching(poId, invoiceStatus, invoiceId);

        InvoiceEventLogBean invoiceEventLogBean=new InvoiceEventLogBean();
        invoiceEventLogBean.setInv_id(invoiceId); invoiceEventLogBean.setEvent_time(LocalDateTime.now().toString());
        invoiceEventLogBean.setStatus(invoiceStatus);
        invoiceEventLogRepository.save(invoiceEventLogBean);
        }
        catch (Exception e) 
        {

        }
    }

}

@Transactional
@Repository
public interface PO_TXN_MasterBeanRepository extends JpaRepository<PO_TXN_MasterBean, Long> 
{

    @Transactional
    @Modifying(clearAutomatically = true)
    @Query("UPDATE PO_TXN_MasterBean p SET p.status= :status, p.inv_id= :invId WHERE p.po_id = :pId")
    public void setPOStatusAfterMatching(@Param("status") String status, @Param("pId") Long poId, @Param("invId") Long invoiceId);
}

@Transactional
@Repository
public interface POEventLogRepository extends JpaRepository<POEventLogBean, Integer> 
{

}

@Transactional
@Repository
public interface PO_GRN_INVBeanRepository extends JpaRepository<PO_GRN_INVBean, Long>
{

    @Transactional
    @Modifying(clearAutomatically = true)
    @Query("UPDATE PO_GRN_INVBean p SET p.inv_id= :invId WHERE p.po_id = :pId")
    public void setInvoiceNumber(@Param("pId") Long poId, @Param("invId") Long invoiceId);

    @Query("SELECT  p.link_id FROM PO_GRN_INVBean p WHERE p.po_id = :pId")
    public Long getLinkIdfromPONumber(@Param("pId") Long poId);
}


@Transactional
@Repository
public interface LinkEventLogBeanRepository extends JpaRepository<LinkEventLogBean, Long>
{

}

@Repository
@Transactional
public interface Invoice_TXN_MasterBeanRepository extends JpaRepository<Invoice_TXN_MasterBean, Long> 
{
    @Modifying(clearAutomatically = true)
    @Transactional
    @Query("UPDATE Invoice_TXN_MasterBean i SET i.po_id = :pid, i.status =:status WHERE i.inv_id = :inid")
    public void setInvoiceStatusAfterMatching(@Param("pid") Long pid, @Param("status") String status, @Param("inid") Long inId);
}

@Repository
public interface InvoiceEventLogRepository extends JpaRepository<InvoiceEventLogBean, Integer>
{

}
Sreeraj
  • 11
  • 1
  • Do you mean you want to rollback operations on two datasource? – Lebecca Mar 18 '20 at 09:03
  • yes...but even i intentionally throw exceptions the transactions wont rollback!! – Sreeraj Mar 18 '20 at 09:29
  • You are looking for distributed tx, [Spring @Transactional with a transaction across multiple data sources ](https://stackoverflow.com/questions/48954763/spring-transactional-with-a-transaction-across-multiple-data-sources) may help – Lebecca Mar 18 '20 at 09:33
  • Remove the try-catch block from `TranscationReceptionService.updateMatchStatus()` . Also unless otherwise specified , the txn rollback happens for exceptions of type `RuntimeException`. – R.G Mar 18 '20 at 10:22
  • I'm sorry, my bad. I wasn't using 2 datasource in a single transaction as of now. even though there is 2 datasource in my application. I am trying to rollback transcation in a single source – Sreeraj Mar 18 '20 at 10:31
  • yeah, i have one doubt though. Most of the exception that might occur during transactions except datatype validity exceptions falls under runtime exceptions, right? – Sreeraj Mar 18 '20 at 10:56
  • Spring framework in this case wraps all the underlying exceptions that it gets to [DataAccessException](https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/dao/DataAccessException.html) which is of type RuntimeException. That would mark a transaction for Rollback. Please go through [reference documentation](https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-rolling-back) to understand the concept better. – R.G Mar 18 '20 at 11:06
  • Also read through [this](https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#dao) as well – R.G Mar 18 '20 at 11:10

1 Answers1

0

Transaction Rollback is not working as expected because the exception is handled with a try-catch block within TranscationReceptionService.updateMatchStatus(). This prevents the spring framework to be aware of the exception raised and hence does not result in rollback.

R.G
  • 6,436
  • 3
  • 19
  • 28