Search This Blog

Friday, 21 September 2012

Spring and Hibernate 2

In the previous post we saw the working of the HibernateTemplate. As discussed Spring doesn't need us to work with it. We can now directly work with the SessionFactory.
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
    <property name="dataSource" ref="c3pDataSource" />
    <property name="mappingResources">
        <list>
            <value>com/data/model/Person.hbm.xml </value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="show_sql">true</prop>
            <prop key="hibernate.hbm2ddl.auto">create</prop>
        </props>
    </property>
</bean>
    
<bean id="personDAO" class="com.data.dao.PersonDAO" >
    <property name="sessionFactory" ref="sessionFactory" />
</bean>
The sessionFactory bean is same as the previous post.What has changed is the PersonDAO class. I wired it with the SessionFactory bean.
public class PersonDAO implements IPersonDAO {

    private SessionFactory sessionFactory;

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
//other methods
}
I tried to access the session using the sessionFactory's getCurrentSession() method. This led to the below failure:
Exception in thread "main" org.hibernate.HibernateException: No Hibernate Session bound to thread, 
and configuration does not allow creation of non-transactional one here
    at org.springframework.orm.hibernate3.SpringSessionContext.currentSession(SpringSessionContext.java:63)
    at org.hibernate.impl.SessionFactoryImpl.getCurrentSession(SessionFactoryImpl.java:622)
    at com.data.dao.PersonDAO.getCrntSession(PersonDAO.java:34)
    at com.data.dao.PersonDAO.save(PersonDAO.java:93)
    at com.test.Client.testPersonLifeCycle(Client.java:56)
    at com.test.Client.main(Client.java:48)
The sessionFactory implementation does not work in the absence of a transactional context unlike the HibernateTemplate. I tries to use the context class setting
<prop key="current_session_context_class">thread</prop>
but that did not help either. So I decided to go with my own session management. The DAO class is as below:
@Repository
public class PersonDAO implements IPersonDAO {

    private SessionFactory sessionFactory;
    private Session session;
    
    public Session getCrntSession() {
        return session;
    }

    public Transaction initialize() {
        if (null != session) {
            throw new RuntimeException("session is still open");
        } else {
            session = sessionFactory.openSession();
        }
        Transaction transaction = session.beginTransaction();
        return transaction;
    }
    
    public void closeAfterOperation() {
        session.flush();
        session.close();
        session = null;
    }
    
    private static final Logger logger = Logger.getLogger(PersonDAO.class);

    @SuppressWarnings("unchecked")
    @Override
    public List<Person> getAllPersons() {
        logger.debug("getAllPersons from system");
        Session session = this.getCrntSession();
        List<Person> persons = new ArrayList<Person>(0);
        Query query = session.createQuery("from Person");
        persons = query.list();
        logger.debug("Total Retrieved items : " + persons.size());
        return persons;
    }

    @Override
    public int findTotalPersons() {
        logger.debug("findTotalPersons: fetching record count ");
        final Session session = this.getCrntSession();
        int total = session.createQuery("from PERSON").list().size();
        return total;
    }

    @Override
    public Person getPersonById(final long personId) {
        logger.debug("fetching record with  id : " + personId);
        Person person = null;
        final Session session = this.getCrntSession();
        person = (Person) session.get(Person.class, personId);
        return person;

    }

    @Override
    public void updatePerson(final Person person) {
        final Session session = this.getCrntSession();
        session.update(person);
    }

    @Override
    public void save(Person person) {
        final Session session = this.getCrntSession();
        session.save(person);
    }

    @Override
    public void delete(Person person) {
        final Session session = this.getCrntSession();
        session.delete(person);
        
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }
    
}
I tested it using the below code:
public static void main(String[] args) {
    final ApplicationContext beanFactory = new ClassPathXmlApplicationContext("spring-hib-template.xml");
    PersonDAO personDAOImpl = (PersonDAO) beanFactory.getBean("personDAO");
    System.out.println(personDAOImpl);
    Transaction transaction = personDAOImpl.initialize();
    testPersonLifeCycle(personDAOImpl);
    transaction.commit();
    personDAOImpl.closeAfterOperation();        
}

public static void testPersonLifeCycle(final IPersonDAO personDAO) {
    Person person = new Person();
    person.setName("Vinod");
    person.setAge(26);
    personDAO.save(person);
    final Long personId = person.getId();
    System.out.println("Person was saved with id " + personId);
    person = personDAO.getPersonById(personId);
    person.setName("Raja");
    personDAO.updatePerson(person);
    System.out.println("Person with id " +personId + " was updated");
    
    person = personDAO.getPersonById(personId);
    System.out.println("Person with id " + personId + " is " + person.getName() + " and age is " + person.getAge());
    personDAO.delete(person);
    System.out.println("person with id " + personId + " has been deleted successfully");
}
As can be seen, I executed my code by starting and managing my own transactions.
The output indicates the code worked !!
com.data.dao.PersonDAO@17b40fe
Person was saved with id 2
78   [main] DEBUG com.data.dao.PersonDAO  - fetching record with  id : 2
Person with id 2 was updated
78   [main] DEBUG com.data.dao.PersonDAO  - fetching record with  id : 2
Person with id 2 is Raja and age is 26
person with id 2 has been deleted successfully
If Hibernate annotations is used then we would need to work with a different sessionFactory
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="annotatedClasses">
        <list>
            <value>com.data.model.Person</value>
        </list>
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="dialect">org.hibernate.dialect.MySQLDialect</prop>
            <prop key="show_sql">true</prop>
        </props>
    </property>
</bean>
This class extends the LocalSessionFactoryBean that we saw earlier. An alternative to annotatedClasses property is
<property name="packagesToScan">
    <list>
        <value>com.data.model.Person</value>
    </list>
</property>

No comments:

Post a Comment