Various sources (e.g. Oracle) say that you have to specify jdbc connection details in your persistence.xml for Java SE apps which use JPA via things like <property name="javax.persistence.jdbc.url" value="..."/>.
This is a real pain when you want to run the app against different databases, for example local, test and production. I currently get around this by having multiple persistence-units that are all effectively the same but with different connection details, and then get the app to pick the right persistence-unit based on the environment that it is running in.
The problems with this are:
Duplication of config. When I add an Entity class I have to add <class>MyClass</class> to every persistence-unit. I would rather just specify it once.
Database connection config packaged with the app. If I want to change what database is being used in an environment, I need to fiddle with persistence.xml and re-build the app. I would rather have a config file in each of my environments which specifies the database credentials. That way, I could have many environments but just a single persistence-unit defined, and I could change the database credentials for a given environment by just editing one file in that environment and then re-starting the app.
Do you know of a better way to configure persistence? Is there some way of getting <jta-data-source> or <non-jta-data-source> to do something appropriate in a Java SE environment?
U can config it manually in code
Map<String, String> props = new HashMap<String, String>();
props.put("javax.persistence.jdbc.url", "YourURL");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("UnitName", props);
EntityManager em = emf.createEntityManager();
Related
I am writing a JEE7 application that runs in WebSphere Liberty Profile 8.5.5. We are using JPA (which is implemented via Eclipselink in WLP).
I have multiple persistence units in the same 'persistence.xml' file. I also need to access two of those units in the same class.
I am getting a runtime error when I try to use the second EntityManager:
#PersistenceContext(unitName = "wwer-list")
private EntityManager entityManagerWwerList;
#PersistenceContext(unitName = "main-dashboard")
private EntityManager entityManagerMainDashboard;
E WTRN0062E: An illegal attempt to use multiple resources that have only one-phase capability has occurred within a global transaction.
How do I get rid of this error?
Also, all of the tables I am using are only needed for reading. So how can I specify that I only want read-only access to JPA?
This issue is prompting because one of your datasource configured as (single phase commit) using ConnectionPoolDataSource and other is configured with XADataSource.
If you want to continue with the same datasource configuration, you will have to update your Server configuration to "Acccept Heuristic Hazard".
In the admin console, click the EAR, select the check box "Accept heuristic hazard". Re-start the server.
This link to enable the Last Participant Support may also help.
http://www.ibm.com/support/knowledgecenter/SSAW57_7.0.0/com.ibm.websphere.nd.doc/info/ae/webui_pme/ui/ueac_laoextensionsettings.html
I can't tell for sure without your persistence.xml and server.xml configurations, but it looks like the <dataSource> elements backing your <persistence-unit> configurations are not XA capable.
By default, a <dataSource> should be a javax.sql.XADataSource (and therefore XA capable), however if you are using a JDBC driver that does not provide an XADataSource implementation, Liberty will pick a simpler DataSource implementation (i.e. javax.sql.ConnectionPoolDataSource or plain javax.sql.DataSource).
A global transaction is whenever you issue a UserTransaction.begin() and lasts until you issue a commit() or a rollback(). There are other ways that you can get into a global transaction too.
Since you want read-only access, converting your DataSources to XA would probably be overkill. Instead, try to eliminate the global transactions from the equation. If you can't eliminate the global transactions, you can specify XADataSource in your server.xml in the following way:
<dataSource type="javax.sql.XADataSource" ...>
<jdbcDriver .../>
<properties .../>
</dataSource>
For a long time in many IT services, I see some complex process to manage Java EE application configuration depending of the environments:
- custom tools, with Database or not, to manage replacement in the properties file (unzip war, replace, zip war...)
- Externalize properties file in obscure directory in the server (and some process to update it some time) and some time with a JNDI configuration...
- maven profile and lot of big properties files
But for database connection everybody use jndi datasource.
Why this is not generalized for all configurations that depend of environment ?
Update : I want deal with other variable than datasource, there is no question about datasource : it's in configured in JNDI for Java EE application. After if you want hack JNDI...
Setting up database connectivity (like user name, password, URL, driver etc.) somewhere in the application server has several advantages over doing it yourself in the WAR:
The app server can be a central point where the DB is configured, and you might have several WARs running on that server sharing a DB. So you need to set it up only once.
The DB settings, especially the credentials (username, password) are stored somewhere in the app server instead of somewhere in the WAR. That can have security implications (for instance, restricting access to that file is easier done than in a WAR archive).
You can set up one JNDI path to retrieve a DataSource instance pointing to the DB and do not need to worry about username and password anymore. If you have multiple app servers (one live system, one test system, several developer machines) with different DB URLs and credentials, then you can just configure that in each app server individually and deploy the WAR files without the need to change DB settings (see below).
The server might provide additional services, like connection pools, container managed transactions, etc. So again, you don't have to do it on your own in the WAR.
This is true for other services provided by the app server as well, for example JavaMail.
There are other cases where it you want to configure something that is specific to one web application and does not rely on the environment (the app server), like logging (although that may be set up in the app server, too). In those cases you might prefer using static config files, for instance log4j.properties.
I want to illustrate the third bullet point a bit further ...
Suppose you have one WAR in three app servers (developer machine, test server, live server).
Option 1 (DB setup in WAR)
Create a database.properties :
db.url=jdbc:mysql://localhost:3306/localdb
db.user=myusername
db.pass=mysecretpassword
#db.url=jdbc:mysql://10.1.2.3:3306/testdb
#db.user=myusername
#db.pass=mysecretpassword
#db.url=jdbc:mysql://10.2.3.4:3306/livedb
#db.user=myusername
#db.pass=mysecretpassword
Before you deploy it somewhere, you need to check if your settings are pointing to the right DB!
Also, if you check this file in to some version control system, then you might not want to publish your DB username/password to your local machine.
Option 2 (DB setup in App Server)
Imagine you have configured the three servers with their individual DB settings, and each of them registers the DB with the JNDI path java:database/mydb.
Then you can retrieve the DataSource like so:
Context context = new InitialContext();
DataSource dataSource = (DataSource) context.lookup("java:database/mydb");
This is working on every app server instance and you can deploy your WAR without the need to modify anything.
Conclusion
By moving the configuration to the app server you'll have the advantage of separating settings depending on the environment from your app code. I would prefer this whenever you have settings involving IP addresses, credentials, etc.
Using a static .properties file on the other hand is simpler to manage. I would prefer this option when dealing with settings that have no dependencies to the environment or are app specific.
I have created the Databse dropdown list using the JSP. If I select anyone of the database and it should be pointing to the database and then the query written should be executed to the database which I have selected.
Present work done.
Now I have created statically like how much database I have that much Properties are written in the property file and all the credentials will be taken by Context.xml so how can i create it dynamically so that I dont want to write the different properties for each database and i dont want to create the different session nor I don't want to restart the server when ever I select the DataBase ?
In the property file I have written the different properties for each and every databases and in XML also we have created the different sessions for each and every databases so i donit need to write the different sessions nor restart my Server after the selection of the Database
My question is to can we implement as per my requirement.??????
And another thing for the different database we have created the interface and for that interface we have created the implementation
I believe there is nothing prohibit you from programmatically creating all DB related artifacts (e.g. Datasource, JdbcTemplate, EntityManager etc), and perform transaction management programmatically. Of course you will be giving up a lot of facilities provided by the container (or, I should say, still achievable with high cost)
Another idea I believe will work (though I haven't tried) is to create a child application context from your main app context. The child context will prepare/lookup datasource etc base on properties. Your parent context will of course need to provide correct properties to the child context. By doing so, it should be easy to leverage on feature provided by Spring.
The problem with hibernate is, you need to put the database info (username/pw etc) in an xml file. However, if you deploy your app on Amazon web services, e.g on Beanstalk, you get the db info passed in via System.getProperty("RDS_DATABASE_USER"), etc. The advantage is, if more instances of your app are created, the db info is passed on automatically, without having to manually edit config files.
Is there a way to pass the db info to hibernate at runtime? If not, is there another good ORM library for java, to which you can pass this info at runtime? I'm using MySQL.
As a matter of fact, the method PersistenceUtil.createEntityManagerFactory allows you to provide a properties map. Using this map you can provide the user name and password in dynamic way.
How you do this may well depend on what specific frameworks you are using.
Based on the tags in your question it is not clear if you are using Hibernate or if you are using OpenJPA.
The Open JPA documentation in the section Obtaining an EntityManagerFactory provides the list of properties you could use.
Map<String,String> properties = new HashMap<>();
properties.put("openjpa.ConnectionUserName", "userName");
properties.put("openjpa.ConnectionPassword", "password");
EntityManagerFactory emf = Persistence.createEntityManagerFactory("MyPersistenceUnit",properties);
Hibernate supports a similar set of properties. Most probably you already have them in your persistence.xml file.
Some dependency injection frameworks, like Spring, don't even require a persistence.xml file and can read such properties dynamically from some other places, like environment variables.
Preface:
Most of J2EE applications are using container managed datasources through JNDI. This is fine as it gives one place for configuring these connections.
The problem arises when we want to use ORM framework (like hibernate) or something that have to know the default schema (mostly for Oracle, may be others too), which can be different from the username that is used to connect to the DB.
I want to put the default schema name somewhere close to the datasource definition. One of the options would be to put it in JNDI. I will then manually read of from there before construction the EntityManager (well actually using Spring).
As I found out there is a simple way to specify custom resource (in this situation it will be String with default schema name) in Apache Tomcat like this (correct me if I'm wrong):
<Environment name="schemaNames/EmployeeDB"
type="java.lang.String"
value="empl"
description="Schema name of Employees Database for HR Applications"/>
Anyway, considering this can be done in Apache Tomcat, how should I configure the same custom JNDI resource (of String type) within other application servers:
JBoss 4/5
WebSphere 6/7
WebLogic 9/10
If you know about other servers that would be great too.
Also, as an alternative I don't want to put the schema name in system properties or environment variables.
Thank you very much !
Update:
Found some way of achieving it on JBoss. I didn't test it tho.
http://forums.java.net/jive/thread.jspa?messageID=316228
Found information for WebLogic, but they talk about doing it programmaticly and not with configuration:
http://weblogic-wonders.com/weblogic/2010/06/12/binding-objects-in-weblogic-servers-jndi-tree/
http://forums.oracle.com/forums/thread.jspa?messageID=4397353
For WebSphere you can actually set the default schema in your defined DataSource. It is a custom property called currentSchema. (ie, in V7 it is Resources > JDBC > Data sources > your data source name > Custom properties > currentSchema.
Otherwise you can use a Name Space Binding and define it there: (ie, in V7 it is Environment > Naming > Name Space Bindings. You can use JNDI to look this up if you don't want to programmatically set it in WebSphere.
Can't speak to JBoss and WebLogic as I haven't worked with them.
If you are using Hibernate, this is the property to add in persistence unit :
<property name="hibernate.default_schema" value="myschema" />
That is the prefix that JPA will insert for table names.
If you need something 'closer' to the AS Datasources definitions, you may inject some DB-specific SQL at DB connection time; for instance Oracle,
ALTER SESSION SET CURRENT_SCHEMA =
On JBoss, you may add this in the datasource definition :
<new-connection-sql>
ALTER SESSION SET CURRENT_SCHEMA=myschema
</new-connection-sql>
Also editable in JBoss 7 Admin.
On Weblogic, you may inject this in the Connection Pools.
On Websphere, this should be similar.
On JBoss, you can use a special MBean(org.jboss.naming.JNDIBindingServiceMgr) and a service.xml to configure JNDI-entries, and then map these entries into your webapps. There is a lengthy explication for this rather non-trivial process here:
http://usna86-techbits.blogspot.com/2011/01/jboss-jndi-and-javacompenv.html
I'm still looking for a a way to place an entire properties-file/resourcebundle into jndi, as this manual mapping gets very tedious when you have a lot of properties that you want to put into jndi and make available for your webapps.
This same problem has been bothering be for quite a while for WebLogic, in particular 10.3.5 (11g).
I spent most of a day looking around and all I found was this: http://code.google.com/p/weblogic-jndi-startup/. It works just fine. It is a little restrictive: it requires the object you want to add to JNDI to have a constructor with a single String parameter.
For what I needed, weblogic-jndi-startup didn't work, so I built on Roger's code and came up with this: https://bitbucket.org/phillip_green_idmworks/weblogic-jndi-custom-resource-configuration/. I have a write up for it at http://coder-in-training.blogspot.com/2012/03/weblogic-jndi-custom-resource.html