Should I instantiate EntityManager for every method in repository [duplicate] - java

I am not using Spring so I am creating an instance of EntityManager within a class.
I used Hibernate-Eclipse reverse engineering to auto-generate the classes. These classes all has an instance of EntityManager.
I am not 100% sure how Hibernate works with the EntityManager so I am wondering if it is okay that so many instances of this class (EntityManager) are made, for example, will there be problems with transactions?
Should I just make a separate class that distributes a static instance of an EntityManager for all my other classes? or does it not matter?
EDIT: I see there's something called #PersistenceContext, it doesn't seem to load my persistence.xml as a bean in to the instance variable, does this feature require spring? (I get null pointer exception, because it was never injected)
snip of code from where I attempt to use #persistencecontext
#PersistenceContext(unitName = "manager1")
private EntityManager entityManager;
my persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="mypassword"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/ptbrowserdb"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>

See this Article: JPA Architecture it explain it very well.
In General you need a single Entity Manager per transaction. And this Entity Manager must not be used in two transactions at the same time.
Clairification: I mean, do not use a single Entity Manager for different unit of works. Typical one transaction in one unit of work, if you have different transactions of one unit of work, then you can use the same Entity Manager
If you use Spring then Spring do this handling for you if you use the #PersistenceContext annotation to inject the EntityManager. Per default Spring "bind" the the injected EntityManager (via a proxy) to the current transaction. (And the transaction is "bound" to the thread.)
#See Spring Reference 13.5.2 Implementing DAOs based on plain JPA - it contains a interesting paragagraph after the code examples.

You need a dependency injection framework like Spring or Google Guice to inject objects into your class otherwise it may not be injected automatically for you.
Basically this is an annotation provided by JPA which will work with in tandem with hibernate or any other ORM framework per say but you need a DI framework to inject the objects.
Regarding the single instance of entity manager i don't think you need that if you go by Spring since it takes care of managing the instances and the transactions for you by tying your entity manager with the jpa transaction.

Related

How can I access an entity manager without providing unit name in #PersistenceContext?

I have defined multiple persistence units with multiple entity manager factories and multiple transaction managers.
I know I can access the respective entity manager by providing a unit name to persistence context like this.
#PersistenceContext(unitName="PU1")
protected transient EntityManager entityManager;
I was wondering if there is a way that I can access a default persistence unit.
#PersistenceContext
protected transient EntityManager entityManager;
I want this entity manager to select my persistence unit "PU1" as default.
While defining my PersistenceUnitManager, I defined the defaultDataSource to the one I want but it did not help.
Any suggestions would be greatly appreciated.
Thank you.
JPA doesn't know which persistence unit to use, try creating a persistence.xml for each persistence unit and choose which one to use in the application context
try this:
<bean id="persistenceUnitManager"
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager">
<property name="persistenceXmlLocations">
<list>
<value>classpath*:META-INF/persistencePU1.xml</value>
</list>
</property>
</bean>

Junit Hibernate creates database schema multiple times

I'm working on a Java Spring+Hibernate project and we have a Junit setup in order to unit-test our code.
The problem I face right now is that I don't understand why Hibernate (with Spring-boot) creates the database schema 2 times before the tests actually run. The sequence is as follows:
Alter tables drop all foreign keys
Drop tables if exist
Create tables
Alter tables add constraints (like FK)
Alter tables drop all foreign keys
Drop tables if exist
Create tables
Alter tables add constraints
Execute all tests
My questions is, if to be more specific: Why points 3-6 including are executed?
Why simply not to execute 1,2,7,8,9. Why do I want this? Because it takes precious time and I don't understand why do I need this.
Below is my persistence configuration:
<persistence-unit name="localContainerEntityForTest">
<description>Spring JPA LocalContainerEntityManagerFactoryBean</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.implicit_naming_strategy" value="legacy-jpa"/>
<property name = "hibernate.show_sql" value = "true" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/myApp?createDatabaseIfNotExist=true"/>
<property name="javax.persistence.jdbc.user" value="hibernate"/>
<property name="javax.persistence.jdbc.password" value="password"/>
</properties>
</persistence-unit>
Also, below are the annotations I use for every unit test class:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = JPAConfigurationTestEnviorement.class)
#WebAppConfiguration
#FixMethodOrder(MethodSorters.NAME_ASCENDING)
I am fairly familiar with Hibernate, but less so with Spring Boot. My guess is that Hibernate is directly responsible for one create-alter-drop cycle and Spring Boot is responsible for the other one. If you are morally opposed to your current setup, then you can try updating your Hibernate XML to the following:
<property name="hibernate.hbm2ddl.auto" value="validate"/>
By choosing the validate option, you are instructing Hibernate to only validate your existing schema and to not create or drop any tables. The trick here is that I'm not sure which of the two cycles you want to remove (nor did you tell us).
Problem found, after starting the process to upgrade the spring boot version and I observed some weird code that was not telling me anything before. The reason was the creation of EntityManagerFactory before defining the LocalContainerEntityManagerBean:
#Bean
public LocalContainerEntityManagerFactoryBean getEntityManagerFactoryBean() {
Persistence.createEntityManagerFactory("localContainerEntityForTest");
LocalContainerEntityManagerFactoryBean lcemfb = new LocalContainerEntityManagerFactoryBean();
lcemfb.setPersistenceUnitName("localContainerEntityForTest");
lcemfb.setPackagesToScan("com.mybasepackage");
lcemfb.setPersistenceXmlLocation("classpath:/META-INF/persistence.xml");
return lcemfb;
}
After removing the line:
Persistence.createEntityManagerFactory("localContainerEntityForTest");
the cycle disappeared.

How to run native SQL queries in the same Hibernate transaction?

We have a Service which is #Stateful. Most of the Data-Operations are atomic, but within a certain set of functions We want to run multiple native queries within one transaction.
We injected the EntityManager with a transaction scoped persistence context. When creating a "bunch" of normal Entities, using em.persist() everything is working fine.
But when using native queries (some tables are not represented by any #Entity) Hibernate does not run them within the same transaction but basically uses ONE transaction per query.
So, I already tried to use manual START TRANSACTION; and COMMIT; entries - but that seems to interfere with the transactions, hibernate is using to persist Entities, when mixing native queries and persistence calls.
#Stateful
class Service{
#PersistenceContext(unitName = "service")
private EntityManager em;
public void doSth(){
this.em.createNativeQuery("blabla").executeUpdate();
this.em.persist(SomeEntity);
this.em.createNativeQuery("blablubb").executeUpdate();
}
}
Everything inside this method should happen within one transaction. Is this possible with Hibernate?
When debugging it, it is clearly visible that every statement happens "independent" of any transaction. (I.e. Changes are flushed to the database right after every statement.)
I've tested the bellow given example with a minimum setup in order to eliminate any other factors on the problem (Strings are just for breakpoints to review the database after each query):
#Stateful
#TransactionManagement(value=TransactionManagementType.CONTAINER)
#TransactionAttribute(value=TransactionAttributeType.REQUIRED)
public class TestService {
#PersistenceContext(name = "test")
private EntityManager em;
public void transactionalCreation(){
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
em.createNativeQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
}
}
Hibernate is configured like this:
<persistence-unit name="test">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<jta-data-source>java:jboss/datasources/test</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform" />
<property name="hibernate.archive.autodetection" value="true" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="connection.autocommit" value="false"/>
</properties>
</persistence-unit>
And the outcome is the same as with autocommit mode: After every native query, the database (reviewing content from a second connection) is updated immediately.
The idea of using the transaction in a manual way leads to the same result:
public void transactionalCreation(){
Session s = em.unwrap(Session.class);
Session s2 = s.getSessionFactory().openSession();
s2.setFlushMode(FlushMode.MANUAL);
s2.getTransaction().begin();
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')").executeUpdate();
String x = "test";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','c','b')").executeUpdate();
String y = "test2";
s2.createSQLQuery("INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('c','b','a')").executeUpdate();
s2.getTransaction().commit();
s2.close();
}
In case you don't use container managed transactions then you need to add the transaction policy too:
#Stateful
#TransactionManagement(value=TransactionManagementType.CONTAINER)
#TransactionAttribute(value=REQUIRED)
I have only seen this phenomenon in two situations:
the DataSource is running in auto-commit mode, hence each statement is executed in a separate transaction
the EntityManager was not configured with #Transactional, but then only queries can be run since any DML operation would end-up throwing a transaction required exception.
Let's recap you have set the following Hibernate properties:
hibernate.current_session_context_class=JTA
transaction.factory_class=org.hibernate.transaction.JTATransactionFactory
jta.UserTransaction=java:comp/UserTransaction
Where the final property must be set with your Application Server UserTransaction JNDI naming key.
You could also use the:
hibernate.transaction.manager_lookup_class=org.hibernate.transaction.JBossTransactionManagerLookup
or some other strategy according to your current Java EE Application Server.
After reading about the topic for another bunch of hours while playing around with every configuration property and/or annotation I could find a working solution for my usecase. It might not be the best or only solution, but since the question has received some bookmarks and upvotes, i'd like to share what i have so far:
At first, there was no way to get it working as expected when running the persistence-unit in managed mode. (<persistence-unit name="test" transaction-type="JTA"> - JTA is default if no value given.)
I decided to add another persistence-unit to the persistence xml, which is configured to run in unmanaged mode: <persistence-unit name="test2" transaction-type="RESOURCE_LOCAL">.
(Note: The waring about Multiple Persistence Units is just cause eclipse can't handle. It has no functional impact at all)
The unmanaged persitence-context requires local configuration of the database, since it is no longer container-provided:
<persistence-unit name="test2" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>test.AEntity</class>
<properties>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost/test"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5InnoDBDialect" />
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.password" value="1234"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.archive.autodetection" value="true" />
<property name="hibernate.jdbc.batch_size" value="20" />
<property name="hibernate.connection.autocommit" value="false" />
</properties>
</persistence-unit>
A change required to the project would now be, that you add an unitName, whenever you use the #PersistenceContext annotation to retrieve a managed instance of the EntityManager.
But be aware, that you can only use #PersistenceContext for the managed persistence-unit. For the unmanaged one, you could implement a simple Producer and Inject the EntityManager using CDI whenever required:
#ApplicationScoped
public class Resources {
private static EntityManagerFactory emf;
static {
emf = Persistence.createEntityManagerFactory("test2");
}
#Produces
public static EntityManager createEm(){
return emf.createEntityManager();
}
}
Now, in the example given in the original Post, you need to Inject the EntityManager and manually take care about transactions.
#Stateful
public class TestService {
#Inject
private EntityManager em;
public void transactionalCreation() throws Exception {
em.getTransaction().begin();
try {
em.createNativeQuery(
"INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','a')")
.executeUpdate();
em.createNativeQuery(
"INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','b')")
.executeUpdate();
em.createNativeQuery(
"INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','c')")
.executeUpdate();
em.createNativeQuery(
"INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','d')")
.executeUpdate();
AEntity a = new AEntity();
a.setName("TestEntity1");
em.persist(a);
// force unique key violation, rollback should appear.
// em.createNativeQuery(
// "INSERT INTO `ttest` (`name`,`state`,`constraintCol`)VALUES('a','b','d')")
// .executeUpdate();
em.getTransaction().commit();
} catch (Exception e) {
em.getTransaction().rollback();
}
}
}
My tests so far showed that mixing of native queries and persistence calls lead to the desired result: Either everything is commited or the transaction is rolledback as a whole.
For now, the solution seems to work. I will continue to validate it's functionality in the main project and check if there are any other sideeffects.
Another thing I need to verify is if it would be save to:
Inject both Versions of the EM into one Bean and mix usage. (First checks seem to work, even when using both ems at the same time on the same table(s))
Having both Versions of the EM operating on the same datasource. (Same data source would most likely be no problem, same tables I assume could lead to unexpected problems.)
ps.: This is Draft 1. I will continue to improve the answer and point out problems and/or drawbacks I'm going to find.
You have to add <hibernate.connection.release_mode key="hibernate.connection.release_mode" value="after_transaction" /> to your properties. After a restart should the Transaction handling work.

Container-managed EntityManager: multiple managers for single persistence unit?

I have a use-case where I think I need two entity managers, that access the same persistence unit. So essentially I want two persistence contexts on the same database. Is this possible via #PersistenceContext annotations?
I want to write something like the following, but don't know how to tell JPA to inject two different manager instances.
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#PersistenceContext(type = PersistenceContextType.EXTENDED)
private EntityManager otherEntityManager;
I think I could switch to application-managed transactions, then I could just create another one using a factory. But I don't want to manage the transactions by myself, if it's not absolutely necessary.
There is some ambiguity in your statement. Are you constrained by using only one 'Persistent Unit'? It is not same as Constrained by using Single Datasource.
You can create multiple persistent units for a single datasource. So, if you are not constrained by the number of persistent units you can create, You can in persistence.xml declare 2 persistent units for the same datasource like below
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0"
xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
<persistence-unit name="PU1"
transaction-type="JTA">
<jta-data-source>jdbc/myDS</jta-data-source>
<!-- Other properties -->
</persistence-unit>
<persistence-unit name="PU2"
transaction-type="JTA">
<jta-data-source>jdbc/myDS</jta-data-source>
<!-- Other properties -->
</persistence-unit>
</persistence>
Then, you can create 2 entitymanagers like below
#PersistenceContext(unitName="PU1", type = PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#PersistenceContext(unitName="PU2", type = PersistenceContextType.EXTENDED)
private EntityManager otherEntityManager;
Hope this helps.

Hibernate EntityManager, is it supposed to be used as a singleton?

I am not using Spring so I am creating an instance of EntityManager within a class.
I used Hibernate-Eclipse reverse engineering to auto-generate the classes. These classes all has an instance of EntityManager.
I am not 100% sure how Hibernate works with the EntityManager so I am wondering if it is okay that so many instances of this class (EntityManager) are made, for example, will there be problems with transactions?
Should I just make a separate class that distributes a static instance of an EntityManager for all my other classes? or does it not matter?
EDIT: I see there's something called #PersistenceContext, it doesn't seem to load my persistence.xml as a bean in to the instance variable, does this feature require spring? (I get null pointer exception, because it was never injected)
snip of code from where I attempt to use #persistencecontext
#PersistenceContext(unitName = "manager1")
private EntityManager entityManager;
my persistence.xml
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0">
<persistence-unit name="manager1" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.password" value="mypassword"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost/ptbrowserdb"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
</properties>
</persistence-unit>
</persistence>
See this Article: JPA Architecture it explain it very well.
In General you need a single Entity Manager per transaction. And this Entity Manager must not be used in two transactions at the same time.
Clairification: I mean, do not use a single Entity Manager for different unit of works. Typical one transaction in one unit of work, if you have different transactions of one unit of work, then you can use the same Entity Manager
If you use Spring then Spring do this handling for you if you use the #PersistenceContext annotation to inject the EntityManager. Per default Spring "bind" the the injected EntityManager (via a proxy) to the current transaction. (And the transaction is "bound" to the thread.)
#See Spring Reference 13.5.2 Implementing DAOs based on plain JPA - it contains a interesting paragagraph after the code examples.
You need a dependency injection framework like Spring or Google Guice to inject objects into your class otherwise it may not be injected automatically for you.
Basically this is an annotation provided by JPA which will work with in tandem with hibernate or any other ORM framework per say but you need a DI framework to inject the objects.
Regarding the single instance of entity manager i don't think you need that if you go by Spring since it takes care of managing the instances and the transactions for you by tying your entity manager with the jpa transaction.

Categories

Resources