版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第4章
Hibernate應(yīng)用4.1Hibernate概述4.2Hibernate應(yīng)用基礎(chǔ)4.3Hibernate關(guān)系映射4.4Hibernate高級功能4.5Hibernate與Struts2整合應(yīng)用4.1Hibernate概述1.ORM簡介對象/關(guān)系映射ORM(Object-RelationMapping)是用于將對象與對象之間的關(guān)系對應(yīng)到數(shù)據(jù)庫表與表之間的關(guān)系的一種模式。簡單地說,ORM是通過使用描述對象和數(shù)據(jù)庫之間映射的元數(shù)據(jù),將Java程序中的對象自動(dòng)持久化到關(guān)系數(shù)據(jù)庫中。對象和關(guān)系數(shù)據(jù)是業(yè)務(wù)實(shí)現(xiàn)的兩種表現(xiàn)形式,業(yè)務(wù)實(shí)體在內(nèi)存中表現(xiàn)為對象,在數(shù)據(jù)庫中表現(xiàn)為關(guān)系數(shù)據(jù)。內(nèi)存中的對象之間存在著關(guān)聯(lián)和繼承關(guān)系。而在數(shù)據(jù)庫中,關(guān)系數(shù)據(jù)無法直接表達(dá)多對多關(guān)聯(lián)和繼承關(guān)系。因此,ORM系統(tǒng)一般以中間件的形式存在,主要實(shí)現(xiàn)程序?qū)ο蟮疥P(guān)系數(shù)據(jù)庫數(shù)據(jù)的映射。一般的ORM包括四個(gè)部分:對持久類對象進(jìn)行CRUD操作的API、用來規(guī)定類和類屬性相關(guān)查詢的語言或API、規(guī)定mappingmetadata的工具,以及可以讓ORM實(shí)現(xiàn)同事務(wù)對象一起進(jìn)行dirtychecking、lazyassociationfetching和其他優(yōu)化操作的技術(shù)。4.1Hibernate概述2.Hibernate體系結(jié)構(gòu)Hibernate作為模型層/數(shù)據(jù)訪問層。它通過配置文件(hibernate.cfg.xml或perties)和映射文件(*.hbm.xml)把Java對象或持久化對象(PersistentObject,PO)映射到數(shù)據(jù)庫中的數(shù)據(jù)表,然后通過操作PO,對數(shù)據(jù)庫中的表進(jìn)行各種操作,其中PO就是POJO(普通Java對象)加映射文件。Hibernate的體系結(jié)構(gòu)如圖4.1所示。圖4.1Hibernate體系結(jié)構(gòu)4.2Hibernate應(yīng)用基礎(chǔ)4.2.1Hibernate應(yīng)用實(shí)例開發(fā)開發(fā)Hibernate項(xiàng)目的步驟如下。1.建立數(shù)據(jù)庫及表本書使用SQLServer2005數(shù)據(jù)庫。在XSCJ數(shù)據(jù)庫中建立KCB表,其表結(jié)構(gòu)如附錄A.2所示。2.在MyEclipse中創(chuàng)建對SQLServer的連接啟動(dòng)MyEclipse,選擇【W(wǎng)indow】→【OpenPerspective】→【MyEclipseDatabaseExplorer】菜單項(xiàng),打開MyEclipseDatabase瀏覽器,右擊菜單,如圖4.2所示,選擇【New…】菜單項(xiàng),出現(xiàn)如圖4.3所示的對話框,編輯數(shù)據(jù)庫連接驅(qū)動(dòng)。4.2.1Hibernate應(yīng)用實(shí)例開發(fā)圖4.2MyEclipseDatabase瀏覽器,創(chuàng)建一個(gè)新的連接圖4.3編輯數(shù)據(jù)庫連接驅(qū)動(dòng)
4.2.1Hibernate應(yīng)用實(shí)例開發(fā)編輯完成以后,在MyEclipseDatabase瀏覽器中,右擊剛才創(chuàng)建的MyConn數(shù)據(jù)庫連接,選擇“Openconnection…”菜單項(xiàng),打開名為“MyConn”的數(shù)據(jù)連接,如圖4.4所示。圖4.4打開數(shù)據(jù)庫連接4.2.1Hibernate應(yīng)用實(shí)例開發(fā)3.創(chuàng)建Web項(xiàng)目,命名為“HibernateTest”4.添加Hibernate開發(fā)能力右擊項(xiàng)目名HibernateTest,選擇【MyEclipse】→【AddHibernateCapabilites】菜單項(xiàng),出現(xiàn)如圖4.5所示的對話框,選擇Hibernate框架應(yīng)用版本及所需要的類庫。圖4.5選擇Hibernate版本及所需Jar包4.2.1Hibernate應(yīng)用實(shí)例開發(fā)單擊【Next】按鈕,進(jìn)入如圖4.6所示界面。創(chuàng)建Hibernate配置文件hibernate.cfg.xml,將該文件放在src文件夾下,后面會(huì)詳細(xì)介紹該文件內(nèi)容。這里先說明添加Hibernate開發(fā)功能的步驟。圖4.6創(chuàng)建配置文件hibernate.cfg.xml4.2.1Hibernate應(yīng)用實(shí)例開發(fā)單擊【Next】按鈕,進(jìn)入如圖4.7所示界面,指定Hibernate數(shù)據(jù)庫連接細(xì)節(jié)。由于在前面已經(jīng)配置一個(gè)名為MyConn的數(shù)據(jù)庫連接,所以這里只需要選擇DBDriver為“MyConn”即可。
圖4.7指定hibernate數(shù)據(jù)庫連接4.2.1Hibernate應(yīng)用實(shí)例開發(fā)單擊【Next】按鈕,出現(xiàn)如圖4.8所示界面。Hibernate中有一個(gè)與數(shù)據(jù)庫打交道重要的類Session。而這個(gè)類是由工廠SessionFactory創(chuàng)建的。這個(gè)界面詢問是否需要?jiǎng)?chuàng)建SessionFactory類。如果需要?jiǎng)?chuàng)建,還需要指定創(chuàng)建的位置和類名。這些接口都會(huì)在后面詳細(xì)介紹。單擊【Finish】按鈕,完成Hibernate的配置。圖4.8創(chuàng)建SessionFactory類來簡化Hibernate會(huì)話處理4.2.1Hibernate應(yīng)用實(shí)例開發(fā)5.生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件首先在MyEclispse下創(chuàng)建一個(gè)名為“org.model”的包,這個(gè)包將用來存放與數(shù)據(jù)庫表對應(yīng)的Java類POJO。從主菜單欄,選擇【W(wǎng)indows】→【OpenPerspective】→【Other】→【MyEclipseDatabaseExplorer】菜單項(xiàng),打開MyEclipseDatabaseExplorer視圖。打開前面創(chuàng)建的MyConn數(shù)據(jù)連接,選擇【XSCJ】→【dbo】→【TABLE】菜單項(xiàng),右擊KCB表,選擇【HibernateReverseEngineering…】菜單項(xiàng),如圖4.9所示,將啟動(dòng)HibernateReverseEngineering向?qū)?,該向?qū)в糜谕瓿蓮囊延械臄?shù)據(jù)庫表生成對應(yīng)的Java類和相關(guān)映像文件的配置工作。圖4.9Hibernate反向工程菜單4.2.1Hibernate應(yīng)用實(shí)例開發(fā)首先,選擇生成的Java類和映像文件所在的位置,如圖4.10所示。POJO(PlainOldJavaObject,簡單的Java對象),通常也稱為VO(ValueObject,值對象)。圖4.10生成Hibernate映射文件和Java類4.2.1Hibernate應(yīng)用實(shí)例開發(fā)使用POJO名稱是為了避免和EJB混淆起來,其中有一些屬性及getter、setter方法。當(dāng)然,如果有一個(gè)簡單的運(yùn)算屬性也是可以的,但不允許有業(yè)務(wù)方法。單擊【Next】按鈕,進(jìn)入如圖4.11所示的界面,選擇主鍵生成策略。圖4.11配置反向工程細(xì)節(jié)4.2.1Hibernate應(yīng)用實(shí)例開發(fā)6.創(chuàng)建測試類在src文件夾下創(chuàng)建包test,在該包下建立測試類,命名為Test.java,其代碼。7.運(yùn)行因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。運(yùn)行程序,控制臺(tái)就會(huì)打印出“機(jī)電”。在完全沒有操作數(shù)據(jù)庫的情況下,就完成了對數(shù)據(jù)的插入。下面將詳細(xì)講解各文件的作用。4.2.2Hibernate各種文件的作用1.POJO類和其映射配置文件POJO類如下:packageorg.model;publicclassKcbimplementsjava.io.Serializable{ privateStringkch; //對應(yīng)表中KCH字段 privateStringkcm; //對應(yīng)表中KCM字段 privateShortkxxq; //對應(yīng)表中KXXQ字段 privateIntegerxs; //對應(yīng)表中XS字段 privateIntegerxf; //對應(yīng)表中XF字段 publicKcb(){ } //上述屬性的getter和setter方法}可以發(fā)現(xiàn),該類中的屬性和表中的字段是一一對應(yīng)的。那么通過什么方法把它們一一映射起來呢?就是前面提到的*.hbm.xml映射文件。這里當(dāng)然就是Kcb.hbm.xml,其代碼。4.2.2Hibernate各種文件的作用該配置文件大致分為3個(gè)部分:(1)類、表映射配置<classname="org.model.Kcb"table="KCB">name屬性指定POJO類為org.model.Kcb,table屬性指定當(dāng)前類對應(yīng)數(shù)據(jù)庫表KCB。(2)id映射配置<idname="kch"type="java.lang.String"> <columnname="KCH"length="3"/> <generatorclass="assigned"/></id>Hibernate的主鍵生成策略分為三大類:Hibernate對主鍵id賦值、應(yīng)用程序自身對id賦值、由數(shù)據(jù)庫對id賦值。assigned:應(yīng)用程序自身對id賦值。當(dāng)設(shè)置<generatorclass="assigned"/>時(shí),應(yīng)用程序自身需要負(fù)責(zé)主鍵id的賦值。例如下述代碼:Kcbkc=newKcb(); //創(chuàng)建POJO類對象kc.setKch("198"); //設(shè)置課程號kc.setKcm("機(jī)電"); //設(shè)置課程名kc.setKxxq(newInteger(5).shortValue()); //設(shè)置開學(xué)學(xué)期kc.setXf(newInteger(4).shortValue()); //設(shè)置學(xué)分kc.setXs(newInteger(59).shortValue()); //設(shè)置學(xué)時(shí)4.2.2Hibernate各種文件的作用native:由數(shù)據(jù)庫對id賦值。當(dāng)設(shè)置<generatorclass="native"/>時(shí),數(shù)據(jù)庫負(fù)責(zé)主鍵id的賦值,最常見的是int型的自增型主鍵。hilo:通過hi/lo算法實(shí)現(xiàn)的主鍵生成機(jī)制,需要額外的數(shù)據(jù)庫表保存主鍵生成歷史狀態(tài)。seqhilo:與hi/lo類似,通過hi/lo算法實(shí)現(xiàn)的主鍵生成機(jī)制,只是主鍵歷史狀態(tài)保存在sequence中,適用于支持sequence的數(shù)據(jù)庫,如Oracle。increment:主鍵按數(shù)值順序遞增。此方式的實(shí)現(xiàn)機(jī)制為在當(dāng)前應(yīng)用實(shí)例中維持一個(gè)變量,以保存當(dāng)前的最大值,之后每次需要生成主鍵的時(shí)候?qū)⒋酥导?作為主鍵。identity:采用數(shù)據(jù)庫提供的主鍵生成機(jī)制,如SQLServer、MySQL中的自增主鍵生成機(jī)制。sequence:采用數(shù)據(jù)庫提供的sequence機(jī)制生成主鍵,如Oraclesequence。uuid.hex:由Hibernate基于128位唯一值產(chǎn)生算法,根據(jù)當(dāng)前設(shè)備IP、時(shí)間、JVM啟動(dòng)時(shí)間、內(nèi)部自增量等4個(gè)參數(shù)生成十六進(jìn)制數(shù)值(編碼后長度為32位的字符串表示)作為主鍵。即使是在多實(shí)例并發(fā)運(yùn)行的情況下,這種算法在最大程度上保證了產(chǎn)生id的唯一性。當(dāng)然,重復(fù)的概率在理論上依然存在,只是概率比較小。uuid.string:與uuid.hex類似,只是對生成的主鍵進(jìn)行編碼(長度16位)。foreign:使用外部表的字段作為主鍵。select:Hibernate3新引入的主鍵生成機(jī)制,主要針對遺留系統(tǒng)的改造工程。4.2.2Hibernate各種文件的作用(3)屬性、字段映射配置屬性、字段映射將映射類屬性與庫表字段相關(guān)聯(lián)。<propertyname="kcm"type="java.lang.String"> <columnname="KCM"length="12"/></property>name="kcm"指定映像類中的屬性名為“kcm”,此屬性將被映像到指定的庫表字段KCM。type="java.lang.String"指定映像字段的數(shù)據(jù)類型。columnname="KCM"指定類的kcm屬性映射KCB表中的KCM字段。4.2.2Hibernate各種文件的作用2.hibernate.cfg.xml文件該文件是Hibernate重要的配置文件,配置該文件主要是配置SessionFractory類。其主要代碼及解釋。
3.HibernateSessionFactoryHibernateSessionFactory類是自定義的SessionFactory,名字可以根據(jù)自己的喜好來決定。這里用的是HibernateSessionFactory,其內(nèi)容及解釋。在Hibernate中,Session負(fù)責(zé)完成對象持久化操作。該文件負(fù)責(zé)創(chuàng)建Session對象,以及關(guān)閉Session對象。從該文件可以看出,Session對象的創(chuàng)建大致需要以下3個(gè)步驟:①初始化Hibernate配置管理類Configuration。②通過Configuration類實(shí)例創(chuàng)建Session的工廠類SessionFactory。③通過SessionFactory得到Session實(shí)例。4.2.3Hibernate核心接口1.Configuration接口Configuration負(fù)責(zé)管理Hibernate的配置信息。Hibernate運(yùn)行時(shí)需要一些底層實(shí)現(xiàn)的基本信息。這些信息包括:數(shù)據(jù)庫URL、數(shù)據(jù)庫用戶名、數(shù)據(jù)庫用戶密碼、數(shù)據(jù)庫JDBC驅(qū)動(dòng)類、數(shù)據(jù)庫dialect。用于對特定數(shù)據(jù)庫提供支持,其中包含了針對特定數(shù)據(jù)庫特性的實(shí)現(xiàn),如Hibernate數(shù)據(jù)庫類型到特定數(shù)據(jù)庫數(shù)據(jù)類型的映射等。使用Hibernate必須首先提供這些基礎(chǔ)信息以完成初始化工作,為后續(xù)操作做好準(zhǔn)備。這些屬性在Hibernate配置文件hibernate.cfg.xml中加以設(shè)定,當(dāng)調(diào)用:Configurationconfig=newConfiguration().configure();時(shí),Hibernate會(huì)自動(dòng)在目錄下搜索hibernate.cfg.xml文件,并將其讀取到內(nèi)存中作為后續(xù)操作的基礎(chǔ)配置。4.2.3Hibernate核心接口2.SessionFactory接口SessionFactory負(fù)責(zé)創(chuàng)建Session實(shí)例,可以通過Configuration實(shí)例構(gòu)建SessionFactory。Configurationconfig=newConfiguration().configure();SessionFactorysessionFactory=config.buildSessionFactory();Configuration實(shí)例config會(huì)根據(jù)當(dāng)前的數(shù)據(jù)庫配置信息,構(gòu)造SessionFacory實(shí)例并返回。SessionFactory一旦構(gòu)造完畢,即被賦予特定的配置信息。也就是說,之后config的任何變更將不會(huì)影響到已經(jīng)創(chuàng)建的SessionFactory實(shí)例sessionFactory。如果需要使用基于變更后的config實(shí)例的SessionFactory,需要從config重新構(gòu)建一個(gè)SessionFactory實(shí)例。SessionFactory保存了對應(yīng)當(dāng)前數(shù)據(jù)庫配置的所有映射關(guān)系,同時(shí)也負(fù)責(zé)維護(hù)當(dāng)前的二級數(shù)據(jù)緩存和StatementPool。由此可見,SessionFactory的創(chuàng)建過程非常復(fù)雜、代價(jià)高昂。這也意味著,在系統(tǒng)設(shè)計(jì)中充分考慮到SessionFactory的重用策略。由于SessionFactory采用了線程安全的設(shè)計(jì),可由多個(gè)線程并發(fā)調(diào)用。4.2.3Hibernate核心接口3.Session接口Session是Hibernate持久化操作的基礎(chǔ),提供了眾多持久化方法,如save、update、delete等。通過這些方法,透明地完成對象的增加、刪除、修改、查找等操作。同時(shí),值得注意的是,HibernateSession的設(shè)計(jì)是非線程安全的,即一個(gè)Session實(shí)例同時(shí)只可由一個(gè)線程使用。同一個(gè)Session實(shí)例的多線程并發(fā)調(diào)用將導(dǎo)致難以預(yù)知的錯(cuò)誤。Session實(shí)例由SessionFactory構(gòu)建:Configurationconfig=newConfiguration().configure();SessionFactorysessionFactory=config.buldSessionFactory();Sessionsession=sessionFactory.openSession();4.Transaction接口Transaction是Hibernate中進(jìn)行事務(wù)操作的接口,Transaction接口是對實(shí)際事務(wù)實(shí)現(xiàn)的一個(gè)抽象,這些實(shí)現(xiàn)包括JDBC的事務(wù)、JTA中的UserTransaction,甚至可以是CORBA事務(wù)。之所以這樣設(shè)計(jì)是可以讓開發(fā)者能夠使用一個(gè)統(tǒng)一的操作界面,使得自己的項(xiàng)目可以在不同的環(huán)境和容器之間方便地移值。事務(wù)對象通過Session創(chuàng)建。例如以下語句:Transactionts=session.beginTransaction();4.2.3Hibernate核心接口5.Query接口在Hibernate2.x中,find()方法用于執(zhí)行HQL語句。Hibernate3.x廢除了find()方法,取而代之的是Query接口,它們都用于執(zhí)行HQL語句。Query和HQL是分不開的。Queryquery=session.createQuery(“fromKcbwherekch=198”);例如以下語句:Queryquery=session.createQuery("fromKcbwherekch=?");就要在后面設(shè)置其值:Query.setString(0,"要設(shè)置的值");上面的方法是通過“?”來設(shè)置參數(shù),還可以用“:”后跟變量的方法來設(shè)置參數(shù),如上例可以改為:Queryquery=session.createQuery("fromKcbwherekch=:kchValue");Query.setString("kchValue","要設(shè)置的課程號值");其使用方法是相同的,例如:Query.setParameter(0,"要設(shè)置的值");Query還有一個(gè)list()方法,用于取得一個(gè)List集合的示例,此示例中包括可能是一個(gè)Object集合,也可能是Object數(shù)組集合。例如:Queryquery=session.createQuery("fromKcbwherekch=198");Listlist=query.list();4.2.4HQL查詢下面介紹HQL的幾種常用的查詢方式。1.基本查詢基本查詢是HQL中最簡單的一種查詢方式。下面以課程信息為例說明其幾種查詢情況。(1)查詢所有課程信息…Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Queryquery=session.createQuery("fromKcb");Listlist=query.list();mit();HibernateSessionFactory.closeSession();…4.2.4HQL查詢(2)查詢某門課程信息...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢一門學(xué)時(shí)最長的課程Queryquery=session.createQuery("fromKcborderbyxsdesc");query.setMaxResults(1); //設(shè)置最大檢索數(shù)目為1//裝載單個(gè)對象Kcbkc=(Kcb)query.uniqueResult();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢(3)查詢滿足條件的課程信息...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢課程號為001的課程信息Queryquery=session.createQuery("fromKcbwherekch=001");Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢2.條件查詢查詢的條件有幾種情況,下面舉例說明。(1)按指定參數(shù)查詢...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢課程名為計(jì)算機(jī)基礎(chǔ)的課程信息Queryquery=session.createQuery("fromKcbwherekcm=?");query.setParameter(0,"計(jì)算機(jī)基礎(chǔ)");Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢(2)使用范圍運(yùn)算查詢...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢這樣的課程信息,課程名為計(jì)算機(jī)基礎(chǔ)或數(shù)據(jù)結(jié)構(gòu),且學(xué)時(shí)在40~60之間Queryquery=session.createQuery("fromKcbwhere(xsbetween40and60)andkcmin('計(jì)算機(jī)基礎(chǔ)','數(shù)據(jù)結(jié)構(gòu)')");Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢(3)使用比較運(yùn)算符查詢...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢學(xué)時(shí)大于51且課程名不為空的課程信息Queryquery=session.createQuery("fromKcbwherexs>51andkcmisnotnull");Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢(4)使用字符串匹配運(yùn)算查詢...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//查詢課程號中包含“001”字符串且課程名前面三個(gè)字為計(jì)算機(jī)的所有課程信息Queryquery=session.createQuery("fromKcbwherekchlike'%001%'andkcmlike'計(jì)算機(jī)%'");Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.2.4HQL查詢3.分頁查詢?yōu)榱藵M足分頁查詢的需要,Hibernate的Query實(shí)例提供了兩個(gè)有用的方法:setFirstResult(intfirstResult)和setMaxResults(intmaxResult)。其中setFirstResult(intfirstResult)方法用于指定從哪一個(gè)對象開始查詢(序號從0開始),默認(rèn)為第1個(gè)對象,也就是序號0。SetMaxResults(intmaxResult)方法用于指定一次最多查詢出的對象的數(shù)目,默認(rèn)為所有對象。如下面的代碼片段:...Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Queryquery=session.createQuery("fromKcb");intpageNow=1; //想要顯示第幾頁intpageSize=5; //每頁顯示的條數(shù)query.setFirstResult((pageNow-1)*pageSize); //指定從哪一個(gè)對象開始查詢query.setMaxResults(pageSize); //指定最大的對象數(shù)目Listlist=query.list();mit();HibernateSessionFactory.closeSession();...4.3Hibernate關(guān)系映射4.3.1一對一關(guān)聯(lián)1.共享主鍵方式在注冊某個(gè)論壇會(huì)員的時(shí)候,往往不但要填寫登錄賬號和密碼,還要填寫其他的詳細(xì)信息,這兩部分信息通常會(huì)放在不同的表中,如表4.1、表4.2所示。字段名稱數(shù)據(jù)類型主鍵自增允許為空描述IDint(4)是ID號USERNAMEvarchar(20)登錄賬號PASSWORDvarchar(20)登錄密碼字段名稱數(shù)據(jù)類型主鍵自增允許為空描述IDint(4)是增1ID號TRUENAMEvarchar(8)是真實(shí)姓名EMAILvarchar(50)是電子郵件表4.1登錄表Login表4.2詳細(xì)信息表Detail4.3.1一對一關(guān)聯(lián)登錄表和詳細(xì)信息表屬于典型的一對一關(guān)聯(lián)關(guān)系,可按共享主鍵方式進(jìn)行。步驟如下:①創(chuàng)建Java項(xiàng)目,命名為“Hibernate_mapping”。②添加Hibernate開發(fā)能力,步驟同4.2.1節(jié)第4步。HibernateSessionFactory類同樣位于org.util包下。③編寫生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件。Login表對應(yīng)的POJO類Login.java:packageorg.model;publicclassLoginimplementsjava.io.Serializable{ privateintid; //ID號
privateStringusername; //登錄賬號 privateStringpassword; //密碼 privateDetaildetail; //詳細(xì)信息 //省略上述各屬性的getter和setter方法}4.3.1一對一關(guān)聯(lián)Detail表對應(yīng)的Detail.java:packageorg.model;publicclassDetailimplementsjava.io.Serializable{ privateintid; //ID號 privateStringtrueName; //真實(shí)姓名 privateStringemail; //電子郵件 privateLoginlogin; //登錄信息 //省略上述各屬性的getter和setter方法}Login表與Login類的ORM映射文件Login.hbm.xml。Detail表與Detail類的ORM映射文件Detail.hbm.xml:4.3.1一對一關(guān)聯(lián)④在hibernate.cfg.xml文件中加入配置映射文件的語句。<mappingresource="org/model/Detail.hbm.xml"/><mappingresource="org/model/Login.hbm.xml"/>⑤創(chuàng)建測試類。在src文件夾下創(chuàng)建包test,在該包下建立測試類,命名為“Test.java”。其代碼。⑥運(yùn)行程序,測試結(jié)果。因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。在完全沒有操作數(shù)據(jù)庫的情況下,程序就完成了對數(shù)據(jù)的插入。插入數(shù)據(jù)后,Login表和Detail表的內(nèi)容如圖4.12、圖4.13所示。
圖4.12Login表
圖4.13Detail表4.3.1一對一關(guān)聯(lián)2.唯一外鍵方式唯一外鍵的情況很多,例如,每個(gè)人對應(yīng)一個(gè)房間。其實(shí)在很多情況下,可以是幾個(gè)人住在同一個(gè)房間里面,就是多對一的關(guān)系。但是如果把這個(gè)多變成唯一,也就是說讓一個(gè)人住一個(gè)房間,就變成了一對一的關(guān)系了,這就是前面說的一對一的關(guān)系其實(shí)是多對一關(guān)聯(lián)關(guān)系的一種特殊情況。對應(yīng)的Person表和Room表如表4.3、表4.4所示。字段名稱數(shù)據(jù)類型主鍵自增允許為空描述Idint是增1ID號namevarchar(20)姓名room_idint(20)是房間號字段名稱數(shù)據(jù)類型主鍵自增允許為空描述idint(4)是增1ID號addressvarchar(100)地址表4.3Person表表4.4Room表4.3.1一對一關(guān)聯(lián)步驟如下:①在項(xiàng)目Hibernate_mapping的org.model包下編寫生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件。Person表對應(yīng)的POJO類Person.java:packageorg.model;publicclassPersonimplementsjava.io.Serializable{privateIntegerid;privateStringname;privateRoomroom;//省略上述各屬性的getter和setter方法}Room表對應(yīng)的POJO類Room.java:packageorg.model;publicclassRoomimplementsjava.io.Serializable{privateintid;privateStringaddress;privatePersonperson;//省略上述各屬性的getter和setter方法}4.3.1一對一關(guān)聯(lián)Person表與Person類的ORM映射文件Person.hbm.xml:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""/hibernate-mapping-3.0.dtd"><hibernate-mapping><classname="org.model.Person"table="Person"><idname="id"column="id"type="java.lang.Integer"><generatorclass="native"/></id><propertyname="name"column="name"type="java.lang.String"/><many-to-onename="room" //屬性名稱column="room_id" //充當(dāng)外鍵的字段名class="org.model.Room" //被關(guān)聯(lián)的類的名稱cascade="all" //主控類所有操作,對關(guān)聯(lián)類也執(zhí)行同樣操作unique="true"/> //唯一性約束,實(shí)現(xiàn)一對一</class></hibernate-mapping>4.3.1一對一關(guān)聯(lián)Room表與Room類的ORM映射文件Room.hbm.xml:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""/hibernate-mapping-3.0.dtd"><hibernate-mapping><classname="org.model.Room"table="Room"><idname="id"column="id"><generatorclass="native"/></id> <propertyname="address" column="address"type="java.lang.String"/> <one-to-onename="person" //屬性名class="org.model.Person" //被關(guān)聯(lián)的類的名稱
property-ref="room"/> //指定關(guān)聯(lián)類的屬性名</class></hibernate-mapping>4.3.1一對一關(guān)聯(lián)②在hibernate.cfg.xml文件中加入如下的配置映射文件的語句。<mappingresource="org/model/Person.hbm.xml"/><mappingresource="org/model/Room.hbm.xml"/>③編寫測試代碼。在src文件夾下的包test的Test類中加入如下代碼:…Personperson=newPerson();person.setName("liumin");Roomroom=newRoom();room.setAddress("NJ-S1-328");person.setRoom(room);session.save(person);…4.3.1一對一關(guān)聯(lián)④運(yùn)行程序,測試結(jié)果。因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。在完全沒有操作數(shù)據(jù)庫的情況下,程序就完成了對數(shù)據(jù)的插入。插入數(shù)據(jù)后,Person表和Room表的內(nèi)容如圖4.14、圖4.15所示。
圖4.14Person表
圖4.15Room表4.3.2多對一單向關(guān)聯(lián)只要把上例中的一對一的唯一外鍵關(guān)聯(lián)實(shí)例稍微修改就可以變成多對一。步驟如下:①在項(xiàng)目Hibernate_mapping的org.model包下編寫生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件。其對應(yīng)表不變,Person表對應(yīng)的類也不變,對應(yīng)的Person.hbm.xml文件修改如下:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""/hibernate-mapping-3.0.dtd"><hibernate-mapping><classname="org.model.Person"table="Person"><idname="id"column="id"type="java.lang.Integer"><generatorclass="native"/></id><propertyname="name"column="name"type="java.lang.String"/><many-to-onename="room" //屬性名稱 column="room_id" //充當(dāng)外鍵的字段名 class="org.model.Room" //被關(guān)聯(lián)的類的名稱 cascade="all"/> //主控類所有操作,對關(guān)聯(lián)類也執(zhí)行同樣操作</class></hibernate-mapping>4.3.2多對一單向關(guān)聯(lián)而Room表不變,對應(yīng)的POJO類如下:packageorg.model;publicclassRoomimplementsjava.io.Serializable{privateintid;privateStringaddress;//省略上述各屬性的getter和setter方法}Room表與Room類的ORM映射文件Room.hbm.xml如下:<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEhibernate-mappingPUBLIC"-//Hibernate/HibernateMappingDTD3.0//EN""/hibernate-mapping-3.0.dtd"><hibernate-mapping><classname="org.model.Room"table="room"><idname="id"column="id"><generatorclass="native"/></id><propertyname="address"column="address"type="java.lang.String"/></class></hibernate-mapping>4.3.2多對一單向關(guān)聯(lián)②編寫測試代碼。在src文件夾下的包test的Test類中加入如下代碼:
…Roomroom=newRoom();room.setAddress("NJ-S1-328");Personperson=newPerson();person.setName("liuyanmin");person.setRoom(room);session.save(person);…4.3.2多對一單向關(guān)聯(lián)③運(yùn)行程序,測試結(jié)果。因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。在完全沒有操作數(shù)據(jù)庫的情況下,程序就完成了對數(shù)據(jù)的插入。插入數(shù)據(jù)后,Person表和Room表的內(nèi)容如圖4.16、圖4.17所示。
圖4.16Person表
圖4.17Room表4.3.3一對多雙向關(guān)聯(lián)下面通過修改4.3.2節(jié)的例子來完成雙向多對一的實(shí)現(xiàn)。步驟如下:①在項(xiàng)目Hibernate_mapping的org.model包下編寫生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件。Person表對應(yīng)的POJO及其映射文件不用改變,現(xiàn)在來修改Room表對應(yīng)的POJO類及其映射文件。對應(yīng)的POJO類Room.java。Room表與Room類的ORM映射文件Room.hbm.xml。該配置文件中cascade配置的是級聯(lián)程度,它有以下幾種取值:all:表示所有操作句在關(guān)聯(lián)層級上進(jìn)行連鎖操作。save-update:表示只有save和update操作進(jìn)行連鎖操作。delete:表示只有delete操作進(jìn)行連鎖操作。all-delete-orphan:在刪除當(dāng)前持久化對象時(shí),它相當(dāng)于delete;在保存或更新當(dāng)前持久化對象時(shí),它相當(dāng)于save-update。另外它還可以刪除與當(dāng)前持久化對象斷開關(guān)聯(lián)關(guān)系的其他持久化對象。4.3.3一對多雙向關(guān)聯(lián)②編寫測試代碼。在src文件夾下的包test的Test類中加入如下代碼:…Personperson1=newPerson();Personperson2=newPerson();Roomroom=newRoom();room.setAddress("NJ-S1-328");person1.setName("李方方");person2.setName("王艷");person1.setRoom(room);person2.setRoom(room);//這樣完成后就可以通過Session對象//調(diào)用session.save(person1)和session.save(person)//會(huì)自動(dòng)保存roomsession.save(person1);session.save(person2);…4.3.3一對多雙向關(guān)聯(lián)③運(yùn)行程序,測試結(jié)果。因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。在完全沒有操作數(shù)據(jù)庫的情況下,程序就完成了對數(shù)據(jù)的插入。插入數(shù)據(jù)后,Person表和Room表的內(nèi)容如圖4.18、圖4.19所示。
圖4.18Person表
圖4.19Room表4.3.3一對多雙向關(guān)聯(lián)由于是雙向的,當(dāng)然也可以從Room的一方來保存Person,在Test.java中加入如下代碼:...Personperson1=newPerson();Personperson2=newPerson();Roomroom=newRoom();person1.setName("李方方");person2.setName("王艷");Setpersons=newHashSet();persons.add(person1);persons.add(person2);room.setAddress("NJ-S1-328");room.setPerson(persons);//這樣完成后,就可以通過Session對象//調(diào)用session.save(room)//會(huì)自動(dòng)保存person1和person2...4.3.3一對多雙向關(guān)聯(lián)運(yùn)行程序,插入數(shù)據(jù)后,Person表和Room表的內(nèi)容如圖4.20、圖4.21所示。
圖4.20Person表
圖4.21Room表4.3.4多對多關(guān)聯(lián)1.多對多單向關(guān)聯(lián)學(xué)生和課程就是多對多的關(guān)系,一個(gè)學(xué)生可以選擇多門課程,而一門課程又可以被多個(gè)學(xué)生選擇。多對多關(guān)系在關(guān)系數(shù)據(jù)庫中不能直接實(shí)現(xiàn),還必須依賴一張連接表。如表4.6、表4.7和表4.8所示。字段名稱數(shù)據(jù)類型主鍵自增允許為空描述IDint是增1ID號SNUMBERvarchar(10)學(xué)號SNAMEvarchar(10)是姓名SAGEint是年齡字段名稱數(shù)據(jù)類型主鍵自增允許為空描述IDint是增1ID號CNUMBERvarchar(10)課程號CNAMEvarchar(20)是課程名表4.6學(xué)生表student表4.7課程表course字段名稱數(shù)據(jù)類型主鍵自增允許為空描述SIDint是學(xué)生ID號CIDint是課程ID號表4.8連接表stu_cour4.3.4多對多關(guān)聯(lián)由于是單向的,也就是說從一方可以知道另一方,反之不行。這里以從學(xué)生知道選擇了哪些課程為例實(shí)現(xiàn)多對多單向關(guān)聯(lián)。步驟如下:①在項(xiàng)目Hibernate_mapping的org.model包下編寫生成數(shù)據(jù)庫表對應(yīng)的Java類對象和映射文件。student表對應(yīng)的POJO類如下:packageorg.model;importjava.util.HashSet;importjava.util.Set;publicclassStudentimplementsjava.io.Serializable{ privateintid; privateStringsnumber; privateStringsname; privateintsage; privateSetcourses=newHashSet(); //省略上述各屬性的getter和setter方法}student表與Student類的ORM映射文件Student.hbm.xml。4.3.4多對多關(guān)聯(lián)course表對應(yīng)的POJO如下:packageorg.model;publicclassCourseimplementsjava.io.Serializable{ privateintid; privateStringcnumber; privateStringcname; //省略上述各屬性的getter和setter方法。}course表與Course類的ORM映射文件Course.hbm.xml。②在hibernate.cfg.xml文件中加入如下的配置映射文件的語句。
<mappingresource="org/model/Student.hbm.xml"/><mappingresource="org/model/Course.hbm.xml"/>③編寫測試代碼。在src文件夾下的包test的Test類中加入如下代碼。4.3.4多對多關(guān)聯(lián)④運(yùn)行程序,測試結(jié)果。因?yàn)樵摮绦驗(yàn)镴avaApplication,所以可以直接運(yùn)行。在完全沒有操作數(shù)據(jù)庫的情況下,程序就完成了對數(shù)據(jù)的插入。插入數(shù)據(jù)后,student表、course表及連接表stu_cour表的內(nèi)容如圖4.22、圖4.23、圖4.24所示。圖4.22student表
圖4.23course表
圖4.24stu_cour表4.3.4多對多關(guān)聯(lián)2.多對多雙向關(guān)聯(lián)首先將其Course表所對應(yīng)的POJO對象修改成如下代碼:packageorg.model;importjava.util.HashSet;importjava.util.Set;publicclassCourseimplementsjava.io.Serializable{ privateintid; privateStringcnumber; privateStringcname; privateSetstus=newHashSet(); //省略上述各屬性的getter和setter方法}Course表與Course類的ORM映射文件Course.hbm.xml:4.4Hibernate高級功能4.4.1Hibernate批量處理1.批量插入(1)通過Hibernate的緩存進(jìn)行批量插入使用這種方法時(shí),首先要在Hibernate的配置文件hibernate.cfg.xml中設(shè)置批量尺寸屬性hibernate.jdbc.batch_size,且最好關(guān)閉Hibernate的二級緩存以提高效率。例如:<hibernate-configuration> <session-factory> … <propertyname="hibernate.jdbc.batch_size">50</property> //設(shè)置批量尺寸 <propertyname="hibernate.cache.use_second_level_cache">false</property> //關(guān)閉二級緩存 </session-factory></hibernate-configuration>4.4.1Hibernate批量處理下面以4.2.1節(jié)的例子中的課程進(jìn)行批量插入為例,說明批量插入操作的具體過程,這里假設(shè)批量插入500個(gè)課程到數(shù)據(jù)中:Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();for(inti=0;i<500;i++){ Kcbkcb=newKcb(); //這里設(shè)置課程號為i,在實(shí)際應(yīng)用中應(yīng)該是被插入的課程對象 //已經(jīng)放在集合或數(shù)組中,這里只要取出 kcb.setKch(i+""); session.save(kcb); if(i%50==0){ //以50個(gè)課程為一個(gè)批次向數(shù)據(jù)庫提交,此值應(yīng)與配置的批量尺寸一致 session.flush();//將該批量數(shù)據(jù)立即插入數(shù)據(jù)庫中 session.clear();//清空緩存區(qū),釋放內(nèi)存供下批數(shù)據(jù)使用 }}mit();HibernateSessionFactory.closeSession();4.4.1Hibernate批量處理(2)繞過Hibernate直接調(diào)用JDBC進(jìn)行插入由于Hibernate只是對JDBC進(jìn)行了輕量級的封裝,因此完全可以繞過Hibernate直接調(diào)用JDBC進(jìn)行批量插入。因此上例可以改成如下代碼:Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Connectionconn=session.connection();try{ PreparedStatementstmt=conn.prepareStatement("insertintoKCB(KCH)values(?)"); for(inti=0;i<500;i++){ stmt.setString(1,i+""); stmt.addBatch(); //添加到批處理命令中 } stmt.executeBatch(); //執(zhí)行批處理任務(wù) }catch(SQLExceptione){ e.printStackTrace(); }mit();HibernateSessionFactory.closeSession();4.4.1Hibernate批量處理2.批量更新(1)由Hibernate直接進(jìn)行批量更新為了使Hibernate的HQL直接支持update/delete的批量更新語法,首先要在Hibernate的配置文件hibernate.cfg.xml中設(shè)置HQL/SQL查詢翻譯器屬性hibernate.query.factory_class。<hibernate-configuration> <session-factory> …… <propertyname="hibernate.query.factory_class"> org.hibernate.hql.ast.ASTQueryTranslatorFactory </property> </session-factory><hibernate-configuration> 4.4.1Hibernate批量處理下面使用HQL批量更新把課程表中的XS修改為30。由于這里是用Hibernate操作,故HQL要用類對象及其屬性。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//在HQL查詢中使用update進(jìn)行批量更新Queryquery=session.createQuery("updateKcbsetxs=30");query.executeUpdate();mit();HibernateSessionFactory.closeSession();4.4.1Hibernate批量處理(2)繞過Hibernate調(diào)用JDBC進(jìn)行批量更新由于這里是直接操作數(shù)據(jù)庫,故要操作對應(yīng)表,而不是類。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Connectionconn=session.connection();try{ Statementstmt=conn.createStatement(); //調(diào)用JDBC的update進(jìn)行批量更新 stmt.executeUpdate("updateKCBsetXS=30");}catch(SQLExceptione){ e.printStackTrace();}mit();HibernateSessionFactory.closeSession();4.4.1Hibernate批量處理3.批量刪除(1)由Hibernate直接進(jìn)行批量刪除與批量更新一樣,為了使Hibernate的HQL直接支持update/delete的批量刪除語法,首先要在Hibernate的配置文件hibernate.cfg.xml中設(shè)置HQL/SQL查詢翻譯器屬性hibernate.query.factory_class。<hibernate-configuration> <session-factory> …… <propertyname="hibernate.query.factory_class"> org.hibernate.hql.ast.ASTQueryTranslatorFactory </property> </session-factory><hibernate-configuration>4.4.1Hibernate批量處理下面將使用HQL批量刪除課程表中課程號大于200的課程。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();//在HQL查詢中使用delete進(jìn)行批量刪除Queryquery=session.createQuery("deleteKcbwherekch>200");query.executeUpdate();mit();HibernateSessionFactory.closeSession();4.4.1Hibernate批量處理(2)繞過Hibernate調(diào)用JDBC進(jìn)行批量刪除同樣刪除課程表中課程號大于200的課程。Sessionsession=HibernateSessionFactory.getSession();Transactionts=session.beginTransaction();Connectionconn=session.connection();try{ Statementstmt=conn.createStatement(); //調(diào)用JDBC的delete進(jìn)行批量刪除 stmt.executeUpdate("deletefromKCBwhereKCH>200"); }catch(SQLExceptione){ //TODOAuto-generatedcatchblock e.printStackTrace();}mit();HibernateSessionFactory.closeSession();4.4.2實(shí)體對象生命周期實(shí)體對象的生命周期有以下3種狀態(tài)。1.transient(瞬時(shí)態(tài))瞬時(shí)態(tài),即實(shí)體對象在內(nèi)存中的存在,與數(shù)據(jù)庫中的記錄無關(guān)。如下面的代碼:Studentstu=newStudent();stu.setSnumber("081101");stu.setSname("李方方");stu.setSage(21);2.persisent(持久態(tài))在這種狀態(tài)下,實(shí)體對象的引用被納入Hibernate實(shí)體容器中加以管理。處于持久狀態(tài)的對象,其變更將由Hibernate固化到數(shù)據(jù)庫中。例如下面的代碼。4.4.2實(shí)體對象生命周期3.Detached(脫管狀態(tài))處于持久態(tài)的對象,其對應(yīng)的Session實(shí)例關(guān)閉之后,此對象就處于脫管狀態(tài)。Session實(shí)例可以看做是持久對象的宿主,一旦此宿主失效,其從屬的持久對象進(jìn)入脫管狀態(tài)。如下面的代碼://stu處于瞬時(shí)態(tài)Studentstu=newStudent();Studentstu1=newStudent();stu.setSnumber("081101");stu.setSname("李方方");stu.setSage(21);stu1.setSnumber("081102");stu1.setSname("程明");stu1.setSage(22);Transactiontx=session.beginTransaction();//stu對象由Hibernate納入管理容器,處于持久狀態(tài)session.save(stu);mit();//stu對象狀態(tài)為脫管態(tài),因?yàn)榕c其關(guān)聯(lián)的session已經(jīng)關(guān)閉session.close();4.4.3Hibernate事務(wù)管理1.基于JDBC的事務(wù)管理Hibernate是JDBC的輕量級封裝,本身并不具備事務(wù)管理能力。在事務(wù)管理層,Hibernate將其委托給底層的JDBC或JTA,以實(shí)現(xiàn)事務(wù)管理和調(diào)度功能。在JDBC的數(shù)據(jù)庫操作中,一項(xiàng)事務(wù)是由一條或多條表達(dá)式組成的不可分割的工作單元,通過提交commit()或回滾rollback()來結(jié)束事務(wù)的操作。將事務(wù)管理委托給JDBC進(jìn)行處理是最簡單的實(shí)現(xiàn)方式,Hibernate對于JDBC事務(wù)的封裝也比較簡單。如下面的代碼:Sessionsession=sessio
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- DB51T 1622-2013 政務(wù)服務(wù)中心 窗口工作人員輪換規(guī)范
- DB51T 1598.1-2023 低壓線路電氣火災(zāi)原因認(rèn)定 第1部分:必要條件
- DB51T 1031-2010 茶葉中稀土的測定方法電感耦合等離子體原子發(fā)射光譜法
- 先天性腸旋轉(zhuǎn)異常病因介紹
- 精制C5項(xiàng)目立項(xiàng)申請報(bào)告
- (施工建設(shè))油氣分離器項(xiàng)目可行性研究報(bào)告
- 紅光激光器生產(chǎn)加工項(xiàng)目可行性研究報(bào)告
- 母料項(xiàng)目立項(xiàng)申請報(bào)告
- 2024-2030年新版中國金晶米黃人造崗石項(xiàng)目可行性研究報(bào)告
- 2024-2030年撰寫:中國聚乙二醇三甲基壬基醚行業(yè)發(fā)展趨勢及競爭調(diào)研分析報(bào)告
- 固體廢物監(jiān)測
- 2023-2024學(xué)年貴州省黔南州高二(上)期末英語試卷
- 司法鑒定技術(shù)
- 長安歐尚X70A說明書
- 燃料電池系統(tǒng)增濕器性能測試規(guī)范
- 【溫商精神導(dǎo)論課程論文:溫商精神形成的歷史文化分析3000字】
- 平行檢查記錄范本
- 陳爽-春晚小品爆笑《如此課堂》臺(tái)詞
- 趣味運(yùn)動(dòng)會(huì)兒童拔河比賽技巧
- 撤場通知書( 模板)
- 2022-2023學(xué)年四川省巴中市巴州區(qū)川教版(三起)四年級上學(xué)期期末英語試卷
評論
0/150
提交評論