【发布时间】:2014-11-25 02:14:41
【问题描述】:
我使用 Spring 4.1 和 Hibernate 4.3.6 根据以下示例设置了 Spring/Hibernate 后端:
http://www.sivalabs.in/2011/02/springhibernate-application-with-zero.html
到目前为止,我基本上一切正常,但有一个小配置问题我无法克服:如果我尝试保存一个实体,我会得到以下 StackTrace:
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.
at org.springframework.orm.hibernate4.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1135)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:620)
at org.springframework.orm.hibernate4.HibernateTemplate$12.doInHibernate(HibernateTemplate.java:617)
at org.springframework.orm.hibernate4.HibernateTemplate.doExecute(HibernateTemplate.java:340)
at org.springframework.orm.hibernate4.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:308)
at org.springframework.orm.hibernate4.HibernateTemplate.save(HibernateTemplate.java:617)
at com.test.database.dao.UserSecurityQuestionDAOImpl.save(UserSecurityQuestionDAOImpl.java:40)
at com.test.database.service.UserSecurityQuestionService.save(UserSecurityQuestionService.java:20)
at com.test.database.UserSecurityQuestionTest.basicCreationAndRetrievalTest(UserSecurityQuestionTest.java:37)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:24)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
我的事务指令放置在服务 Bean 中,如下所示:
@Service
@Transactional
public class UserSecurityQuestionService implements UserSecurityQuestionDAO{
@Autowired
private UserSecurityQuestionDAO userSecurityQuerstionDAO;
@Override
@Transactional(readOnly=false)
public void save(UserSecurityQuestion userSecurityQuestion) {
userSecurityQuerstionDAO.save(userSecurityQuestion);
}
这是我的保存方法的DAO实现:
@Repository
public class UserSecurityQuestionDAOImpl implements UserSecurityQuestionDAO {
@Autowired
private HibernateTransactionManager transactionManager;
public void save(UserSecurityQuestion userSecurityQuestion) {
Session session = transactionManager.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
session.persist(userSecurityQuestion);
tx.commit();
session.close();
}
从数据库中选择工作正常,但插入/更新被拒绝抛出错误消息。我错过了什么?
更新
UserSecurityQuestionDAOImpl:
public class UserSecurityQuestionDAOImpl implements UserSecurityQuestionDAO{
@Autowired
private SessionFactory sessionFactory;
public void save(UserSecurityQuestion userSecurityQuestion) {
this.sessionFactory.getCurrentSession().save(userSecurityQuestion);
}
UserSecurityQuestionDAO / UserSecurityQuestionService - 接口:
public interface UserSecurityQuestionService {
public void save(UserSecurityQuestion userSecurityQuestion);
public UserSecurityQuestion findById(Short id);
public List<UserSecurityQuestion> findAll();
public void delete(UserSecurityQuestion userSecurityQuestion);
public void deleteById(Short... id);
}
服务实现:
@Service
public class UserSecurityQuestionServiceImpl implements UserSecurityQuestionService {
@Autowired
private UserSecurityQuestionDAO userSecurityQuestionDAO;
@Transactional
public void save(UserSecurityQuestion userSecurityQuestion) {
userSecurityQuestionDAO.save(userSecurityQuestion);
}
用于测试的单元测试代码:
public class UserSecurityQuestionTest {
private AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
private UserSecurityQuestionService usqService;
@Before
public void setUp(){
//Setup App Context
ctx.scan("com.test.database");
ctx.refresh();
//Initilize Service Bean
usqService = ctx.getBean("userSecurityQuestionService",UserSecurityQuestionServiceImpl.class);
}
新问题:如果我将@Autowired 添加到private UserSecurityQuestionService usqService; 并省略设置部分,我将得到一个空指针异常。如果我保持原样,我会得到org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userSecurityQuestionService' is defined
【问题讨论】:
-
您没有交易。在您的配置中添加
<tx:annotation-driven />或@EnableTransactionManagement。此外,您不应该使用HibernaetTemplate,而应该使用SessionFactory.getCurrentSession(实际上这是自Hibernate 3.0.1 以来的建议!)。 -
好的,我刚刚注意到我用作模板的示例并不是那么新。检查我更新的帖子,现在配置正确了吗?
-
否,因为您仍在使用手动 tx 管理,实际上通过注入事务管理器使情况变得更糟。注入
SessionFactory而不是openSession使用getCurrentSession并删除所有事务性内容和会话关闭。你的方法应该是 2 行。 -
好吧,我想我现在差不多了(见更新)。只是不知何故,自动布线似乎在单元测试中正常工作。
-
不要自己动手,而是使用弹簧测试支持。此外,bean 将以小写首字母的类名命名,因此
UserSecurityQuestionServiceImpl变为userSecurityQuestionServiceImpl并且您应该使用接口而不是具体类(由于创建了动态代理来应用事务,后者将不起作用)。
标签: spring hibernate dao transactional