方法1:在出現(xiàn)異常的方法中加入
1 |
|
方法2:重寫OpenSessionInViewFilter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
配置web.xml:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
總結(jié):
從異常信息可以清晰地知道在事務(wù)切入的方法中(數(shù)據(jù)庫寫入操作)必須將session設(shè)置為FlushMode.COMMIT或者FlushMode.AUTO。
轉(zhuǎn)自 https://blog.csdn.net/yangxiaovip/article/details/45824077
最近在配置 Structs, Spring 和Hibernate整合的問題:
開啟OpenSessionInViewFilter來阻止延遲加載的錯誤的時候拋出了這個異常:
org.springframework.dao.InvalidDataAccessApiUsageException錯誤
但是在我們開啟OpenSessionInViewFilter這個過濾器的時候FlushMode就已經(jīng)被默認設(shè)置為了MANUAL!
如果FlushMode是MANUAL或NEVEL,在操作過程中 hibernate會將事務(wù)設(shè)置為readonly,所以在增加、刪除或修改操作過程中會出現(xiàn)如下錯誤:
org.springframework.dao.InvalidDataAccessApiUsageException:
Write operations are not allowed in read-only mode (FlushMode.NEVER) turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition;
解決辦法1:
直接修改OpenSessionInViewFilter過濾器的配置,配置過濾器的時候配置就是在一般的配置里面加上下面藍色部分就可以了,直接指定flushMode的配置就OK了:
下面是配置文件:(web.xml)
解決方法2:
就是配置事務(wù)的邊界,在你方法的執(zhí)行時配置事務(wù)邊界!
下面是sessionFactor.xml配置:
下面是總結(jié):
原理:因為配置openSessionInView時,啟動后他默認是給沒有配置事務(wù)邊界的方法都默認為只讀的,所以在插入數(shù)據(jù)時就會報上面的錯
轉(zhuǎn)自 https://blog.csdn.net/enterys/article/details/7927840
在寫HQL語句的時候?qū)傩裕▽嶓w類和數(shù)據(jù)庫必須都要有)寫錯了,檢查大小寫,實體類中是否有這個屬性,數(shù)據(jù)庫中是否有這個字段。
因為getCurrentSession()本意是從事務(wù)中獲取session。
1. getCurrentSession()
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Teacher t = (Teacher)session.get(Teacher.
class
,
1
);
session.getTransaction().commit();
2. openSession();
Session session = HibernateUtil.getSessionFactory().openSession();
Teacher t2 = (Teacher)session.get(Teacher.
class
,
1
);
session.close();
使用getCurrentSession(),一定要開啟事務(wù)。否則,報錯 is not valid without active transaction。
Session session = HibernateUtils.getCurrentSession();
String sql = "from Customer";
Query q = session.createQuery(sql);
session.getTransaction().commit();
return q.list();
commit后就關(guān)閉了session,所以這樣寫也會報錯,return q.list()這行,報錯 session is closed。
需要這樣寫:
Session session = HibernateUtils.getCurrentSession();
String sql = "from Customer";
Query q = session.createQuery(sql);
List<Customer> list = q.list();
session.getTransaction().commit();
return list;
通常項目中是這樣寫:
service層:
public List<Customer> getAll(DetachedCriteria dc) {
HibernateUtils.getCurrentSession().beginTransaction();
List<Customer> list = customerDao.getAll(dc);
HibernateUtils.getCurrentSession().getTransaction().commit();
return list;
}
dao層:
public List<Customer> getAll() {
Session session = HibernateUtils.getCurrentSession();
String sql = "from Customer";
Query q = session.createQuery(sql);
return q.list();
}
產(chǎn)生此問題的原因:
有兩張表,table1和table2.產(chǎn)生此問題的原因就是table1里做了關(guān)聯(lián)<one-to-one>或者<many-to-one unique="true">(特殊的多對一映射,實際就是一對一)來關(guān)聯(lián)table2.當hibernate查找的時候,table2里的數(shù)據(jù)沒有與table1相匹配的,這樣就會報No row with the given identifier exists這個錯.(一句話,就是數(shù)據(jù)的問題!)
假如說,table1里有自身的主鍵id1,還有table2的主鍵id2,這兩個字段.
如果hibenrate設(shè)置的單項關(guān)聯(lián),即使table1中的id2為null值,table2中id2中有值,查詢都不會出錯.但是如果table1中的id2字段有值,但是這個值在table2中主鍵值里并沒有,就會報上面的錯!
如果hibernate是雙向關(guān)聯(lián),那么table1中的id2為null值,但是table2中如果有值,就會報這個錯.這種情況目前的解決辦法就是改成單項關(guān)聯(lián),或者把不對應(yīng)的數(shù)據(jù)改對!
這就是報這個錯的原因了,知道原因了就相應(yīng)的改就行了.或許還有些人迷惑hibernate關(guān)聯(lián)都配好了,怎么會出現(xiàn)這樣的錯?其實這是編程的時候出現(xiàn)的問題,假如說我在添加信息的時候,頁面?zhèn)鬟^來的struts的formbean到dao方法中需要封裝成hibernate的po(就是hibenrate的bean),要是一個個po.get(form.set())實在太麻煩了,這樣一般都會寫個專門的方法來封裝,遇到po.get(form.set())這種情況直接把struts的formbean對象傳到此方法中封裝就行了,假如我有個字段是創(chuàng)建人id,那么這個字段是永遠不會改的,我在添加的時候還調(diào)用這個方法,這個專門封裝的方法是有一些判斷的,假如說我判斷一下,如果遇到創(chuàng)建人id傳過來為空值,我判斷如果是空值,我把創(chuàng)建人id設(shè)為0,但是用戶表中userid是主鍵從1開始自增的,那么這樣數(shù)據(jù)就對應(yīng)不上了,一查就會出這個錯了.這個錯在開發(fā)剛開始的時候經(jīng)常發(fā)生,因為每個人的模塊都是由相應(yīng)的人獨立開發(fā)完成以后再整合在一起的,每個人寫單獨那一塊的時候往往會忽略這些,所以整合的時候這些問題往往就都一下子全冒出來了....整合很辛苦,tnnd!
hibernate的查詢的比較
hibernate的查詢有很多,Query,find,Criteria,get,load
query使用hsql語句,可以設(shè)置參數(shù)是常用的一種方式
criteria的方式,盡量避免了寫hql語句,看起來更面向?qū)ο罅恕?/span>
find方式,這種方式已經(jīng)被新的hibernate丟棄
get和load方式是根據(jù)id取得一個記錄
下邊詳細說一下get和load的不同,因為有些時候為了對比也會把find加進來。
1,從返回結(jié)果上對比:
load方式檢索不到的話會拋出org.hibernate.ObjectNotFoundException異常
get方法檢索不到的話會返回null
2,從檢索執(zhí)行機制上對比:
get方法和find方法都是直接從數(shù)據(jù)庫中檢索
而load方法的執(zhí)行則比較復(fù)雜
1,首先查找session的persistent Context中是否有緩存,如果有則直接返回
2,如果沒有則判斷是否是lazy,如果不是直接訪問數(shù)據(jù)庫檢索,查到記錄返回,查不到拋出異常
3,如果是lazy則需要建立代理對象,對象的initialized屬性為false,target屬性為null
4, 在訪問獲得的代理對象的屬性時,檢索數(shù)據(jù)庫,如果找到記錄則把該記錄的對象復(fù)制到代理對象的target
上,并將initialized=true,如果找不到就拋出異常
轉(zhuǎn)自 https://www.cnblogs.com/haitao-fan/archive/2013/10/25/3387727.html
很多時候我們使用hibernate的session時,都是讓session在某一運行環(huán)境中保持其唯一。
例如在同一線程內(nèi)用同一個session,在同一方法內(nèi)用同一session,這樣我們就可以用session里面緩存好的數(shù)據(jù)。
最近試用spring3.0.2+struts2.18+hibernate3.3.2學習搭建一個web項目,出現(xiàn)問題。配置好spring管理hibernate事務(wù)了,當我在dao中執(zhí)行hibernate的方法時,如save,delete,update,createQuery,總是說不能在沒有活動的事務(wù)中執(zhí)行(org.hibernate.HibernateException: createSQLQuery is not valid without active transaction)。
你spring不是幫我管理事務(wù)么?你不自動開啟事務(wù)啊,還要我手動開啟啊。查spring文檔一無所獲。
發(fā)現(xiàn)用spring的hibernatetemplate來進行數(shù)據(jù)操作又正常無比。不死心的去查了hibernate的doc,發(fā)現(xiàn)了一個冗長的配置屬性:hibernate.current_session_context_class。
hibernate.current_session_context_class,是配置session綁定到某一運行環(huán)境,例如從同一個線程中用getCurrentSession()取得的session都是同一個,當前沒有session就自動創(chuàng)建一個返回給你用。問題就出在這里了,官方文檔如下說:
使用 Hibernate 的大多數(shù)應(yīng)用程序需要某種形式的“上下文相關(guān)的”會話,特定的會話在整個特
定的上下文范圍內(nèi)始終有效。然而,對不同類型的應(yīng)用程序而言,要為什么是組成這種“上下文”下一個定義通常是困難的;不同的上下文對“當前”這個概念定義了不同的范圍。在 3.0 版本之前,使用 Hibernate 的程序要么采用自行編寫的基于 ThreadLocal 的上下文會話,要么采用HibernateUtil 這樣的輔助類,要么采用第三方框架(比如 Spring 或 Pico),它們提供了基于代理(proxy)或者基于攔截器(interception)的上下文相關(guān)的會話。從 3.0.1 版本開始,Hibernate 增加了SessionFactory.getCurrentSession() 方法。一開始,它假定了采用 JTA 事務(wù),JTA 事務(wù)定義了當前 session 的范圍和上下文(scope 和 context)。因為有好幾個獨立的 JTA TransactionManager 實現(xiàn)穩(wěn)定可用,不論是否被部署到一個 J2EE 容器中,
大多數(shù)(假若不是所有的)應(yīng)用程序都應(yīng)該采用 JTA 事務(wù)管理?;谶@一點,采用 JTA 的上下文相關(guān)的會話可以滿足你一切需要。
再來看我的配置,講hibernate.current_session_context_class的值設(shè)成thread。按我簡單的理解就是將getCurrentSession()返回的session綁定到當前運行線程中。比較專業(yè)的說法是此session的上下文是thread,但不是spring已經(jīng)托管的那個Session對象。
所以獲取的session是在spring代理的上下文之外的的當前線程之中,所以此session并非事務(wù)管理器代理的那個session,不會自動開啟事務(wù)。根據(jù)官方提示:第三方框架提供了基于代理(proxy)或者基于攔截器(interception)的上下文相關(guān)的會話的管理,所以把hibernate.current_session_context_class設(shè)置刪除了。
參考http://justsee.iteye.com/blog/1061576,終于了解這個問題的前因后果。摘錄如下:
在ssh2中的sessionFactory配置文件中應(yīng)將hibernate.current_session_context_class設(shè)為org.springframework.orm.hibernate3.SpringSessionContext(默認為此值),并應(yīng)用spring管理事務(wù)。
如果為<prop key="hibernate.current_session_context_class">thread</prop> 則會報異常,
原因還是spring中hibernate.current_session_context_class的問題
在spring的類LocalSessionFactoryBean源碼,方法buildSessionFactory中將hibernate.current_session_context_class設(shè)為org.springframework.orm.hibernate3.SpringSessionContext
轉(zhuǎn)自 https://blog.csdn.net/yinjian520/article/details/8666695
主鍵生成策略:native
主鍵生成策略:assigned
因為表生成完以后改了主鍵生成策略,所以需要手動修改表結(jié)構(gòu),給id加上自增
整合spring和hibernate時,使用注解的情況下,容易出現(xiàn)該問題。
因為繼承了HibernateDaoSupport,HibernateDaoSupport需要一個sessionFactory。
問題:如何將sessionFactory給它?
public class BaseDao extends HibernateDaoSupport{
//通常會直接這樣寫:
@AutoWired
private SessionFactory sessionFactory;
//但這樣父類HibernateDaoSupport是無法獲得sessionFactory。
}
下面這種配置方法是對的,但配置的bean錯了。配置的應(yīng)該是模塊的dao(例如:UserDao,LoginDao,RegistDao),而非BaseDao。因為spring創(chuàng)建的BaseDao和子類通過extends的BaseDao不是同一個BaseDao對象,每一個子類都會在內(nèi)部創(chuàng)建出1個BaseDao出來。BaseDao不需要spring創(chuàng)建,他只是起到將共有的方法抽取出來的作用。
<!-- 配置 SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties" ref="hibernate-hibernateProperties"></property>
<property name="packagesToScan" ref="hibernate-packagesToScan"></property>
<property name="mappingLocations" ref="hibernate-mappingLocations"></property>
</bean>
<bean id="baseDao" class="com.myprj.auth.dao.BaseDao">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
查看HibernateDaoSupport源代碼:只有setSessionFactory(),沒有sessionFactory字段,而且setSessionFactory()用了final,子類不能重寫。但可以調(diào)用,所以可以在xml里用bean property的方式傳參,因為property的原理是調(diào)用setXXX方法傳參。
public final void setSessionFactory(SessionFactory sessionFactory) {
if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
this.hibernateTemplate = createHibernateTemplate(sessionFactory);
}
}
辦法2:調(diào)用super.setSessionFactory()
@Resource(name="sessionFactory")//通過形參parameter來注入
private void setMySessionFactory(SessionFactory sessionFactory){
super.setSessionFactory(sessionFactory);
}
在整合spring和hibernate時出現(xiàn)了這個問題。
兩種可能
1.hibernate是5.0版本,而spring是4.0版本。5.0版本的hibernate中的相應(yīng)包中把那個類給取消了。而在spring中配置時,我們最多只能配置到hibernate4,所以就出現(xiàn)了上述問題。
2.spring-hibernate.xml中,使用的sessionfactory是4.0版本的,但包是5.x版本的,包括transaction,和dao繼承的HibernateDaoSupprt
聯(lián)系客服