Help! I'm using Spring+Hibernate and I'm trying to use AOP like this :
package ua.i.pustovalov.table;
enter code here
#Aspect
public class Aoprad {
#Pointcut("execution(* *getAll(..))")
public void performance() {
}
public Aoprad() {
}
#Around("performance()")
public void AfterAndPriv(ProceedingJoinPoint joinPoint) {
try {
System.out.println("Open query");
joinPoint.proceed();
System.out.println("Close query");
} catch (Throwable e) {
e.printStackTrace();
}
}
}
When I try to use my method, it returns null.
public class TestDao {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
new String[] { "applicationContext.xml" }, true);
DaoInterface das = (DaoInterface) context.getBean("dataDao");
System.out.println(das.getAll());
}
<context:annotation-config />
<aop:aspectj-autoproxy />
<context:component-scan base-package="ua.i.pustovalov.*">
</context:component-scan>
<bean id="audience" class="ua.i.pustovalov.table.Aoprad" />
<aop:config>
<aop:pointcut id="myPointcut"
expression="execution(* ua.i.pustovalov.maven.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- <tx:method name="get*" propagation="REQUIRED" read-only="true" /> -->
<tx:method name="getAll*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="url">
<value>jdbc:mysql://localhost:3306/homebase</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value></value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="classpath:/hibernate.cfg.xml" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<!-- <prop key="hibernate.hbm2ddl.auto">create</prop> -->
</props>
</property>
</bean>
<bean id="dataDao" class="ua.i.putsovalov.dao.DaoStudent">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
My DAO class
package ua.i.putsovalov.dao;
public class DaoStudent extends HibernateDaoSupport implements DaoInterface {
public DaoStudent() {
}
#Override
protected HibernateTemplate createHibernateTemplate(
SessionFactory sessionFactory) {
HibernateTemplate result = super
.createHibernateTemplate(sessionFactory);
result.setAllowCreate(true);
return result;
}
#Override
public Student get(int id) {
return (Student) getSession().get(Student.class, id);
}
#Override
public Student get(String text) {
return (Student) getSession().get(Student.class, text);
}
#SuppressWarnings("unchecked")
#Override
public Collection<Student> getAll() {
return getSession().createCriteria(Student.class).list();
}
}
And interface
public interface DaoInterface {
Student get(int id);
Student get(String text);
Collection<Student> getAll();
}
What steps can I take to debug this issue?
When using an around aspect you should always use a method signature that returns Object and not void and you should always return the result of the call to the proceed() method. If you fail to do so every method that is advices by this aspect will return null because there is nothing returned.
#Around("performance()")
public Object AfterAndPriv(ProceedingJoinPoint joinPoint) {
try {
System.out.println("Open query");
return joinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
} finally {
System.out.println("Close query");
}
}
Related
I have this in my servlet:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="12345" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.tricas.models" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.enable_lazy_load_no_trans">true</prop>
<prop key="hibernate.default_schema">test</prop>
<prop key="format_sql">true</prop>
<prop key="use_sql_comments">true</prop>
<!--<prop key="hibernate.hbm2ddl.auto">create</prop> -->
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
and my DaoImp
#Repository
#Transactional
public class UserDaoImp implements UserDao {
#Autowired
SessionFactory session;
public List<Users> list() {
return session.getCurrentSession().createQuery("from Users").list();
}
here is my HibernateUtil
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from standard (hibernate.cfg.xml)
// config file.
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
And After executing the application I have a NullPointerException:
SEVERE [http-nio-8084-exec-97] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service () for servlet [spring-web] in context with path [/ Holaspringmvc] threw exception [Request processing failed; Nested exception is java.lang.NullPointerException] with root cause
Java.lang.NullPointerException
At com.tricas.dao.UserDaoImp.list (UserDaoImp.java:32)
Please help me.
Be simpler. Just declare SessionFactory bean
#Bean
public AbstractSessionFactoryBean sessionFactoryBean(){
AnnotationSessionFactoryBean sessionFactoryBean = new AnnotationSessionFactoryBean();
sessionFactoryBean.setConfigLocation(new ClassPathResource("hibernate.cfg.xml"));
return sessionFactoryBean;
}
similar for LocalSessionFactoryBean
btw: did you define component-scan ?
<context:component-scan base-package="<my.base.package>" />
I found the error, results that I had to define in the service and in the controller also with #Autowired
Here is my Service.
#Autowired
UserDao usrdao;
//private UserDao usrdao = new UserDaoImp();
#Transactional
public List<Users> getAllUsers() {
return usrdao.list();
}
and here is my controller
#Autowired
UserService usrv;
//private UserService usrv = new UserService();
#RequestMapping(value = "/verusuarios", method = RequestMethod.GET)
public String listPersons(Model model) {
List<Users> list = usrv.getAllUsers();
model.addAttribute("user", new Users());
model.addAttribute("list", list);
return "verusuarios";
}
Additionally I must add to guide me from this answer: answer here
I am facing problem in multi data source connection with spring, one of the transaction is working, but other one is not working. please help.
***********Data Source 1 start************
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database1.ds" />
<property name="persistenceUnitName" value="database1" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />
***********Data Source 1 end************
***********Data Source 2 start************
<bean id="entityManagerFactory2"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="database2.ds" />
<property name="persistenceUnitName" value="database2" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter2" />
<property name="persistenceXmlLocation" value="classpath:jpa-persistence.xml" />
</bean>
<bean id="jpaVendorAdapter2
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="showSql" value="false" />
</bean>
<bean id="transactionManager2" class="org.springframework.orm.jpa.JpaTransactionManager"
p:entityManagerFactory-ref="entityManagerFactory2" />
***********Data Source 2 end************
<context:component-scan base-package="com.wmi.lakshya" annotation-config="true" scope-resolver="org.springframework.context.annotation.Jsr330ScopeMetadataResolver"/>
<tx:annotation-driven />
<cache:annotation-driven />
Entity Manager class
#Repository
#Scope("singleton")
public class EntityManagerImpl implements EntityManagerGenerator {
#PersistenceContext(unitName = "database1",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager;
#PersistenceContext(unitName = "database2",type=PersistenceContextType.EXTENDED)
private EntityManager entityManager2;
#Override
public EntityManager getEntityManager() {
try {
if (isUser1()) {
return entityManager;
}
return entityManager2;
} catch (Exception e) {
return entityManager;
}
}
}
#Transactional(value ="transactionManager")
public Query createNativeQuery(String sqlString) {
return entityManager.createNativeQuery(sqlString);
}
#Transactional(value ="transactionManager2")
public Query createNativeQuery1(String sqlString) {
return entityManager1.createNativeQuery(sqlString);
}
javax.persistence.TransactionRequiredException: Executing an
update/delete query
#Component
#Scope("prototype")
public class UserDAO extends AbstractDAO<User> {
/**
*
*/
private static final Logger LOGGER = Logger.getLogger(UserDAO.class);
/**
*
*/
protected UserDAO() {
super(User.class);
}
public void resetFailAttempts(String userName){
// em is entity manager class
em.createNativeQuery("update OMS_USER_MASTER set fail_attempts = 0 where login_id = :loginId ")
.setParameter(QueryParameters.LOGIN_ID, userName)
.executeUpdate();
}
}
Datasource is switched based on the condition, when connecting with datasource 1 is working, but not for datasource2.
On production environment I got following error.
org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLException: Cannot create PoolableConnectionFactory (The Network Adapter could not establish the connection)
When I connect through toad, it said ORA-12541 no listener error. The issue resolved after restart of linstener.
But the actual issue may be that lot of connections opened by the web application and it is not closing that. Following are my code and configuration.
I am using EcllipseLink, dbcp2 for connections
<persistence-unit name="persistance-unit" transaction-type="RESOURCE_LOCAL">
<class>com.company.model.Characteristic</class>
...
<!--more classes -->
<exclude-unlisted-classes>true</exclude-unlisted-classes>
<properties>
<property name="eclipselink.weaving" value="false"/>
</properties>
</persistence-unit>
dbcp2 settings
<bean id="datasource" class="org.apache.commons.dbcp2.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="maxIdle" value="10" />
<property name="maxTotal" value="200" />
<property name="maxWaitMillis" value="60000" />
<property name="validationQuery" value="select 1 from dual" />
<property name="validationQueryTimeout" value="10" />
<property name="testOnBorrow" value="true" />
<property name="testWhileIdle" value="true" />
<property name="timeBetweenEvictionRunsMillis" value="30000" />
<property name="minEvictableIdleTimeMillis" value="60000" />
<property name="numTestsPerEvictionRun" value="5" />
<property name="defaultAutoCommit" value="true" />
</bean>
Connection Factory
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="persistance-unit"/>
<property name="dataSource" ref="datasource"/>
<property name="jpaVendorAdapter">
<bean id="jpaAdapter" class="org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
</bean>
Transaction Management
Abstract GenericDao
public abstract class GenericDao<T> implements IGenericDao<T> {
#PersistenceContext
protected EntityManager entityManager
private Class<T> type
public GenericDao() {
Type t = getClass().getGenericSuperclass()
ParameterizedType pt = (ParameterizedType) t
type = (Class) pt.getActualTypeArguments()[0]
}
#Override
public T save(final T t) {
this.entityManager.persist(t)
return t
}
public def saveObj(def t) {
try {
this.entityManager.persist(t)
}catch(e){
log.info("Error occured: ", e)
}
return t
}
#Override
public void delete(final Object id) {
this.entityManager.remove(this.entityManager.getReference(type, id))
}
#Override
public T find(final Object id) {
return (T) this.entityManager.find(type, id)
}
#Override
public T update(final T t) {
return this.entityManager.merge(t)
}
#Override
public def executeNamedQuery(String namedQueryName, Map<String, Object> queryParams)
{
List results = null
try {
Query query = entityManager.createNamedQuery(namedQueryName)
if (queryParams) {
addPrametersToQuery(query, queryParams)
}
results = query.getResultList()
} catch (NoResultException e) {
} catch (Exception e) {
log.error("Error occured: ", e)
throw e
}
return results
}
}
Dao component using that Generic Dao
#Component("characteristicDao")
class CharacteristicDao extends GenericDao<Characteristic> implements ICharacteristicDao {
public def getCharacteristics(String name){
log.info("Entering getCharacteristics")
Characteristic characteristic = (PrmCharacteristic) executeQueryWithSingleResult("select b from Characteristic b where b.name=:name", [name:name])
log.info("Exiting getCharacteristics")
return characteristic
}
}
I use CharacteristicDao component to interact with database. Similarly I have other dao also. I have just given one example.
I use #Transactional in service for the transaction. Any master can help me please what I am doing wrong.
I am using spring 3.2 with hibernate 4. I want to use spring to control the transactions.
However with the configuration mentioned below I get the
'Servlet.service() for servlet spring threw exception: org.hibernate.HibernateException: No Session found for current thread'
exception:
<aop:config>
<aop:pointcut id="serviceMethods"
expression="execution(* com.locator.service.impl.ServiceTypeService.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods" />
</aop:config>
<tx:advice id="txAdvice" transaction-manager="hbTransactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- Hibernate session factory -->
<bean id="hbSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>../spring/model/ServiceType.hbm.xml</value>
</list>
</property>
</bean>
<bean id="hbTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="hbSessionFactory" />
</bean>
<bean id="serviceTypeService" class="com.locator.service.impl.ServiceTypeService">
<property name="serviceTypeDao" ref="serviceTypeDao"></property>
</bean>
<bean id="serviceTypeDao" class="com.locator.dao.impl.ServiceTypeDao">
<property name="sessionFactory" ref="hbSessionFactory"></property>
</bean>
The code for the Dao layer and the Service is as follows:
public class ServiceTypeDao implements IServiceTypeDao{
private static final Log log = LogFactory.getLog(ServiceTypeDao.class);
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory(){
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public ServiceType findById(int id) {
log.debug("getting ServiceType instance with id: " + id);
try {
Session session = getSessionFactory().getCurrentSession();
ServiceType instance = (ServiceType) session.get("com.locator.model.ServiceType", id);
if (instance == null) {
log.debug("get successful, no instance found");
} else {
log.debug("get successful, instance found");
}
instance.setName(instance.getName()+"0");
session.saveOrUpdate(instance);
return instance;
}catch (RuntimeException re) {
log.error("get failed", re);
throw re;
}
}
}
public class ServiceTypeService implements IServiceTypeService{
private ServiceTypeDao serviceTypeDao;
public void setServiceTypeDao(ServiceTypeDao serviceTypeDao){
this.serviceTypeDao = serviceTypeDao;
}
public ServiceType getServiceTypeById(int id){
return serviceTypeDao.findById(id);
}
}
Replacing getSessionFactory().getCurrentSession() with getSessionFactory().openSession() will resolve the above issue however, it will mean that the developer will then be responsible for the session open/close rather than spring. Therefore, please advise how this can be resolved using spring.
I was able to resolve the issue. It was occurring due to the following problems:
The Service class had not been Auto wired into the controller i.e. the #Autowired annotation was missing.
The configuration for the web.xml had to be modified with the listener class 'org.springframework.web.context.ContextLoaderListener' and the context-param was added.
I have two Quartz (1.8.3) jobs, configured via Spring (2.5.6), one of them writes (send) to database, and one reads from it (check).
<bean id="scheduleFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="Check"/>
<ref bean="Send"/>
</list>
</property>
</bean>
<bean id="Send" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="sendMessage" />
</bean>
</property>
<property name="cronExpression" value="0 0/1 * * * ?" />
</bean>
<bean id="Check" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="StatusMonitor" />
<property name="targetMethod" value="checkAndUpdateStatus" />
</bean>
</property>
<property name="cronExpression" value="30 0/1 * * * ?" />
</bean>
Transaction manager is set up:
<tx:annotation-driven transaction-manager="TransactionManager"/>
In both jobs I explicitly run read/write operations in transactions like this:
#Override
public synchronized void sendMessage() {
try {
TransactionTemplate tt = new TransactionTemplate(ptm);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
...
statusDAO.update(status);
...
}
});
log.info("Status was updated");
} catch (Exception e) {
...
}
}
where ptm is a TransactionManager bean, injected via Spring.
I see "Status was updated" record in logs, but when I read this record from transactional read method it is outdated sometimes. Moreover, when I use an SQL editor to read this record it is outdated too.
I don't understand, why transactions dont work in this case, do you have any ideas?
Thanks.
For anyone that might be interested. This worked for me
<bean name="applicationDataCollectorControllerJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass" value="org.mypckage.controller.jobs.ApplicationDataCollectorController" />
<property name="jobDataAsMap">
<map>
<!--<entry key="timeout" value="1" />-->
<entry key="genericService" value-ref="genericService" />
<entry key="applicationDataCollectorService" value-ref="applicationDataCollectorService" />
<entry key="transactionManager" value-ref="transactionManager" />
</map>
</property>
</bean>
--- in the scheduler bean---
#Override
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
getApplicationDataCollectorService().collectData(transactionManager);
}
----In the applicationDataCollectorService bean-----
public void collectData( org.springframework.transaction.jta.JtaTransactionManager transactionManager) {
try {
this.transactionManager = transactionManager;
testTransactionalSave();
} catch (Exception e) {
BUSY = false;
e.printStackTrace();
}
}
}
private void testTransactionalSave() throws Exception {
TransactionTemplate tt = new TransactionTemplate(transactionManager);
tt.execute(new TransactionCallbackWithoutResult() {
#Override
protected void doInTransactionWithoutResult(TransactionStatus ts) {
try {
ApplicationParameter appPara = null;
List<ApplicationParameter> appParaList = genericService.getListFromHQL("select o from ApplicationParameter as o order by o.id desc", false);
if (appParaList != null) {
if (appParaList.size() > 0) {
appPara = (ApplicationParameter) appParaList.get(0);
appPara.setLastBankStatementMailNum(appPara.getLastBankStatementMailNum() + 10);
appPara = (ApplicationParameter) genericService.mergeObject(appPara);
System.out.println(" num is now = " + appPara.getLastBankStatementMailNum());
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
}
Note: dont forget to declare transactionManager as private properties in both beans with public setter and getter for spring to wire it up. Any Questions? yemiosigbesan#gmail.com