I've created a new project on my IntelliJ IDEA, using hibernate (+ hibernate entitymanager) 5, hsqldb 1.8 (for testing only), as well as junit 4.
I've got my test class
UserRoundRelationsTest
EntityManagerFactory emf;
EntityManager em;
Date currentDate;
User user;
Round round1;
Round round2;
And some #After and #Before methods:
#Before
public void saveDummyUserAndTwoDummyRounds() {
emf = Persistence.createEntityManagerFactory("testPersistence");
em = emf.createEntityManager(); // Retrieve an application managed entity manager
currentDate = new Date();
user = new User.UserBuilder("alias").fullName("Full Name").phoneNumber("Phone Number").height(100).weight(100).birthDate(currentDate).build();
round1 = new Round(new GameMode(1, ButtonTargetStrategy.RANDOM, ButtonSkipStrategy.SKIP_ON_MISTAKE));
round2 = new Round(new GameMode(2, ButtonTargetStrategy.RANDOM, ButtonSkipStrategy.SKIP_ON_MISTAKE));
round1.setUser(user);
round2.setUser(user);
HashSet<Round> rounds = new HashSet<Round>(2);
rounds.add(round1);
rounds.add(round2);
em.getTransaction().begin();
user.setRounds(rounds);
em.persist(user);
em.persist(round1);
em.persist(round2);
em.flush();
em.getTransaction().commit();
}
and
#After
public void deleteData() {
em.remove(user);
em.remove(round2);
em.remove(round2);
em.getTransaction().commit();
em.close();
emf.close();
}
Firstly, when I try to run the test, hibernate can't find the tables for User and Round classes, as well as everything they are dependent on (a class called ButtonPress for example). I assume this happens due to the automatic create-drop I have configured at my persistence.xml
<persistence-unit name="testPersistence">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<class>com.carloworks.model.User</class>
<class>com.carloworks.model.Round</class>
<class>com.carloworks.model.ButtonPress</class>
<properties>
<!--<property name="hibernate.archive.autodetection" value="class,hbm"></property>-->
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"></property>
<property name="hibernate.show_sql" value="true"></property>
<property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"></property>
<property name="hibernate.connection.username" value="sa"></property>
<property name="hibernate.connection.password" value=""></property>
<property name="hibernate.connection.url"
value="jdbc:hsqldb:mem:buttonMasherModelsTestDb;MV_STORE=FALSE;MVCC=FALSE"></property>
<!--<property name="hibernate.default_schema" value="buttonMasherModelsTestDb"/>-->
<property name="hibernate.hbm2ddl.auto" value="create-drop"></property>
</properties>
</persistence-unit>
Scrolling further down the error logs, I also get an error at this line:
em.persist(user);
null identifier (plus 'This function is not supported'/'GenericJDBCException: could not prepare statement').
What did I do wrong?
The project is also available on Github
Full Error Log
Changing the version to the latest one fixed the problem
*Some may experience a broken path error (caused by maven). If you are using intelliJ navigate to Project Settings -> Modules and Fix any problems under the "Problems" tab.
Related
I'm developing a multi-tenant web app with "Shared Database/Separate Schemas" approach using java, jpa(eclipselink), mysql. My persistence file looks like:
<persistence-unit name="GroupBuilderPU" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="eclipselink.cache.shared.default" value="false"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/?"/>
<property name="eclipselink.ddl-generation" value="create-or-extend-tables"/>
<--- Here goes other properties definition -->
</persistence-unit>
Now here is my EntityMangerFactory and EntityManager:
emfForTenant = Persistence.createEntityManagerFactory("GroupBuilderPU");
EntityManager em = emfForTenant.createEntityManager();
em.setProperty("eclipselink.tenant-id", schemaNameAsTenantId);
Its working fine untill I'm adding any new persistence column in any entity.
Like I've a Entity UserAccount where I've added a new column 'String rentalinfo' :
#Entity
#Multitenant(MultitenantType.TABLE_PER_TENANT)
#TenantTableDiscriminator(type = TenantTableDiscriminatorType.SCHEMA, contextProperty = PersistenceUnitProperties.MULTITENANT_PROPERTY_DEFAULT)
public class UserAccount implements Serializable {
...
private String rentalinfo;//Newly added column
...
}
Now after that this the following line is giving error:
em.createQuery("SELECT ua FROM UserAccount ua").getResultList();
The error is:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'RENTALINFO' in 'field list'
So what will be the solution for adding new column (extend table) in this approach?
You are getting this exception because the 'RENTALINFO' column does not exist on your UserAccount table. Under normal circumstances, setting "create-or-extend-tables" will have EclipseLink issue an ALTER to your existing table, adding the new column. However, it would appear ddl generation is not supported for MultitenantType.TABLE_PER_TENANT: https://wiki.eclipse.org/EclipseLink/DesignDocs/Multi-Tenancy/TablePerTenant
Not supported:
Schema generation will not be supported since it requires knowledge of all the tenants (schema's) and further to that, access provision must be set once the tables are created if using schema level table per tenant.
So there is no ALTER and your table does not have the column.
As a side note, you can turn on EclipseLink SQL logging using the following persistence properties:
<properties>
<property name="eclipselink.logging.level" value="ALL"/>
<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>
</properties>
This way, you can see what queries EclipseLink is (or in this case, isn't) executing.
My application is running perfectly fine in JBoss AS 5.1.0. My goal is to migrate it to Wildfly 10.
Below is my persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="ApplicationPersistenceUnit">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MySQL_DS</jta-data-source>
<jar-file>application_db_interface.jar</jar-file>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="jboss.entity.manager.jndi.name" value="java:/ApplicationPersistenceUnit"/>
<property name="jboss.entity.manager.factory.jndi.name" value="java:/ApplicationPersistenceUnitFactory"/>
</properties>
</persistence-unit>
</persistence>
Below is my transaction manager class;
public class TransactionManager implements TransactionManagerI {
#PersistenceContext(unitName="ApplicationPersistenceUnit")
private EntityManager em;
...
}
I also try to use lookup but it still returns null;
public Session getSession() throws DAOException {
..
em = (EntityManager) new InitialContext().lookup("java:/ApplicationPersistenceUnit");
..
}
Below is the project schema;
->application.ear
->application.ear/application.war
->application.ear/db.jar
->application.ear/db.jar/META-INF/persistence.xml
I looked into other solutions and try one by one but couldn't figure out mine yet. I can provide more info if you need.
UPDATE: I check JNDI view from wildfly admin console. I don't see ApplicationPersistenceUnit there. It looks like server doesn't bind my persistence.xml file. I am now trying to figure out this problem.
I'm new in JavaEE. I'm trying to make webapp using JPA with DAO and Service layer. Part of the task is not to use Spring and Hibernate. So i can use only JPA.
As i understand, Service and Dao should be a Singletones. I should get EntityManager on each database operation, and close it after. I'm using GenericDao for some operation, and EntityManager is needed in Dao, as a field.
How to use it? How can i get entityManager in Service, start transaction in service, and pass it inside the DAO implementation?
Here's example of my DAO interface.
public interface GenericDAO<T> {
void save(T entity);
void merge(T entity);
void delete(T entity);
...
}
I can get EntityManager in Service. In implementation all these method's will be using EntityManager. So i need it there as a field.
So how can i pass EntityManager in my DAO implementation and still make all this construction thread safe?
I don't think make inerface method like this is a good idea:
void save(T entity, EntityManager entityManager);
void merge(T entity, EntityManager entityManager);
EntityManager without Hibernate? What will make the ORM to it? Maybee you should use JDBC in the DAL instead of the EntityManager without Hibernate.
Using only JPA is a good goal. Spring has been around a long time and has a very vendor specific implementation of data repositories. Hibernate is much closer to JPA (in my opinion), but is also quite specific. The EntityManager is effectively a generic DAO as you describe it. It has persist, merge, find, and delete methods, as well as many others.
In order to learn JPA a bit you can create a simple project with a simple entity and go from there. I have many such "playground" projects, but my simplest one is courtesy of Geoffroy Warin
A main App class:
public class App {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("persistence");
EntityManager em = emf.createEntityManager();
try {
EntityTransaction tx = em.getTransaction();
tx.begin();
User user = new User();
em.persist(user);
tx.commit();
System.out.println("user=" + user);
User found = em.find(User.class, 1L);
System.out.println("found=" + found);
} finally {
emf.close();
}
}
}
A simple User entity:
#Entity
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
public Long getId() { return id; }
#Override
public String toString() {
return "User:"+id;
}
}
and a persistence.xml (goes in resources/META-INF directory):
<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="persistence" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>model.User</class>
<properties>
<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:mem:standalone" />
<property name="javax.persistence.jdbc.user" value="sa" />
<property name="javax.persistence.jdbc.password" value="" />
<property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" />
<property name="hibernate.hbm2ddl.auto" value="create" />
<property name="hibernate.show_sql" value="true" />
</properties>
</persistence-unit>
</persistence>
And, of course, a POM file to bring in all the dependencies.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>jpa-playground</groupId>
<artifactId>jpa-playground</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>4.3.11.Final</version>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.2.9</version>
</dependency>
</dependencies>
</project>
Figure out how to put all this together and you can play with JPA to your hearts content. Note that is uses Hibernate as the JPA provider, but it does not use any hibernate specific constructs.
Creating a service layer is usually done with EJB's, e.g., stateless and statefull beans, and for that you need a container like Wildfly or Tomcat EE, among others. However, you can simulate them by creating a class called ServiceLayer and putting methods like createUser, changeUserName, removeUser and things like that in it. It would use the EntityManager on behalf of the application.
I'm using Hibernate's JPA-Implementation to access our SQL Server 2012 database.
When trying to select a nvarchar field in a native query, I get an exception "No Dialect mapping for JDBC type: -9".
It looks much like No Dialect mapping for JDBC type: -9 with Hibernate 4 and SQL Server 2012 or No Dialect mapping for JDBC type: -9 but I couldn't find a solution for me there (both are not using JPA).
My database setup:
CREATE TABLE NvarcharExample(
exampleField nvarchar(20) PRIMARY KEY
)
INSERT INTO NvarcharExample(exampleField) VALUES ('hello')
My code:
import java.io.IOException;
import javax.persistence.*;
#Entity
class NvarcharExample {
#Id
public String exampleField;
}
public class NvarcharTest {
public static void main(String[] args) throws IOException, InterruptedException {
String queryString = "SELECT e.exampleField FROM NvarcharExample e";
// establish connection
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("persistenceUnit");
try {
EntityManager entityManager = entityManagerFactory.createEntityManager();
// access data using JPQL
entityManager.createQuery(queryString).getResultList(); // works
// access data using SQL (native query)
entityManager.createNativeQuery(queryString).getResultList(); // fails
} finally {
entityManagerFactory.close();
}
}
}
My persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="persistenceUnit">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
<properties>
<!-- database connection settings -->
<property name="javax.persistence.jdbc.driver" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" />
<property name="javax.persistence.jdbc.url" value="jdbc:sqlserver://<servername>:<port>;databaseName=<databasename>" />
<property name="javax.persistence.jdbc.user" value="<user>" />
<property name="javax.persistence.jdbc.password" value="<password>" />
</properties>
</persistence-unit>
</persistence>
With sql logging enable, I get this output in my console
select nvarcharex0_.exampleField as col_0_0_ from NvarcharExample nvarcharex0_
SELECT e.exampleField FROM NvarcharExample e
I'm using
hibernate-core-4.3.10.Final.jar
hibernate-entitymanager-4.3.10.Final.jar
hibernate-jpa-2.1-api-1.0.0.Final.jar
hibernate-commons-annotations-4.0.5.Final.jar
sqljdbc41.jar
What I've tried:
using a varchar instead of nvarchar makes it work, but I need nvarchar
using jpql instead of sql works (see my example code), but I need a native query
I tried sqljdbc4.jar in Version 4.0 and 4.1 and I tried sqljdbc41.jar
I head about subclassing the SQL Server Dialect class, but did not have any success with that
I added <property name="dialect" value="org.hibernate.dialect.SQLServerDialect" /> to my persistence.xml (right behind the password property)
I added <property name="hibernate.dialect" value="org.hibernate.dialect.SQLServerDialect" /> to my persistence.xml
I changed the persistence provider to <provider>org.hibernate.ejb.HibernatePersistence</provider>
Using #Nationalized attribute helped me to map String to nvarchar for MS SQL 2012 without dialect subclassing.
At the same time setting the hibernate.use_nationalized_character_data property to true did not worked for me.
For futher information watch docs National Character Types.
I was able to resolve that issue by subclassing the SQLServerDialect:
package packagename;
import java.sql.Types;
public class SqlServerDialectWithNvarchar extends org.hibernate.dialect.SQLServerDialect {
public SqlServerDialectWithNvarchar() {
registerHibernateType(Types.NVARCHAR, 4000, "string");
}
}
and referencing it in my persistence.xml:
<property name="hibernate.dialect" value="packagename.SqlServerDialectWithNvarchar" />
PS: It seems to be fixed with hibernate 5.1 according to this ticket: https://hibernate.atlassian.net/browse/HHH-10183
My application use JPA/hibernate to read data from database. The application is read only, and data is inserted by other program.
The problem is that my application can only read flesh data in the first time. When new data is inserted by other program, my application cannot see it.
Here is my test code:
public class TestJpaRead {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.hibernate.tutorial.jpa");
public static void main(String[] args) {
LOG.debug("first time");
countRow(); //output row size = X
//set break point here, and manually insert an new row by using mysql client
LOG.debug("second time");
countRow(); //should output row size = X + 1, but it is still X
}
public static void countRow() {
EntityManager em = emf.createEntityManager();
Query query = em.createQuery("SELECT a FROM " + Report.class.getSimpleName() + " a");
List result = query.getResultList();
LOG.debug("countRow: {}", result.size());
em.close();
}
}
and here is my persistence.xml (nothing special):
<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="org.hibernate.tutorial.jpa" transaction-type="RESOURCE_LOCAL">
<description>
Persistence unit for the JPA tutorial of the Hibernate Getting Started Guide
</description>
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/foo" />
<property name="javax.persistence.jdbc.user" value="root" />
<property name="javax.persistence.jdbc.password" value="bar" />
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.hbm2ddl.auto" value="auto" />
</properties>
</persistence-unit>
Thanks!
From MySQL query log, I find the reason of the problem:
48 Query SET autocommit=0
140606 11:35:41 48 Query select report0_.id from Report report0_ /*countRow()*/
48 Query SHOW WARNINGS
140606 11:35:42 48 Query select report0_.id from Report report0_ /*countRow()*/
48 Query SHOW WARNINGS
Hibernate does not work in the autocommit mode by default.
em.close() does not implicit commit or rollback the transaction, i.e., the JDBC connection and transaction is still alive/open.
This is what I misunderstood. (emf.close() will actually close the connection.)
When you get EntityManager from emf.createEntityManager(), the new
EntityManager may reuse old JDBC connection. It means that you may
in the transaction opened by previous closed EntityManager.
When you are in a uncommit/opened transaction, and use the default
MySQL isolation level, you cannot see change made by others.
Solution: explicit open and commit the transaction, or tell Hibernate to allow autocommitted JDBC connections. Refs: Select using hibernate