【问题标题】:org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only modeorg.springframework.dao.InvalidDataAccessApiUsageException:只读模式下不允许写操作
【发布时间】:2014-04-26 19:23:55
【问题描述】:

我是 SSH 新手,我正在使用 Spring 4、Hibernate 4 和 Struts 2。 当我为 DAO 类创建单元测试时,我遇到了这个异常。

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:testApplicationContext.xml"})
public class UserDaoTest {
    @Test
    public void testAddUserNotExists() {
        User user = new User("20116524", "785ee107c11dfe36de668b1ae7baacbb");
        userDao.addUser(user);

        assertNotNull(userDao.getUserByUsername("20116524"));
    }

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    /**
     * UserDao object to test.
     */
    private UserDao userDao;
}

我尝试在web.xml 中添加以下行,但它不起作用。

参考:Java / Hibernate - Write operations are not allowed in read-only mode

我认为我的applicationContext.xml 有问题,内容如下:

<!-- Session Factory -->
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.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.HSQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
            <value>emis.accounts.model</value>
        </list>
    </property>
</bean>
<!-- Transaction -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

没有关于AOPtx:advice的配置。所以我尝试添加一些行:

<!-- Transaction -->
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        <tx:method name="get*" propagation="REQUIRED" read-only="true" />
        <tx:method name="find*" propagation="REQUIRED" read-only="true" />
        <tx:method name="list*" propagation="REQUIRED" read-only="true" />
        <tx:method name="load*" propagation="REQUIRED" read-only="true" />
        <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="save" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="update" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="delete" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<aop:aspectj-autoproxy />
<aop:config>
    <aop:pointcut id="aopPointcut"
        expression="execution(* emis.*.service.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="aopPointcut"/>
</aop:config>

但是,我遇到了另一个例外:

WARNING: Exception thrown from ApplicationListener handling ContextClosedEvent
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: Root WebApplicationContext: startup date [Thu Mar 20 13:53:51 CST 2014]; root of context hierarchy
    at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:346)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:880)
...

WARNING: Exception thrown from LifecycleProcessor on context close
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: Root WebApplicationContext: startup date [Thu Mar 20 13:53:51 CST 2014]; root of context hierarchy
    at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:359)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:888)
    at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:841)
...

我该怎么办?谁能帮我?非常感谢!!

【问题讨论】:

  • 应该如何将东西添加到您的 web.xml 以帮助您的单元测试,它对存在 web.xml 的事实一无所知。你能发布完整的测试用例,hibernate.cfg.xmlUserDao的内容。
  • hibernate.cfg.xml 中没有任何内容。仅限&lt;mapping resource="map/account/User.hbm.xml"/&gt;

标签: java spring hibernate ssh


【解决方案1】:

首先确定要用于交易的内容。 XML 配置或注解@Transactional。不要试图混合它们。

如果您使用@Transactional,请确保您的UserDao 带有正确的注释。

如果您使用 XML,请确保您在 tx:advice 中的顺序正确。目前一切都是只读的。第一场比赛获胜,因为您在顶部有一个通配符*,所有内容都将匹配该切入点。接下来你不需要&lt;aop:aspectj-autoproxy /&gt;,因为你已经用&lt;aop:config /&gt; 块声明了你的方面。

【讨论】:

  • 您的意思是在方法中添加@Transactional(readOnly = false)?我做到了,但我遇到了另一个例外:Could not autowire method: public void emis.accounts.dao.UserDaoTest.setUserDao(emis.accounts.dao.UserDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [emis.accounts.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}
  • 然后解决这个问题。我的猜测是 UserDao 是一个实现一些接口的具体类。默认情况下,Spring 使用基于接口的 JDK 动态代理。将 proxy-target-class 添加到您的 &lt;tx:annotation-driven /&gt; 以强制使用基于类的代理。
猜你喜欢
  • 2016-12-12
  • 2011-12-01
  • 1970-01-01
  • 2011-10-12
  • 2015-03-14
  • 1970-01-01
  • 2011-07-21
  • 2014-10-03
  • 2018-01-20
相关资源
最近更新 更多