I don't understand the difference between the concepts. Pro JPA 2 says the following:
Transaction synchronization is the process by which a persistence context is registered with a transaction so that the persistence context can be notified when a transaction commits. The provider uses this notification to ensure that a given persistence context is correctly flushed to the database.
Transaction association is the act of binding a persistence context to a transaction. You can also think of this as the active persistence
context within the scope of that transaction.
Could you please give some more explanation, maybe practical examples? Should I care about it in Java SE environment not using any JTA transactions? Thank you for any note!
Transaction Synchronization : You can think of this as Spring's TransactionSynchronization interface which receives callback for transaction synchronization..It has various methods like afterCommit(), afterCompletion(),beforeCommit() which get called as per transaction's state..Consider a practical example where you want to send an email to user once user registration is completed ,notify any external service depending on transaction state or log any particular event..
Transaction association:we basically commit transaction under active persistence context..let it be JPA's Entity manager or Hibernate's session..
Should I care about it in Java SE environment not using any JTA transactions?Yes..you will have to fall back to JDBC transaction demarcation..
Related
What is the main difference between using sessionTransacted=true (in JmsTemplate and/or DefaultMessageListenerContainer) and using JmsTransactionManager? Is using sessionTransacted=true enough for both JmsTemplate and DefaultMessageListenerContainer usages? (I don't need XA)
The doc said (in setSessionTransacted method in JmsAccessor), and it seems that shouldn't be a problem:
Setting this flag to "true" will use a short local JMS transaction
when running outside of a managed transaction, and a synchronized
local JMS transaction in case of a managed transaction (other than an
XA transaction) being present.
Correct.
On the DefaultMessageListenerContainer(DMLC) you typically only need acknowledgemode=transacted; you would only use a transaction manager on a DMLC if you need to synchronize the JMS transaction with, say, a JDBC transaction or you need to use a platform (JTA) transaction manager.
Further, any downstream JmsTemplate operation on the container's thread will be done in the same session and participate in the transaction.
Similarly, for JmsTemplate operations on a thread that is not a container thread you generally don't need a transaction manager, unless the platform requires it.
session transactioned means transaction start when session start, transaction end when session end.if you need more control on the transaction you need JmsTransactionManager (local)
I had a web software running in a Jboss AS 7 container witch saves our data in a PostgreSQL 9.1 database via JPA, an its configuration delegated to JTA.
Last year it was adapted to run at AWS EC2 cloud. As the user demand grown our database usage growed too. As expected our database server becomes busy at rush times, an it affected the usage experience from our users.
After some replication researches on PostgreSQL we realise that PGPool2 could be a nice replication solution for our case: it offers Load Balancing for SELECT queries, and Replication for CUD operations ( UPDATE, INSERT and DELETE ) as well.
So far so good, except that it turns the software slow. If fact, as explicited in PGPool2 documentation, SELECT queries will not be load balanced if it was defined in explicit BEGIN/END transaction.
For a query to be load balanced, all the following requirements must be met:
- PostgreSQL version 7.4 or later
- the query must not be in an explicitly declared transaction (i.e. not in a BEGIN ~ END block)
- it's not SELECT nextval or SELECT setval
- it's not SELECT INTO
- it's not SELECT FOR UPDATE nor FOR SHARE
- it starts with "SELECT" or one of COPY TO STDOUT, EXPLAIN, EXPLAIN ANALYZE SELECT...
- ignore_leading_white_space = true will ignore leading white space.
Two questions:
How I could figure out our SELECT queries that was running in explicit transactions?
Does _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_ fix the transaction scopes, granting that my SELECT method will be running as "transaction-free"?
How I could figure out our SELECT queries that was running in explicit transactions?
Turn on pgpool2 logging of SQL and connections:
Put the following statements into pgpool.conf (which you can setup via cp $prefix/etc/pgpool.conf.sample $prefix/etc/pgpool.conf):
log_per_node_statement
log_connections
Alternatively, turn on log tracing of JPA:
This requires a different method depending or your JPA implementation ( How to view the SQL queries issued by JPA? , JPA 2.0 (logging and tracing through) with Glassfish 3.0.1 and NetBeans 6.9.1: ).
This will log SQL, but will not log transaction start/commit/rollback.
Additionally, put your own debug logging code into methods which start & end transactions, so that you can see when transaction start/commit/rollback.
Does _javax.ejb.TransactionAttributeType.NOT_SUPPORTED_ fix the transaction scopes, granting that my SELECT method will be running as "transaction-free"?
If you are using Container Managed Transactions (annotations #TransactionManagement(CONTAINER) and #TransactionAttribute), then NOT_SUPPORTED will temporarily disassocate the JTA transaction from the current thread. Then the method will run with no transaction context.
Your subsequent JPA query will run outside of the JTA transaction - because the JTA transaction is not available for it to use.
If you already use a Transaction-Scoped EntityManager
Within your Stateless Session Bean you have an EntityManager annotated
#PersistenceContext(type=PersistenceContextType.TRANSACTION), or
annotated #PersistenceContext without type attribute (because
TRANSACTION is the default):
then that EM will lose it's persistence context within the NOT_SUPPORTED method because the PC is associated with the current transaction, which is no longer accessible
so you cannot use such an EM in the method (e.g. to run queries or lookup cached objects)
so you must use an additional application-managed EM within the NOT_SUPPORTED method
you must create the app-managed EM from an EntityManagerFactory in a place where no JTA transaction is active (e.g. in the NOT_SUPPORTED method), because the app-managed EM will automatically associate itself with the current thread's JTA transaction during creation
any objects returned from queries by the new app-managed EM will be in a different persistence context from the original EM, so you need great care to cleanly detach such objects from the PC (e.g. appMgdEM.clear() or appMgdEM.close() or appMgdEM.detach(someEntity)) if you are to modify/merge them with the original EM.
If you already use an Extended-Scoped EntityManager
Within your Stateful Session Bean you have an EntityManager annotated #PersistenceContext(type=PersistenceContextType.EXTENDED).
then that EM will still have it's persistence context within the NOT_SUPPORTED method because the PC is associated with the stateful session bean
but the EM is using a connection that is already in the middle of a "live" transaction
so if you want to run queries outside of a transaction, you cannot use such an EM in the method
so again, you must use an additional application-managed EM within the NOT_SUPPORTED method (same points apply as above).
Example
#Stateless
public class DepartmentManagerBean implements DepartmentManager {
#PersistenceUnit(unitName="EmployeeService")
EntityManager txScopedEM;
#PersistenceUnit(unitName="EmployeeService")
EntityManagerFactory emf;
#TranactionAttribute(REQUIRED)
public void modifyDepartment(int deptId) {
Department dept = txScopedEM.find(Department.class, deptId);
dept.setName("New Dept Name");
List<Employee> empList = getEmpList();
for(Employee emp : empList) {
txScopedEM.merge(emp);
dept.addEmployee(emp);
}
dept.setEmployeeCount(empList.size());
}
#TranactionAttribute(NOT_SUPPORTED)
public void getEmpList() {
EntityManager appManagedEM = emf.createEntityManager();
TypedQuery<Employee> empQuery = appManagedEM.createQuery("...", Employee.class);
List<Employee> empList = empQuery.getResultList();
// ...
appManagedEM.clear();
return empList;
}
}
Alternative/Adjusted Approach
The above has some restrictions on how you query and how you use resulting objects. It requires creating an EM "on the fly", if you use stateless session beans, and also requires entityManager.merge() to be called. It may not suit you.
A strong alternative is to redesign your application, so that you run all queries before the transaction starts. Then it should be possible to use a single Extended-Scoped EntityManager. Run the queries in "NOT_SUPPORTED" method 1 (no transaction), using extended-scope EM. Then run modifications in "REQUIRED" method 2 (with transaction), using the same extended-scope EM. A Transaction-Scoped EntityManaged wouldn't work (it would try to be transactional from the very start, and would have no PC in NOT_SUPPORTED methods).
Cheers :)
You may want to consider partitioning in JPA using EclipseLink data partitioning,
http://java-persistence-performance.blogspot.com/2011/05/data-partitioning-scaling-database.html
I had been using #Transactional annotations in my Service Layer. But to resolve an error due to Lazy Loading in View I had to use Open Session in View Filter. After this, without use of #Transaction itself a Session gets opened and transaction starts. So does that mean #Transactions are not required? How will transactions and roll-backs be handled, then in Service Layers?
The javadoc explains it:
This filter makes Hibernate Sessions available via the current thread, which will be autodetected by transaction managers. It is suitable for service layer transactions via HibernateTransactionManager or JtaTransactionManager as well as for non-transactional execution (if configured appropriately).
NOTE: This filter will by default not flush the Hibernate Session, with the flush mode set to FlushMode.NEVER. It assumes to be used in combination with service layer transactions that care for the flushing: The active transaction manager will temporarily change the flush mode to FlushMode.AUTO during a read-write transaction, with the flush mode reset to FlushMode.NEVER at the end of each transaction. If you intend to use this filter without transactions, consider changing the default flush mode (through the "flushMode" property).
I understand that Hibernate uses transparent write behind by default for committing the transactions.
However, I would like my entity-manager to commit my transaction on the database immediately after the transaction is committed. Is there anyway I can configure this in persistence.xml of JPA ?
Hibernate would have to commit in the database at the time is made commits the transaction. You can also find it helpful to have two additional options:
Define the Session and autocommit (entering the property "hibernate.connection.autocommit" in the properties of the connection)
Forcing hibernate transaction synchronize with the database transaction in the middle of the transaction (by session.flush ())
Regards,
Using Spring-JMS it is possible to receive messages within an external transaction context via the DefaultMessageListenerContainer.
However the only documented way to write a message is via JmsTemplate.send(…) and I can't see how this can be coerced to use a given TransactionManager.
Can anyone point me in the right direction?
More info: Ensuring a transaction manager is available (WebSphereUowTransactionManager), using JmsTemplate.write against an Oracle AQjmsFactory.getQueueConnectionFactory(dataSource) results in:
org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
at org.springframework.jms.support.JmsUtils.convertJmsAccessException(JmsUtils.java:316)
at org.springframework.jms.support.JmsAccessor.convertJmsAccessException(JmsAccessor.java:168)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:469)
at org.springframework.jms.core.JmsTemplate.send(JmsTemplate.java:534)
Caused by: oracle.jms.AQjmsException: could not use local transaction commit in a global transaction
at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1053)
at oracle.jms.AQjmsSession.commit(AQjmsSession.java:1021)
at org.springframework.jms.support.JmsUtils.commitIfNecessary(JmsUtils.java:217)
at org.springframework.jms.core.JmsTemplate.doSend(JmsTemplate.java:573)
at org.springframework.jms.core.JmsTemplate$3.doInJms(JmsTemplate.java:536)
at org.springframework.jms.core.JmsTemplate.execute(JmsTemplate.java:466)
... 24 more
Caused by: java.sql.SQLException: could not use local transaction commit in a global transaction
at oracle.jdbc.driver.PhysicalConnection.disallowGlobalTxnMode(PhysicalConnection.java:6647)
at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3635)
at oracle.jdbc.driver.PhysicalConnection.commit(PhysicalConnection.java:3680)
at oracle.jdbc.OracleConnectionWrapper.commit(OracleConnectionWrapper.java:133)
at oracle.jms.AQjmsSession.commitNoCheck(AQjmsSession.java:1049)
... 29 more
So whilst I have no reason to doubt the advise below, I am not able to test it as I can't figure out how to get AQ JMS to not attempt a commit. Will update as I learn more.
My understanding is that JMS producers are inherently transacted via JTA. By sending a message via JMS MessageProducer, the thread-local JTA transaction is used (if one is present).
This is hinting at by the Spring manual (section 21.2.5):
JmsTemplate can also be used with the JtaTransactionManager and an XA-capable JMS ConnectionFactory for performing distributed transactions. Note that this requires the use of a JTA transaction manager as well as a properly XA-configured ConnectionFactory.
This is also suggested by JmsAccessor.setSessionTransacted (the superclass of JmsTemplate) (javadoc):
Set the transaction mode that is used when creating a JMS Session. Default is "false".
Note that within a JTA transaction, the parameters passed to create(Queue/Topic)Session(boolean transacted, int acknowledgeMode) method are not taken into account. Depending on the J2EE transaction context, the container makes its own decisions on these values. Analogously, these parameters are not taken into account within a locally managed transaction either, since the accessor operates on an existing JMS Session in this case.
Setting this flag to "true" will use a short local JMS transaction when running outside of a managed transaction, and a synchronized local JMS transaction in case of a managed transaction (other than an XA transaction) being present. The latter has the effect of a local JMS transaction being managed alongside the main transaction (which might be a native JDBC transaction), with the JMS transaction committing right after the main transaction.
So by start a JTA transaction (i.e. by using Spring's transaction API with JtaTransactionManager) and calling JmsTemplate.send(...), you will be sending the message bound to that transaction.