I've been trying to mess around with MongoDB and Hibernate in Java. I'm having some troubles with the configuration file for it.
I've already used Hibernate in the past with SQL DB, but it seems that the config file has to be quite different for MongoDB.
According to this documentation, it should looks something like this:
<?xml version="1.0" encoding="UTF-8"?>
<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="eshop" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<class>org.hsnr.rest.domain.entities.Address</class>
<class>org.hsnr.rest.domain.entities.Order</class>
<class>org.hsnr.rest.domain.entities.Person</class>
<class>org.hsnr.rest.domain.entities.Product</class>
<class>org.hsnr.rest.domain.entities.User</class>
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.JBossStandAloneJtaPlatform" />
<property name="hibernate.ogm.datastore.provider"
value="mongodb" />
</properties>
</persistence-unit>
</persistence>
However, when I try to create a session with
new Configuration().configure().buildSessionFactory();
I get a following error:
org.hibernate.internal.util.config.ConfigurationException: Unable to perform unmarshalling at line number 5 and column 28 in RESOURCE hibernate.cfg.xml. Message: cvc-elt.1: Cannot find the declaration of element 'persistence'.
Is my aproach wrong or is there something I overlooked?
You can try basic test set up like below for your config.
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory( "eshop" );
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.getTransaction().begin();
// perform operations here
entityManager.getTransaction().commit();
entityManager.close();
entityManagerFactory.close();
From the javadoc of configure():
Use the mappings and properties specified in an application resource
named hibernate.cfg.xml.
You are setting the persistence.xml instead. Using using javax.persistence.Persistence should work:
EntityManagerFactory emf = Persistence.createEntityManagerFactory( "eshop" );
If for some reason you need the session factory instead, but you are working with JPA, you can obtain it using the unwrap() method
SessionFactory sf = emf.unwrap( SessionFactory.class );
UPDATE:
You can also create the factory programmatically, there is a class OgmConfiguration (that extends Configuraiton):
OgmConfiguration configuration = new OgmConfiguration();
// This is optional, if you want to set some options using
// a fluent API
configuration.configureOptionsFor( MongoDB.class )
.writeConcern( WriteConcernType.UNACKNOWLEDGED );
SessionFactory sf = configuration
.addAnnotatedClass( org.hsnr.rest.domain.entities.Address.class )
// ... Other annotated classes
.setProperty( OgmProperties.DATABASE, "mongodb_database" )
.setProperty( OgmProperties.DATASTORE_PROVIDER, DatastoreProviderType.MONGODB.name() )
// All this properties are optional, appropriate default will be used if missing
.setProperty( OgmProperties.CREATE_DATABASE, "false" )
.setProperty( OgmProperties.USERNAME, "username" )
.setProperty( OgmProperties.PASSWORD, "password" )
.setProperty( OgmProperties.HOST, "localhost:12897" )
// Check MongoDBProperties for MongoDB specific options
.setProperty( MongoDBProperties.AUTHENTICATION_MECHANISM, AuthenticationMechanismType.BEST.name() )
.buildSessionFactory();
In this example I've added several options to give an overview but if you are using defaults and you don't need the authentication, only the database name and the datastore provider are needed
use bellow code :
<hibernate-configuration
xmlns="http://www.hibernate.org/xsd/hibernate-configuration"
xsi:schemaLocation="http://www.hibernate.org/xsd/hibernate-configuration hibernate-configuration-4.0.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
Related
I have an application running on Websphere Liberty which should compare tables from 2 databases/schemas.
The user should be able to input the connection data, like the host and the credentials.
I'm using Hibernate to access the application DB.
I've tried to use multiple Persistence Units, one for the application DB and one for all other DBs.
But i got 2 problems:
i get an "Illegal attempt to enlist multiple 1PC XAResources"
error sometimes
can query the 2 DBs with
user-submitted credentials, but i get no results except if i connect
to the same db listed in server.xml file as DataSource
This are the DataSources on the server.xml on the server (dbs are oracle dbs)
<dataSource id="MyAppDS" jndiName="jdbc/MyDS" type="javax.sql.ConnectionPoolDataSource">
<jdbcDriver javax.sql.ConnectionPoolDataSource="oracle.jdbc.pool.OracleConnectionPoolDataSource" libraryRef="OracleSQLLib"/>
<connectionManager agedTimeout="30m" connectionTimeout="10s" maxPoolSize="20" minPoolSize="5"/>
<properties password="..." url="jdbc:oracle:thin:#...:1521:..." user="..."/>
</dataSource>
<dataSource id="OtherOracle" jndiName="jdbc/OtherOracle" type="javax.sql.ConnectionPoolDataSource">
<jdbcDriver javax.sql.ConnectionPoolDataSource="oracle.jdbc.pool.OracleConnectionPoolDataSource" libraryRef="OracleSQLLib"/>
<connectionManager agedTimeout="30m" connectionTimeout="10s" maxPoolSize="20" minPoolSize="5"/>
<properties password="..." url="jdbc:oracle:thin:#127.0.0.1:1521:XE" user="..."/>
</dataSource>
This is persistence.xml on the EJB module
<?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="main-persistence">
<jta-data-source>jdbc/MyDS</jta-data-source>
<class>classes...</class>
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.Oracle9iDialect" />
<property name="hibernate.temp.use_jdbc_metadata_defaults"
value="false" />
</properties>
</persistence-unit>
<persistence-unit name="other-persistence" transaction-type="RESOURCE_LOCAL">
<non-jta-data-source>jdbc/OtherOracle</non-jta-data-source>
<class>classes...</class>
<properties>
<property name="hibernate.transaction.jta.platform"
value="org.hibernate.service.jta.platform.internal.WebSphereExtendedJtaPlatform" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.Oracle9iDialect" />
<property name="hibernate.temp.use_jdbc_metadata_defaults"
value="false" />
</properties>
</persistence-unit>
On the Java Bean i use the EntityManagerFactory
#PersistenceUnit(unitName = "other-persistence")
private EntityManagerFactory emf;
And i create the entity manager with custom credentials like this
Map<String, String> properties = new HashMap<String, String>();
properties.put("hibernate.connection.driver_class", "oracle.jdbc.OracleDriver");
properties.put("hibernate.connection.url", myCustomCreatedConnectionUrl);
properties.put("hibernate.connection.username", customUser);
properties.put("hibernate.connection.password", customPassword);
properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle9iDialect");
properties.put("hibernate.show-sql", "true");
EntityManager entityManager = emf.createEntityManager(properties);
If i check EntityManager properties with getProperties everything seems to be right. But the queries works only if the credentials/host are = to the DataSource. Otherwise i get no results (but no errors)
What could the problem be?
Is there a way to use just one Persistence Unit but with custom host/credentials for different queries?
Regarding the first error, ""Illegal attempt to enlist multiple 1PC XAResources", this occurs because you are using both resources within the same transaction. I can see <non-jta-data-source>jdbc/OtherOracle</non-jta-data-source> in your configuration, which indicates that you might have intended for jdbc/OtherOracle to be a non-enlisting resource. To make that work, the data source itself needs to be configured as non-enlisting. You can do this with the transactional="false" attribute as follows:
<dataSource id="OtherOracle" jndiName="jdbc/OtherOracle" type="javax.sql.ConnectionPoolDataSource" transactional="false">
...
On the other hand, if you actually want both resources to enlist in the transaction, then you need to use XADataSource rather than ConnectionPoolDataSource. Here is an example of how to do that (notice that both type type under dataSource and the attribute & class under jdbcDriver must be updated for this:
<dataSource id="MyAppDS" jndiName="jdbc/MyDS" type="javax.sql.XADataSource">
<jdbcDriver javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource" libraryRef="OracleSQLLib"/>
<connectionManager agedTimeout="30m" connectionTimeout="10s" maxPoolSize="20" minPoolSize="5"/>
<properties password="..." url="jdbc:oracle:thin:#...:1521:..." user="..."/>
</dataSource>
<dataSource id="OtherOracle" jndiName="jdbc/OtherOracle" type="javax.sql.XADataSource">
<jdbcDriver javax.sql.XADataSource="oracle.jdbc.xa.client.OracleXADataSource" libraryRef="OracleSQLLib"/>
<connectionManager agedTimeout="30m" connectionTimeout="10s" maxPoolSize="20" minPoolSize="5"/>
<properties password="..." url="jdbc:oracle:thin:#127.0.0.1:1521:XE" user="..."/>
</dataSource>
In the second question, I think you are saying the different users cannot see the data. Could this be because the different database users are using different schema and do not have access each others' data? If you can get all of the users using a common schema, then adding #Table(schema="YOUR_SCHEMA_NAME") to the JPA #Entity might help. JavaDoc for the Table annotation can be found here.
I have recently had the same request where a user can connect to application and enter their database details. From this point on every JPA Query is executed on this new connection.
The additional problem was that there were more than 100 bases to choose from and creating all datasources at start was not a good idea.
We have thus created a single RoutingDatasource that manages the JDBC connections. We were heavily inspired by Spring's implementation org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource.
The main idea is:
You extend AbstractDataSource and getConnection() method which is called on every JPA query. You are basically tinkering the JDBC layer under the JPA layer.
You then create a new datasource according to what your user entered
Set Your routing datasource as main datasource for your entity manager
Optionally add some caching to avoid recreating datasources every time (or implement some pool)
Here is a demo class:
public class RoutingDataSource extends AbstractDataSource {
...
...
#Override
public Connection getConnection() throws SQLException {
return determineTargetDataSource().getConnection();
}
DataSource determineTargetDataSource() {
EmployeeDatabase lookupKey = determineCurrentLookupKey();
DataSource dataSource = this.datasources.get(lookupKey);
if (dataSource == null) {
logger.debug("Datasource not found. Creating new one");
SQLServerDataSource newDatasource = new SQLServerDataSource();
newDatasource.setURL("jdbc:sqlserver://" + lookupKey.getDatabaseHost());
newDatasource.setPassword(dbPass);
datasources.put(lookupKey, newDatasource);
dataSource = newDatasource;
} else {
logger.debug("Found existing database for key " + lookupKey);
}
logger.debug("Connecting to " + dataSource);
return dataSource;
}
}
I'm try to use the Sun Java PetStore Demo.
In the CatalogFacade class there is the following annotation:
#PersistenceUnit(unitName="myPetStorePU")
private EntityManagerFactory emf;
In all the methods of the CatalogFacade Sun has:
EntityManager em = emf.createEntityManager();
But I am getting a null pointer exception for emf when trying to createEntityManager. But... if I add the following line above that line as such
EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory("myPetStorePU");
EntityManager em = emf.createEntityManager();
then emf gets successfully created and the persistence unit myPetStorePU also successfully connects to the database. So it looks like persistence.xml syntax and its location is correct. I'd like to understand why the annotation doesn't work since I think there was a reason for just using the annotation as opposed to adding the createEntityManagerFactory line in every method.
My src/META-INF/persistence.xml file looks like this:
<persistence-unit name="myPetStorePU">
<description>Petstore Persistence Unit</description>
<provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
<class>com.sun.javaee.blueprints.petstore.model.Tag</class>
<class>com.sun.javaee.blueprints.petstore.model.SellerContactInfo</class>
<class>com.sun.javaee.blueprints.petstore.model.Product</class>
<class>com.sun.javaee.blueprints.petstore.model.Item</class>
<class>com.sun.javaee.blueprints.petstore.model.Category</class>
<class>com.sun.javaee.blueprints.petstore.model.Address</class>
<class>com.sun.javaee.blueprints.petstore.model.ZipLocation</class>
<properties>
<property name="toplink.jdbc.driver" value="oracle.jdbc.driver.OracleDriver"/>
<property name="toplink.jdbc.url" value="jdbc:oracle:thin:##############"/>
<property name="toplink.jdbc.user" value="####"/>
<property name="toplink.jdbc.password" value="#####"/>
<property name="toplink.logging.level" value="INFO"/>
</properties>
</persistence-unit>
Edit:
CatalogFacade is in the petstore.model package and implements the ServletContextListener
<listener>
<listener-class>com.sun.javaee.blueprints.petstore.model.CatalogFacade</listener-class>
</listener>
in the index.jsp Sun has the following:
<%
CatalogFacade cf = (CatalogFacade)config.getServletContext().getAttribute("CatalogFacade");
List<Tag> tags=cf.getTagsInChunk(0, 12);
%>
public List<Tag> getTagsInChunk(int start, int chunkSize) {
//The next line is required since the #PersistenceUnit annotation at the top of this class does not work
EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory("myPetStorePU");
EntityManager em = emf.createEntityManager();
System.out.println("Entity manager " + emf);
Query query = em.createQuery("SELECT t FROM Tag t ORDER BY t.refCount DESC, t.tag");
List<Tag> tags = query.setFirstResult(start).setMaxResults(chunkSize).getResultList();
em.close();
return tags;
}
If the annotated object is not managed by a container (either spring/CDI/EJB container), nothing gets injected into it.
So depending on your environment, obtain a contextual instance of that object.
If you are not using any of the above technologies (spring/CDI/EJB) - then you can't use #PersistenceUnit and #PersistenceContext. Use the manual way to obtain the unit.
For some reasons this happens when using this in you persistence.xml
<provider>org.hibernate.ejb.HibernatePersistence</provider>
switching to
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
fixes the problem
I am trying to create a Java application that will migrate an old schema to a new schema. I've chosen Java for the following reasons:
I need to perform data sanitation.
Business logic needs to be done to default previously null/bad data.
We are using JPA for our server code anyway. Using this in a migration will ensure our data migration has the correct integrity constraints.
My problem is; that when I increase the number of JPA Entity classes it takes a very long time to instantiate the EntityManager. Is there anything I can do to speed this up?
persistence.xml
<?xml version="1.0" encoding="UTF-
<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="puMigration" transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<class>com.myCompany.MyEntity</class>
. . .
<exclude-unlisted-classes>false</exclude-unlisted-classes>
</persistence-unit>
</persistence>
Java Code
Map<String, String> properties = new HashMap<>();
properties.put("javax.persistence.jdbc.driver", "com.mysql.jdbc.Driver");
properties.put("javax.persistence.jdbc.url", url);
properties.put("javax.persistence.jdbc.user", username);
properties.put("javax.persistence.jdbc.password", password);
// TODO Refactor, this call takes 2 minutes. Why?
EntityManagerFactory emf = Persistence.createEntityManagerFactory("puMigration", properties);
entityManager = emf.createEntityManager();
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.
This is my SLSB:
#Stateless
public class MyService {
PersistenceContext(unitName = "abc")
EntityManager em;
public boolean exists(int id) {
return this.em.find(Employee.class, id) != null;
}
}
This is my persistence.xml (I'm using Glassfish v3):
<persistence>
<persistence-unit name="abc">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/MyDS</jta-data-source>
<properties>
<property name="hibernate.archive.autodetection" value="class" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.MySQLInnoDBDialect" />
</properties>
</persistence-unit>
</persistence>
Now I'm trying to create a test, using OpenEJB embedded container. This is my test class:
class MyServiceText {
#Test
public void testChecksExistence() throws Exception {
Properties properties = new Properties();
properties.setProperty(
javax.naming.Context.INITIAL_CONTEXT_FACTORY,
"org.apache.openejb.client.LocalInitialContextFactory"
);
InitialContext ic = new InitialContext(properties);
// actual testing skipped
}
}
I would like to use HSQL for testing. How can I instruct OpenEJB that my persistence unit "abc" has to point to HSQL during testing? Shall I create a new version of persistence.xml? Shall I use openejb.xml? I'm lost in their examples and documentation.. :(
It's a Maven-3 project.
I would suggest placing a file named jndi.properties in src/test/resources for your OpenEJB configuration. This will then be available in the test classpath, you can then use the no-argument contructor of InitialContext to lookup datasources and ejbs. An example configuration looks like this, I'm using mysql for my datasource:
java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
myDS=new://Resource?type=DataSource
myDS.JdbcDriver=com.mysql.jdbc.Driver
myDS.JdbcUrl=jdbc:mysql://127.0.0.1:3306/test
myDS.JtaManaged=true
myDS.DefaultAutoCommit=false
myDS.UserName=root
myDS.Password=root
OpenEJB should then automatically replace the reference in persistence.xml with this datasource, if this is the only datasource then this should work even if the names are different.
Edit: Persistence unit settings
According to the documentation you referenced it should also be possible to configure persistence unit properties through jndi.properties:
abc.hibernate.hbm2ddl.auto=update
abc.hibernate.dialect=org.hibernate.dialect.MySQLInnoDBDialect
I haven't tested this myself since I'm using mysql for both tests and normal executions, only with different database names. Please let me know if this works, I've been thinking about replacing mysql in my testcases too.