It is said in Spring javadoc article about DriverManagerDataSource class, that this class is very simple and that it is recommended
to use a JNDI DataSource provided by the container. Such a DataSource can be exposed as a DataSource bean in a Spring ApplicationContext via JndiObjectFactoryBean
The question is: how to accomplish this?
For example if I wish to have DataSource bean to access my custo oracle database, what I require then? What to write in context configuration etc?
To access a JNDI data source you do something like:
<bean id="dbDataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jdbc/MyDatabase"/>
</bean>
or look et the spring 'jee' schema.
The details of the database connection are configured in WebLogic, the application accesses
the database through the jndi name.
Or use Java based configuration and do it like this:
#Bean(destroyMethod = "")
public DataSource dataSource() throws NamingException{
Context context = new InitialContext();
return (DataSource)context.lookup("jdbc.mydatasource");
}
There is another option:
<jee:jndi-lookup id="dbDataSource" jndi-name="jdbc/MyLocalDB"
expected-type="javax.sql.DataSource" />
You can use following jndi configuration.
<beans:bean id="weblogicDataSource" class="org.springframework.remoting.rmi.JndiRmiProxyFactoryBean">
<beans:property name="jndiName" value="ConnectionPoolJNDINameAsConfigured"></beans:property>
<beans:property name="jndiEnvironment">
<beans:props>
<beans:prop key="java.naming.factory.initial">weblogic.jndi.WLInitialContextFactory</beans:prop>
<beans:prop key="java.naming.provider.url">iiop://localhost:7001</beans:prop>
</beans:props>
</beans:property>
<beans:property name="serviceInterface" value="javax.sql.DataSource"></beans:property>
</beans:bean>
and you make the reference to your injected class file as
<beans:bean id="xxxx" class="xxxxxxxx">
<beans:property name="wlDataSource" ref="weblogicDataSource" />
</beans:bean>
and in your implemenation class, use
import javax.sql.DataSource;
make an instance as
private DataSource wlDataSource;
and corresponding setter. Now you are free to use JDBCTemplate or SimpleJDBCCall etc as per your implementation thinking.
Hope this will help.
Related
I was using programmatic transaction management in spring, now I have switched to declarative transaction management.
SessionFactory
<beans:bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="com.hcentive.cig.domain" />
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
<beans:prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
TransactionManager
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory">
<beans:ref bean="sessionFactory" />
</beans:property>
</beans:bean>
Now If run my code
#Override
#Transactional
public Request saveRequest(Request request) {
sessionFactory.getCurrentSession().save(request);
return request;
}
I get exception save is not valid without an active transaction
if I remove below line
<beans:prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</beans:prop>
I get
No CurrentSessionContext configured!
You definitely don't need this setting:
<beans:prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</beans:prop>
Spring Transaction Management layer should bind the Hibernate Session to the current running Thread.
The settings are fine, the only thing that might cause it comes from this statement of yours:
no it is getting called from service layer , and also I have tried
moving # transactional to service layer
You need to expose this method:
Request saveRequest(Request request);
through a Service interface, that you inject in any other component (web or other service layer beans).
To validate this, you can place a debug break-point in the saveRequest method implementation, and look for the TransactionInterceptor up the call-stack. If it's not there, then Spring couldn't wrap your method call into a Transaction Aspect processing logic.
Having your function annotated as Transactional is not necessarily enough. You also need to ensure that:
Your bean gets created via Spring (defined as #Component and found via componentScan OR declared in xml configuration)
The reference to your bean needs to be obtained through Spring dependency injection
For #Transactional to be effective you have to tell the Spring context that you want to use that. Annotations without a processor for that annotation is pretty useless. To enable the processor for the #Transactional annotation add <tx:annotation-driven /> to your context. (As explained here in the reference guide).
Your hibernate configuration is also problematic when using Spring you shouldn't mess around with the hibernate.current_session_context_class configuration property (unless you use some specific JTA provider but apparently you aren't). If you start setting that property you will break proper spring integration for transaction management. Spring already sets that property for you and your setting overrides the default.
Your configuration should look something like this.
<beans:bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="dataSource" />
<beans:property name="packagesToScan" value="com.hcentive.cig.domain" />
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</beans:prop>
<beans:prop key="hibernate.show_sql">true</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<beans:bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref bean="sessionFactory" />
</beans:bean>
<tx:annotation-driven />
I am working on an existing project using Spring and Hibernate and am getting confused because I get a
org.springframework.dao.InvalidDataAccessApiUsageException: Write
operations are not allowed in read-only mode (FlushMode.MANUAL): Turn
your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker
from transaction definition.
error when trying to save objects but I still can't find what exactly is wrong.
There is a service layer that is annotated using #Service and a save method that it should be transactional so it is annotated with #Transactional(readOnly = false). To me that means that spring should handle transactions itself.
#Service
public class LadyService {
Logger log = Logger.getLogger(LadyService.class);
#Autowired
private PictureDAO pictureDao;
#Autowired
private LadyDAO ladyDao;
#Autowired
private AddressDAO addressDao;
#Transactional(readOnly = false)
public void save(Lady lady) {
Address a = addressDao.getExistingAddress(lady.getAddress());
if (a == null) {
a = addressDao.save(lady.getAddress());
}
lady.setAddress(a);
ladyDao.save(lady);
pictureDao.savePictures(lady.getPictures());
}
The error happens when doing a save in the AddressDAO. It is annotated as #Repository.
#Repository
public class AddressDAO extends HibernateDaoSupport {
public Address save(Address address) {
getHibernateTemplate().save(address); <-- write not permitted error happens here
return address;
}
#SuppressWarnings({ "unchecked" })
public Address getExistingAddress(Address address) {
DetachedCriteria cd = DetachedCriteria.forClass(Address.class);
cd.add(Restrictions.eqOrIsNull("administrative_area_level_1",
address.getAdministrative_area_level_1()));
cd.add(Restrictions.eqOrIsNull("administrative_area_level_2",
address.getAdministrative_area_level_2()));
List<Address> result = (List<Address>) getHibernateTemplate()
.findByCriteria(cd);
if (result.isEmpty()) {
return null;
} else {
return (Address) result.get(0);
}
}
}
What I thought would happen was that #Transactional makes spring create a session and a transaction for the save on the service layer, and that in the DAOs, the hibernate template would get the current session and transaction that spring manages and use it to save the objects.
The error message, though, makes me think that my service method and dao methods are not in the same transaction.
In the servlet-context.xml there are these statements:
<annotation-driven />
<context:component-scan base-package="com.kog.fable" />
<beans:bean id="mySessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<beans:property name="dataSource" ref="myDataSource" />
<beans:property name="packagesToScan">
<beans:array>
<beans:value>com.kog.fable.**.*</beans:value>
</beans:array>
</beans:property>
<beans:property name="hibernateProperties">
<beans:props>
<beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
</beans:prop>
<!-- create, validate, update -->
<beans:prop key="hibernate.hbm2ddl.auto">create</beans:prop>
<beans:prop key="hibernate.show_sql">false</beans:prop>
<beans:prop key="hibernate.connection.pool_size">10</beans:prop>
<beans:prop key="hibernate.connection.autocommit ">false</beans:prop>
</beans:props>
</beans:property>
</beans:bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<beans:bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="addressDAO" class="com.kog.fable.dao.AddressDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="ladyDAO" class="com.kog.fable.dao.LadyDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
<beans:bean id="pictureDAO" class="com.kog.fable.dao.PictureDAO">
<beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>
Here I don't understand why, if component scan is used, the DAO beans are still declared explicitly. Shouldn't the component scan feature be able to create those by itself since the DAO classes are annotated with #Repository?
Since I thought this configuration could create duplicate beans, I tried deleting the xml entries, but then I started getting:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'addressController': Injection of autowired
dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Could not
autowire field: private com.kog.fable.dao.AddressDAO
com.kog.fable.controller.AddressController.addressDAO; nested
exception is org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'addressDAO' defined in file
[***\com\kog\fable\dao\AddressDAO.class]: Invocation of init method
failed; nested exception is java.lang.IllegalArgumentException:
'sessionFactory' or 'hibernateTemplate' is required
Here I thought that the extension of HibernateDaoSupport for my DAOs would make them inherit the sessionFactory and related methods so I don't understand what happens.
I have read that I could set the flush mode to AUTO or set the setCheckWriteOperations on the template to FALSE to solve that kind of problems and it seems to work, but I guess that this would not ensure the transaction coherence in all cases as I would like it.
Any help would be appreciated as I am quite new to Spring and Hibernate and am a bit stuck here.
When extending HibernateDaoSupport you will not benefit from autowiring, you will have to override the setSessionFactory method and put an #Autowired annotation on it. Else it won't work.
I would also expect a <tx:annotation-driven /> without that the #Transactional is pretty much useless and doesn't do anything.
if your app is Spring MVC based...
in application-context try this..
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="yourSessionFactory"></property>
</bean>
but in dispatcher-servlet (not in appContext !!!)
<tx:annotation-driven />
Dont forget namespaces for tx, and jar libraries spring-tx,spring-orm,hibernate-core
In configuration file
do the change:-
#Configuration
#EnableTransactionManagement <-----Put this line
public PersistenceConfig{
//your code
}
(OR)
#Bean
#Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory session) {
HibernateTemplate hb = new HibernateTemplate();
hb.setCheckWriteOperations(false);
hb.setSessionFactory(session);
return hb;
}
I have ftp connection properties in .properties file and following code for spring bean.
<bean id="ftpConnectionFactory" class="org.springframework.integration.ftp.session.DefaultFtpSessionFactory">
<property name="host" value="${ftp.host}"/>
<property name="port" value="${ftp.port}"/>
<property name="username" value="${ftp.username}"/>
<property name="password" value="${ftp.password}"/>
</bean>
Above method does work using properties file inside web app and placeholder configuration. But what I want is to keep these properties in server, let's say tomcat context.xml file.
I have spring integration which uses this factory.
<int-ftp:outbound-channel-adapter id="ftpOutbound"
channel="ftpChannel"
remote-directory="${ftp.remoteDir}"
remote-file-separator="\"
session-factory="ftpConnectionFactory"
/>
Is there a way that I can externalize these properties in server and look up using jndi. For datasource I am currently doing it. But I don't know how to do it for session factory. The reason why I want to do this is to hide the password and other details.
If Tomcat can correctly bind the object to the JNDI from context.xml, there is no difference to get access to that object from JNDI lookup as you do it for DataSource.
Show, please, how you do it for DataSource from Spring, and how you configure ftpConnectionFactory, and I'll try to help you.
You could use a PropertyPlaceholderConfigurer as follows
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:external.properties</value>
</property>
</bean>
See more examples at 5.8.2 Customizing configuration metadata with a BeanFactoryPostProcessor and Spring PropertyPlaceholderConfigurer Example
I am trying to connect to a mysql database on my first Spring Project and I seem to be overlooking something really simple.
I have this bean in my application-context.xml file which is commented out!
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.url}"
p:username="${jdbc.username}"
p:password="${jdbc.password}" />
I know this is going to sound stupid, but in order to create a class that connects to a Mysql database using JDBC and the or the Spring JDBCTemplate, what do I do from here?
I am confused about how to populate properties in the bean above, do I do it in a superclass like this and then extend my subclasses from it.
import org.springframework.jdbc.datasource.DriverManagerDataSource;
public class JdbcDao {
protected DriverManagerDataSource dataSource = new DriverManagerDataSource();
JdbcDao(){
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost/db_name");
dataSource.setUsername("bcash");
dataSource.setPassword("");
}
}
I am confused so any help is truly apprecated,
Many Thanks
If you are using Tomcat as your application server you can do something more like this.
Define the connection with the user name/password in your server's context.xml file (as opposed to in the application):
<Resource name="jdbc/resourceNameToUse"
auth="Container"
type="javax.sql.DataSource"
username="<UserName>"
password="<Password>"
driverName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/db_name"
maxActive="100"
maxIdle="5"
validationQuery="Select 1"
useCompression="true" />
Then when you configure Spring you create a data source that looks up the resource defined above using JNDI:
<bean id="targetDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName"
value="java:comp/env/jdbc/resourceNameToUse"/>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy">
<property name="targetDataSource">
<ref local="targetDataSource"/>
</property>
</bean>
At this point you can create an instance of your JdbcTemplate as a Spring bean that references your data source:
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource">
<ref bean="dataSource" />
</property>
</bean>
If you are using Spring 3 you can simply mark JdbcTemplate in your DAO as #AutoWired and Spring will match the variable name to the id of the bean you have defined and inject the JdbcTemplate for you. If you aren't using Spring 3 you can simply inject the JdbcTemplate when you define your DAO bean.
public class MyDao {
#AutoWired
private JdbcTemplate jdbcTemplate;
}
See JdbcTemplate Best Practices for further info.
Nutshell: no, your DAO wouldn't create a new datasource via new; that defeats the purpose of using Spring. Implementations should be injected, not instantiated directly; roughly:
public class TheDaoImpl implements TheDao {
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.jdbcTemplate = new JdbcTemplate(dataSource);
}
// JDBC-backed implementations of TheDao follow...
}
Then in your Spring config (if not using annotations), also roughly:
<bean id="theDao" class="com.bar.plugh.TheDaoImpl" p:dataSource-ref="dataSource" />
(This uses a setter; you could also use an annotation and skip the XML config.)
You could also use JdbcTemplate as your base class and save more energy.
I recommend going over the Data access with JDBC reference docs (if you're using JDBC), or the corresponding section that deals directly with your ORM choice.
I'm trying to set up a Spring JPA Hibernate simple example WAR for deployment to Glassfish.
I see some examples use a persistence.xml file, and other examples do not.
Some examples use a dataSource, and some do not. So far my understanding is that a dataSource is not needed if I have:
<persistence-unit name="educationPU"
transaction-type="JTA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.coe.jpa.StudentProfile</class>
<properties>
<property name="hibernate.connection.driver_class"
value="com.mysql.jdbc.Driver" />
<property name="hibernate.connection.url"
value="jdbc:mysql://localhost:3306/COE" />
<property name="hibernate.connection.username" value="root" />
<property name="show_sql" value="true" />
<property name="dialect" value="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
I can deploy fine, but my EntityManager is not getting injected by Spring.
My applicationContext.xml:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="educationPU" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="StudentProfileDAO" class="com.coe.jpa.StudentProfileDAO">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="studentService" class="com.coe.services.StudentService">
</bean>
My class with the EntityManager:
public class StudentService {
private String saveMessage;
private String showModal;
private String modalHeader;
private StudentProfile studentProfile;
private String lastName;
private String firstName;
#PersistenceContext(unitName="educationPU")
private EntityManager em;
#Transactional
public String save()
{
System.out.println("*** em: " + this.em); //em is null
this.studentProfile= new StudentProfile();
this.saveMessage = "saved";
this.showModal = "true";
this.modalHeader= "Information Saved";
return "successs";
}
My web.xml:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
Are there any pieces I am missing to have Spring inject "em" in to StudentService?
Just to confirm though you probably did...
Did you include the
<!-- tell spring to use annotation based congfigurations -->
<context:annotation-config />
<!-- tell spring where to find the beans -->
<context:component-scan base-package="zz.yy.abcd" />
bits in your application context.xml?
Also I'm not so sure you'd be able to use a jta transaction type with this kind of setup? Wouldn't that require a data source managed connection pool? So try RESOURCE_LOCAL instead.
I'm confused. You're injecting a PU into the service layer and not the persistence layer? I don't get that.
I inject the persistence layer into the service layer. The service layer contains business logic and demarcates transaction boundaries. It can include more than one DAO in a transaction.
I don't get the magic in your save() method either. How is the data saved?
In production I configure spring like this:
<jee:jndi-lookup id="entityManagerFactory" jndi-name="persistence/ThePUname" />
along with the reference in web.xml
For unit testing I do this:
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
p:dataSource-ref="dataSource" p:persistence-xml-location="classpath*:META-INF/test-persistence.xml"
p:persistence-unit-name="RealPUName" p:jpaDialect-ref="jpaDialect"
p:jpaVendorAdapter-ref="jpaVendorAdapter" p:loadTimeWeaver-ref="weaver">
</bean>
If anyone wants to use purely Java configuration instead of xml configuration of hibernate, use this:
You can configure Hibernate without using persistence.xml at all in Spring like like this:
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean()
{
Map<String, Object> properties = new Hashtable<>();
properties.put("javax.persistence.schema-generation.database.action",
"none");
HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setDatabasePlatform("org.hibernate.dialect.MySQL5InnoDBDialect"); //you can change this if you have a different DB
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(adapter);
factory.setDataSource(this.springJpaDataSource());
factory.setPackagesToScan("package name");
factory.setSharedCacheMode(SharedCacheMode.ENABLE_SELECTIVE);
factory.setValidationMode(ValidationMode.NONE);
factory.setJpaPropertyMap(properties);
return factory;
}
Since you are not using persistence.xml, you should create a bean that returns DataSource which you specify in the above method that sets the data source:
#Bean
public DataSource springJpaDataSource()
{
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setUrl("jdbc:mysql://localhost/SpringJpa");
dataSource.setUsername("tomcatUser");
dataSource.setPassword("password1234");
return dataSource;
}
Then you use #EnableTransactionManagement annotation over this configuration file. Now when you put that annotation, you have to create one last bean:
#Bean
public PlatformTransactionManager jpaTransactionManager()
{
return new JpaTransactionManager(
this.entityManagerFactoryBean().getObject());
}
Now, don't forget to use #Transactional Annotation over those method that deal with DB.
Lastly, don't forget to inject EntityManager in your repository (This repository class should have #Repository annotation over it).
I have a test application set up using JPA/Hibernate & Spring, and my configuration mirrors yours with the exception that I create a datasource and inject it into the EntityManagerFactory, and moved the datasource specific properties out of the persistenceUnit and into the datasource. With these two small changes, my EM gets injected properly.
This may be old, but if anyone has the same problem try changing unitname to just name in the PersistenceContext annotation:
From
#PersistenceContext(unitName="educationPU")
to
#PersistenceContext(name="educationPU")