Could you please explain to me how to add a standalone c3pO or DBCP connection pool to my toplink-based JPA project?
I have a persistence.xml file, and everytime I want to query the database, I'm doing this:
EntityManagerFactory emf = this.getEntityManagerFactory();
// Surely using persistence.xml to set up the factory
EntityManager em = emf.createEntityManager();
...
Where do I build the bridge between my external connection pool manager and Toplink? Any ideas or links are welcomed.
Regards,
Jean
I don't use Toplink so I didn't test this but, my understanding of various resources found over the net is that you'll need to provide an implementation of SessionCustomizer. In this implementation, use the JNDIConnector class to give a DataSource object (c3p0 implements the DataSource API) using the setDataSource(javax.sql.DataSource) method.
Adapt the sample from Working with a non JTA DataSource in Toplink Essentials.
I really don't understand what to do. So blurry page for a beginner. Nevertheless, I have created a SessionCustomizer class apart. Here is my customize() method, using c3p0:
public void customize(Session session) throws Exception{
DataSource ds = DataSources.unpooledDataSource("myServerURL", "login", "pwd");
DataSource pooled = DataSources.pooledDataSource(ds);
JNDIConnector conn = (JNDIConnector)session.getLogin().getConnector();
conn.setDataSource(pooled);
conn.setLookupType(JNDIConnector.STRING_LOOKUP);
}
I don't even think it's correct. I'm putting my connection infos in clear in code, really weird.
Secondly, in persistence.xml example from the link, they have put:
<non-jta-data-source>java:comp/env/jdbc/DefaultDS</non-jta-data-source>
<class>sample.MyEntity</class>
<properties>
<property name="toplink.session.customizer" value="es.claro.commons.ds.DataSourceSessionCustomizer"/>
</properties>
What should I put in mine, particularly for "non-jta-data-source" tag? Is there a way to put connection informations in that xml instead of in code?
Help.
Related
The problem I am experiecning is that the auto configuration from Springboot version: 1.5.9.RELEASE seems not to be effective.
Note, I probably will be able to overcome my current problem if I define a bean that returns out a DataSource bean.
Probably the DataSource bean could look very similar to the:
Example in the following snippet:
https://www.atomikos.com/Documentation/ConfiguringPostgreSQL
I am switching my application.properties configuration to stop using the default H2 database used by spring boot and switching it to postgres.
The configuration snippet illustrated in the following page:
https://dzone.com/articles/configuring-spring-boot-for-postgresql
Is definitely not working.
Here is what my configuration looks like:
spring.datasource.url=jdbc:postgresql://localhost:5432/dummydb
spring.datasource.username=DUMMYDB
spring.datasource.password=DUMMYDB
spring.jpa.hibernate.ddl-auto=create-drop
This does not work, and why?
Apparently for a very simple reason.
While the user name and password are definitely of use and getting transferred over at the time that the connection factory tries to build a connection for the database.
The URL attribute is of no use when it comes to configuring the data source.
Let me start by giving you the final stack trace:
Caused by: org.postgresql.util.PSQLException: FATAL: database "null" does not exist
at org.postgresql.core.v3.ConnectionFactoryImpl.readStartupMessages(ConnectionFactoryImpl.java:469) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:112) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc2.AbstractJdbc2Connection.<init>(AbstractJdbc2Connection.java:125) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc3.AbstractJdbc3Connection.<init>(AbstractJdbc3Connection.java:30) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc3g.AbstractJdbc3gConnection.<init>(AbstractJdbc3gConnection.java:22) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc4.AbstractJdbc4Connection.<init>(AbstractJdbc4Connection.java:30) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.jdbc4.Jdbc4Connection.<init>(Jdbc4Connection.java:24) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.Driver.makeConnection(Driver.java:393) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.Driver.connect(Driver.java:267) ~[postgresql-9.1-901.jdbc4.jar:na]
at java.sql.DriverManager.getConnection(DriverManager.java:664) ~[na:1.8.0_112]
at java.sql.DriverManager.getConnection(DriverManager.java:247) ~[na:1.8.0_112]
at org.postgresql.ds.common.BaseDataSource.getConnection(BaseDataSource.java:91) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:47) ~[postgresql-9.1-901.jdbc4.jar:na]
at org.postgresql.xa.PGXADataSource.getXAConnection(PGXADataSource.java:32) ~[postgresql-9.1-901.jdbc4.jar:na]
at com.atomikos.jdbc.AtomikosXAConnectionFactory.createPooledConnection(AtomikosXAConnectionFactory.java:60) ~[transactions-jdbc-3.9.3.jar:na]
... 44 common frames omitted
Why this does not work is because the postgres base data source does not care at all for being configured via URL.
Rather it wants to be configured via setters that pass over:
databaseName, port, etc...
Please have a look at the following class:
org.postgresql.ds.common.BaseDataSource
This class provides multiple setters. For username, for password etcc..
But there is no setter for an URL. The individual elements that compose the URL such as the database name need to go into the dedicated fields.
So instead what the class offers is this getURL() method that is retuning the strange URL where the datbase is null.
Here is a code snippet for the method.
/**
* Generates a DriverManager URL from the other properties supplied.
*/
private String getUrl()
{
StringBuffer sb = new StringBuffer(100);
sb.append("jdbc:postgresql://");
sb.append(serverName);
if (portNumber != 0) {
sb.append(":").append(portNumber);
}
sb.append("/").append(databaseName);
sb.append("?loginTimeout=").append(loginTimeout);
sb.append("&socketTimeout=").append(socketTimeout);
sb.append("&prepareThreshold=").append(prepareThreshold);
sb.append("&unknownLength=").append(unknownLength);
sb.append("&loglevel=").append(logLevel);
if (protocolVersion != 0) {
sb.append("&protocolVersion=").append(protocolVersion);
}
if (ssl) {
sb.append("&ssl=true");
if (sslfactory != null) {
sb.append("&sslfactory=").append(sslfactory);
}
}
sb.append("&tcpkeepalive=").append(tcpKeepAlive);
if (compatible != null) {
sb.append("&compatible="+compatible);
}
if (applicationName != null) {
sb.append("&ApplicationName=");
sb.append(applicationName);
}
return sb.toString();
}
So then the question for me was.
Ok... if the postgres data source does not wished to be configured via url but rather via the various different setters, perhaps I can get away by adding to the application.properties file fields such as:
#spring.datasource.databaseName=dummydb
Nope, it turns out this seems to be of no use at all.
After some debugging, I a managed to find out this spring boot auto configuration class:
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration
The above class is very interesting, since it is at the route of the configuration of the atomics JTA transaction subsytem.
IT will setup the data source:
org.postgresql.xa.PGXADataSource
But the only problem is that this auto configurator only cares for three attributes in our application.properties file.
See the code snippet bellow:
private void bindXaProperties(XADataSource target, DataSourceProperties properties) {
MutablePropertyValues values = new MutablePropertyValues();
values.add("user", this.properties.determineUsername());
values.add("password", this.properties.determinePassword());
values.add("url", this.properties.determineUrl());
values.addPropertyValues(properties.getXa().getProperties());
new RelaxedDataBinder(target).withAlias("user", "username").bind(values);
}
As you can see, it appears that I am "toasted".
The auto configurator has no notion of any other data source properties that could be relevant.
Which I find surprising to say the least.
I was expecting some sort of class that would not have any thing such as hard-coded subset of properties such as user name and password.
I was expecting some sort of code that would trivially be looping all of the applicaton.properties and hunting for any property whose key would start with:
spring.datasource.whatever
And call the datasource.setWhatever on the data source class.
Seems not to be the case.
So I am certain I must be messing up something.
I cannot believe that springboot would not be able to configure postgres database without forcing a developer to create his own datasource bean.
Postgress is simply too main stream...
So I was wondering if someone could help me figure out how to properly configure the application.properties file to ensure that indeed I can connect to postgres with springboot.
Meanwhile, I will see if I acn work-around this problem by creating programtically a class like:
#AutoConfigureBefore(DataSourceAutoConfiguration.class)
#EnableConfigurationProperties(DataSourceProperties.class)
#ConditionalOnClass({ DataSource.class, TransactionManager.class,
EmbeddedDatabaseType.class })
#ConditionalOnBean(XADataSourceWrapper.class)
#ConditionalOnMissingBean(DataSource.class)
public class XADataSourceAutoConfiguration implements BeanClassLoaderAware {
But in my case the class would know how to programatically build the postgres data source with all necessary properties to connect.
Many thanks for the help.
I would like to set isolation level using eclipse link,
I tried these 2 ways to do it:
java.sql.Connection
mgr = EMF.get().createEntityManager();
tx = mgr.getTransaction();
tx.begin();
java.sql.Connection connection = mgr.unwrap(java.sql.Connection.class);
connection.setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_COMMITTED);
System.out.println("Connection: "+connection.getTransactionIsolation());
//prints TRANSACTION_READ_COMMITED as expected
org.eclipse.persistence.sessions.DatabaseLogin databaseLogin = new DatabaseLogin();
System.out.println("DatabaseLoging: "+databaseLogin.getTransactionIsolation());
//prints -1, representing transaction isolation is not set
DatabaseLogin setTransationIsolation method
mgr = EMF.get().createEntityManager();
tx = mgr.getTransaction();
tx.begin();
org.eclipse.persistence.sessions.DatabaseLogin databaseLogin = new DatabaseLogin();
databaseLogin.setTransactionIsolation(DatabaseLogin.TRANSACTION_READ_COMMITTED);
System.out.println("DatabaseLoging: "+databaseLogin.getTransactionIsolation());
//prints TRANSACTION_READ_COMMITED as expected
java.sql.Connection connection = mgr.unwrap(java.sql.Connection.class);
System.out.println("Connection: "+connection.getTransactionIsolation());
//prints TRANSACTION_REPEATABLE_READ
As you can see there are some inconsistencies between the return values of getTransacationIsolation() method. My question is, which transaction isolation is really set in both cases ? I know that eclipse link uses different connection for read and write operations by default, DatabaseLogin.setTransactionIsolation should set the isolation level for both connections, so why Connection.getTransactionIsolation still returns another isolation level ?
I am using Application scoped EntityManager, JPA 2.0, EclipseLink 2.5.2.
If there are more preferable ways setting the transaction isolation, please let me know.
After having a small pause with eclipse link, I finally found out how to set transaction isolation level.
As #Chris correctly mentioned in his answer I need to obtain DatabaseLogin used by sessions. After a small research on eclipse link sessions I have found out, that I can change the Session properties in my own SessionCustomizer, see the code below:
package com.filip.blabla;
import org.eclipse.persistence.sessions.DatabaseLogin;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.factories.SessionCustomizer;
public class DFSessionCustomizer implements SessionCustomizer {
#Override
public void customize(Session session) throws Exception {
DatabaseLogin databaseLogin = (DatabaseLogin) session.getDatasourceLogin();
databaseLogin.setTransactionIsolation(DatabaseLogin.TRANSACTION_READ_COMMITTED);
}
}
set SessionCustomizer in persistence.xml
<property name="eclipselink.session.customizer" value="com.filip.blabla.DFSessionCustomizer"/>
The databaseLogin class is an internal object that EclipseLink uses to configure how it accesses the database, and the settings used to configure those connections. Any changes you make directly to a connection will not be reflected in a DatabaseLogin instance.
Just creating a new DatabaseLoging instance is not going to give you access to the settings being used by the persistence unit. You need to obtain the DatabaseLogin being used by the sessions underneath the the EntityManager/EMF.
I am working on an application, to be deployed in WebLogic 12c, which needs to be able to obtain a JPA EntityManager (EclipseLink 2.5.2) connected to an arbitrary Data Source at runtime. I do not currently know what the JNDI name of that Data Source will be; there will be several to many of them, connected to different databases but all with identical schemas. So the data source name cannot be specified in the persistence.xml inside the application; it must come from outside (configuration file most likely).
I don't think I can have an EntityManagerFactory or EntityManager injected; they are pretty tightly coupled to the configuration in persistence.xml and I do not seem to be able to override the JTA data source name. This, for example, does not work:
#PersistenceUnit(unitName="myPU")
private EntityManagerFactory emf;
// ...
Map<String, Object> emProps = new HashMap<String, Object>();
emProps.put(EntityManagerProperties.JTA_DATASOURCE, "jdbc/foobar");
EntityManager em = emf.createEntityManager(emProps);
My as my EntityManager here is still connected to the JTA datasource that was actually specified in the persistence.xml.
So I started looking at creating the EntityMangerFactory through non-injected means, like with Persistence.createEntityManagerFactory(puName, propMap) but here, it seems, no matter what persistence.xml or my property map says, I get a RESOURCE_LOCAL EntityManagerFactory!
How can I get an EntityManager or EntityManagerFactory that is JTA-enabled and associated with an arbitrary datasource name that is not known at compile-time?
This does the trick, at least in EclipseLink 2.5.2:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put(PersistenceUnitProperties.TRANSACTION_TYPE, "JTA");
properties.put(PersistenceUnitProperties.JTA_DATASOURCE, "jdbc/foobar");
emf = Persistence.createEntityManagerFactory("myPU", properties);
JpaEntityManagerFactory jemf = (JpaEntityManagerFactory)emf;
WebLogicTransactionController wlstx = new WebLogicTransactionController();
if (jemf.getDatabaseSession() != null && jemf.getDatabaseSession().getExternalTransactionController() == null) {
jemf.getDatabaseSession().setExternalTransactionController(wlstx);
}
if (jemf.getServerSession() != null && jemf.getServerSession().getExternalTransactionController() == null) {
jemf.getServerSession().setExternalTransactionController(wlstx);
}
By adding the transaction controller to the EMF, it is once again enlisted with JTA and will respect JTA transactions. My persistence.xml provides a dummy value for the JTA datasource; I override in code and away we go!
NB: Currently getDatabaseSession() and getServerSession() in fact return the exact same object. I could get away with only setting one of these, but this is undocumented and you're better off safely setting both of them, just to be sure.
I can't find how my connectionString syntax is wrong. Can anyone suggest a way to figure this out? I am having a difficulty using EF with my connection string. I am new to EF.
I am using Sybase Anywhere 12 database.
I'm using the Table-First ObjectContext with EDMX in a separate class library refenced by a web application.
I'm using a Ninject Module in my class library to bind my repositories.
I'm using a ODBC DataStore called "Test"
Other information EF 4.3.1.0, .NET 4, VS2010
My main web application web.config has the EF connection string copied to it as:
<connectionStrings>
<add name="Entities"connectionString="metadata=res://*/MyEntities.csdl|res://*/MyEntities.ssdl|res://*/MyEntities.msl;provider=iAnywhere.Data.SQLAnywhere;provider connection string="UserID=aUser;Password=aPassword;DataSourceName=Test"" providerName="iAnywhere.Data.SQLAnywhere"/>
</connectionStrings>
When I initialize my Entity/ObjectContext in my Repository (see using statement below) it returns an error: "The specified named connection is either not found in the configuration, not intended to be used with the EntityClient provider, or not valid."
using (var context = new Entities())
{
return {Linq to Entity here}
}
I turned on CLR exceptions on the debugger and found the code throws the error in the .NET Framework here:
EntityConnection.cs
effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms, false);
edmx designer generated:
/// <summary>
/// Initializes a new Entities object using the connection string found in the 'Entities' section of the application configuration file.
/// </summary>
public Entities() : base("name=Entities", "Entities")
{
this.ContextOptions.LazyLoadingEnabled = true;
OnContextCreated();
}
I can see my connection string there, so it is having a difficult time parsing the connectionString. I have tried many different permutations of syntax and haven't found anything it accepts including:
Explicitly naming the assembly for entity files instead of a wildcard(e.g. metadata=res://MyDomain/MyEntities.csdl...)
Using Sybase friendly ODBC attributes such as UID instead of UserID, PWD instead of Password, and DBN instead of DataSourceName.
Thanks.
I got everything working and the only reason I can think of is that I deleted my ASP .NET 4.0 temp files. Also, I must add I changed my process from using an integration test to test this piece to using a unit test. I did not do unit tests first, because our build server does not have a database on it.
Once I was able to prove that it was working there, I decided to delete my temp files. After that, everything started working properly. So, some sort of cache issue was occurring in my application. I used the same connectionString that I mentioned above.
Actually, I used the domain name of the Metadata "metadata=res://MyDomain/MyEntitities.csdl" rather than */MyEntities.csdl. I don't plan on changing the domain any time soon. In fact, that is just what may have caused some of the issue, because I had changed the location, name, and namespace of MyEntities.Domain where the EF was.
ETA an explanation of what this is supposed to do.
An employee has to keep track of 2 weeks worth of activities.
Each week(tqiActivitySheetActionBean) contains 7 days (tqiDayActionBean).
Each day contains tasks for that day(tqiTasks)
Tasks are displayed one week at a time(so the employee can switch between this week and last week).
What I did was use an enum to iterate over the week - creates a dataTable of tqiActivitySheetActionBeans and iterate over those in a nested dataTable.
The employee needs to be able to add, delete and edit tasks for each day in place(in the dataTable). I wrapped the tqiTasks in the tqiDayActionBean to group them.
I posted this over at the Seam website, but I'm not getting any bites, I've tried everything I know and some stuff I don't to get this working, but so far no joy.
There's configuration information for Jboss 5 using EJB's, Jboss 4 without. I have an exploded WAR using Jboss 5 and Seam 2.2.0, and no EJB's. I cannot inject an entityManager into my action POJOs.
I tried removing the persistence-unit-ref-name reference from web.xml, added and removed
<transaction:entity-transaction />
<transaction:ejb-transaction />
tags from components.xml (with and without entity-manager="#{entityManager}") . The app won't load when I use either of these.
Used the default values and hardcoded them one at a time. I still can't get this to work.
I'm currently using this configuration:
persistence.xml:
<persistence-unit name="myEmployee" transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:/myEmployeeDatasource</jta-data-source>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.OracleDialect"/>
<property name="hibernate.hbm2ddl.auto" value="validate"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<property name="hibernate.default_schema" value="MY_PROD"/>
<!-- Only relevant if Seam is loading the persistence unit (Java SE bootstrap) -->
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<!-- this binds emf to jndi under java namespace - but only for jboss prior to 5.0 - I shouldn't need this. -->
<property name="jboss.entity.manager.factory.jndi.name" value="java:/EntityManagerFactories/myEmployee"/>
</properties>
</persistence-unit>
components.xml:
<persistence:managed-persistence-context name="entityManager"
persistence-unit-jndi-name="java:/EntityManagerFactories/myEmployee"
auto-create="true"/>
This deploys and starts correctly, but entityManager is still null.
I have a bunch of EntityHome classes in the same package, these can use an entityManager with no problem. All the docs I've looked at state that I should be able to inject an entityManager, I've followed the configuration info from the Seam docs page, the Seam in Action book and the Seam wiki for JBoss 5 (Seam wiki)
I've set breakpoints in the ManagedPersistence class - where it looks like I have an entityManager right up to the time I want to use it, added #Transactional annotations to the class and method. Still nothing. I can get an EM using
(EntityManager)Component.getInstance("entityManager")
But then I have no transactional access to the underlying entityBean and end up with hibernate LazyInitializationExceptions.
I've been using Seam for almost a year now and I have yet to get this to work. Up til now using the Component method has worked, but There must be something fundamentally wrong with our setup that I cannot get injection to work.
I'd appreciate any help.
ETA code for user classes.
The entity class is TQITask. TQIDayActionBean class is supposed to handle the CRUD for a group of TQITasks for one day, TQIActivitySheetActionBean handles the TQIDayActionBeans for one week.
entity bean:
#Entity
#Table(name = "TQI_TASK")
#Name("tqitask")
public class TqiTask implements java.io.Serializable {
static Logger log = Logger.getLogger(TqiTask.class);
private Integer sysid;
private TqiActivitySubtype tqiActivitySubtype;
private TqiActivityType tqiActivityType;
// ... more fields, getters and setters
dayActionBean(a days tasks):
#Name("tQIDayActionBean")
#Transactional(TransactionPropagationType.REQUIRED) //this is latest attempt
#Scope(ScopeType.CONVERSATION)
public class TQIDayActionBean implements Serializable {
static Logger log = Logger.getLogger(TQIDayActionBean.class);
#In(required=true)
EntityManager entityManager;
//this doesn't work either
#DataModel("tqiTasksForOneDay")
#Out(required = false)
private List<TqiTask> tqiTasksForOneDay;
// .... more stuff
// method that should get an entityManager
/**
* tasks are children of tqiActivitySheet, info we need is in tqiActivitySheetV, so use peopleSoftIdSelected and weekSelected.weekSysid
* to get the tqiActivitySheet sysid needed to load the right tasks
* TODO for now lets just get it straight from the db
*/
#SuppressWarnings("unchecked")
#Begin(flushMode=FlushModeType.MANUAL)
public void generateTasksForDayOfWeek() {
log.debug("date to search for: " + this.tqiTaskDate);
this.tqiTasksForOneDay = this.entityManager.createQuery("SELECT t from TqiTask t where t.workDate = ?1 AND t.activitySheetSysid = ?2 order by t.sysid")
.setParameter(1, this.tqiTaskDate).setParameter(2, this.activitySheetSysid).getResultList();
}
getter/setters etc ...
activitySheetActionBean(a week's dayActionBeans):
/**
* handle the activity sheet weekly code generation here
*/
#Name("tqiActivitySheetActionBean")
public class TQIActivitySheetActionBean implements Serializable{
static Logger log = Logger.getLogger(TQIActivitySheetActionBean.class);
// tried it here first
// #In
// EntityManager entityManager;
#Out(value="tqiDayActionBeansForTheWeek", required=false)
List<TQIDayActionBean> tqiDayActionBeansForTheWeek;
// List<DaysOfTheWeek> daysOfTheWeekEnum;
private BigDecimal currentlySelectedWeekActivitySheetSysid;
#PostConstruct
public void init(){
log.debug("calling init");
this.tqiDayActionBeansForTheWeek = new ArrayList<TQIDayActionBean>();
this.updateDataWhenWeekChanges();
}
getters/setters more stuff ....
The bean named tQIDayActionBean of class TQIDayActionBean cannot be instantiated with new, and there is absolute no way to have a List<TQIDayActionBean> in the application.
This bean, like any other Seam managed bean, can only be injected with #In or instantiated with Component.getInstance(). In the second case (that is with Component.getInstance()) you should understand that Seam will always return the same instance as far as you stay in the context boundaries (in this case until the conversation ends).
I suggest that you rework your code in order to separate a TQIDay standard class (without #Name and #Inject) to model the data you need to manage and collect in multiple instances, from an TQIActionBean where you can have your EntityManager injected.