![](/img/trans.png)
[英]Spring/Hibernate Write operations are not allowed in read-only mode
[英]“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.