I'm using JPA quite often in command line java applications. With an application server I can easily link to an external configuration via <jta-data-source>jdbc/myDatabase</jta-data-source> in the persistence.xml. How is that possible without an application server? I could find some information about the attribute <non-jta-data-source/>. But how can I reference the values from an external file (probably in the properties format) in an elegant way? It would be nice to have as few as possible boilerplate code.
I've found an approach to this here, but I think there is a more elegant way:
JPA Desktop application
Now I'm working with this solution:
I need a properties file which looks like this:
javax.persistence.jdbc.url = jdbc:mysql://localhost:3306/database
javax.persistence.jdbc.user = root
javax.persistence.jdbc.password = root
javax.persistence.jdbc.driver = com.mysql.jdbc.Driver
Respecting this scheme allows me to use the values without any mapping later. I can then pass the values easily to cretae the EntityManagerFactory like this:
try (final InputStream jpaFileInput = Files.newInputStream(propFile)) {
final Properties properties = new Properties();
properties.load(jpaFileInput);
emf = Persistence.createEntityManagerFactory(PU_NAME, properties);
}
It is easy to use JPA with desktop applications. It's almost the same thing but you will need to manage transactions. As you have no application server the management of each and every transaction has to be done by you. Access to your JPA unit can be achieved through EntityManagerFactory.
Example:
EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("jpa-example");
EntityManager em = emFactory.getEntityManager();
em.getTransaction().begin();
em.persist(address);
em.getTransaction().commit();
You need to put your persistence.xml file under META-INF folder. You need to point out in your persistence config file that transaction type is RESOURCE_LOCAL. This is needed for running independently with no Application Server:
<persistence-unit name="jpa-example" transaction-type="RESOURCE_LOCAL">
You will however need to download and link the libraries in your project classpath. You will need the JTA jar and your persistence provider JARs which could be of Hibernate or any other vendor of your choosing. This could be achieved cleanly with Maven.
You may want to check this tutorial:
http://java.dzone.com/articles/jpa-tutorial-setting-jpa-java
Related
I'm looking to distribute my web app to many different departments of the company i work for and i'm wondering what would be the best way of allowing each deployment to provide their own database instance. I am using Hibernate and the first deployment actually creates the database and imports tons of data in it but i'm looking for the cleanest, most reliable way of allowing the users to specify their own database URL and credentials. Currently my code has a hard coded reference for the database info :
public DataSource dataSource()
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
try
{
dataSource.setDriverClass("net.sourceforge.jtds.jdbc.Driver");
String hostName = InetAddress.getLocalHost().getHostName();
dataSource.setJdbcUrl("jdbc:jtds:sqlserver://localhost:1433/MDHIS;InstanceName=ADT;sendUnicode=false");
dataSource.setUser("sa");
dataSource.setPassword("N0tY0urBu$1nes$");
}
catch (Exception ignored) {}
return dataSource;
}
I read online that you cannot easily read a config file using a relative path from a web app (by all means please crush this myth if it is one) so i was thinking of using environment variables. I want this to be completely portable and work on Ubuntu as well as Windows so not sure how well that would work. I am using a 100% annotation based method so there is no XML file whatsoever and i intend it to stay that way.
Any suggestions?
Thanks!
Thanks for the help, i ended up annotating my configuration class with :
#PropertySource("classpath:config.properties")
I then placed said file in the java folder which is the base of the classpath. I put this in the file :
dbUrl=jdbc:jtds:sqlserver://localhost:1433/MDHIS;InstanceName=ADT;sendUnicode=false
I can now access the info in the code by doing :
dataSource.setJdbcUrl(environment.getProperty("dbUrl"));
Environment is a dependency that is autowired in my Hibernate config class.
Thanks!
I know it's possible to configure Hibernate in the 2 following ways:
hibernate.cfg.xml
persistence.xml - JPA - with specific hibenate configuration
when you add the provider like this:
org.hibernate.ejb.HibernatePersistence
But , I don't understand when should I use which ?
What should be the correct behavior?
Thanks!
You can use hibernate.cfg.xml when you want to use Hibernate in your project. When you create different queries (SELECT, INSERT, etc) you open session.
Session session = sessions.openSession();
where session is instance of org.hibernate.Session.
But as you can see we need sessions for creating session. Sessions is instance of org.hibernate.SessionSessionFactory. SessionFactory is global factory for concrete DB.
Session can be got by this action:
SessionFactory sessions = new Configuration().configure().buildSessionFactory();
where new Configuration().configure().buildSessionFactory() - parses hibernate.cfg.xml
Persistence.xml contains settings for using JPA in your project. Persistence units are defined in a persistence.xml file, which has to be located in the META-INF directory in the classpath. One persistence.xml file can include definitions for one or more persistence units. The portable way to instantiate an EntityManagerFactory in JPA (as explained in the JPA Overview section) requires a persistence unit.
See also: http://www.objectdb.com/java/jpa/entity/persistence-unit
Sorry for the long back story but I wanted to give a good idea of why we're doing what we're doing.
Our application currently uses Hibernate 3.6 and we wish to upgrade to Hibernate 4.3.
The application was specifically written to avoid using persistence.xml to configure JPA and create the EntityManagerFactory and instead uses Hibernate's Ejb3Configuration class like this (example):
Properties properties = new Properties();
properties.put("javax.persistence.provider", "org.hibernate.ejb.HibernatePersistence");
properties.put("javax.persistence.transactionType", "RESOURCE_LOCAL");
properties.put("hibernate.dialect", "org.hibernate.dialect.Oracle10gDialect");
properties.put("hibernate.show_sql", "false");
properties.put("hibernate.format_sql", "true");
Ejb3Configuration cfg = new Ejb3Configuration();
cfg.addProperties(properties);
DataSource dataSource = dataSourceProvider.get();
cfg.setDataSource(dataSource);
//add the annotated classes
cfg.addAnnotatedClass(SomePersistentObject.class);
EntityManagerFactory factory = cfg.buildEntityManagerFactory();
The reason we do it this way is because we have a web app (war file) deployed to Tomcat that provides "core" functionality. Then, we install what we call "client bundles" which are jar files in the exploded /WEB-INF/lib directory. The "client bundles" contain overrides to the existing "core" behavior of the web app. This allows us to service multiple clients, each with various customizations from the "core" behavior, in one instance of the web app. We know which client bundle to use based on the domain or subdomain of the incoming HTTP request.
Each client bundle always gets its own database instance, and thus each client bundle defines its own EntityManagerFactory. The schemas are almost identical, although client bundles can add new persistent classes if needed.
So, the reason we do JPA configuration in Java is so that each client bundle extend the "core" classes and add their own entity classes. Java is great for inheritance while XML stinks. If we have to configure via XML, then each client bundle would need to copy the core's persistence.xml and update it from there. I would much rather use inheritance over copy/paste.
I think we have a pretty valid use case for preferring JPA configuration via Java rather than XML.
My question: Does Hibernate 4.3 allow this in any way? If so, how can I go about it?
If not, does anybody have any suggestions on how to make my above scenario as easy as possible while being stuck with XML configuration?
Can multiple jar files within a single web app contain /META-INF/persistence.xml files, or do multiple persistence units need to be defined another way?
Thank you!!!
-Ryan
I overcame the problem by dynamically writing a new persistence.xml file to the web app's classpath, before JPA is bootstrapped.
When the web app starts up, the JPA configuration for all the client bundles is read, and then a single persistence.xml file is written to the classpath. Each client bundle gets its own entry as a persistence-unit within persistence.xml.
Then, after the new persistence.xml is written, JPA is bootstrapped. JPA doesn't know or care, obviously, that the persistence.xml file was written dynamically.
It seems a little like a hack but I couldn't figure out any other way to do it. One nice benefit is that it keeps me away from Hibernate specific APIs, so if I ever want to switch to something like DataNucleus as the JPA provider I will have the flexibility to do so.
Is there a way to set the EclipseLink properties (e.g. target database) in a place different from persistence.xml?
Rational: I have a JPA module defining the data structure and containing persistence.xml. The module might be used with different target databases. In a Java SE application one can set the eclipse link properties programmatically upon creation of EntityManagerFactory. However, when the JPA module is packaged in an EAR for the Glassfish application server the target database must be defined in persistence.xml ... or is there another way?
You can use a RESOURCE_LOCAL persistence unit and access it the same way through EntityManagerFactory.
I am trying to understand the following things:
When I make an EJB project and deploys it to Glassfish do I set up JDBC resources/connection pools at the administrator center of Glassfish or do I add all the different properites for username, password etc in the persistence.xml? I don't understand one bit of that.
I do not understand why we have both JDBC resource and JDBC Connection pool either. What is it and what is the difference between them? Could somebody explain me these things or/and provide some good link about the persistence.xml file and the part around it?
It's better to define a JDBC resource rather than putting the information in the persistence.xml. In this way you are going to take advantage of connection pooling. You are going to define the JNDI name you provided for the JDBC resource in the persistence.xml.
What is it and what is the difference between them
Below I pasted some parts of the Glassfish 3.x help. Check it out. It's really helpful
JDBC connection pool
A JDBC connection pool contains a group of JDBC connections that are created when the connection pool is registered
JDBC resource
A Java DataBase Connectivity (JDBC) resource (data source) provides applications with the means of connecting to a database. Typically, the administrator creates a JDBC resource for each database accessed by the applications deployed in a domain; however, more than one JDBC resource can be created for a database.
Applications get a database connection from a connection pool by looking up a data source on the Java Naming and Directory Interface (JNDI) API tree and then requesting a connection. The connection pool associated with the data source provides the connection to the application.
Think of the data source(JDBC) resource as a factory for a facade of some type of data service(Connection Pool). In this case it implicitly gets a connection from the pool and provides it to your application.
An example persistence.xml:
<?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="WebApplication2PU" transaction-type="JTA">
<jta-data-source>jdbc/sample</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties/>
</persistence-unit>
</persistence>
This line is the JNDI name I gave to my JDBC resourse:
<jta-data-source>jdbc/sample</jta-data-source>
You dont need to define anything related to the database connection in your persistence.xml this way...just the JNDI name of the resource
When you configure a data source in your application server, all you need to set in persistence.xml is the JNDI name of that data source.
I found this in the book that I read to learn Spring and Hibernate. The book name is Professional Java for Web Applications written by Nicholas S. Williams. I think this will be helpful for many people.
Creating the Persistence Configuration:
To use the entities you create, you must define a persistence unit. Doing so is simple. Create a
persistence.xml file not dissimilar from a deployment descriptor, but with far fewer options
to worry about. The root element of a persistence configuration file is <persistence>. This
element may contain one or more <persistence-unit> elements. No other elements are
within <persistence>. <persistence-unit> has two attributes: name specifies the name of
the persistence unit and transaction-type indicates whether this persistence unit uses Java
Transaction API (JTA) transactions or standard local transactions.
You must specify a name, which is how you locate the persistence unit in code. If not specified,
transaction-type defaults to JTA in a Java EE application server and RESOURCE_LOCAL in a Java
SE environment or simple Servlet container. However, to prevent unexpected behavior it’s best to
always set this value explicitly instead of relying on a default value.
<persistence-unit> contains the following inner elements. None of them are required (so
<persistence-unit> may be empty); however, you must specify whichever elements you use in the
following order:
<description> contains a useful description for this persistence unit. Although it makes
reading the persistence file easier, it has no semantic value.
<provider> specifies the fully qualified class name of the javax.persistence.spi
.PersistenceProvider implementation used for this persistence unit. By default, when you
look up the persistence unit, the API will use the first JPA provider on the classpath. You
can include this element to mandate a specific JPA provider.
You can use either <jta-data-source> or <non-jta-data-source> (but not both) to
use a JNDI DataSource resource. You may use <jta-data-source> only if
transaction-type is JTA; likewise you may use <non-jta-data-source> only
if transaction-type is RESOURCE_LOCAL. Specifying a DataSource causes the persistence
unit to use that DataSource for all entity operations.
<mapping-file> specifies the classpath-relative path to an XML mapping file. If you don’t
specify any <mapping-file>, the provider looks for orm.xml. You may specify multiple
<mapping-file> elements to use multiple mapping files.
You can use one or more <jar-file> elements to specify a JAR file or JAR files that the
JPA provider should scan for mapping-annotated entities. Any #Entity, #Embeddable,
#javax.persistence.MappedSuperclass, or #javax.persistence.Converter classes
found are added to the persistence unit.
You can use one or more <class> elements to indicate specific #Entity, #Embeddable,
#MappedSuperclass, or #Converter classes that should be added to the persistence unit.
You must annotate the class or classes with JPA annotations.
Using <exclude-unlisted-classes /> or <exclude-unlisted-classes>true</exclude-unlisted-classes> indicates that the provider should ignore classes not
specified with <jar-file> or <class>. Omitting <exclude-unlisted-classes> or using
<exclude-unlisted-classes>false</exclude-unlisted-classes> causes the JPA
provider to scan the classpath location of the persistence file for JPA-annotated classes. If
persistence.xml is located in a JAR file, that JAR file (and only that JAR file) is scanned
for classes. If persistence.xml is located in a directory-based classpath location (such as /
WEB-INF/classes), that directory (and only that directory) is scanned for classes. Prior to
Hibernate 4.3.0 and Spring Framework 3.2.5, specifying this element with the value false
was incorrectly interpreted as true.
<shared-cache-mode> indicates how entities are cached in the persistence unit (if the JPA
provider supports caching, which is optional). NONE disables caching, whereas ALL enables
caching for all entities. ENABLE_SELECTIVE means that only entities annotated #javax
.persistence.Cacheable or #Cacheable(true) (or marked as cacheable in orm.xml)
are cached. DISABLE_SELECTIVE results in caching of all entities except those annotated
#Cacheable(false) (or marked as non-cacheable in orm.xml). The default value,
UNSPECIFIED, means that the JPA provider decides what the effective default is. Hibernate
ORM defaults to ENABLE_SELECTIVE, but relying on this is not portable.
<validation-mode> indicates if and how Bean Validation should be applied to entities.
NONE means that Bean Validation is not enabled, whereas CALLBACK makes the provider
validate all entities on insert, update, and delete. AUTO has an effective value of CALLBACK
if a Bean Validation provider exists on the classpath and an effective value of NONE if no
Bean Validation provider exists on the classpath. If you enable validation, the JPA provider
configures a new Validator to validate your entities. If you have configured a special
Spring Framework Validator with your custom localized error codes, the JPA provider
ignores it. As such, it’s best to set the validation mode to NONE and use Bean Validation
before your persistence layer is invoked.
<properties> provides a way to specify other JPA properties, including standard JPA
properties (such as JDBC connection string, username, and password, or schema generation
settings) as well as provider-specific properties (such as Hibernate settings). You specify
one or more properties using nested elements, each with a name and value
attribute.
Nicholas S. Williams, Professional Java for Web Applications, (Indianapolis, Indiana: John Wiley & Sons, Inc., 2014), pg 584-585