I refer to the example stated in the URL which is to apply spring aop transaction across all methods in service layers, but this will also apply transaction management for read-only methods like SELECT.
Is there any adverse effect, if I apply transaction management for readOnly transaction?
<aop:config>
<aop:advisor pointcut="execution(* com.xyz.someapp.service.*.*(..)))"
advice-ref="transactionAdvice" />
</aop:config>
http://www.studytrails.com/frameworks/spring/spring-declarative-transactions.jsp
I have another question. If I have orderService.create() which invokes billingService.create(), how will the transaction isolation be applied?
You generally want to use transactions even for read-only operations, since a transaction will give you a consistent view of your data. If you skip transactions, you risk seeing partial updates from some other incomplete transaction.
I dont't think that there will be any adverse effects because a transaction simply defines an atomic set of operations. If a transaction fails then a rollback will be performed, but read-only operations don't affect the database in any way.
The only big disadvantage I can think of is related to performance. The locking-strategy of the underlying database (whether table or row is locked) determines your isolation level. Acoording to your locking-strategy some kind of isolation is applied during the transaction. For example, when you're writing to a database your isolation level decides if the changes in progress could be seen by parallel reads (causing e.g. dirty reads, non-repeatable reads and so on) or if these changes have to be commited before they become visible to others.
As a consequence you would lock resources you only want to read, which could be performance overkill on highly available applications. Summing up: It doesn't have bad effects aside from causing performance issues.
Addressing your second question: This depends on how you're managing transactions. I guess in this case both service methods require transactions, so I think the default behavior is that the transaction of the first service call is inherited by the second service method call (this is called 'transaction propagation'). This is required because nested transactions aren't allowed.
Related
I am trying to create an API in Spring Boot using #Transactional annotation regarding bank fund transfer.
Now I want to know - if there are multiple calls to the same API at the same time, how to manage transaction between them. Suppose for example transferBalance method is called by Transaction X which transfers funds from accounts A to B and another transaction Transaction Y transfer funds from B to C. Both transactions occur at the same time. How would these transactions be handled? What propagation should it have and also what about the isolation?
Check this below changes: for your case check bold description below.
if more than one transaction can also go with SERIALIZED
Isolation level defines how the changes made to some data repository by one transaction affect other simultaneous concurrent transactions, and also how and when that changed data becomes available to other transactions. When we define a transaction using the Spring framework we are also able to configure in which isolation level that same transaction will be executed.
#Transactional(isolation=Isolation.READ_COMMITTED)
public void someTransactionalMethod(Object obj) {
}
READ_UNCOMMITTED isolation level states that a transaction may read data that is still uncommitted by other transactions.
READ_COMMITTED isolation level states that a transaction can't read data that is not yet committed by other transactions.
REPEATABLE_READ isolation level states that if a transaction reads one record from the database multiple times the result of all those reading operations must always be the same.
SERIALIZABLE isolation level is the most restrictive of all isolation levels. Transactions are executed with locking at all levels (read, range and write locking) so they appear as if they were executed in a serialized way.
Your doubt has nothing to do with #Transactional.
Its simple question of concurrency.
Actually both the transaction, form a to b and form b to c can work concurrently.
By putting #Transactional states something like
works out whether a given exception should cause transaction rollback by applying a number of rollback rules, both positive and negative. If no rules are relevant to the exception, it behaves like DefaultTransactionAttribute (rolling back on runtime exceptions).
I am beginner to spring , now in my project we have method to make booking ,now if the available booking is 1 , when two user are trying booking at same time ideally only one booking is allowed , but my application is allowing two bookings, now i made the method as synchronized now it is working fine, but synchronization concept belongs to JVM now if I am configuring my application in cluster mode there are different servers in different machines(so different JVMS), now synchronization wont work.
Can any one please tell me the possible solution for this to restrict the booking,tell me solution from JAVA side and and also from DB side
If the application may be deployed in cluster, the synchronized method will indeed not be enough.
You should rely on a node shared by all server instances : the DB.
You could use DB locking features, especially optimistic locking and pessimistic locking.
With them, you could avoid collisions resulting from concurrent updates to the same line by concurrent clients.
Choose which one that matches better to your use case.
Concurrency control in databases extract:
Optimistic - Delay the checking of whether a transaction meets the
isolation and other integrity rules (e.g., serializability and
recoverability) until its end, without blocking any of its (read,
write) operations ("...and be optimistic about the rules being
met..."), and then abort a transaction to prevent the violation, if
the desired rules are to be violated upon its commit. An aborted
transaction is immediately restarted and re-executed, which incurs an
obvious overhead (versus executing it to the end only once). If not
too many transactions are aborted, then being optimistic is usually a
good strategy.
Pessimistic - Block an operation of a transaction, if
it may cause violation of the rules, until the possibility of
violation disappears. Blocking operations is typically involved with
performance reduction.
JDBC and JPA support both.
You should try with ETags - optimistic locking mechanism.
It can be easily implemented with Spring. Please check official documentation.
Hope this will help.
I understand the fact that a transaction that spans multiple transactional resources is called a global transaction.
Question 1:
Is this just an another name for distributed transaction or is that something different?
Question 2:
Have gone through spring's documentation on Transaction Management.
What i could infer from that is
a. JTA is purely designed for distributed transactions.
b. Only through EJBs and EJB CMT, we could enforce distributed transactions.
c. If EJBs, then it mandates an Application Server and indirectly JNDI too.
What is Spring's counterpart to facilitate global/distributed transactions?
Question 3:
If we don't want to go with an application server with JTA capability,
should we be using Atomikos / JOTM like standalone Transaction managers to enforce global transactions?
Question 4:
A simple usecase of updating Table A in DB_1 (MySql) and Table B in DB_2 (Oracle) under a single transaction:
What is Spring's answer to this usecase?
Yes
a) No, not every transaction will be distributed, only if more than one resource is involved. The TM handles the management of the transactions executed on the involved resources
b) No, there are transactionsmanagers usable outside ejb-servers like atomikos, bitronix,... but I am not sure what you mean by enforce, as I wrote earlier, distributed transactions are used when necessary.
c) yes
d) Springs counterpart
if you want to use transactions on multiple resources at the same time yes.
you define two datasources in a way, that they let a TM handle their resources. Both MySql and Oracle provide XA-Datasources which allow it to handle distributed transactions. You define a TM and make it possible to annotate your beans with Transaction Attributes. There are many tutorials out there which show how this can be done.
Additional remarks:
Meanwhile transactions are also included in the CDI-Spec. So you can also use CDI.
Handle the distributed transactions wisely. The two way commit makes it almost impossible to set a reasonable transaction timeout. There are development-sites where distributed transactions only are used between one SQL-DBMS-Resource and one JMS-Resource if necessary.
There are various transaction propagations like
REQUIRED - This is the case for DML operation.
SUPPORTS - This is the case for querying database.
MANDATORY - ?
REQUIRES_NEW - ?
NOT_SUPPORTED - ?
NEVER - ?
NESTED - ?
What are some real life scenarios for these transaction propagations? Why these are perfect fit into that situation?
There are various usages and there is no simple answer but I'll try to be the most explainatory
MANDATORY (expecting transaction): Typically used when you expect that any "higher-context" layer started the transaction and you only want to continue in it. For example if you want one transaction for whole operation from HTTP request to response. Then you start transaction on JAX-RS resource level and lower layers (services) require transaction to run within (otherwise exception is thrown).
REQUIRES_NEW (always create new transaction): This creates a new transaction and suspends the current one if any exists. From above example, this is the level you set on your JAX-RS resource for example. Or generally if your flow somehow changes and you want to split your logic into multiple transactions (so your code have mutliple logic operations that should be separated).
REQUIRED (continue in transaction or create if needed): Some kind of mix between MANDATORY and REQUIRES_NEW. In MANDATORY you expect that the transaction exists, for this level you hope that it exists and if not, you create it. Typically used in DAO-like services (from my experience), but it really depends on logic of your app.
SUPPORTS (caller decides whether to not/run in transaction): Used if want to use the same context as caller (higher context), if your caller was running in transaction, then you run in too. If it didn't, you are also non-transactional. May also be used in DAO-like services if you want higher context to decide.
NESTED (sub-transaction): I must admit I didn't use this one in real code but generally you create a real sub-transaction that works as some kind of checkpoint. So it runs in the context of "parent" transaction but if it fails it returns to that checkpoint (start of nested transaction). This may be useful when you require this kind of logic in your application, for example if you want to insert large number of items to the database, commiting valid ones and keeping track of invalid ones (so you can catch exception when nested transaction fails but can still commit the whole transaction for valid ones)
NEVER (expecting there is no transaction): This is the case when you want to be sure that no transaction exists at all. If some code that runs in transaction reaches this code, exception is thrown. So typically this is for cases completely opposite to MANDARTORY. E.g. when you know that no transaction should be affected by this code - very likely because the transaction should not exist.
NOT_SUPPORTED (continue non-transactionally): This is weaker than NEVER, you want the code to be run non-transactionally. If somehow you enter this code from context where transaction is, you suspend this transaction and continue non-transactionally.
From my experience, you very often want one business action to be atomic. Thus you want only one transaction per request/... For example simple REST call via HTTP that does some DB operations all in one HTTP-like transaction. So my typical usage is REQUIRES_NEW on the top level (JAX-RS Resource) and MANDATORY on all lower level services that are injected to this resource (or even lower).
This may be useful for you. It describes how code behave with given propagation (caller->method)
REQUIRED: NONE->T1, T1->T1
REQUIRES_NEW: NONE->T1, T1->T2
MANDATORY: NONE->Exception, T1->T1
NOT_SUPPORTED: NONE->NONE, T1->NONE
SUPPORTS: NONE->NONE, T1->T1
NEVER: NONE->NONE, T1->Exception
Is it possible to use different transaction isolation levels within the same application? For example, I want to use READ_COMMITTED for simple client requests and READ_REPEATABLE for more complicated requests.
I have wasted weeks trying to figure this out so I am posting a record of what I learned. Additional answers are welcome.
While it is technically possible to change the transaction isolation level using Connection.setTransactionIsolation(int) I highly recommend against doing this.
The transaction isolation must be set before the beginning a transaction. Doing otherwise results in "implementation-defined" behavior.
In order to detect the appropriate transaction isolation you will have to figure out the transaction isolation required by any methods you invoke (and any methods they invoke).
This quickly evolves into a maintenance nightmare where you're struggling to keep track of the right isolation level for each method.
If you attempt to programmatically query the right isolation level at runtime (by asking your dependencies what isolation level they need) you will end up with very ugly code and again it becomes a maintenance nightmare.
Instead, I recommend biting the bullet and picking a single transaction isolation level across your entire application. Start out with something safe and slowly move to the higher-performing isolation levels.