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.
Related
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
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
Update: It seems it's failing after one insert, #412, fails a not null constraint at the database level. The transaction is probably rolling itself back. Given this setup, is it possible to get a new transaction established?
I'm trying to insert a lot of rows into my oracle database, and JPA works just fine until about the 400th insert. I expect to have several thousand rows to insert.
Here's my psuedo-code (shortened for clarity) & persistence.xml:
#Stateless
public class LocalContentService
{
#Inject EntityManager em;
public void mySavingMethod(){
for(Foo foo : fooDao.fetchAllFoos()){
Bar bar = new Bar(foo);
em.persist(bar);
em.flush();
em.clear();
log.debug("Saved content for: " + bar.getId());
}
}
<persistence-unit name="databaseTest" >
<jta-data-source>java:/jdbc/testDS</jta-data-source>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<class>org.myorg.Bar</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect" />
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.format_sql" value="false" />
<property name="hibernate.use_sql_comments" value="true" />
</properties>
</persistence-unit>
After roughly 400 rows, I get this error message and all subsequent inserts fail:
ERROR [stderr] (http--127.0.0.1-8080-1)
javax.persistence.TransactionRequiredException: JBAS011469:
Transaction is required to perform this operation (either use a
transaction or extended persistence context)
So my question is two fold
1) What on earth happened to my transaction midway through the process? Can it be avoided?
2) Is there a better approach to doing a bulk insert like this one (keeping in mind that i'm loading a bunch of Foo's and they need to be transformed into Bar's before persisting.
I'm running inside a jBoss 7.1.1.Final AS and hibernate-jpa-2.0-api
I have Hsqldb 1) in memory
<jdbc:embedded-database id="idtSimulatorDataSource" type="HSQL">
<jdbc:script location="classpath:hsql/idt_schema.sql"/>
</jdbc:embedded-database>
2) on server-mode
<bean id="idtSimulatorDataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbc.JDBCDriver"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="url" value="jdbc:hsqldb:hsql://localhost:9001/idt_simulatordb"/>
</bean>
1) all works properly
2) can't create schema. If I create schema manually, then hibernate create all necessary DDL manipulations and everethyng works properly too.
But I don't know where should I assign property for db initialization script
Here are my persistence file
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="IDTSimulator" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.nxsystems.simulator.idt.domain.IDTAccount</class>
<class>com.nxsystems.simulator.idt.domain.IDTCard</class>
<class>com.nxsystems.simulator.idt.domain.IDTCurrency</class>
<class>com.nxsystems.simulator.idt.domain.IDTCardHolder</class>
<class>com.nxsystems.simulator.idt.domain.IDTProgram</class>
<class>com.nxsystems.simulator.idt.domain.IDTTransaction</class>
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<!-- -->
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
<property name="hibernate.default_schema" value="simulators"/>
<!-- -->
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<!-- -->
<property name="hibernate.cache.use_second_level_cache" value="true"/>
<property name="hibernate.cache.use_query_cache" value="false"/>
<property name="hibernate.cache.region.factory_class" value="net.sf.ehcache.hibernate.EhCacheRegionFactory"/>
<!-- -->
<!--<property name="hibernate.hbm2ddl.auto" value="create"/>-->
<property name="hibernate.hbm2ddl.auto" value="create-drop"/>
<property name="hibernate.connection.pool_size" value="10"/>
</properties>
</persistence-unit>
</persistence>
And here are my init file script
DROP SCHEMA IF EXISTS simulators CASCADE;
CREATE SCHEMA SIMULATORS AUTHORIZATION SA -- not work yet
CREATE TABLE SIMULATORS.dirtyhack();
Maybe it would be better to create schema automatically, but I don't know how
UPDATE
I've founf how to launch db init script:
jdbc:initialize-database data-source="idtSimulatorDataSource">
Also I set
<property name="hibernate.hbm2ddl.auto" value="create"/>
But now I've got following error:
11:15:57,337 WARN (main) [JDBCExceptionReporter] SQL Error: -5501, SQLState: 42501
11:15:57,370 ERROR (main) [JDBCExceptionReporter] user lacks privilege or object not found: IDT_CARD
http://publib.boulder.ibm.com/iseries/v5r1/ic2924/index.htm?info/rzala/rzalastc.html
SQLSTATE Value: 42501
Meaning: The authorization ID does not have the privilege to perform the specified operation on the identified object.
What are privileges ?????
UPDATE:
Now I'm really confused.
I look into log. And see following:
/C2/SET SCHEMA PUBLIC DROP SCHEMA IF EXISTS simulators CASCADE
CREATE SCHEMA SIMULATORS AUTHORIZATION SA CREATE TABLE
SIMULATORS.dirtyhack() DISCONNECT /C3/SET SCHEMA PUBLIC DISCONNECT
/C4/SET SCHEMA PUBLIC DROP SCHEMA IF EXISTS simulators CASCADE
CREATE SCHEMA SIMULATORS AUTHORIZATION SA DISCONNECT /C5/SET SCHEMA
PUBLIC DISCONNECT /C6/SET SCHEMA PUBLIC
But I recently changed my init script:
DROP SCHEMA IF EXISTS simulators CASCADE;
CREATE SCHEMA SIMULATORS AUTHORIZATION sa -- not work yet
CREATE TABLE SIMULATORS.dirtyhack1();
Where is my dirtyhack1 () table???
I deleted all mentions about previous launches
UPDATE
I've found the reason.
This block is executed after Hibernate create its DDL manipulations:
<jdbc:embedded-database id="idtSimulatorDataSource" type="HSQL">
<jdbc:script location="classpath:hsql/idt_schema.sql"/>
</jdbc:embedded-database>
And my code contains such lines:
public static Server server = new Server();
#AfterClass
public static void tearDown1() throws Exception {
server.shutdown();
}
#BeforeClass
public static void setUp() throws Exception {
HsqlProperties p = new HsqlProperties();
p.setProperty("server.database.0", "file:./idt_simulatordb");
p.setProperty("server.dbname.0", "idt_simulatordb");
p.setProperty("server.port", "9001");
server.setProperties(p);
server.start();
Connection conn = DriverManager.getConnection("jdbc:hsqldb:hsql://localhost:9001/idt_simulatordb", "sa", "");
conn.setAutoCommit(true);
Statement st = conn.createStatement(); // statements
String expression1 = "DROP SCHEMA IF EXISTS simulators CASCADE;\n";
(1)String expression2 = "CREATE SCHEMA SIMULATORS AUTHORIZATION SA;";
String expression3 = "CREATE TABLE SIMULATORS.dirtyhack1();";
st.executeUpdate(expression1); // run the query
st.executeUpdate(expression2); // run the query
st.executeUpdate(expression3); // run the query
st.close();
conn.close();
}
That's why I didn't find my dirtyhack1 table, and that's why I got error. Init-database just removed my simulators schema
So there is a question. How to launch init script before Hibernate? Cause if I wouldn't write line (1) then I get error about wrong schema export
You could use the Spring EmbeddedDatabaseBuilder to create the database. Something like this:
new EmbeddedDatabaseBuilder().addScript("classpath:hsql/idt_schema.sql").build();
Then you don't need Hibernate to create the schema for you because it will already exist.
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.