Programmatic Transaction Management<\/strong> where developers draw the transaction boundaries inside the service class methods.<\/p>\n\n\n\nLet us consider the following code snippet. We make some DB calls, then we call external API and then again we make DB calls and then we make an internal API Call.<\/p>\n\n\n\n
@Transactional<\/p>\n\n\n\n
public void completeOrder(OrderRequest request) {<\/p>\n\n\n\n
generateOrder(request); \/\/ DB call<\/p>\n\n\n\n
generateInvoice(request); \/\/ DB call<\/p>\n\n\n\n
paymentApi(request); \/\/ external API call<\/p>\n\n\n\n
savePaymentInfo(request); \/\/ DB call<\/p>\n\n\n\n
createSubscription(request) \/\/ DB call<\/p>\n\n\n\n
sendInvoiceEmail() \/\/ internal API call<\/p>\n\n\n\n
}<\/p>\n\n\n\n
The @Transactional <\/strong>aspect creates a new EntityManager<\/em><\/strong>and starts a new transaction by borrowing one Connection <\/em>from the connection pool (HikariCP<\/strong> is the default in Spring Boot)<\/p>\n\n\n\n- The Connection is opened and it starts generating the orders until all the code snippet of the completeOrder method is executed.<\/li>
- If there is any delay in the payment API, the connection is on hold and it is not returned to the connection pool<\/li>
- If we have concurrent users doing complete orders, the application will run out of Database Connections resulting in the application lag<\/li>
- Hence we should not mix the DB and I\/O calls inside a Transactional method<\/li><\/ol>\n\n\n\n
This is a very good use case for Programmatic Transaction Management <\/strong>and we use TransactionTemplate<\/strong> for this purpose<\/p>\n\n\n\n@Autowired private TransactionTemplate template;<\/p>\n\n\n\n
public void completeOrder(OrderRequest request) { template.execute(<\/p>\n\n\n\n
status -> {<\/p>\n\n\n\n
generateOrder(request); \/\/ DB call<\/p>\n\n\n\n
generateInvoice(request); \/\/ DB call return request;<\/p>\n\n\n\n
});<\/p>\n\n\n\n
paymentApi(request); \/\/ external API calltemplate.execute(<\/p>\n\n\n\n
status -> {<\/p>\n\n\n\n
savePaymentInfo(request); \/\/ DB call<\/p>\n\n\n\n
createSubscription(request) \/\/ DB call return request;<\/p>\n\n\n\n
}); <\/p>\n\n\n\n
sendInvoiceEmail() \/\/ internal API call<\/p>\n\n\n\n
}<\/p>\n\n\n\n
In the above snippet, we did not use @Transactional<\/strong> but we have used TransactionTemplate <\/strong>twice and wrapped the DB operations inside. The following steps are performed<\/p>\n\n\n\n- The Template starts a new transaction with a borrowed connection and executes generateOrder and generateInvoice in a single transaction.<\/em><\/li>
- Then the transaction is closed and connection is returned to the connection pool<\/li>
- payment API call is made<\/li>
- Then again the template starts a new transaction with a borrowed connection and executes savePaymentInfo and createSubscription in a single transaction.<\/em><\/li>
- Then the transaction is closed and the connection is returned to the connection pool<\/li>
- Then the internal API call is made and the response is sent to the user.<\/li><\/ol>\n\n\n\n
In this article, we have seen how Spring Boot performs the 2 types of transaction management namely Declarative and Programmatic through diagrams and code snippets.<\/p>\n\n\n\n
I work as a freelance Architect at Ontoborn, who are experts in putting together a team needed for building your product. This article was originally published on my personal blog<\/a>.<\/em><\/mark><\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"Transaction management is one of the difficult features to understand for the developers and hence I decided to write on this topic. Let us take a look at how the Spring framework does transaction management. …<\/p>\n","protected":false},"author":11,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_mi_skip_tracking":false,"footnotes":""},"categories":[72],"tags":[],"_links":{"self":[{"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/posts\/1609"}],"collection":[{"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/users\/11"}],"replies":[{"embeddable":true,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/comments?post=1609"}],"version-history":[{"count":6,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/posts\/1609\/revisions"}],"predecessor-version":[{"id":1652,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/posts\/1609\/revisions\/1652"}],"wp:attachment":[{"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/media?parent=1609"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/categories?post=1609"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ontoborn.com\/blog\/wp-json\/wp\/v2\/tags?post=1609"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}