I'm using Spring 4.1.3.RELEASE and Hibernate 4.3.7.
The following issue came up while I was trying to use both JTA transaction and Hibernate criteria-query. Code:
#Resource
private UserTransaction userTransaction;
#Resource
private SessionFactory sessionFactory;
public User getUserById(Integer id){
try {
userTransaction.begin();
} catch (Exception e) { }
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(User.class);
criteria.add(Restrictions.eq("id", id));
try {
userTransaction.commit();
} catch (Exception e) { }
return (User) criteria.uniqueResult();
}
I got the Exception that createCriteria is not valid without active transaction. By going through the method's code with a debugger I ensured that I had a valid JTA - transaction. What was wrong?
Once you are spring based why don't you want to manage your transactions using spring? take a look at the link:
Configuring Spring and JTA without full Java EE
You're probably getting an exception on the userTransaction.begin(). Your catch does nothing so the createCriteria() fails because you don't have a transaction.
Related
Consider this two classes: EmployeeDetailDAOImpl and EmployeeDAOImpl. Assume if I want to create a new employee, I should also create a new record for EmployeeDetail.
Given the below implementation, I wonder if the outer transaction(EmployeeDAOImpl's tx) is rolled back due to any exceptions happened after the detailDAO.create(employeeId) call, will the transaction of new EmployeeDetail be rolled back as well?
public class SessionHandler {
public static getSession() {
return Configuration.buildSessionFactory().openSession(); //ignore the isConnected or other exception handling for now
}
}
public class EmployeeDetailDAOImpl {
public void create(Serializable employeeId) {
Session session = SessionHandler().getSession();
Transaction tx = session.beginTransaction();
try {
EmployeeDetail detail = new EmployeeDetail(employeeId);
session.save(detail );
} catch (Exception e) {
if (tx!= null) {
tx.rollback;
}
}
session.close();
}
}
public class EmployeeDAOImpl {
public void add(String name) {
Session session = SessionHandler().getSession();
Transaction tx = session.beginTransaction();
try {
Employee employee = new Employee(name);
Serializable employeeId= session.save(employee);
EmployeeDetailDAOImpl detailDAO = new EmployeeDetailDAOImpl();
detailDAO.create(employeeId);
//more things here, that may through exceptions.
} catch (Exception e) {
if (tx!= null) {
tx.rollback;
}
}
session.close();
}
}
Actually, none of the given answers is 100% correct.
It depends on the calling party/service.
If you are calling the methods from an EJB, you will have 1 transaction covering both method calls. That way, the transaction will roll back both operations in case of an exception. Reason behind this is that every method in EJB is transaction Required, unless specified otherwise in the annotation or ejb deployment descriptor.
If you are using spring or any other DI framework, then it depends on your configuration. In a normal setup, your calling transaction will be suspended, since the JPA EJB will create its own transaction. You can however use the JTATransactionManager (As specified here) to make sure that both your EJB and your Spring bean share the same transaction.
If you call the JPA methods from a POJO, then you will have to take care of the JTA transaction handling yourself.
Yes, it will rollback the entity Employee as well. It doesn't even depend on whether the other entities are related.
It depends on the scope of the transaction, which here includes both Employee and EmployeeDetails
You are creating two different transaction for each method.Hence rollback can not happen.
To rollback the transaction you require the propogation in Transaction.
You need to write the code like below::
#Transactional(propagation=Propagation.REQUIRED)
public void testRequired(User user) {
testDAO.insertUser(user);
try{
innerBean.testRequired();
} catch(RuntimeException e){
// handle exception
}
}
Below is link for more information of Propogation.
http://docs.spring.io/spring-framework/docs/2.5.6/api/org/springframework/transaction/annotation/Propagation.html
http://www.byteslounge.com/tutorials/spring-transaction-propagation-tutorial
I am using Spring MVC and hibernate. My underlying database is Sybase ASA. Inside my DAO I want to find out what is the transaction level used for the query
This is what my DAO has.
Session session = getSession();
String SQL_QUERY = "select ..... ";
Query query = session.createSQLQuery(SQL_QUERY);
query.executeUpdate();
I referred to this link but this seems to be outdated so doesn't work
What is default isolation level hibernate uses if not explicitely set?
I would say that question is raised incorrectly: a query itself doesn't have any isolation level. An Isolation level is a feature of a transaction.
So you, most probably, want to know what is the isolation level of current transaction? Hence you, most probably, do not manage this level by your code. In this case it is managed by DBMS default or current settings.
One of possible ways to explore it is described here:
try {
session = getSessionFactory().openSession();
txn = session.beginTransaction();
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
LOGGER.debug("Transaction isolation level is {}", Environment.isolationLevelToString(connection.getTransactionIsolation()));
}
});
txn.commit();
} catch (RuntimeException e) {
if ( txn != null && txn.isActive() ) txn.rollback();
throw e;
} finally {
if (session != null) {
session.close();
}
}
I am developing an application with EJB, when I make a transaction on the database I get the following error:
Grave: RAR5031:System Exception
javax.resource.spi.LocalTransactionException:
Can't call commit when autocommit=true
The following is the code:
public boolean update(Person vo) {
boolean r = false;
try
{
entityManager.getTransaction().begin();
entityManager.merge(vo);
entityManager.getTransaction().commit();
r = true;
} catch (Exception e)
{
} finally {
return r;
}
}
If this code does not invoke from an EJB not get error. I only get the error when I invoke from an EJB.
Put this annotation #TransactionManagement(TransactionManagementType.BEAN) on your session bean.
Example:
#TransactionManagement(TransactionManagementType.BEAN)
public class YourSessionBean ...
All EJB methods are transactional per default. The transaction handling is performed by the EJB and thus you dont need to invoke begin() and commit().
I am moving a JPA-Hibernate application from a Java EE 6 environment to a Tomcat 7 one.
The application has several DAO classes making queries on the EntityManager. In the Java EE environment I could just inject it using the #PersistenceContext annotation, and let the container manage the EntityManager. Now that I have to do it manually, I was wondering what is the way to go.
Should the entity manager be unique? If so can it be a static final field, created on startup and that every DAO class uses? Does it have a lifecycle that involves closing it and then re-opening it?
Unfortunately, you'll have to do it manually. The way I usually do it is to define a special class:
public class EMF {
private static EntityManagerFactory factory = Persistence.createEntityManagerFactory("name");
public static EntityManager getEntityManager() {
return factory.createEntityManager();
}
}
So, every time you need EntityManager, you have to create it manually. You need to handle transactions as well:
EntityManager em = EMF.getEntityManager();
EntityTransaction et = em.getTransaction();
try {
MyEntity my = new MyEntity();
et.begin();
try {
em.persist(my);
et.commit();
} catch (Exception ex) {
if (et.isActive())
et.rollback();
}
} finally {
em.close();
}
In a Stateless Session Bean an EntityManager is injected but I would like to get hold of a Connection object in order to invoke a DB Procedure.
Is there any solution to this ?
This is going to be JPA provider specific code. Typically this is done by invoking unwrap() on the EntityManager class.
If you are using EclipseLink, the following code (from the EclipseLink wiki) will be useful (in the case you are using an application-managed EntityManager) :
JPA 2.0
entityManager.getTransaction().begin();
java.sql.Connection connection = entityManager.unwrap(java.sql.Connection.class); // unwraps the Connection class.
...
entityManager.getTransaction().commit();
JPA 1.0
entityManager.getTransaction().begin();
UnitOfWork unitOfWork = (UnitOfWork)((JpaEntityManager)entityManager.getDelegate()).getActiveSession();
unitOfWork.beginEarlyTransaction();
Accessor accessor = unitOfWork.getAccessor();
accessor.incrementCallCount(unitOfWork.getParent());
accessor.decrementCallCount();
java.sql.Connection connection = accessor.getConnection();
...
entityManager.getTransaction().commit();
Note, that the solution provided for JPA 2.0 will fail for Hibernate 3.6.5 with a PersistenceException containing the message
Hibernate cannot unwrap interface java.sql.Connection
Use the code provided by Skaffman to get it to work against Hibernate (verified to work under 3.6.5 even for container managed persistence contexts).
However, the EclipseLink wiki points out one useful bit of info - if you are using JTA managed datasources, you should be injecting it using the #Resource annotation or retrieving it using a JNDI lookup. As long as you need to perform transactional work against the database, it is immaterial as to whether you are obtaining a new connection from the data source or an existing one; most connection pools will anyway provide the same connection that is associated with the current thread (i.e. the one already used by the entity manager). You would therefore avoiding unwrapping the entity manager this way, and also perform transactional activity against the database; do remember that the persistence context cache, and a second-level cache may not be synchronized if you do this.
In Hibernate, the solution posted by skaffman resulted in the following error message:
Hibernate cannot unwrap class org.hsqldb.Session
I did get it to work using SessionImpl rather than Session:
Connection connection = entityManager().unwrap(SessionImpl.class).connection();
An example of solving the problem using Session.doWork() is as follows:
private void executeNative(final String query) {
Session session = entityManager.unwrap(Session.class);
session.doWork(new Work() {
#Override
public void execute(Connection connection) throws SQLException {
Statement s = null;
try {
s = connection.createStatement();
s.executeUpdate(query);
}
finally {
if (s != null) {
s.close();
}
}
}
});
}
The JPA API itself doesn't seem to offer this, not surprisingly, but if you're willing to couple your code to a specific implementation, then you can use something like this (Hibernate):
Session hibernateSession = entityManager.unwrap(Session.class);
Connection jdbcConnection = hibernateSession.connection();
Note that Session.connection() is deprecated for removal in Hibernate 4. Consider using Session.doWork() instead.
You must take the underlying delegate using entitymanager.getDelegate() or entitymanager.unwrap(which is the better way), cast it to the specific implementation(in Hibernate it is called Session). Then you can call the connection() method. Be aware this is deprecated, use the Work class instead. Read more here.
In JPA2.0, if need JDBC is por DTO nomodel or entity for query more
complex. Sometimes JPA is not all...
I hope this will help you:
Statement statement = null;
EntityManager em = null;
em = emf.createEntityManager();
EntityTransaction et = em.getTransaction();
if(!et.isActive()) {
et.begin();
}
java.sql.Connection connection = em.unwrap(java.sql.Connection.class);
String qquerry="SELE ...
try {
statement = connection.createStatement();
ResultSet rs = statement.executeQuery(qquerry);
if (!rs.next()) {
return null;
}
else{
wwwwas=rs.getString(4);
}
statement.close();
}
catch (SQLException e) {
System.out.println("\n b-03:"+e);
throw new RuntimeException(e.getMessage(), e);
}
finally {
try {
// em.getTransaction().commit();
if(connection != null )
connection.close();
}
catch (Exception e) {
throw new RuntimeException(e.getMessage(), e);
}
}
This works awesomely and you can use the connection object elsewhere if needed
SessionImpl sessionImpl = (SessionImpl) session;
Connection conn = sessionImpl.connection();
Where session is the name of the Hibernate Session object
Below is the code that worked for me. We use jpa 1.0, Apache openjpa implementation.
import java.sql.Connection;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAPersistence;
public final class MsSqlDaoFactory {
public static final Connection getConnection(final EntityManager entityManager) {
OpenJPAEntityManager openJPAEntityManager = OpenJPAPersistence.cast(entityManager);
Connection connection = (Connection) openJPAEntityManager.getConnection();
return connection;
}
}