簡體   English   中英

“在只讀模式下不允許寫操作”錯誤:與Spring @Service @transaction @Repository和Hibernate相混淆

[英]“Write operations are not allowed in read-only mode” error : confused with Spring @Service @transaction @Repository and Hibernate

我正在使用Spring和Hibernate處理一個現有的項目,並且因為我得到一個而感到困惑

org.springframework.dao.InvalidDataAccessApiUsageException:在只讀模式下不允許寫入操作(FlushMode.MANUAL):將會話轉換為FlushMode.COMMIT / AUTO或從事務定義中刪除“readOnly”標記。

嘗試保存對象時出錯但我仍然無法找到究竟是什么錯誤。

有一個使用@Service注釋的服務層和一個應該是事務性的save方法,因此它使用@Transactional(readOnly = false)注釋。 對我來說,這意味着春天應該處理交易本身。

@Service
public class LadyService {
    Logger log = Logger.getLogger(LadyService.class);
    @Autowired
    private PictureDAO pictureDao;
    @Autowired
    private LadyDAO ladyDao;
    @Autowired
    private AddressDAO addressDao;

    @Transactional(readOnly = false)
    public void save(Lady lady) {
        Address a = addressDao.getExistingAddress(lady.getAddress());
        if (a == null) {
            a = addressDao.save(lady.getAddress());
        }
        lady.setAddress(a);
        ladyDao.save(lady);
        pictureDao.savePictures(lady.getPictures());
    }

AddressDAO進行保存時發生錯誤。 它注釋為@Repository

@Repository
public class AddressDAO extends HibernateDaoSupport {

    public Address save(Address address) {
        getHibernateTemplate().save(address);  <-- write not permitted error happens here
        return address;
    }

    @SuppressWarnings({ "unchecked" })
    public Address getExistingAddress(Address address) {
        DetachedCriteria cd = DetachedCriteria.forClass(Address.class);
        cd.add(Restrictions.eqOrIsNull("administrative_area_level_1",
                address.getAdministrative_area_level_1()));
        cd.add(Restrictions.eqOrIsNull("administrative_area_level_2",
                address.getAdministrative_area_level_2()));
        List<Address> result = (List<Address>) getHibernateTemplate()
                .findByCriteria(cd);

        if (result.isEmpty()) {
            return null;
        } else {
            return (Address) result.get(0);
        }
    }
}

我認為會發生的事情是@Transactional使spring創建一個會話和一個事務來保存服務層,而在DAO中,hibernate模板將獲得Spring管理的當前會話和事務並使用它來保存對象。

但是,錯誤消息讓我認為我的服務方法和dao方法不在同一個事務中。

在servlet-context.xml中有以下語句:

<annotation-driven />

<context:component-scan base-package="com.kog.fable" />

<beans:bean id="mySessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <beans:property name="dataSource" ref="myDataSource" />
    <beans:property name="packagesToScan">
        <beans:array>
            <beans:value>com.kog.fable.**.*</beans:value>
        </beans:array>
    </beans:property>
    <beans:property name="hibernateProperties">
        <beans:props>
            <beans:prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect
            </beans:prop>
            <!-- create, validate, update -->
            <beans:prop key="hibernate.hbm2ddl.auto">create</beans:prop>
            <beans:prop key="hibernate.show_sql">false</beans:prop>
            <beans:prop key="hibernate.connection.pool_size">10</beans:prop>
            <beans:prop key="hibernate.connection.autocommit ">false</beans:prop>
        </beans:props>
    </beans:property>
</beans:bean>

<tx:annotation-driven transaction-manager="transactionManager" />

<beans:bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>

<beans:bean id="addressDAO" class="com.kog.fable.dao.AddressDAO">
    <beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>

<beans:bean id="ladyDAO" class="com.kog.fable.dao.LadyDAO">
    <beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>

<beans:bean id="pictureDAO" class="com.kog.fable.dao.PictureDAO">
    <beans:property name="sessionFactory" ref="mySessionFactory" />
</beans:bean>

在這里,我不明白為什么,如果使用組件掃描,DAO bean仍然是顯式聲明的。 組件掃描功能是否應該能夠自己創建它們,因為DAO類是用@Repository注釋的? 因為我認為這個配置可以創建重復的bean,我嘗試刪除xml條目,但后來我開始得到:

org.springframework.beans.factory.BeanCreationException:創建名為'addressController'的bean時出錯:注入自動連接的依賴項失敗; 嵌套異常是org.springframework.beans.factory.BeanCreationException:無法自動裝配字段:private com.kog.fable.dao.AddressDAO com.kog.fable.controller.AddressController.addressDAO; 嵌套異常是org.springframework.beans.factory.BeanCreationException:創建文件[*** \\ com \\ kog \\ fable \\ dao \\ AddressDAO.class]中定義名稱為'addressDAO'的bean時出錯:init方法的調用失敗; 嵌套異常是java.lang.IllegalArgumentException:'sessionFactory'或'hibernateTemplate'是必需的

在這里,我認為HibernateDaoSupport對我的DAO的擴展會使它們繼承sessionFactory和相關的方法,所以我不明白會發生什么。

我已經讀過我可以將刷新模式設置為AUTO或將模板上的setCheckWriteOperations設置為FALSE以解決這類問題並且它似乎有效,但我想這不會確保所有情況下的事務一致性,因為我會喜歡它。

任何幫助都會受到贊賞,因為我對Spring和Hibernate很新,而且有點卡在這里。

擴展HibernateDaoSupport您不會受益於自動裝配,您必須覆蓋setSessionFactory方法並在其上放置@Autowired注釋。 否則它將無法工作。

我也期望一個<tx:annotation-driven />而沒有@Transactional幾乎沒用,也沒有做任何事情。

如果你的應用程序是基於Spring MVC ...

在應用程序上下文中試試這個..

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

但是在dispatcher-servlet中(不在appContext !!!中)

<tx:annotation-driven />

不要忘記tx的命名空間,以及jar庫spring-tx,spring-orm,hibernate-core

在配置文件中

做改變: -

@Configuration
@EnableTransactionManagement   <-----Put this line

public PersistenceConfig{
//your code
}

(要么)

@Bean
@Autowired
public HibernateTemplate getHibernateTemplate(SessionFactory session) {
        HibernateTemplate hb = new HibernateTemplate();
        hb.setCheckWriteOperations(false);
        hb.setSessionFactory(session);
        return hb;
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM