Save succeeds but no record inserted

73 views
Skip to first unread message

Bercy

unread,
Sep 18, 2013, 8:09:44 AM9/18/13
to java-gen...@googlegroups.com
Hi,

I have a JUnit test saving an object instance.  There is no exception.  When I step through the code, I see that the DAO gets a new key for the object (it's auto-increment in the DB).  But, when the test concludes, there is no new record in the database.

I'm new to Spring, Hibernate, and obviously the GDAO, so I've had lots to learn in the last couple of days.

I'm guessing my problem has to do with the transaction not being committed somehow ?  I'm just wondering what it is I forgot...

I'm posting the JUnit, configuration files, entity model class, and DAO interface and implementation below.


Here's the JUnit:

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;

import java.util.Date;

import org.apache.log4j.Logger;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import <my package>.dao.VsAgencyDAO;
import <my package>.model.VsAgency;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml"})
public class VsAgencyTest {
    VsAgencyDAO dao;
   
    static Logger log = Logger.getLogger(VsAgencyTest.class);

    public VsAgencyDAO getDao() {
        return dao;
    }

    @Autowired
    public void setDao(VsAgencyDAO dao) {
        this.dao = dao;
    }


    @Test
    @Transactional
    public void testWrite() {
        log.debug("testWrite start");
        // Just a write, verify id set
        VsAgency agency = new VsAgency();
        agency.setName("Junit Test Agency");
        agency.setTs(new Date());
        assertNull(agency.getId());
        log.debug("testWrite calling dao.save()");
        try {
            dao.save(agency);
        } catch (Exception e) {
            log.error("Exception calling dao.save()", e);
        }
        log.debug("testWrite back from dao.save()");
        assertNotNull(agency.getId());
    }
}


Here's the applicationContext.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans ... namespaces....>

    <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager" autowire="autodetect">
        <property name="dataSource">
            <ref local="dataSource" />
        </property>
    </bean>

    <!-- C3P0 Configuration -->
    <bean id="mainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">
        <property name="driverClass" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUrl" value="<my jdbc url>" />
        <property name="user" value="<my user>" />
        <property name="password" value="<my password>" />
        <property name="idleConnectionTestPeriod" value="60" />
        <property name="maxIdleTime" value="240" />
        <property name="maxPoolSize" value="30" />
        <property name="minPoolSize" value="10" />
        <property name="initialPoolSize" value="10" />
        <property name="maxStatements" value="100" />
        <property name="acquireIncrement" value="3" />
    </bean>

    <bean id="dataSource"
        class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <ref local="mainDataSource" />
        </property>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />
    </bean>

    <!-- Switch on transactions -->
    <tx:annotation-driven />

    <context:component-scan base-package="<my package>" />
    <context:component-scan base-package="<my test package>" />
</beans>


Here's hibernate.cfg.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password"><my password></property>
        <property name="hibernate.connection.url"><my jdbc url></property>
        <property name="hibernate.connection.username"><my user></property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>

        <!-- Don't drop the database !!! -->
        <property name="hbm2ddl.auto">update</property>
       
        <!-- List of entities -->
        <mapping class="<my package>.model.VsAgency"/>
    </session-factory>
</hibernate-configuration>


Here's the model class:

package <my package>.model;

// Generated 17 sept. 2013 17:27:46 by Hibernate Tools 3.4.0.CR1

import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 * VsAgency generated by hbm2java
 */
@Entity
@Table(name = "VS_AGENCY", catalog = "videospeed")
public class VsAgency implements java.io.Serializable {

    private Integer id;
    private String name;
    private Date ts;
    private Set<VsUser> vsUsers = new HashSet<VsUser>(0);
    private Set<VsClient> vsClients = new HashSet<VsClient>(0);
    private Set<VsVideomaker> vsVideomakers = new HashSet<VsVideomaker>(0);
    private Set<VsOrder> vsOrders = new HashSet<VsOrder>(0);

    public VsAgency() {
    }

    public VsAgency(String name, Date ts) {
        this.name = name;
        this.ts = ts;
    }

    public VsAgency(String name, Date ts, Set<VsUser> vsUsers, Set<VsClient> vsClients, Set<VsVideomaker> vsVideomakers, Set<VsOrder> vsOrders) {
        this.name = name;
        this.ts = ts;
        this.vsUsers = vsUsers;
        this.vsClients = vsClients;
        this.vsVideomakers = vsVideomakers;
        this.vsOrders = vsOrders;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Column(name = "name", nullable = false, length = 100)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "ts", nullable = false, length = 19)
    public Date getTs() {
        return this.ts;
    }

    public void setTs(Date ts) {
        this.ts = ts;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "vsAgency")
    public Set<VsUser> getVsUsers() {
        return this.vsUsers;
    }

    public void setVsUsers(Set<VsUser> vsUsers) {
        this.vsUsers = vsUsers;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "vsAgency")
    public Set<VsClient> getVsClients() {
        return this.vsClients;
    }

    public void setVsClients(Set<VsClient> vsClients) {
        this.vsClients = vsClients;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "vsAgency")
    public Set<VsVideomaker> getVsVideomakers() {
        return this.vsVideomakers;
    }

    public void setVsVideomakers(Set<VsVideomaker> vsVideomakers) {
        this.vsVideomakers = vsVideomakers;
    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "vsAgency")
    public Set<VsOrder> getVsOrders() {
        return this.vsOrders;
    }

    public void setVsOrders(Set<VsOrder> vsOrders) {
        this.vsOrders = vsOrders;
    }

}


And here's the DAO interface and implementation:

package <my package>.dao;

import com.googlecode.genericdao.dao.hibernate.GenericDAO;
import <my package>.model.VsAgency;

/**
 * <p>
 * Interface for the VsAgency DAO. This is created very simply by extending
 * GenericDAO and specifying the type for the entity class (VsAgency) and the
 * type of its identifier (Integer).
 *
 * <p>
 * As a matter of best practice other components reference this interface rather
 * than the implementation of the DAO itself.
 *
 */
public interface VsAgencyDAO extends GenericDAO<VsAgency, Integer> {

}


package <my package>.dao;

import org.springframework.stereotype.Repository;

import <my package>.model.VsAgency;

/**
 * <p>
 * This is the implementation of the VsAgency DAO. You can see that we don't
 * actually have to implement anything, it is all inherited from GenericDAOImpl
 * through BaseDAO. We just specify the entity type (VsAgency) and its identifier
 * type (Integer).
 *
 * <p>
 * The @Repository allows Spring to recognize this as a managed component (so we
 * don't need to specify it in XML) and also tells spring to do DAO exception
 * translation to the Spring exception hierarchy.
 *
 * @author dwolverton
 *
 */
@Repository
public class VsAgencyDAOImpl extends BaseDAO<VsAgency, Integer> implements VsAgencyDAO {

}

jacques...@gmail.com

unread,
Sep 18, 2013, 8:52:00 AM9/18/13
to java-gen...@googlegroups.com, jacques...@gmail.com
Answering my own post here...

I turned on Spring debug in log4j and found that a Rollback is applied after the write :

[20130918082144] DEBUG <my package>.test.VsAgencyTest testWrite calling dao.save()
Hibernate: insert into <my table>.VS_AGENCY (name, ts) values (?, ?)
[20130918082144] DEBUG <my package>.test.VsAgencyTest testWrite back from dao.save()
[20130918082144] DEBUG org.springframework.test.context.transaction.TransactionalTestExecutionListener No method-level @Rollback override: using default rollback [true] for test context [TestContext@3b835282 testClass = VsAgencyTest, testInstance = com.videospeed.test.VsAgencyTest@2a9df354, testMethod = testWrite@VsAgencyTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@67d225a7 testClass = VsAgencyTest, locations = '{classpath:/applicationContext.xml}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]]

This led me to more googling, and I found out that this is by design : each test will issue a rollback when run with SpringJUnit4ClassRunner...

Ok, fair enough, but I guess my question now is : what is the best practice for writing Junit tests for Spring/Hibernate to make sure that inserts work, if by default the test rolls back the transaction ?!?


David Wolverton

unread,
Sep 18, 2013, 8:58:36 AM9/18/13
to java-gen...@googlegroups.com
Within the test method where you insert the data also read the data back and make sure it's as expected.


--
You received this message because you are subscribed to the Google Groups "java-generic-dao" group.
To unsubscribe from this group and stop receiving emails from it, send an email to java-generic-d...@googlegroups.com.
To post to this group, send email to java-gen...@googlegroups.com.
Visit this group at http://groups.google.com/group/java-generic-dao.
For more options, visit https://groups.google.com/groups/opt_out.

Reply all
Reply to author
Forward
0 new messages