Changing Persistence Unit dynamically - JPA - java

Persistence units in persistence.xml are created during building the application. As I want to change the database url at runtime, is there any way to modify the persistence unit at runtime? I supposed to use different database other than pre-binded one after distributed.
I'm using EclipseLink (JPA 2.1)

Keep the persistence unit file (Persistence.xml) as it's. You can override the properties in it as follows.
EntityManagerFactory managerFactory = null;
Map<String, String> persistenceMap = new HashMap<String, String>();
persistenceMap.put("javax.persistence.jdbc.url", "<url>");
persistenceMap.put("javax.persistence.jdbc.user", "<username>");
persistenceMap.put("javax.persistence.jdbc.password", "<password>");
persistenceMap.put("javax.persistence.jdbc.driver", "<driver>");
managerFactory = Persistence.createEntityManagerFactory("<current persistence unit>", persistenceMap);
manager = managerFactory.createEntityManager();

You can use Persistence.createEntityManagerFactory(Map) to pass properties to choose the database URL and other settings.

In Long-lived Session Architecture you should create a Plug-in-Framework.
Therefore you need to create a different Thread-Group and Class-Repository.
This might be your Class-Loader-Tree
System-Class-Loader (usually a URLClassLoader, contains the Entitys)
JPA-Class-Loader
Load your jpa.jar with persistence.xml inside, specify the Database-Configuration from Application-Class-Loader
Instanciate your entityManager/session-factory.
Load any plugin you need to work with the DataBase. Execute Unit-Tests (;D) and Plugin-Integration-Tests.

If you are using Thorntail framework, you can wire-up the persistence.xml file to fetch runtime variables from "project-defaults.yml" file.
<persistence-unit name="java:jboss/datasources/my-postgres-ds">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.package.jpa.EntityClass1</class>
<class>com.package.jpa.EntityClass2</class>
<class>com.package.jpa.EntityClass3</class>
<properties>
<property name="hibernate.archive.autodetection" value="class"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect"/>
<property name="hibernate.connection.url"
value="${thorntail.datasources.data-sources.my-postgres-ds.connection-url}"/>
<property name="hibernate.connection.username"
value="${thorntail.datasources.data-sources.my-postgres-ds.user-name}"/>
<property name="hibernate.connection.password"
value="${thorntail.datasources.data-sources.my-postgres-ds.password}"/>
<property name="hibernate.default_schema" value="public"/>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
Take note of the dynamic DB values in ${...} as the point to values in the project-default.yml file.
Then you project-defaults.yml file will have an entry like this:
thorntail:
http:
port: 8989
datasources:
data-sources:
my-postgres-ds:
driver-name: my-postgres-driver
connection-url: "jdbc:postgresql://localhost:5432/my-db-name"
user-name: my-user-name
password: "my-password#"
jdbc-drivers:
my-postgres-driver:
driver-module-name: org.postgresql
driver-xa-datasource-class-name: org.postgresql.xa.PGXADataSource
I expect this should also work for Spring boot using application.properties and persistence.xml

Related

Retrieve information from existing database using JPA

I'm developing a Java Web Project using JPA (EclipseLink) to connect with our databases. I have a persistence unit where I configured the database where my data is going to persisted. The question is that I also have to access another database that is already created and populated with info, and I just want to access one table of this database to retrieve some information. How can I access it using JPA just to retrieve info (neither save nor update anything).
After setting up your entity managers you can just run a native query :
entityManager.createNativeQuery("SELECT ...");
So, you can create another persistent-unit poiting to your other database
<persistence-unit name="read-and-write-database">
...
<properties>
<!-- conection -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/database-write" />
<.../>
</properties>
</persistence-unit>
<persistence-unit name="read-database">
...
<properties>
<!-- conection -->
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/database-read" />
<.../>
</properties>
</persistence-unit>
And, in a SE environment, you would something like that to create the EntityManager:
EntityManagerFactory readWriteEntityManagerFactory = Persistence.createEntityManagerFactory("read-and-write-database");
EntityManager readWriteEntityManager = readWriteEntityManagerFactory.createEntityManager();
EntityManagerFactory readEntityManagerFactory = Persistence.createEntityManagerFactory("read-database");
EntityManager readEntityManager = readEntityManagerFactory.createEntityManager();
if you are in a container, the PersistenceContext anotation have the unitName field that you can use to define the persistente-unit
Keep in mind that by doing that, you will have two different persistence context. So, changes made in one of then, not gonna be "visiable" to the other one until the persistence of the data.
obs: sorry any typo.
I hope this helps you.
Cheers

Hibernate - H2 database is not created

I want to use Hibernate with H2 and I want the schema to be created automatically. There are many examples online and my configurations seem fine, but it is not created. Previously I used it with MySQL and did not have any problem. Are there additional parameters to be included in anywhere for H2?
My persistence unit is defined in persistence.xml as follows:
<persistence-unit name="some.jpa.name"
transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<!-- tried with and without class property
<class>some.package.KeywordTask</class>
-->
<properties>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:h2:./test" />
<property name="javax.persistence.jdbc.user" value="" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="show_sql" value="true" />
</properties>
</persistence-unit>
Since show_sql is set to true, I expect to see create statements but nothing happens, i.e. the schema is not created.
I keep my EntityManagerFactory as a final static variable:
public static EntityManagerFactory emf = Persistence.createEntityManagerFactory("some.jpa.name");
In some place in my code, I am trying to persist an entity:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
KeywordTask task = new KeywordTask();
task.setKeyword(keywordTask.getKey());
task.setLimit(keywordTask.getValue());
em.persist(task);
em.getTransaction().commit();
em.close();
This throws exception with cause:
org.h2.jdbc.JdbcSQLException: Table "KEYWORDTASK" not found;
which is expected since the schema is not created.
How can I get the schema created?
The reason of this problem was quite unrelated! I am writing it here in case some other guys might face it too, and spend half a day for such a stupid thing.
First, I changed from H2 to Derby to check, and it worked. In this way, I was sure that there was no problem with persistence.xml configuration.
After searching around the logs, I realized that hibernate was not able to create the table since one of the properties of the KeywordTask entity was limit, and it is a reserved word! (Remember the place that I persist an instance and observe the name of the setter: setLimit.) After changing the name of the property, it worked.

Spring Bootstrap Context for dropping Tables should they exist

I am trying to create an application bootstrap that will drop all the tables in the application if they exist and then intialise them with fresh data.
I have created a Spring Context that loads the datasource context - however I dont know how to override the initialisation of the datasource such that the behaviour can be customised depending on how the datasource is loaded. So.. using Hibernate as my JPA implementation..
If the datasource is loaded from the application - then I would like the schemas to update:
<persistence-unit name="myDB" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
If the datasource is loaded from the bootstrap - then I need to overload this behaviour somehow so that the database is always created from scratch before fresh data is loaded:
<persistence-unit name="myDB" transaction-type="RESOURCE_LOCAL">
<properties>
<property name="hibernate.hbm2ddl.auto" value="create"/>
</properties>
</persistence-unit>
The approach I have been taking doesn't work as I would load the datasource using the 'update' setting and then drop the tables if they exist before attempting to load new data. However - the tables no longer exist for writing data !
Thanks in advance
Simon
You can pass JPA properties from Spring configuration instead of persistance.xml and use placeholder that can be configured by PlaceholderConfigurer (possibly system-properties="OVERRIDE"), or Spring profiles (since 3.1) or using Maven filtering:
<util:map id="jpaPropertyMap" key-type="java.lang.String" value-type="java.lang.Object">
<entry key="hibernate.hbm2ddl.auto" value="${database.ddl.mode}" />
</util:map>
<bean id="managementEntityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource"
p:jpaPropertyMap-ref="jpaPropertyMap" />

JPA No Persistence provider for EntityManager

I know there are some other questions on this subject, but none of the answers worked.
I am new to JPA and I am using EclipseLink as implementation and Eclipse as IDE.
This is my persistence.xml (it is in META-INF folder):
<?xml version="1.0" encoding="UTF-8" ?>
<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" xmlns="http://java.sun.com/xml/ns/persistence">
<persistence-unit name="DBService" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.maze.model.EventModel</class>
<class>com.maze.model.StoryModel</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/mazedb;create=true" />
<property name="javax.persistence.jdbc.user" value="user" />
<property name="javax.persistence.jdbc.password" value="pass" />
<!-- EclipseLink should create the database schema automatically -->
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode" value="database" />
</properties>
</persistence-unit>
</persistence>
and here I am trying to get an EntityManagerFactory
private EntityManagerFactory emf;
emf = Persistence.createEntityManagerFactory("DBService");
At runtime, I get this error:
javax.persistence.PersistenceException: No Persistence provider for EntityManager named DBService
I have followed the steps from tutorials, but no results...
Edit: I have also added into WEB-INF/lib these jars: eclipselink.jar; javax.persistence_2.0.3.v201010191057.jar; mysql-connector-java-5.1.17-bin.jar, added JPA to the Project Facets but no have seen no results yet...
put your persistence.xml in the META-INF directory of your war file. Also, put a copy in your lib directory and the classes directory.
I am using eclipselink at work, using a standalone jar package that contains my entity classes, a MET-INF directory with the persistence.xml and it works fine.
Probably you need to make a jar file containing the entity classes, plus a MET-INF/persistence.xml, and add this jar file to your lib directory, alongside the eclipselink.jar.
The other thing to check is the RESOURCE-LOCAL, you should use this if you are using JPA in a web-app, with no entity beans components, or in a standalone application.
You must put your persistence.xml in the META-INF and write persistence.xml with Lowercase letter.
I think you wrote first letter or some letter with Capital letter and i have this error too.
You must write exactly like this: persistence.xml

javax.persistence.PersistenceException: No Persistence provider for EntityManager named customerManager

I am new to JPA & Hibernate. After reading some online materials I now understand what Hibernate is and how it can be used with JPA.
Now, I am trying to run this JPA & Hibernate tutorial. I've done everything they mention in this tutorial.
I don't have Oracle DB, only MySQL. So I made some changes to persistence.xml using my understanding of JPA & Hibernate (I don't know if it's correct or not... Seems to me it is.)
Here is 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_1_0.xsd" version="1.0">
<persistence-unit name="customerManager" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>Customer</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="1234"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/general"/>
<property name="hibernate.max_fetch_depth" value="3"/>
</properties>
</persistence-unit>
</persistence>
But I don't seem to get the output they describe. It's giving me:
Customer id before creation:null
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" javax.persistence.PersistenceException: No Persistence provider for EntityManager named customerManager
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:55)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:33)
at CustomerDAO.create(CustomerDAO.java:8)
at CustomerDAO.main(CustomerDAO.java:22)
Any suggestions will be appreciated.
Update:
I have made the changes that are asked to done. But, still getting the asme error lines!!!
They didnt mentioned anything about orm.xml in that tutorial. may it be a problem causer!!!
Just for completeness. There is another situation causing this error:
missing META-INF/services/javax.persistence.spi.PersistenceProvider
file.
For Hibernate, it's located in hibernate-entitymanager-XXX.jar, so, if hibernate-entitymanager-XXX.jar is not in your classpath, you will got this error too.
This error message is so misleading, and it costs me hours to get it correct.
See JPA 2.0 using Hibernate as provider - Exception: No Persistence provider for EntityManager.
Your persistence.xml is not valid and the EntityManagerFactory can't get created. It should be:
<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_1_0.xsd" version="1.0">
<persistence-unit name="customerManager" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>Customer</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLInnoDBDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value="1234"/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/general"/>
<property name="hibernate.max_fetch_depth" value="3"/>
</properties>
</persistence-unit>
</persistence>
(Note how the <property> elements are closed, they shouldn't be nested)
Update: I went through the tutorial and you will also have to change the Id generation strategy when using MySQL (as MySQL doesn't support sequences). I suggest using the AUTO strategy (defaults to IDENTITY with MySQL). To do so, remove the SequenceGenerator annotation and change the code like this:
#Entity
#Table(name="TAB_CUSTOMER")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="CUSTOMER_ID", precision=0)
private Long customerId = null;
...
}
This should help.
PS: you should also provide a log4j.properties as suggested.
I had the same problem today. My persistence.xml was in the wrong location. I had to put it in the following path:
project/src/main/resources/META-INF/persistence.xml
I was facing the same issue. I realised that I was using the Wrong provider class in persistence.xml
For Hibernate it should be
<provider>org.hibernate.ejb.HibernatePersistence</provider>
And for EclipseLink it should be
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
If you use Hibernate 5.2.10.Final, you should change
<provider>org.hibernate.ejb.HibernatePersistence</provider>
to
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
in your persistence.xml
According to Hibernate 5.2.2: No Persistence provider for EntityManager
If you are using Maven you may have both src/{main,test}/resources/META-INF/persistence.xml. This is a common setup: test your JPA code with h2 or Derby and deploy it with PostgreSQL or some other full DBMS. If you're using this pattern, do make sure the two files have different unit names, else some versions of the Persistence class will try to load BOTH (because of course your test-time CLASSPATH includes both classes and test-classes); this will cause conflicting definitions of the persistence unit, resulting in the dreaded annoying message that we all hate so much!
Worse: this may "work" with some older versions of e.g., Hibernate, but fail with current versions. Worth getting it right anyway...
A bit too late but I got the same issue and fixed it switching schemalocation into schemaLocation in the persistence.xml file (line 1).
I have seen this error , for me the issue was there was a space in the absolute path of the persistance.xml , removal of the same helped me.
I was also facing the same issue when I was trying to get JPA entity manager configured in Tomcat 8. First I has an issue with the SystemException class not being found and hence the entityManagerFactory was not being created. I removed the hibernate entity manager dependency and then my entityManagerFactory was not able to lookup for the persistence provider. After going thru a lot of research and time got to know that hibernate entity manager is must to lookup for some configuration. Then put back the entity manager jar and then added JTA Api as a dependency and it worked fine.
my experience tells me that missing persistence.xml,will generate the same exception too.
i caught the same error msg today when i tried to run a jar package packed by ant.
when i used jar tvf to check the content of the jar file, i realized that "ant" forgot to pack the persistnece.xml for me.
after I manually repacked the jar file ,the error msg disappered.
so i believe maybe you should try simplely putting META-INF under src directory and placing your persistence.xml there.

Categories

Resources