ChatGPT解决这个技术问题 Extra ChatGPT

javax.transaction.Transactional vs org.springframework.transaction.annotation.Transactional

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.


J
JB Nizet

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.


More than that: in order to rule the universe, Spring also added implicit support for javax.transaction.Transactional so one could now use it also in Spring applications without any additional actions. IMO, this was quite bad decision from design standpoint, because out of my experience a lot of developers unconciously confuse these two in their code which leads to problems afterwards.
Furthermore, org.springframework.transaction.annotation.Transactional offers more options (like readOnly, timeout) than javax.transaction.Transactional
@yura, what problems have you observed?
@LeeCheeKiam please see two answers below
"Java EE 7 has finally done the same thing" is quite misleading: this annotation exists since EJB 3.0, actually at about the same time that Spring has been having such annotation (in 1.2). Support in CDI was quite "new" when this was published (but so was CDI).
J
Jidehem

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.


its not always taken, if its on a private method for example it won't be taken.
c
chiwangc

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]

Note: this answer is a special case of my answer
V
Vlad Mihalcea

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.


Does the Java/Jakarta EE @Transactional annotation work for private methods?
Most likely, not. The transaction boundary should start when calling a service from a different layer, like the web or a scheduler.
Actually, I'm already having a delegate method in the same class with the method annotated with @Transactional. I know that I can just move the annotation to this delegate method, but I was curious about this and I didn't find anything on the web.
Private methods don't count. Only inter-services methods count for propagation rules.