My question is somewhat related to this; Can I use multiple C3P0 datasources for DB instance?
I have two Spring web services which accesses the same mySQL database schema. And I am using c3p0 to pool database connections. I am accessing the database using JPA/Hibernate
I have configured two data base pools, entitity manager factories and transaction managers similar to the above question.
In the first service
<bean id="dataSource1" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test?zeroDateTimeBehavior=convertToNull"
p:user="test1" p:password="test1"
p:acquireIncrement="1" p:idleConnectionTestPeriod="10" p:maxPoolSize="25"
p:maxStatements="20" p:minPoolSize="5" >
</bean>
<bean id="entityManagerFactory1"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
<property name="persistenceUnitName" value="hibernatePersistenceUnit1" />
<property name="dataSource" ref="dataSource1" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManager1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource1" />
<property name="entityManagerFactory" ref="entityManagerFactory1" />
</bean>
In the second service
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close" p:driverClass="com.mysql.jdbc.Driver" p:jdbcUrl="jdbc:mysql://localhost/test?zeroDateTimeBehavior=convertToNull"
p:user="test1" p:password="test1"
p:acquireIncrement="1" p:idleConnectionTestPeriod="10" p:maxPoolSize="25"
p:maxStatements="20" p:minPoolSize="5" >
</bean>
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceXmlLocation" value="classpath*:META-INF/persistence.xml"></property>
<property name="persistenceUnitName" value="hibernatePersistenceUnit2" />
<property name="dataSource" ref="dataSource2" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
</bean>
</property>
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource2" />
<property name="entityManagerFactory" ref="entityManagerFactory2" />
</bean>
Also I have annotated the two data access classes with relevant transaction manager
#Transactional("transactionManager1")
public class JPADataAccessObject1<T, ID extends Serializable> implements DataAccessObject<T, ID>
#Transactional("transactionManager2")
public class JPADataAccessObject2<T, ID extends Serializable> implements DataAccessObject<T, ID>
One of my services has a spring message channel which uses a jpa-inbound-channel-adapter
<int:channel id="testChannel">
<int:priority-queue capacity="20" />
</int:channel>
<int-jpa:inbound-channel-adapter
channel="testChannel" entity-class="com.test.TestObject"
entity-manager-factory="entityManagerFactory1" auto-startup="true"
jpa-query="SELECT x FROM TestObject AS x WHERE x.testColumns LIKE '1'"
delete-after-poll="true">
<int:poller fixed-rate="5000">
<int:transactional propagation="REQUIRED"
transaction-manager="transactionManager1" />
</int:poller>
</int-jpa:inbound-channel-adapter>
Now the problem is when I deploy both services in tomcat 7 they become not responding. Any idea on this?
I went on a different approach and setup a container managed database pool in tomcat and referred as a JNDI resource.
In Server.xml
<Resource type="javax.sql.DataSource"
name="jdbc/TEST"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/test?zeroDateTimeBehavior=convertToNull"
username="test1"
password="test1"
initialSize="10"
maxActive="100"
maxIdle="50"
minIdle="10"/>
In Context.xml
<ResourceLink type="javax.sql.DataSource"
name="jdbc/LocalTEST"
global="jdbc/TEST"/>
And the bean configuration for the datasource is,
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/LocalTEST"/>
</bean>
Related
i have the following declared in spring.xml:
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
...
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- Adapters -->
<bean id="ADBAdapter" class="model.adapter.ADBAdapter">
<constructor-arg>
<ref bean="sessionFactory" />
</constructor-arg>
</bean>
So after i created the context. I can Access my ADBAdapter and do stuff.
The Problem is, that i want to use ADBAdapter in another Thread.
But then i get sometimes a SessionClosed Exception, because the session gets closed in the parent thread.
How can I handle this ?
Thank you for your help
In hibernate you can use
hibernate.current_session_context_class=thread
I have a problem with my spring boot configuration in xml I created this configuration :
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="false"/>
<property name="database" value="ORACLE"/>
</bean>
<bean id="dataSource" primary="true" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#localhost:20300:test"/>
<property name="username" value="test"/>
<property name="password" value="test"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="entityManagerFactory" primary="true" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<!-- spring based scanning for entity classes-->
<property name="packagesToScan" value="model.entity"/>
<property name="persistenceUnitName" value="msPersistenceUnit" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="controllerService"
class="...impl.ControllerServiceImpl">
<property name="entityManager" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" >
<constructor-arg index="0" ref="entityManagerFactory" />
</bean>
And I had the java code like this :
public void setEntityManager(final HibernateEntityManagerFactory entityManager) {
final RepositoryFactorySupport factorySupport = new JpaRepositoryFactory(entityManager.createEntityManager());
controlRepository = factorySupport.getRepository(ObjControlRepository.class);
}
when i'm using find method it's ok, but when I'm doing a save, there are not exception but the value it's not insert.
Thank your for your help.
[Edit]
To save I'm using :
/**
* The Interface ObjControlRepository.
*/
public interface ObjControlRepository extends CrudRepository<ObjControl, String> {
}
And I'm calling the method like that :
controlRepository.save(newValue);
You should try to explicitly set the hibernate.hbm2ddl.auto variable to auto. This will prevent your application to release previous data when you start your application.
You can learn more about the hibernate.hbm2ddl.auto variable here.
You should use transactions and commit the transaction in order to save an entity.
So Use #Transactionl annotation on your service layer, like this:
#Transactional
public class ControllerServiceImpl {
...
}
As ControllerServiceImpl is already declared as a bean in spring configuration file, Spring will take care about committing the transaction once you save an entity.
I previously had this config for Hibernate using RESOURCE-LOCAL transaction type:
persistence.xml:
<persistence-unit name="myPU" transaction-type="JTA">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
</persistence-unit>
applicationContext (dataaccess bit):
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory"></bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceUnitName" value="myPU"/>
<property name="jpaProperties">
<props>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
<bean id="entityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.jpa.vendor.HibernateJpaSessionFactoryBean">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<!-- Are there any other properties required? -->
</bean>
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
</bean>
<bean id="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/jdbc/CNTXESDB" />
<property name="lookupOnStartup" value="true" />
<property name="cache" value="true" />
<property name="proxyInterface" value="javax.sql.DataSource" />
</bean>
But this kind of transaction seems not to work with Glassfish, so I had to switch to JTA transactions.
The problem is -- to get Spring to manage transaction creation (through #Transactional) I need to define a TransactionManager bean but JtaTransactionManager included in spring-tx does not accept an entityManagerFactory bean, so it does not know where the entityManager is in order to open/close/flush Hibernate session.
So how can I configure Spring with Hibernate to use JTA transactions?
EDIT:
turns out you can use RESOURCE_LOCAL transactions with Glassfish, but somehow you cannot have a persistence.xml file. I renamed this file to my_persistence.xml and configured LocalContainerEntityManagerFactoryBean like this:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaAdapter" />
<property name="persistenceUnitName" value="myPU"/>
<property name="persistenceXmlLocation" value="classpath:META-INF/my_persistence.xml" />
<property name="jpaProperties">
<props>
<prop key="javax.persistence.validation.mode">none</prop>
</props>
</property>
</bean>
I had a similar problem and finally I solved as you can see in this little demo:
https://github.com/miguelangelprogramacion/spring4_jpa_hibernate
With [1] as a reference, I prefer to use Spring's Transaction Support before JTA.
Also, I've used an annotation based approach.
[1] http://spring.io/blog/2011/08/15/configuring-spring-and-jta-without-full-java-ee/
I am having an issue creating xa datasources in spring 4.0.
I have setup my datasources in weblogic using an xa driver.
I then added added jndi-lookups for the data sources in spring:
<jee:jndi-lookup id="dataSourceOne" jndi-name="/jdbc/XAONE" resource-ref="true" />
<jee:jndi-lookup id="dataSourceTwo" jndi-name="/jdbc/XATWO" resource-ref="true" />
I have then created the configuration for the entity managers:
<bean id="emfone" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceOne" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="packagesToScan" value="..." />
</bean>
<bean id="emftwo"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSourceTwo" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="packagesToScan" value="..." />
</bean>
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="true" />
<property name="generateDdl" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
</bean>
After this I have my transaction manager configured:
<tx:annotation-driven />
<tx:jta-transaction-manager />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emfone" />
<qualifier value="tmOne"/>
</bean>
<bean id="docTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="emftwo" />
<qualifier value="tmTwo"/>
</bean>
I have a service class method annotated with #Transactional that calls a DAO. The DAO uses both entity managers for persisting data.
When the DAO tries to persist using the emftwo a no transaction in progress error is thrown. Does anybody know where I am going wrong?
Thanks,
I have a Spring application, i want to change the data source dynamically,ie. when input a DS URL, the Spring beans and all dependency will get updated automatically.I know this is somewhat strange, but anyway i want to achieve that.
My Spring configuration as following:
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.serverName}" />
<property name="portNumber" value="${jdbc.portNumber}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="databaseName" value="${jdbc.databaseName}" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="majorDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="majorDataSource"/>
<property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>
The questions are:
The JDBC URL is stored in properties, which could be changed runtime.
Once the URL is changed, i need to re-create the data source and maybe the dependent objects. I could not figure out how to do it elegantly in Spring?
I have known that Spring did could dynamically route data source based on one key, but the data source URL is predefined in Spring and will not change runtime. It is not my case.
You can use spring's AbstractRoutingDataSource by extending it and overriding the method determineCurrentLookupKey() that should return the key referencing the datasource's spring bean to be used.
Take a look at this blog article on spring source's blog which will show you an example of how to use that feature.
Basically to answer your questions, what you will need to do is to define the two datasources as different spring bean in your XML config. There is no need to create one dynamically, spring will load both, and use one or the other dynamically depending on your criteria in the determineCurrentLookupKey() method.
This would lead to something like:
XML config
<!-- first data source -->
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.major.serverName}" />
<property name="portNumber" value="${jdbc.major.portNumber}" />
<property name="user" value="${jdbc.major.username}" />
<property name="password" value="${jdbc.major.password}" />
<property name="databaseName" value="${jdbc.major.databaseName}" />
</bean>
<!-- second data source -->
<bean id="minorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="${jdbc.minor.serverName}" />
<property name="portNumber" value="${jdbc.minor.portNumber}" />
<property name="user" value="${jdbc.minor.username}" />
<property name="password" value="${jdbc.minor.password}" />
<property name="databaseName" value="${jdbc.minor.databaseName}" />
</bean>
<!-- facade data source -->
<bean id="dataSource" class="blog.datasource.CustomerRoutingDataSource">
<property name="targetDataSources">
<map>
<entry key="MINOR" value-ref="minorDataSource"/>
<entry key="MAJOR" value-ref="majorDataSource"/>
</map>
</property>
<property name="defaultTargetDataSource" ref="majorDataSource"/>
</bean>
<!-- wiring up -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:sqlmap-config.xml"/>
</bean>
Java
public class MyRoutingDataSource extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
// get the current url
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
if (request.getRequestURL().toString().endsWith("/minor"))
return "MINOR";
else
return "MAJOR";
}
}
I am not sure if this is the correct Way of doing this but what you can do is something like this.
<bean id="majorDataSource" class="org.postgresql.ds.PGSimpleDataSource">
<property name="serverName" value="dummydata" />
<property name="portNumber" value="dummydata" />
<property name="user" value="dummydata" />
<property name="password" value="dummydata" />
<property name="databaseName" value="dummydata" />
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="majorDataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
and in Java Class
public class TestTransaction {
#Autowired
private DataSourceTransactionManager manager;
private PlatformTransactionManager transactionManager;
public testExecution(DataSource ds) {
manager.setDataSource(ds);
transactionManager = manager;
TransactionDefinition def = new DefaultTransactionDefinition();
TransactionStatus status = transactionManager.getTransaction(def);
try {
jdbcTemplate.update();
transactionManager.commit(status);
} catch (Exception ex) {
transactionManager.rollback(status);
}
}
}
Please suggest if this Approach could Work as i am Still new to Spring