Using Nativequery to delete/update records in JTA - jpa

I was stuck in very hard situation for a moment.
The problem is: I have to use NativeQuery to delete and/or update some DB records in a JTA context (EJB).
my JPA persistence.xml looks like:
<persistence-unit name="OzsscJPANBPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/postgres_ozssc</jta-data-source>
<mapping-file>com/longz/ozssc/model/PostcodeEntity.xml</mapping-file>
<class>com.longz.ozssc.model.CustomerEntity</class>
......
If I use delete statement in this way:
#Override
public void remove(SmsdOutboxEntity toberemoved){
em.createNativeQuery("Delete from outbox where \"ID\" = " + toberemoved.getId()).executeUpdate();
TransactionRequiredException thrown:
root cause
javax.persistence.TransactionRequiredException:
Exception Description: No transaction is currently active
Such there is no transaction existing.
If we use transaction manually as:
#Override
public void remove(SmsdOutboxEntity toberemoved){
em.getTransaction().begin();
em.createNativeQuery("Delete from outbox where \"ID\" = " + toberemoved.getId()).executeUpdate();
/*em.flush();*/
em.getTransaction().commit();
IllegalStateException thrown:
root cause
javax.ejb.EJBException: EJB Exception: ; nested exception is:
java.lang.IllegalStateException: The method public abstract javax.persistence.EntityTransaction javax.persistence.EntityManager.getTransaction() cannot be invoked in the context of a JTA EntityManager.
Seems I can't use transaction manually, as JTA will manage transaction their self.
So my question is: How I can use Native Query to delete/update records in a JTA managed context?
Please advise.

For JTA the transaction is provided by the container and you should not create it by yourself. To obtain the transaction in JTA, you have to access it as a resource:
#Resource public UserTransaction utx;
#Resource public EntityManagerFactory factory;
#Override
public void remove(SmsdOutboxEntity toberemoved){
EntityManager em = factory.createEntityManager();
try {
em.createNativeQuery("Delete from outbox where \"ID\" = " + toberemoved.getId()).executeUpdate();
utx.commit();
catch (RuntimeException e) {
if (utx != null) utx.rollback();
throw e; // or display error message
}
finally {
em.close();
}
If you want to omit the part where you have commit/rollback the transaction by yourself, you need to have your transaction managed by some container like EJB3. For that you can use stateless/stateful ejb beans.
UPDATE:
For WebLogic, try to use its user weblogic.transaction.UserTransaction instead of javax.transaction.UserTransaction. As the doc says:
This interface defines WebLogic-specific extensions to
javax.transaction.UserTransaction.

Related

spring data jpa transaction not rollbacking

I am Using Spring Data Jpa and adding inserting into 2 table when something happen while adding into second table the first transaction is not rollbacking
and first insert is commiting immidiatally after insert
#Override
#Transactional(propagation = Propagation.REQUIRED, rollbackFor =
Exception.class)
public void addVehicleType(Map<String, Object> model)throws Exception {
VehicleType vehicleType = null;
VehicleStatus vehicleStatus = null;
try {
vehicleType = (VehicleType) model.get("vehicleType");
vehicleStatus = (VehicleStatus) model.get("vehicleStatus");
vehicleStatusRepository.save(vehicleStatus);
vehicleTypeRepository.save(vehicleType);
} catch (Exception e) {
throw e;
}
VehicleTypeRepository.java
public interface VehicleTypeRepository extends JpaRepository<VehicleType, Long> {
#Override
void delete(VehicleType role);
long count();
}
If you use mysql, you must have InnoDB Engine.
Second, problem could be if you are testing on local pc.
Uncomment in my.ini default_tmp_storage_engine=MYISAM
; The default storage engine that will be used when create new tables
; default-storage-engine=MYISAM
; New for MySQL 5.6 default_tmp_storage_engine if skip-innodb enable
default_tmp_storage_engine=MYISAM
The only exceptions that set a transaction to rollback state by default are the unchecked exceptions (like RuntimeException).
Please note that the Spring Framework's transaction infrastructure code will, by default, only mark a transaction for rollback in the case of runtime, unchecked exceptions; that is, when the thrown exception is an instance or subclass of RuntimeException. (Errors will also - by default - result in a rollback.) Checked exceptions that are thrown from a transactional method will not result in the transaction being rolled back.

Merge doesn't reflect in Derby database immediately

I have the following code which I call from the front end
public Login update(Login i) {
em = emf.createEntityManager();
em.getTransaction().begin();
Login result=infoDAO.update(i);
em.getTransaction().commit();
em.close();
return result;
}
public Login update(Login i) {
return em.merge(i);
}
I have
private static final EntityManagerFactory emf = Persistence.createEntityManagerFactory("HRTool-JPA");
protected EntityManager em=emf.createEntityManager();
The methods are being called and the values are passed to the DB correctly(I am using Apache derby) but I can see the new changed values in the DB only after I disconnect and reconnect to it. Am I missing some step after merge ? I am new to JPA and appreciate any suggestions on the same
By default Hibernate keep the requests in its cache and Hibernate decides when it wants to execute them.
You can try to add a em.flush() after em.merge()
It will execute all the requests left in its cache.

Is it possible to annotate a method with #TransactionAttribute in BMT EJB?

I came across a piece of code where the bean implementation class has #TransactionManagement(TransactionManagementType.BEAN) annotation wherein methods are annotated with CMT #TransactionAttribute. Is is valid?
Can an EJB with BMT persistence use CMT transaction annotation? What will be the behavior at runtime?
Though javadoc http://docs.oracle.com/javaee/6/api/javax/ejb/TransactionAttribute.html says that "It can only be specified if container managed transaction demarcation is used.", specifying it doesn't throw any compilation error. Does it mean that jvm simply ignores it at runtime?
#Stateless( mappedName = "Abc")
#Remote("AbcRemote.class")
#Local("AbcLocal.class")
#TransactionManagement(TransactionManagementType.BEAN)
public class AbcBean implements AbcLocal, AbcRemote{
#Resource
private UserTransaction utx;
#PersistenceUnit
private EntityManagerFactory emf;
#Override
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public Abc getAlpbabets(String name) {
EntityManager em = null;
try {
em = emf.createEntityManager();
}
catch (RuntimeException re) {
throw re;
}
finally {
}
}
}
If you use CMT, then #TransactionAttribute(TransactionAttributeType.REQUIRED) would tell the container to check for an existing transaction and open one if there is none.
But if you use BMT, then it's your responsibility to do such a thing, so there's no one to observe the annotation above. Since it is still syntactically correct and the class is available, there is no need for the JVM to complain about.
Concerning ignoring annotations, there's a hint in the answer to this question.

How to propagate a client-side UserTransaction into a stateless session bean using BMT

This scenario using CMT is working:
Stateless session bean with CMT, one method annotated with #TransactionAttribute(TransactionAttributeType.MANDATORY). Within this method, a record is written into a RDBMS using an XA data source and plain JDBC.
The stand-alone client (separate JVM, command-line Java application) is getting a UserTransaction from the application server (by JNDI lookup),
starts the transaction, and calls the EJB.
If the client commits the UserTransaction, the record is written into the database.
If the client rollbacks the UserTransaction, the record is not written into the database.
In the PostgreSql log files, one can see the prepared transaction with BEGIN, and COMMIT or ROLLBACK
If the client does not start a transaction before calling the EJB, a javax.ejb.EJBTransactionRequiredException is thrown (as expected, TransactionAttributeType.MANDATORY).
Now I switch from CMT to BMT
Again, if the client does not start a transaction before calling the EJB, a javax.ejb.EJBTransactionRequiredException is thrown (as expected, TransactionAttributeType.MANDATORY).
If I call sessionContext.getUserTransaction().getStatus(), it always reports Status.STATUS_NO_TRANSACTION.
The record is always written into the database, if the client calls commit or rollback.
In the PostgreSql log files, there are no prepared transactions, just plain insert commands.
The source of the EJB:
#Remote(DemoIfc.class)
#Stateless(name = "DemoBmt")
#TransactionManagement(TransactionManagementType.BEAN)
public class DemoBmt implements DemoIfc {
#Resource
private SessionContext sessionContext;
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public String ping(final String s) throws SystemException {
try {
System.out.println("TX: status: "
+ this.sessionContext.getUserTransaction().getStatus());
} catch (Exception e) {
System.out.println("TX: status: " + e.getMessage());
}
try {
writeIntoDb();
if (s.startsWith("crash")) {
throw new SystemException("Simulated crash");
}
return s.toUpperCase();
} catch (NamingException e) {
throw new SystemException(e.getMessage());
} catch (SQLException e) {
throw new SystemException(e.getMessage());
}
}
}
The client's source:
final UserTransaction ut = (UserTransaction) initialContext
.lookup("UserTransaction");
try {
ut.begin();
System.out.println(demo.ping("crash: DemoBmt with UT"));
ut.commit();
} catch (Exception ex) {
System.out.println("Expected rollback");
ut.rollback();
}
I am using JBoss 6.0.0 final.
How can I properly propagate the client-side UserTransaction into the EJB with BMT?
BMT beans cannot participate in an existing transaction
From EJB 3.1 spec.:
13.6.1 Bean-Managed Transaction Demarcation
The container must manage client invocations to an enterprise bean
instance with bean-managed transaction demarcation as follows. When a
client invokes a business method via one of the enterprise bean’s
client views, the container suspends any transaction that may be
associated with the client request....

Why transaction can't commit in a self-invoked ejb method with #REQUIRES_NEW Annotation

First I want to explain my self-invoked ejb method in this situation. I have a stateful session bean with a method which starts a new transaction (Annotated by #REQUIRES_NEW). To invoke this method inside the bean itself and make the annotation effective, I use SessionContext#getBusinessObject() to achieve the effect of #EJB (#EJB here causes stackoverflow?!). My code is shown below:
#Stateful
#Local
public class TransactionTest implements ITransactionTest {
#PersistenceContext(unitName="Table",Type=PersistenceContextType.EXTENDED)
private EntityManager manager;
#Resource
SessionContext sc;
ITransactionTest me;
#PostConstruct
public void init(){
me = this.sc.getBusinessObject(ITransactionTest.class);
}
public void generateRecord(int i) throws RuntimeException{
Record record = new Record();
record.setId(i+"");
record.status(1);
manager.persist(record);
manager.flush(); //If not flush, result is correct. Why?
me.updateRecord(i);
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateRecord(int i) throws RuntimeException{
try {
Record record = manager.find(Record.class, i+"");
record.setStatus(2);
manager.flush();
} catch(Exception e) {
e.printStackTrace();
throw new RuntimeException();
}
}
}
While,generateRecord() runs properly. The console shows it executes 'insert' and 'update' HQL without any exception (I use Hibernate as JPA provider). However, the 'update' result doesn't appear in the database. Why? Does updateRecord() commit correctly?
Also, I try it in two altenative ways: First is invoking generateRecord() (it will no longer invoke updateRecord()) and updateRecord() consecutively in another bean. It can give me the right result.
The second is removing the first flush(). Then both 'insert' and 'update' HQL will be executed at the second flush(). This method can also produce right result.
My program is running under JBOSS 6.1.0-Final and database is Oracle.
Best Regards,
Kajelas