Hibernate / Spring rolling back insert without error
I've got 2 classes, Foo and FooType where FooType is just 3 rows in the database representing the 3 possible types. I do map FooType in Hibernate but there's nothing besides the ID and description fields. There's no mapping back to Foo in the FooType hbm file.
In Foo, I have a many-to-one mapping since each Foo needs to have a Type.
<hibernate-mapping>
<class name="com.blah.domain.Foo" table="foos" lazy="false">
<id name="id" type="int">
<column name="id" />
<generator class="identity" />
</id>
<many-to-one name="type" class="com.blah.domain.FooType" column="type" not-null="true" unique="false" update="false" fetch="join"/>
</class>
</hibernate-mapping>
Here's the relevant bit of my Spring config
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>WEB-INF/hibernate.cfg.xml</value>
</property>
<property name="mappingResources">
<list>
<value>com/secretry/domain/Foo.hbm.xml</value>
<value>com/secretry/domain/FooType.hbm.xml</value>
</list>
</proper开发者_开发技巧ty>
</bean>
I think this is correct but if not please help. I have a FooDao that uses the HibernateDaoSupport for transactions.
public class FoonDao extends HibernateDaoSupport implements IFooDao {
private IFooTypeDao fooTypeDao;
@Override
public Foo createFoo(String name, String description, int fooTypeId) {
FooType type = fooTypeDao.getFooType(fooTypeId);
Foo newFoo = new Foo(name, description, type);
try {
getHibernateTemplate().save(newFoo);
}
catch(Exception e) {
logger.error("ERROR: ", e);
return null;
}
return newFoo;
}
}
When I run createFoo, I don't see any errors but in my MySQL logs I see the Insert
statement followed immediately by a rollback
. I have full logging turned on for Hibernate but I don't see anything that strikes me as an error. When I copy the insert out of the logs and run it in mysql manually, it works fine, which is probably the most confounding thing.
I'm new to Hibernate so I guess it's probably something I'm doing wrong with the many-to-one mapping but I cannot figure this out for the life of me. Any help with the problem or direction on what I might be doing wrong would be massively appreciated. Thanks.
Do you have a @Transactional annotation on the interface "IFooDao"
With the mention about HibernateTemplate not being the correct way of doing things any more, and the suggestion of the @Transactional annotation, I've come up with the following which seems to work. I make no claims that this is the best or only way but it works and I want to keep a record of this config for future readers.
Note that the "old way" of using HibernateTemplate is the way described in the book "Spring in Action 2nd Edition" but this new way mostly comes from the 3rd Edition.
Spring config
<bean id="FooDao" class="com.foo.dao.FooDao" >
<constructor-arg name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven />
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="configLocation">
<value>WEB-INF/hibernate.cfg.xml</value>
</property>
<property name="packagesToScan">
<list>
<value>com.secretry.domain</value>
</list>
</property>
<property name="mappingResources">
<list>
<value>com/secretry/domain/Mission.hbm.xml</value>
<value>com/secretry/domain/MissionType.hbm.xml</value>
<value>com/secretry/domain/Spy.hbm.xml</value>
<value>com/secretry/domain/CompletedMission.hbm.xml</value>
</list>
</property>
</bean>
Java code for DAO I use to get objects from Hibernate.
@Repository
@Transactional
public class FooDao implements IFooDao {
private SessionFactory sessionFactory;
@Autowired
public FooDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public FooDao() {
}
private Session currentSession() {
return sessionFactory.getCurrentSession();
}
@Override
@Cacheable(cacheName="secretryCache")
public Foo getFoo(int id) {
return (Foo)currentSession().load(Foo.class, id);
}
}
Make sure to remove the following from your hibernate config file if you have it
<property name="current_session_context_class">thread</property>
精彩评论