How to do Distributed Transactions XA in Spring and GlassFish 5? - java

I am trying to create a transaction comprising two REST web services, whose data source point to the same data base. The first service, named 1, invokes another web service named 2 using Spring RestTemplate.
To implement the transaction I am using a JNDI connection pool, the MySql JDBC driver (version 5.1.35), JTA, XA, Spring and the GlassFish 5 AppServer.
Now, I have downloaded the maven dependencies in the Spring project, defined a configuration class using JtaTransactionManager, and configured the datasource and JTA properties in an application.yml file, like in the following code:
Configuration class:
#Configuration
#EnableTransactionManagement
public class Transacciones {
#Bean
public PlatformTransactionManager platformTransactionManager(){
return new JtaTransactionManager();
}
}
application.yml file
spring:
datasource:
jndi-name: jdbc/Prueba
driver-class-name: com.mysql.jdbc.Driver
jta:
enabled: true
I configured the JNDI datasource in GlassFish 5 defining a "JDBC Resource" named jdbc/Prueba in the "Connections pools" page using a javax.sql.XADataSourcedatasource named pruebaXA:
In the control layer of the web service 1, the method calls the service 2 using the RestTemplate class of Spring Framework:
Service 1 code:
#RestController
#RequestMapping("/servicio")
#EnableTransactionManagement
public class a {
#Autowired
private JdbcTemplate objJdbcTemplate;
#Transactional(rollbackFor = RuntimeException.class)
#GetMapping("/1")
public Integer getValor(){
try{
int numero;
int n=50;
RestTemplate restTemplate = new RestTemplate();
Integer intRes1;
Integer intRes2;
numero = (int) (Math.random() * n) + 1;
intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-SNAPSHOT/servicio/2",numero,Integer.class);
intRes1=objJdbcTemplate.update("INSERT INTO A VALUES(" +numero + ")");
return numero;
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
Service 2 code:
#RestController
#RequestMapping("/servicio")
public class a {
#Autowired
private JdbcTemplate objJdbcTemplate;
#Transactional(rollbackFor = RuntimeException.class)
#PostMapping("/2")
public Integer getValor(#RequestBody Integer intNum){
try{
Integer intRes;
intRes=objJdbcTemplate.update("INSERT INTO B VALUES(" + intNum + ")");
return intRes;
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
If the two services work without errors, there is not problem. However, when the service 1 falls, the service 2 does not know about the error and does not do the rollback.
I do not know if I need to configure another feature/option in the GlassFish 5, or in the Spring program.
I have read that in Spring only needs a JtaTransactionManager bean and the framework performs all the work related to configure and use JTA-transactions.Spring and JTA
JTA
Now, if you still need to use JTA, at least the choice is yours to
make. There are two common scenarios: using JTA in a heavyweight
application server (which has all the nasty disadvantages of being
tied to a JavaEE server), or using a standalone JTA implementation.
Spring provides support for JTA-based global transaction
implementations through a PlatformTransactionManager implementation
called JtaTransactionManager. If you use it on a JavaEE application
server, it will automatically find the correct
javax.transaction.UserTransaction reference from JNDI. Additionally,
it will attempt to find the container-specific
javax.transaction.TransactionManager reference in 9 different
application servers for more advanced use cases like transaction
suspension. Behind the scenes, Spring loads different
JtaTransactionManager subclasses to take advantage of specific, extra
features in different servers when available, for example:
WebLogicJtaTransactionManager, WebSphereUowTransactionManager and
OC4JJtaTransactionManager.
So, if you’re inside a Java EE application server, and can’t escape,
but want to use Spring’s JTA support, then chances are good that you
can use the following namespace configuration support to factory a
JtaTransactionManager correctly (and automatically):
Alternatively, you can register a
JtaTransactionManager bean instance as appropriate, with no
constructor arguments, like this:
#Bean public PlatformTransactionManager platformTransactionManager(){
return new JtaTransactionManager(); } Either way, the end result in a JavaEE application server is that you can now use JTA to manage
your transactions in a unified manner thanks to Spring.
Thanks for your help and time.

How to do Distributed Transactions XA ?
If you invoke first a REST or web service and then another one, both operations will not be part of a transaction. To form a transaction, these operations must "start" a transaction or be "joined" to an existing one. To execute that transaction, your program must interact with a transaction monitor (TM) such as the proposed by AT&T/Oracle Tuxedo (released in the 80s), the X/Open XA standard (released in the 90s) and the JTA-based systems.
Note how the TM-based transaction works:
A transaction using XA datasources is basically a program that invokes database operations on two different databases. The same program (e.g. invoking methods in one or more bean) starts the transaction, performs some operations on a database and performs other operations on another database. If one of the operation fails, the other operations are not performed or are rollbacked.
A transaction using XA datasources and JTA-enabled components is basically a program that combines operations on one or more databases with other transaction-enabled operations. For instance, you can combine operations on a database with operations on a content repository or a network-based file system. You can define transactions that, when a database operation fails, does not perform or rollbacks operations on the file system. Non-transactional applications such as COBOL-based programs can be integrated in a transaction by defining operations and compensations in the transaction monitor.
A transaction integrating web-services requires an special handling. For instance, there is a proposal for webservice transactions such as the WS-Transaction and WS-Coordination specification. There is a coordinator that works like the transaction monitor. The software must invoke the coordinator to start the transaction. Each participant in the transaction reports if each operation is successful or failed. The coordinator invokes the other operations or invokes the compensations according to the results.
Nowadays, there are some proposals for software architecture that do not rely on TM-based transactions. Designs based on CQRS and Event Sourcing implement transactions using the Sagas design pattern. If you are interested on defining a transaction-like operation that invokes two REST services, you may consider to avoid the XA/JTA and program a Sagas.
How to do Distributed Transactions XA in Spring and GlassFish 5?
You may check many tutorials in the Internet. For instance,
a tutorial that shows you three use cases: one updating two databases, one combining database operations and outgoing JMS-messages, and another one combining incoming JMS messages and database operations.
a video describing how to manage distributed transactions in Spring with JTA
and the documentation from the Spring Framework.
If the two services work without errors, there is not problem. However, when the service 1 falls, the service 2 does not know about the error and does not do the rollback.
That is the correct behavior. When you invoke a REST/webservice, the operations performed by that REST/webservice do not join to the transaction. If the invoking service fails, the invoked service will not notice it and will not rollback their operations in the database.
I do not know if I need to configure another feature/option in GlassFish 5, or in the Spring program.
No. You only have to configure the XA-datasources. Spring will use your configuration class and annotations to join automatically into a transaction the operations performed by your application on these datasources. For instance, if you have a bean that invokes multiple methods that performs operations on one or more XA-datasources, these operations will join into a transaction.
However, when you invoke a method in REST/webservice in another application, the database operations performed by that REST/webservice will not join to the transaction.

rest web services (http based) are non-transactional by their nature (they are http based). you have made each method/operation transactional, but they do not share any state between the resources (rest operations). generally - you can have XA transactions over database or mesaging, not over http calls.
intRes2 = restTemplate.postForObject("http://localhost:8080/servicio2-1.0-
SNAPSHOT/servicio/2",numero,Integer.class);
Calling a remote web service is without any transaction context. If you need to maintains transaction between services, call the secord service as EJB (or as an injected managed bean)
Basically: using http-based rest services - forget any transactions between them. The protocol (HTTP) is not built for that.
The only thing I've seen transactional is SOAP with WS-RM extension (SOAP with reliable messaging)., however it is not very easy to setup (read: it can be nightmare to make it work when you don't know what are you doing) and not all WS frameworks support it.
When you really need reliable delivery between web services, there's a way. what is comonly used to achieve assured delivery is messaging with idempotent services (https://en.m.wikipedia.org/wiki/Idempotence) with store-and-forward pattern. In simple terms - service 1 stores a JMS message to a queue and there's a processor (MDB) which calls service 2. (yes, calling a remote web service it may happen that the service 2 will receive a message multiple times. Indempotency is a way how to deal with it.)

Transactions across REST services are supported by http://www.atomikos.com
Cheers

Related

What's the role of spring boot cache annotations in a application which use Redis for caching?

I am using Redis as the in-memory data store for caching purposes in my spring boot application. At the moment I have already implemented the Redis support with basic CRUD functionalities for the entities which I need to cache [Scenario 1] . But suddenly I found that there are lots of resources out there that use additional spring boot caching annotations like #Cachable #CahceEvict to implement the caching with Redis [Scenario 2] . And I monitored that when we start using those annotations in an operation like find(params) only the first method call will be going to the Redis. From the second method onwards, Redis won't get hit. So according to my observations, I think, Spring boot maintains a separate cache. But my problem is we are already using Redis as our cache. So what's the advantage of stopping the second Redis data store hit and maintaining another cache. I mean Redis is already in the RAM and it's highly capable of caching. Why do we need to maintain two caches? Is there any advantage of having this mechanism or does implement the Redis only is enough ?.
Scenario 1 :
public class RestController{
#GetMapping("/{id}")
public Product findProductById(#PathVariable int Id){
return dao.findProductById(id);
}
}
#Repository
public class ProductDao {
public static final String HASH_KEY = "Product";
#Autowired
private RedisTemplate template;
public Product findProductById(int id){
return (Product) template.opsForHash().get(HASH_KEY,id);
}
}
Scenario 2 :
public class RestController{
#GetMapping("/{id}")
#Cachable(key = "#id" ,value="Product")
public Product findProductById(#PathVariable int Id){
return dao.findProductById(id);
}
}
#Repository
public class ProductDao {
public static final String HASH_KEY = "Product";
#Autowired
private RedisTemplate template;
public Product findProductById(int id){
System.out.println("called findProductById() from DB");//Here only for the first time method will be called
return (Product) template.opsForHash().get(HASH_KEY,id);
}
}
References for Scenario 1 implementation
References for Scenario 2 implementation
The Spring Cache abstraction provides a cache abstraction layer you can configure to support different, pluggable, underlying cache mechanisms, Redis through Spring Data among others.
You are using Redis as the actual persistence mechanism. As a consequence, probably you do not need any cache and, due to the in-memory nature of the Redis database, the scenario 1 can be appropriate.
Having said that, please, consider a different point of view.
Let's consider for example a backend that uses a persistence layer with an underlying not in-memory database, relational or other flavor of NoSQL.
This is a perfect use case for Spring Cache, #Cacheable and the rest of related annotations to effectively cache your results.
And, how Redis fits in to this puzzle? Because you configure Spring to use Redis as the actual cache manager. For example:
#Bean
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
return RedisCacheManager.create(connectionFactory);
}
Under the hood RedisCacheManager will provide the necessary mechanisms to transparently write and read from Redis as required by the application cache.
With this new point of view, the scenario 2, with the above-mentioned differences, is the one to choose and in fact is a common scenario you usually find when architecting enterprise applications.
In any case, the scenario 2 as described in your question, I mean, using Redis directly as the persistence mechanism in addition to Spring Cache, can be also applicable if you are trying:
Reducing the number of requests - and associated costs - performed against Redis. This could be relevant especially if you are using Redis (or a Redis-like service such as GCP Memorystore) in a cloud provider.
Despite the fact that Redis is fast enough, you can use a cache to store the results in the local RAM of the machine running your application to improve performance, just like with any other database system.
Or because you need to interact with Redis in some specific way.
If you are using Redis only for caching and do not require any specific stuff, probably it would be preferable to use it through the Spring Cache abstraction instead of manually perform the cache operations: it will provide no performance benefit, but you will get a several advantages like a well structured cache framework, with a set of helpful annotations, and portability/usability because you can switch the cache implementation only using a different configuration if required, for testing or local development, for example.

Wildfly treating concurrency management as transactional

I had a class that looked like this:
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
#Lock(LockType.WRITE)
#AccessTimeout(value = 20, unit = TimeUnit.MINUTES)
public class MyClass{
public void someLongRunningQuery(){
}
}
However, this would fail with:
org.jboss.resteasy.spi.UnhandledException: javax.ejb.EJBTransactionRolledbackException: Transaction rolled back
I was able to resolve this by adding this annotation.
#TransactionTimeout(value = 20, unit = TimeUnit.MINUTES)
My question is - why is jboss treating this method as a transaction? My understanding is the concurrency management and transaction management are different things.
Transaction timeout handling is not defined in EJB spec and JBoss uses a separate transaction management module to do that. Your example points at a REST access to your singleton - is the Singleton also a REST endpoint or is it invoked from some REST endpoint bean? Just a couple of ideas:
If you have a REST endpoint that injects your singleton and invokes the long running op, isn't it by any chance a #Stateless bean? EJB beans are transaction enabled by default, therefore if a client(REST endpoint) initiates a transaction(it does by default - #TransactionAttribute(REQUIRED)), your singleton will also participate in the same transaction, but because its invocation takes longer than the default transaction timeout value(300s) it causes transaction rollback. If you do not need a transaction on the rest layer, try disabling it with #TransactionAttribute(NOT_SUPPORTED)
If you invoke this long running op from REST layer, wouldn't it be better to use #Asynchronous and return some kind of request/job handle to the client, so that it can query the status of the operation instead of waiting and blocking while it finishes? Keep in mind that EJBs are pooled resources, therefore invoking this long op multiple times can drain your pool and cause acquisition timeouts.

Transaction Management in Spring Data REST

Do we have any in-built transaction management when using Spring Data REST or it has to be manually maintained/handled from the calling application/service.
Say, I have two calls(first POST(for creation) and PATCH(update/insert association resource using uri-lists)) which I want to be considered as a transaction.
Thanks
Bharath
In spring data rest every repository action runs within a transaction. Even the event handlers are not running inside the repository transaction. And of course different actions on the REST API do run in separate transactions.
Here is an interesting question on this topic:
Handle spring-data-rest application events within the transaction
If you want to have creation and association in one transaction then the only way to achieve this with your current entity mapping is to create a custom controller that does just that.
An alternative mapping strategy would be to treat the associated entity as a containment - so the associated entity does not have an exported repository and is maintained within the parent.
The who point of REST is to have isolated units of work. If you are wanting to keep transactions open across calls it's probably a sign you need to adjust your RESTful strategy.
Have a look at: Transaction strategy for microservices
I found this question when researching the transaction behavior of data-rest.
I needed control over the transaction behavior of the default controllers, especially during serialization of relationships, so i could mark transactions as read-only and route them to read-replicas of our database.
By default every call to a repository has its own transaction and database access during events or resource-assembly is managed by hibernate directly, outside of these transactions. There is no intended way for users to control transactions.
Spring does however provide methods to do that using aop-interceptors. These interceptors use a property source do decide weather or not a method requires a transaction. Springs own Transactional-Annotation is nothing more than one of these property-sources.
The following Configuration creates an advisor for the default rest-controllers that creates customized transactions for some Methods:
#Configuration
#ConditionalOnClass(name = {
"org.springframework.data.rest.webmvc.RepositoryEntityController",
"org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController",
"org.springframework.data.rest.webmvc.RepositorySearchController"
})
public class RepositoryRestControllerTransactionConfiguration {
/**
* A custom Transaction Advisor that starts customized transactions based on what data-rest controller method is called
*
* #param transactionManager
* #return
*/
#Bean
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
TransactionManager transactionManager) {
//Specify transaction management methods and attribute values required for transaction control
MethodMapTransactionAttributeSource source = new MethodMapTransactionAttributeSource();
Map<String, TransactionAttribute> methodMap = new HashMap<>();
// methods are identified by their FQDN, simple placeholders using * are possible
// methods that should only require reads
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.get*", createTransactionRule(true));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.headForItemResource", createTransactionRule(true));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.follow*", createTransactionRule(true));
methodMap.put("org.springframework.data.rest.webmvc.RepositorySearchController.execute*", createTransactionRule(true));
// methods that will require write
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.put*", createTransactionRule(false));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.patch*", createTransactionRule(false));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.delete*", createTransactionRule(false));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryEntityController.post*", createTransactionRule(false));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.delete*", createTransactionRule(false));
methodMap.put("org.springframework.data.rest.webmvc.RepositoryPropertyReferenceController.create*", createTransactionRule(false));
source.setMethodMap(methodMap);
source.afterPropertiesSet();
// Generate an AOP Advisor that controls transactions
// Advice for transaction control (TransactionInteceptor)
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(source);
advisor.setAdvice(new TransactionInterceptor(transactionManager, source));
return advisor;
}
private RuleBasedTransactionAttribute createTransactionRule(boolean readOnly) {
RuleBasedTransactionAttribute rule = new RuleBasedTransactionAttribute();
rule.setReadOnly(readOnly);
return rule;
}
}

Will Spring estabilish connection to DB, when I use transacional bean in non-transacional?

Good day, guys!
If I have non-transactional bean(BannerSizeServiceUntransact), which uses transactional bean(bannerSizeService), will Spring estabilish connection to DB, when I use non-transacional bean?
(I have many refused connections to PostgreSQL in log. I belive my logic does;t create new connection on each request, but may be I wrong.)
#Repository
public class BannerSizeServiceUntransactImpl implements BannerSizeServiceUntransact {
#Resource
BannerSizeService bannerSizeService;
public List<BannerSizeVO> sizesByType(String type) throws BannerServiceException{
return bannerSizeService.sizesByType(type);
} }
#Repository
#Transactional
public class BannerSizeServiceImpl implements BannerSizeService {
....
}
Yes, Spring will establish a database connection even when you're using beans that aren't marked #Transactional, so that's not the cause of your refused connections.
What's going to happen in this scenario is that when you invoke the call to bannerSizeService.sizesByType(type), Spring will start a new transaction, and when control returns to BannerSizeServiceUntransact.sizesByType(), it will end. So if BannerSizeServiceUntransact.sizesByType() did other database calls before or after the call to bannerSizeService.sizesByType(type), those calls would happen in separate transactions, one per DB call. (Not annotating a Service as #Transactional doesn't mean that transactions aren't used, just that they only span a single database call.)
Also note that if the method that calls BannerSizeServiceUntransact.sizesByType() was marked #Transactional, then the transaction started there will carry over all of the code you've shown here, because that transaction will start when that higher-up method is called and will end when it ends, and all of the code here will have executed while it was in effect. Not annotating something as #Transactional doesn't forbid its participation in an existing transaction, it just doesn't require the initiation of a new one.
Also, keep in mind that #Transactional controls transactions. Spring might end up making a new connection for each transaction it opens, or using only one and reusing it for each transaction, or rotating through a pool of connections (resulting in more than one but fewer than N connections for N transactions). It's guaranteed that if Spring talks to the database, there will be a connection in use, but you can't guarantee how many will be used over N calls simply by your #Transactional annotations. (Though of course you can set settings in your Spring config that might impact the number used, e.g. specifying a connection pool with a max size of 1.)

Seeking a Spring (3.0.5) Solution for: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here

I have a Transaction problem on Spring 3.0.5. In my case I get the so-called exception "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here"... I have tried everything so far. I can see in my log that the transactional services are detected and registered as Spring beans and I can also see in the logs that they are proxied and associated with underlying Spring transaction interceptors. (Advise) When I run my Spring MVC app my controller will call the service...... :-( but the transaction interceptors are not triggered. (??) I expect my Spring service proxy to open a session and start a transaction before calling my target service method. Since this does not happen, I get the above exception. I have been almost two days on this problem. Tried everything which I found on the internet...but in vain.
I have layered architecture: presentation (springmvc), service (transaction annotated), dataacess (Spring/Hibernate classic sessionfactory). My model objects are annotated with jpa (javax.persistence.*). My spring context config files are separated in appContext.xml, appContext-service.xml and appContext-dao.xml. I have defined my Spring LocalSessionFactoryBean, Datasource and TransactionManager (HibernateTransactionManager) in appContext-dao.xml. I have put in appContext-service.xml where my service implementations resides. In all of my config files I have included and to detect my beans through Controller, Service and Repository annotations.
I appreciate any kind of help.
It sounds like you are doing everything correctly and you know what you are doing. There's not much we can do here unless you show some configuration.
What I'd suggest is some debugging.
First: do you have Unit tests in the service layer that test the queries you are using? Perhaps you can find the error in the service layer.
Then: debug the MVC app, check the types of the injected services. Verify that they are proxies, not the original types.
If they are the original types, you
have an error in your transaction
configuration .
If they are proxies, step through the
query methods and verify that the
transaction logic is applied.
This sounds like accessing a lazily-loaded list or set of you dao after the closing of the transaction. This typically happens if you access that list in the view in stead of the controller, as your controller probably calls methods in transaction scope, and then leaves the transaction and forwards the loaded bean to the view.
Simple solutions:
Configure your data bean to eagerly load
Force loading of the dependencies in the controller (just loop through them)
have a look at this article ans possibly also quite a few right here on SO on lazy loading / lazy fetching of one-to-many associations and the like
Imagine:
// your dao
public class Foo {
// lots of other properties
List<Something> stuff;
// getters and setter for stuff
}
// repository
#Transactional
public class FooRepo {
public Foo loadFoo(int id) {
...
}
}
// Controller
public class Controller {
public void Control() {
sessionContext.set("foo", repo.loadFoo(1)); // transaction managed by spring
}
public void setFooRepo(FooRepo repo) {this.repo = repo};
}
// View
for (Something something : foo.getStuff()) {
// Ooops transaction is closed! stuff is lazily loaded so NOT AVAILABLE
// practical solutions:
// - do not load lazily (Foo.hbm.xml)
// - or force loading by getting all Somethings in the controller
}

Categories