Spring boot hibernate no transaction is in progress - java

I'm using spring boot and it perfectly makes me entity manager. And I decided to test getting session factory from the entity manager and to use it for an example. But I get the next problem:javax.persistence.TransactionRequiredException: no transaction is in progress
properties
spring.datasource.url= jdbc:postgresql://localhost:5432/ring
spring.datasource.username=postgres
spring.datasource.password=root
spring.jpa.show-sql = false
spring.jpa.properties.hibernate.format_sql=false
#Note: The last two properties on the code snippet above were added to suppress an annoying exception
# that occurs when JPA (Hibernate) tries to verify PostgreSQL CLOB feature.
spring.jpa.database-platform=org.hibernate.dialect.PostgreSQL9Dialect
spring.jpa.properties.hibernate.temp.use_jdbc_metadata_defaults = false
spring.jpa.properties.hibernate.current_session_context_class = org.springframework.orm.hibernate5.SpringSessionContext
service class
package kz.training.springrest.service;
import kz.training.springrest.entity.User;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceUnit;
#Service
public class UserService {
#PersistenceContext
private EntityManager entityManager;
#Transactional
public void insertUser(User user) {
SessionFactory sessionFactory = entityManager.unwrap(Session.class).getSessionFactory();
Session session = sessionFactory.getCurrentSession();
session.save(user);
}
}
runner
package kz.training.springrest.run;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication
#EntityScan("kz.training.springrest.entity")
#EnableTransactionManagement
#ComponentScan(basePackages="kz.training.springrest")
public class SpringrestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringrestApplication.class, args);
}
}
Do you have any ideas how to solve it?

I don't quite understand why you're making your service method so unnecessarily complex. You should simply be able to do it this way
#Transactional
public void insertUser(User user) {
entityManager.persist( user );
}
If there are points where you need access to the native Hibernate Session you can simply unwrap and use the Session directly like this:
#Transactional
public void doSomethingFancyWithASession() {
Session session = entityManager.unwrap( Session.class );
// use session as needed
}
The notion here is that Spring provides you an already functional EntityManager instance by you using the #PersistenceContext annotation. That instance will safely be usable by the current thread your spring bean is being executed within.
Secondly, by using #Transactional, this causes Spring's transaction management to automatically make sure that the EntityManager is bound to a transaction, whether that is a RESOURCE_LOCAL or JTA transaction is based on your environment configuration.
You're running into your problem because of the call to #getCurrentSession().
What is happening is Spring creates the EntityManager, then inside your method when you make the call to #getCurrentSession(), you're asking Hibernate to create a second session that is not bound to the transaction started by your #Transactional annotation. In short its essentially akin to the following:
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
Session aNewSession = entityManager.unwrap( Session.class )
.getFactory()
.getCurrentSession();
// at this point entityManager is scoped to a transaction
// aNewSession is not scoped to any transaction
// this also likely uses 2 connections to the database which is a waste
So follow the paradigm I mention above and you should no longer run into the problem. You should never need to call #getCurrentSession() or #openSession() in a Spring environment if you're properly allowing Spring to inject your EntityManager instance for you.

I have same your error, when I deploy my spring boot app to WebLogic Server.
(Even It works fine if I run it directly via Eclipse (Or deploy to Tomcat) ).
I solved the problem by adding #EnableTransactionManagement to UserService.

salved my problem using in hibernate conf "hibernate.allow_update_outside_transaction","true"

Related

Spring boot Persistence Context annotation

I am new in Spring Boot and trying to create a basic REST example in Spring boot. I am taking help from Spring Boot REST example website to create a basic example.
Most of the things are clear to me but I am stuck with one annotation which is being used to fetch the data from the database with the code as below
package com.springbootrest.repository;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.transaction.Transactional;
import org.springframework.stereotype.Repository;
import com.springbootrest.model.BookDetails;
#Transactional
#Repository
public class BookDetailsRepoImpl implements BookDetailsRepo {
#PersistenceContext
private EntityManager entityManager;
public List<BookDetails> listBookDetails() {
return (List<BookDetails>) entityManager.createQuery("FROM BookDetails").getResultList();
}
}
I don't understand how #PersistenceContext is actually working - can anyone please explain?.
#PersistenceContext – We need to understand how we are able to connect with the database using just simple annotation #PersistenceContext and what it is.
Entities are managed by javax.persistence.EntityManager instance
using persistence context.
Each EntityManager instance is associated with a persistence
context.
Within the persistence context, the entity instances and their
lifecycle are managed.
Persistence context defines a scope under which particular entity
instances are created, persisted, and removed.
A persistence context is like a cache which contains a set of
persistent entities , So once the transaction is finished, all
persistent objects are detached from the EntityManager’s persistence
context and are no longer managed.
The #PersistenceContext annotation in your code is being used to indicate that the EntityManager must be automatically injected, in other words its lifecycle will be managed by the container running your application (which is a good thing). The other option would be having all required configurations provided by you (application managed) via different options, all of them cumbersome (config files or beans) and running the risk of tying your application to some environment-specific configuration (which is a bad thing).
#PersistenceContext is JPA standard annotation which gives you better control of which persistence context you are Injecting.
My answer comes after quite a few years but here goes .
this annotation #PersistentContext works in conjunction with another bean defined in your application context:
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
The way the two work together is that the PersistenceAnnotationBeanPostProcessor will lookup the appropriate EntityManagerFactory to inject the entity manager where we have attributes annotated with #PersistenceContext
My understanding is based on the answers to this question: so question here
In Short or layman language, Its a space(just to say) where entities are managed using Entity Manager.

Spring managed transactions, EclipseLink JPA, custom isolation level

I suspect this one is embarrassing an I am doing it wrong in a terrible way, but please bear with me.
I have a Spring application with Spring-managed transactions.
It uses EclipseLink JPA.
I have a method which does a findByNativeQuery() followed by a merge(). I need this to happen in a real SERIAL transaction isolation level.
I tried adding
#Transactional(isolation=Isolation.SERIALIZABLE)
This doesn't work because org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect#beginTransaction
does not support any transaction isolation level but the default.
So then I tried getting to UnitOfWork internals of ElcipseLink and starting/comitting my own transactions, but then I get an error:
"java.lang.IllegalStateException : Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
Which of course makes sense... but what do I do??
I've given a try to this, but I am not completely sure of the solution. I've taken the code from this blog and adapted it for EclipseLink. Here's the code:
package com.byteslounge.spring.tx.dialect;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
public class CustomEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
private static final long serialVersionUID = 1L;
private boolean lazyDatabaseTransaction = false;
#Override
public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) {
this.lazyDatabaseTransaction = lazyDatabaseTransaction;
}
#Override
public Object beginTransaction(final EntityManager entityManager,
final TransactionDefinition definition)
throws PersistenceException, SQLException, TransactionException {
UnitOfWork uow = (UnitOfWork) getSession(entityManager);
uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());
entityManager.getTransaction().begin();
if (!definition.isReadOnly() && !lazyDatabaseTransaction) {
uow.beginEarlyTransaction();
}
return null;
}
}
I'm seeing the SERIALIZABLE isolation being logged when the transaction is initiated, but this needs to be tested properly to confirm it works.
Support for custom isolation level was added in Spring 4.1.2 to EclipseLinkJpaDialect
You can refer
"To achieve serializable transaction isolation with EclipseLink, we recommend that you use an isolated client session as follows:
Configure the database transaction isolation as serializable.
Configure objects as isolated (see Configuring Cache Isolation at the Project Level or Configuring Cache Isolation at the Descriptor Level).
Use the UnitOfWork method beginTransactionEarly (see Unit of Work Method beginTransactionEarly).
If you are only concerned about the write aspect of serializable, optimistic locking is sufficient."
at http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm or go through
http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm
if any of isolation level meets your requirement

JBoss - User transaction not inited

In the following code, a Null pointer exception is raised when I try to call beginTransaction method. I thought that JBoss would init my transaction... apparently not :\
What am I missing ?
JBoss 5.1.0.GA
JPA 1
JDK 6
import javax.annotation.Resource;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import javax.transaction.UserTransaction;
public abstract class AbstractDAO {
#PersistenceUnit(unitName = "miniDS")
protected static EntityManagerFactory emf;
#Resource
protected UserTransaction t;
public AbstractDAO() {
}
protected void beginTransaction() throws Throwable {
t.begin();
}
protected void commitTransaction() throws Throwable {
t.commit();
}
protected void rollbackTransaction() throws Throwable {
t.rollback();
}
}
Your AbstractDAO does not seem to be managed. Injection only works in container managed objects. This is not specific to injection of UserTransaction, but injection in general. As result emf is null as well. Java EE specification lists following classes to be able to use injection:
Servlet: servlets, servlet filters, event listeners
JSP: tag handlers, tag library event listeners
JSF: scoped managed beans
JAX-WS: service endpoints, handlers
EJB: beans, interceptors
Managed Beans: managed beans
CDI: CDI-style managed beans, decorators
Java EE Platform: main class (static), login callback handler
Possible workaround are to move injection of resources to managed class or use JNDI lookup.
Your concrete class ConcreteDAO which extends AbstractDAO, should be an ejb, as said by Mikko Maunu and should manage itself transaction (beans that manage transaction themselves BMT), in other words:
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class ConcreteDAO extends AbstractDAO {
...
}
And it be better if you inject EntityManager in your AbstractDAO, and configure JBOSS datasource to manage transaction (local-tx-datasource or xa-datasource).
you can look at JBOSS DS config at:
https://community.jboss.org/wiki/ConfigDataSources
if you want to manage transaction yourself through EntityManager, with entityManagerFactory
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
you can't use UserTransaction and the JBoss DS should be no-tx-datasource
If you inject your persistence unit, try to get the transaction through the EntityManager.
EntityManager entityManager = emf.createEntityManager();
entityManager.getTransaction().begin();
For more information, have a look here: https://github.com/wicketstuff/core/wiki/How-to-use-#PersistenceUnit-annotation

Dynamic JPA Connection

I have a fairly standard Java EE6 web application using JPA 2 with dependency injection connecting to a MySQL database and everything is working fine. What I would like to do now is have this application interact with the databases of other applications we have installed at a clients site - essentially acting as a single point of control for our other application installs.
What I'm struggling with is how best to perform the interaction with the other databases. Ideally I would like to create an EntityManager for each install and interact using JPA but I can't see any way to set this up. I may, for example, have 5 installs (and therefore databases) of one application type and the master control application won't know about the other installs until runtime. This seems to preclude using dependency injection of an EntityManager and all the automatic transaction demacation etc etc. The alternative option is to just create a DataSource and do the interactions manually. While flexible this clearly requires a lot more effort.
So, my question really is how do I best tackle this problem?
I'm also looking into this, and so far I have found the following blog post that describes a way to do it
http://ayushsuman.blogspot.com/2010/06/configure-jpa-during-run-time-dynamic.html :
Removed all your database properties from persistance.xml
<persistence>
<persistence-unit name="jpablogPUnit" transaction-type="RESOURCE_LOCAL">
<class>com.suman.Company</class>
</persistence-unit>
</persistence>
Changed your java file where you are configuring entityManager, in our case TestApplication.java
package com.suman;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import org.apache.log4j.Logger;
/**
* #author Binod Suman
*/
public class TestApplication {
Logger log = Logger.getLogger(TestApplication.class);
public static void main(String[] args) {
TestApplication test = new TestApplication();
test.saveCompany();
}
public void saveCompany(){
log.info("Company data is going to save");
EntityManagerFactory emf;
Map properties = new HashMap();
properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
properties.put("hibernate.connection.url", "jdbc:mysql://localhost:3306/sumandb");
properties.put("hibernate.connection.username", "root");
properties.put("hibernate.connection.password", "mysql");
properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect");
properties.put("hibernate.show-sql", "true");
//emf = Persistence.createEntityManagerFactory("jpablogPUnit");
emf = Persistence.createEntityManagerFactory("jpablogPUnit",properties);
EntityManager entityManager = (EntityManager) emf.createEntityManager();
entityManager.getTransaction().begin();
Company company = new Company(120,"TecnoTree","Espoo, Finland");
entityManager.persist(company);
entityManager.getTransaction().commit();
log.info("Company data has been saved");
}
}

How to use JPA EclipseLink to connect to the DB in a multi layer environment (REST + EJB + Core)?

I am using Glassfish v3 server.
Usually the DB connection with EJB3 + JPA (Eclipselink) is done through injection, with #PersistenceUnit or #Persistencecontext.
However, there are 3 layers in my App :
Core (contains business logic, entities, exception handling etc)
an EJB on top of it, calling the right core objects and methods to do the job. This EJB is called by other internal modules of our ERP.
a REST layer on top of it for uses by frontend web sites.
I do not want to get the entityManager, nor the EMF (EM factory) in the EJB, because I want my middle layer to be unaware that there is a DB used under it. I could after all, later, decide to change my core implementation for a non-DB-using one.
I see only two bad solutions :
1) Add an EM parameter every time i call a method of the core layer that needs DB connection. Very ugly and goes againt what I said above.
2) In every method of core needing DB connection, I create a factory, an EM, use them, and then close them both.
I tried to cut things in the middle, having one factory per class of the Core level, and EMs are created and closed in every method. But I still have memory leaks like this :
javax.servlet.ServletException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.0.v20091127-r5931): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: Error in allocating a connection. Cause: In-use connections equal max-pool-size and expired max-wait-time. Cannot allocate more connections.
I guess it's because if one of my EJB methods uses 10 different objects, it creates 10 EM factories, and none of them is closed.
Example of typical use in a Core object:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
// do some stuff with em; for example persist, etc
em.flush();
em.close();
Should I go for solution 2?
Is there a way to use a single EM factory at this core level ? I seems like the JPA spec assumes you're going to use the entities at the EJB level only, which is bad in a multi layers apps.
EDIT : here is the current status after trying #Inject :
Added an empty beans.xml file in the /META-INF directory on my CORE jar.
The parent DAO class is now like this :
public class ExampleBZL {
public EntityManagerFactory emf;
#Inject public Emf emfobject;
public ExampleBZL()
{
this.emf = emfobject.emf;
}
The Emf class is very simple, and Stateless.
#Stateless
public class Emf implements EmfAbstract {
#PersistenceUnit(unitName = Setup.persistenceUnitName)
public EntityManagerFactory emf;
public Emf()
{
}
}
I must be doing something wrong, but the injection doesn't work, altough in glassfish I see "[ejb, weld, web]" in the engines list, so the CDI is loaded.
Servlet.service() for servlet Jersey Web Application threw exception
java.lang.NullPointerException
at com.blablabla.core.bizlogic.ExampleBZL.<init>(ExampleBZL.java:40)
Am I missing other annotations ?? Is it really working to do an inection in a JAR with those two small annotations (Stateless on one side, Inject on the other) ?
With JavaEE 6 you can define your core level classes as Beans and inject resources there.
Please check Context and Dependency Injection (CDI) with JavaEE 6.
What if you had two session beans? One with the injected EntityManager that can leverage JTA, and the other is your current session bean.
I am currently putting together a series on my blog using a session bean as the REST service using EclipseLink & Glass Fish v3:
Part 1 - The Database Model
Part 2 - Mapping the Database Model to JPA Entities
Part 3 - Mapping JPA Entities to XML using JAXB
Part 4 - The RESTful Service
Below is how I inject the EntityManager on my session bean that is serving as my REST service:
package org.example.customer;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
import javax.ws.rs.Path;
import org.eclipse.persistence.rest.JPASingleKeyResource;
#Stateless
#LocalBean
#Path("/customers")
public class CustomerService {
#PersistenceContext(unitName="CustomerService", type=PersistenceContextType.TRANSACTION)
EntityManager entityManager;
}
You can link your session beans using the #EJB annotation:
package org.example;
import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;
#Stateless
#LocalBean
#EJB(name = "someName", beanInterface = CustomerService.class)
public class OtherSessionBean {
public Customer read(long id) {
try {
Context ctx = new InitialContext();
CustomerService customerService = (CustomerService) ctx.lookup("java:comp/env/someName");
return customerService.read(id);
} catch(Exception e) {
throw new RuntimeException(e);
}
}
}
I am not sure it is a good answer, but I have found this :
link of forum saying :
it appears that interaction between
JPA and CDI was considered but not
made part of the spec for some unknown
reason. If I come to know of the
reason, I shall update this thread. In
the mean while, it has been sent as a
feedback to appropriate folks. So,
this one is definitely not a bug in
GlassFish.
So, does that explain why my #Inject (of a class containing an entity manager) in a java class is not working ?
Here is the final working code, thanks to Blaise :
The father class that "receives" the connection
import com.wiztivi.apps.wsp.billing.interfaces.bin.db.NewInterface;
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
#Stateless
#LocalBean
public class FatherService {
public EntityManager em;
public FatherService()
{
}
public EntityManager getGoodEm()
{
try {
Context ctx = new InitialContext();
NewInterface dp = (NewInterface) ctx.lookup("java:global/billing-ear/billing-connection/DataProvider");
em = dp.getEm();
} catch(Exception e) {
throw new RuntimeException(e);
}
return em;
}
}
The class who "provides" the connection (in a separate connection JAR, with the entities)
import javax.ejb.LocalBean;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceContextType;
#Stateless
#LocalBean
public class DataProvider implements NewInterface
{
#PersistenceContext(unitName=Setup.persistenceUnitName, type=PersistenceContextType.TRANSACTION)
public EntityManager entityManager;
public DataProvider() {
}
#Override
public EntityManager getEm()
{
return entityManager;
}
}
Something important : You have to put #Stateless on any class of "higher level" layer" that will call the FatherService EJB (in my case, the REST classes).
The Core layer must be packaged as an EJB, and the connection too, both in an EAR

Categories

Resources