I have a method that uses Springs #Transactional for database rollbacks. It works fine when i define the transaction manager like this:
<tx:annotation-driven transaction-manager="txManager" mode="proxy" />
but when i change to mode="aspectj" it does not rollback when the method throws an exception.
are there some differences in how the two modes should be used?
The "aspectj" mode will only work if load-time weaving or compile-time weaving are enabled. If not then the #Transactional annotation will not be applied to the annotated method.
The default proxy mode cannot be used to annotate private methods. This is where aspectj mode is useful. Certain frameworks (such as W2O for Web Services) require the class type itself to work. This can be impossible using proxy mode as the class is wrapped in a proxy class wrapper. This is another reason for using AspectJ.
If public methods are used and there are no special framework restrictions, then proxy mode is sufficient.
See Also: Transaction Management
Related
I'm trying to write a integration test for my SpringBoot microservice that interacts with another service inside the product ecosystem.
Since this kind of testing is consider function/integration testing (depending on what nomenclature you use) it is usually done on some development environment.
However, I wanted to test a basic interaction between my service and a STUB/dummy app which are connected with RPC (so not exactly a typical TestRestTemplate test).
I know that there is a way to embed a service while booting up the Spring Context but have never done it by myself.
Does anyone have any experience with the upper or maybe a few helpful links where I can explore.
I have used WireMock in tests to mock services external to what I want to test that communicate over HTTP.
My test class annotated with #SpringBootTest is also annotated with #ContextConfiguration. In the classes attribute #ContextConfiguration I explicitly specify the configuration classes required to set up the Spring Context for the test in question. Here I can also include additional configuration classes in which I create beans only used in the test. In test configuration classes I can also override beans for the purpose of the test, creating mock beans etc.
Note that Spring Boot 2.1 and later disables bean overriding by default. It can be enabled by setting the following property to true:
spring.main.allow-bean-definition-overriding=true
To set the property for a single test, use the #TestPropertySource annotation like this:
#TestPropertySource(properties = {
"spring.main.allow-bean-definition-overriding=true"
})
I was reading this regarding to where to place Transactional(interface vs implementation):
The Spring team's recommendation is that you only annotate concrete classes with the #Transactional annotation, as opposed to annotating interfaces. You certainly can place the #Transactional annotation on an interface (or an interface method), but this will only work as you would expect it to if you are using interface-based proxies. The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy (which would be decidedly bad). So please do take the Spring team's advice and only annotate concrete classes (and the methods of concrete classes) with the #Transactional annotation.
So the question is what is interface-based proxy exactly and how can I see if it is used? Is it some configuration or it is the way how I instantiate/use instances?
If Spring cannot create a JDK proxy (or if you force Spring to create a CGLIB proxy by setting proxyTargetClass to true) then the code will not execute in a transactional context because (as the Spring docs state):
The fact that annotations are not inherited means that if you are using class-based proxies then the transaction settings will not be recognised by the class-based proxying infrastructure and the object will not be wrapped in a transactional proxy
So, I think your concerns are:
How can you be sure that Spring does not create a CGLIB proxy
You must be configuring AOP based transactional support. If you are doing this by using <tx:annotation-driven/> then the default value for proxy-target-class (false) will suffice though could be explicit about this by setting: <tx:annotation-driven proxy-target-class=“false"></tx:annotation-driven>. If you are configuring transactional support in some other way (using Java config, for example) then just ensure that the value of TransactionProxyFactoryBean.proxyTargetClass is false.
How can you be sure that your #Transactional annotations are respected
This is easy, just annotate the concrete class with the #Transactional annotation instead of annotating the interfaces. This avoids any issues with proxying.
In summary, Spring should use interface based proxying as long as TransactionProxyFactoryBean.proxyTargetClass is false however, if you annotate a concrete class rather than an implementation then the issue of proxying won't affect transactional support.
I use multiple TransactionManagers with #Transactional("txXyz") annotations. It works well in beans annotated with #Component and created during Spring startup. I have another type of beans that I create later in runtime via
applicationContext.getAutowireCapableBeanFactory().createBean(beanClassName)
The latter approach successfully injects #Autowired resources and calls all interface hooks (e.g. InitializingBean). However it doesn't create transactional proxies for annotated methods. I have been looking around but haven't found an obvious way to force transactional proxi generation on createBean. My question is there a "legal" way to force transactional proxy processing for beans created when application is already running?
I don't understand what is the actual difference between annotations javax.transaction.Transactional and org.springframework.transaction.annotation.Transactional?
Is org.springframework.transaction.annotation.Transactional an extension of javax.transaction.Transactional or they have totally different meaning? When should each of them be used? Spring #Transactinal in service layer and javax in DAO?
Thanks for answering.
Spring has defined its own Transactional annotation to make Spring bean methods transactional, years ago.
Java EE 7 has finally done the same thing and now allows CDI bean methods to be transactional, in addition to EJB methods. So since Java EE 7, it also defines its own Transactional annotation (it obviously can't reuse the Spring one).
In a Java EE 7 application, you'll use the Java EE annotation.
In a Spring application, you'll use the Spring annotation.
Their use is the same: informing the container (Java EE or Spring) that a method is transactional.
Another difference is how Spring handles the #Transactional annotations
org.springframework.transaction.annotation.Transactional is always taken into account
javax.transaction.Transactional is taken into account only when EJB3 transactions are present. EJB3 transactions' presence is done by checking if class javax.ejb.TransactionAttribute is available in the classpath (from version 2.5.3 to 3.2.5).
Thus you can end up with your annotations not being taken into account if only javax.transaction.Transactional is in your classpath and not javax.ejb.TransactionAttribute.
This can be the case if you're working with Hibernate: hibernate-core (4.3.7.Final) depends on jboss-transaction-api_1.2_spec (1.0.0.Final), which doesn't provide javax.ejb.TransactionAttribute.
Declarative transaction scope
Both the Spring and JPA #Transaction annotation allow you to define the scope of a given application transaction.
So, if a service method is annotated with the #Transactional annotation, it will run in a transactional context. If the service method uses multiple DAO or Repositories, all read and write operations will be executed in the same database transaction.
Spring #Transactional
The org.springframework.transaction.annotation.Transactional annotation has been available since the 1.2 version of the Spring framework (circa 2005), and it allows you to set the following transactional properties:
isolation: the underlying database isolation level
noRollbackFor and noRollbackForClassName: the list of Java Exception classes that can be triggered without triggering a transaction rollback
rollbackFor and rollbackForClassName: the list of Java Exception classes that trigger a transaction rollback when being thrown
propagation: the transaction propagation type given by the Propagation Enum. For instance, if the transaction context can be inherited (e.g., REQUIRED) or a new transaction context should be created (e.g., REQUIRES_NEW) or if an exception should be thrown if no transaction context is present (e.g., MANDATORY) or if an exception should be thrown if a current transaction context is found (e.g., NOT_SUPPORTED).
readOnly: whether the current transaction should only read data without applying any changes.
timeout: how many seconds should the transaction context be allowed to run until a timeout exception is thrown.
value or transactionManager: the name of the Spring TransactionManager bean to be used when binding the transaction context.
Java EE #Transactional
The javax.transaction.Transactional annotation was added by the Java EE 7 specification (circa 2013). So, the Java EE annotation was added 8 years later than its Spring counterpart.
The Java EE #Transactional defines just 3 attributes:
dontRollbackOn: the list of Java Exception classes that can be triggered without triggering a transaction rollback
rollbackOn: the list of Java Exception classes that trigger a transaction rollback when being thrown
value: the propagation strategy, given by the TxType Enum. For instance, if the transaction context can be inherited (e.g., REQUIRED) or a new transaction context should be created (e.g., REQUIRES_NEW) or if an exception should be thrown if no transaction context is present (e.g., MANDATORY) or if an exception should be thrown if a current transaction context is found (e.g., NOT_SUPPORTED).
Which one to choose?
If you're using Spring or Spring Boot, then use the Spring #Transactional annotation, as it allows you to configure more attributes than the Java EE #Transactional annotation.
If you are using Java EE alone, and you deploy your application on a Java EE application server, then use the Java EE #Transactional annotation.
Please be careful, (this issue happened in tomcat),
If your application is SPRING web application and you are using Spring's transaction handling mechanism that is #org.springframework.transaction.annotation.Transactional, then don't mix it with javax.transaction.Transactional.
That is Always use, #org.springframework.transaction.annotation.Transactional in a spring application consistently.
Otherwise we may end up with this error,
org.springframework.orm.jpa.JpaSystemException: commit failed; nested exception is org.hibernate.TransactionException: commit failed
........
Caused by: java.sql.SQLException: Protocol violation: [0]
In my custom authentication provider, I was able to get the domain object through my Service API, but when I crawled from one domain object to another to get certain value to perform additional checks, Spring complains the Hibernate session doesn't exist:-
domain.getAnotherDomain().getProperty(); // epic FAIL
I have the following AOP transaction to wrap all my project APIs with transaction, and I'm pretty sure my custom authentication provider falls into the following pattern:-
<tx:advice id="txAdvice">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor pointcut="execution(* my.project..*.*(..))" advice-ref="txAdvice" />
</aop:config>
I also have OpenSessionInView filter configured, but I don't think that applies to Spring Security anyway.
I guess I can create a specific Service API to perform all the required checks, but I'm curious why I'm not able to wrap my custom authentication provider with a proper transaction.
Any explanation? Thanks.
My workaround solution is to create a service API to perform the checks to avoid lazy loading errors in my custom authentication provider.
Spring complains the Hibernate session doesn't exist
Not quite sure I follow all your question, but I think the above statement represents your main problem, right? You didn't provide any stacktrace, but I imagine this is the infamous "no session or session closed", typical of the scenario you just described:
domain.getAnotherDomain().getProperty(); // epic FAIL
Maybe I'm missing something, but I think the typical answer would apply here too: map your relationship with fetch=FetchType.EAGER, so that you don't have to lazy load it when the session is already closed.
I ran into this same issue, and the cause was that I had Spring Security's filter declared before the OpenSessionInView filter in the web.xml file. Once I swapped them, the problem went away.
The reason is because Spring Security is being called before the Hibernate session is opened by the OpenSessionInView filter, and so there was no session opened.
You haven't posted any code that would let us do any meaningful suggestions.
But one problem with custom authentication provider might be that you maybe marked as #Transactional an abstract method which you are overriding and is being called from the abstract class instance.
For example retreiveUser from AbstractUserDetailsAuthenticationProvider. This method is called from within the instance (see method authenticate) and therefore cannot initialize the transaction through AOP proxy mechanism. For more details check #Transactional method calling another method without #Transactional anotation?
Spring declarative transaction model uses AOP proxy. so the AOP proxy is responsible for creation of the transactions. The AOP proxy will be active only if the methods with in the instance are called from out side the instance.