I have a little C program that connects to Oracle using OCI. I can start global transactions, suspend them, resume the same transaction in a different process, suspend again, commit back in the first process - all works fine. What I'd like to be able to do is inside my global transaction make a call to a Java app server, passing my Xid as a parameter, and have the web call do some work as part of the global transaction.
I've set up Glassfish 4.1 and I'm using eclipselink as the JPA implementation, but I don't see how I can use the passed in Xid to resume the original transaction. I'm guessing I need to use application managed persistence, so I have some code that looks like:
if (emf == null){
emf=Persistence.createEntityManagerFactory("xaPU");
}
EntityManager em = emf.createEntityManager();
TransactionManager tm = (TransactionManager)ctx.lookup("java:appserver/TransactionManager");
I can then do:
tm.begin();
em.joinTransaction();
em.persist(data);
tm.commit();
And all the data is written to the DB but obviously this is done in a new transaction. If I get the transaction with:
Transaction tx = tm.getTransaction();
and look at tx in the debugger it seems to have a Xid set, but I don't see how I can set this Xid, or associate it with the Xid I pass in from my C program.
Am I on the right tracks with this, or is there an easier way to do this?
Related
I am trying to load entity by doing this:
public void reloadRepository() {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
Hibernate.initialize(Repository.class);
}
From this stack overflow post (Hibernate openSession() vs getCurrentSession()), it says
When you call SessionFactory.getCurrentSession, it creates a new
Session if it does not exist, otherwise use same session which is in
current hibernate context. It automatically flushes and closes session
when transaction ends, so you do not need to do it externally.
What does it mean by "transaction ends"? If I don't make any transaction (guessing Hibernate.initialize() is not making transaction), does hibernate close this session?
Probably.
I'm guessing you set current_session_context_class to thread (since you're using beginTransaction). This means that, according to the javadoc, the session is only usable after transaction is started and is destroyed automatically when transaction ends.
I'm not sure what you mean by 'not making any transaction', you just made one using beginTransaction(). Once you commit or rollback, the transaction will end. Even if you do neither, the transaction will eventually time out,and that will also count as ending the transaction.
It's written like that because in modern apps you control transactions with the #Transactional annotation. You simply put it on top of the service methods and Hibernate opens a transaction automatically and closes it when it reaches the end of the method.
I don't really know what you think your last row of code is doing but it looks very wrong. If you want to load an entity you can simply write session.get(), add #Transactional to your method and delete session.beginTransaction() and Hibernate.initialize().
I am working on an assignment to make the code transactional. I am having this problem about read-only transaction for while and none of a single suggestion I found on the internet didn't work. (Spring and hibernate integrated project)
This is my read-only transactional method
#Transactional(propagation=Propagation.REQUIRES_NEW, readOnly=true
,rollbackFor=Exception.class)
public void
editInternationalExportConsigment(InternationalExportConsignmentFormWrapper
exportConssi (){}
Inside this method, there is a translator process happening. Where the process fetch (select ) data from DB and set to an Object
Contact contact =inquiry.loadCustomerContactById(consignmentVO.getCustomerContactId().intValue());
if (contact != null && contact.getCity() != null) {
consignment.setOrgin(contact.getCity().getCountry());
consignment.setUniqueOriginCountry((contact.getCity().getCountry()!=null)?contact.getCity().getCountry().getId():null);
consignment.setOrginCity(contact.getCity());
}
There are no any update or insert query run in the middle, Only select. But end of the this code snippet execution it commit the data to DB (whatever the value set to setter method will persist into DB )
Can someone please tell me what wrong is happening here. your feedback will be much appricated.
After tedious research, I have found the answer. In our project there are two session factories are running. And also it uses spring OpenSessionInViewFilter to avoid 'lazy initializing' issue. OpenSessionInViewFilter has set flushMode to Auto. Since the OpenSessionInViewFilter keeping binding a hibernate session to the thread along in the entire process, it will override the transactional hibernate session object which gets creates once I start the new transaction.Therefore even if I kept the flushmode for transactional scope as 'COMMIT' it get override with the AUTO property by the properties declared OpenSessionInViewFilter.
When the flushMode is AUTO hibernate will flush dirty objects to DB.
Read this for understand hibernate data flushin
As a solution, I manually change the flush mode to 'COMMIT' inside my transactional method.
Thank you for everyone replied and commented. :)
Do you know how I can get XAResource that is automaticaly enlist to my transaction when I use my entity manager ?
I use Bitronix, JPA, hibernate, my code works fine, but I don't want to rollback all my XAResources if one specific failed. I just want to delist it from the current transaction and others will be commited.
But for delist it of the current transaction, I need the object XaResource and I don't know how i get it with JPA/Bitronix. example of code :
transactionManager.begin();
try {
(...)
EntityManager em = emf.createEntityManager();
(...)
em.close();
} catch (Exception e) {
// old version - rollback every XaResource in the current transaction
//transactionManager.rollback();
//new version wanted - rollbackonly this XaResource
transactionManager.getTransaction().delistResource(XaResource ...);
throw e;
}
transactionManager.commit();
Thanks for your help.
The A(tomicity) property of ACID doesn't allow such scenario. The transaction can only be successful if all data sources were able to commit.
I think the Command Pattern can help you with your problem. Let's say you want to update two data sources, and if one fails you still have control whether to undo the already executed commands.
If you never want to undo, then you don't need XA transactions. You just have to use Resource Local transactions, and if one data source fails, the rest could proceed.
In my application I open session, create criteria but dont close it. Then in other method I open session again, update object and receive database is locked on tr.commit().
If I put session.close() in first instance I receive
could not initialize proxy - no Session.
How do I close and open sessions correctly? Or do I need to copy proxy objects to those created by me and then close()?
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tr=session.beginTransaction();
Criteria criteria = session.createCriteria(MyDocument.class);
criteria.add(Expression.like("isMainDoc", 1));
List docs = criteria.list();
tr.commit();
session.close();
I am a complete begginer. i use sqlite. Any help would be appreciated. Thanks in advance.
Hibernate Session is generally tied to a thread.
So, perhaps you should restructure your code to get a session at the beginning of your processing (e.g. in ServletFilter instance of a web-app).
And then in each method, you can use the same session object, to start a new transaction (and then of course, end the transaction also.
public void doWork(){
Transaction tx = null;
try{
tx = session.beginTransaction();
}catch(){
} finally {
// if tx != null then.. close transaction, or rollback?
}
}
EDIT: And then ofcouse, close the session when the processing is done (in web-app, that could be also in the same ServletFilter)
Google: "Open Session In View" pattern.
Cause
You might be getting the error when you are trying to access properties of the MyDocument class instances returned by the query.
Hibernate is lazy by default. It returns you a proxy for an object instead of hitting the database whenever a reference property is accessed. This behavior can be overwritten whenever required.
Always remember that could not initialize proxy - no Session is recieved when the code tries to access a proxy properties (by hitting the database) and finds that the session is not available ( Session is needed as Hibernate accesses database using this interface)
Solution
Make sure that your session is open whenever Hibernate tries to load object which have not been loaded yet. How do you do that?
(In simple words) There are two schools of thoughts in Hibernate:
Fetch all the data that you might access before you close the Session OR
keep the Session open for the entire duration of time you work on the objects.
I would like you brush up topics such as the unit of work in Hibernate. Hibernate provides a wonderful interface to define boundaries on database access. Data must be accessed (read/written) between these boundaries. Check Here
hibernate.current_session_context_class in the hibernate configuration which can take the values jta | thread | managed | custom.Class. This variable defines the unit of work for your Session.
Last but most importantly try using Contextual Sessions (you must have come across .getCurrentSession()
which helps you to get the same session which is open everytime anywhere in your code. Hibernate handles everything behind the scenes.
Hope this answer serves as a guide for you for taking the correct path in using Hibernate rather than just solving this particular problem.
Follow the below steps when you are using hibernate transactions Read the API here.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Or any other operation.
session.save(a);
tx.commit();
session.close();
Using Ejb3.0, Weblogic 11g, JDBC
I am invoking a method which is running remotely in another deployment EAR.
The method in the remote deployment being invoked but it's annotated with the
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
the problem is that all the logic I do in the database before the remote method is being invoked wont commit till the remote method finished.
What I willing to do is a commit to let the "before" logic take place" and when I get back after the remote call to continue normally.
Any idea?
Some code to explain:
#CallByReference
#Stateless(mappedName = "ejb/OperatorProccessBean")
#Local({ OperatorProccessBeanLocal.class })
#Remote({ OperatorProccessBeanRemote.class })
public class OperatorProccessBean implements OperatorProccessBeanLocal,
OperatorProccessBeanRemote
{
...
SBNDispatchBeanRemote SBNDispatchBean = (SBNDispatchBeanRemote) context.lookup("ejb/SBNDispatchBean#com.mirs.sbn.dispatch.SBNDispatchBeanRemote");
if (SBNDispatchBean == null)
{
logger.error(TAG + " SBNDispatchBean is null");
}
else
{
//until here I want all my data to be commited without waiting for the upcoming remote method to finish
SBNDispatchBean.updateSubscriberInBlockingList(...);
}
...
}
Now the method updateSubscriberInBlockingList() is annotated with
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
i want the data to be commited before that method being invoked.
Thanks in advance,
ray.
Now the method updateSubscriberInBlockingList() is annotated with #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
I want the data to be commited before that method being invoked.
Given that you are using container managed transactions, it is not possible. The rationale behind this, is that when the container is already performing a transaction, then starting a new transaction will result in the original being suspended. When the new transaction has committed, the original transaction will be resumed.
This behavior is not configurable, for the EJB container and the JTA Transaction Manager is expected adhere to the behavior specified in the JTA specification, which is derived from X/Open DTP transaction model. In the X/Open DTP model, if there is a new transaction is started, while another is in progress, the current one is suspended, and resumed at a later point in time. It should be noted that no transaction model, would possibly (I haven't studied all) allow for committing the current transaction and starting a new one. I have only seen nested transactions or suspended transactions being supported in the various transaction processing models.
If you want to have the work committed, you must have the existing transaction context terminated completely, so that the existing transaction will commit, and then start the new transaction.
Put the "before remote call" logic in a separate bean method annotated with REQUIRES_NEW as well. You will thus have three transactions :
one for the main method (but which won't do anything until th remote call is done);
one for the logic before the remote call;
one for the remote call.