<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 6, comments - 8, trackbacks - 0, articles - 6
      BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    作為測(cè)試,我們新建一個(gè)TUser對(duì)象,其image屬性中,保存了一個(gè)圖片文件的二進(jìn)制內(nèi)容。而其resume屬性,我們以一個(gè)簡(jiǎn)單的字符串作為填充。

    ?

    ?1 TUser?user? = new ?TUser();?
    ?2
    ?3 user.setAge( new ?Integer( 20 ));?
    ?4
    ?5 user.setName( " Shark " );?
    ?6
    ?7 FilelnputStream?imgis? = new ?FileinputStream( " C:\\inimage.jpg " ?
    ?8
    ?9 Blob?img? = ?Hibernate.createBlob(imgis);?
    10
    11 user.setlmage(img);?
    12
    13 Clob?resume? = ?Hibernate.createClob( " This?is?Clob " );?
    14
    15 user.?setResume(resume);?
    16
    17 Transaction?tx? = ?session.beginTransaction();?
    18
    19 session.save(user);?
    20
    21 tx.commit();?
    22
    23

    上面的代碼中,我們通過(guò)Hibemate.createBlobHibemate.createClob創(chuàng)建了對(duì)應(yīng)的BlobClob對(duì)象。其中Blob對(duì)象基于一個(gè)FileInputStream構(gòu)建,而Clob對(duì)象基于一個(gè)字符串構(gòu)建。

    ?

    完成了寫(xiě)入操作,對(duì)應(yīng)的讀取操作代碼如下:

    ?

    ?1 // ?假設(shè)庫(kù)表記錄的id字段等于3?
    ?2 TUser?user = (TUser)??session.load(TUger.elaa.,?load(TUser. class ,?? new ?Integer( 3 ));?
    ?3 Clob?resume = user.getResume();?
    ?4 // ?通過(guò)Clob.getSubString()方法獲取Clob字段內(nèi)容?
    ?5 System.out.println( " User?resume=> " + resume.getSubString( 1 ,( int )resume.length()));?
    ?6 Blob?img? = ?user.getImage();?
    ?7 // ?通過(guò)Blob.getBinaryS=ream()方法獲取二進(jìn)制流?
    ?8 InputStream?is? = ?img.getBinaryStream();?
    ?9 FileOutputStream?fos = new ?FileOutputStream( " C:\\outimage.jpg " );?
    10 byte []?buf = new ? byte ( 102400 );?
    11 int ?len;?
    12 while ((len? = ?is.read(buf)) !=- 1 ) {?
    13 ????fos.write(buf, 0 ,len);?
    14 }
    ?
    15 fos.close();?
    16 is.close();?
    17
    18

    ?

    通過(guò)上面的代碼,我們完成了針對(duì)SQLServerBlob/Clob型字段操作.看起來(lái)非常簡(jiǎn)單,不過(guò),并非侮種數(shù)據(jù)庫(kù)都如此友善。讓我們接著來(lái)看看Oracle數(shù)據(jù)庫(kù)下的Blob/Clob字段讀寫(xiě),

    通過(guò)修改hibernate.cfg.xml中的Dialect配置完成數(shù)據(jù)庫(kù)切換后,我們?cè)俅芜\(yùn)行上面的TUser對(duì)象保存例程。

    程序運(yùn)行期間拋出異常:

    ?

    Hibernate:select hibernate_sequence.nextval from dual

    Hibernate:insert into T_USER (name, age,? image,resume. id) values(?, ?, ?, ?, ?)

    17:27:24,161 ERROR JDBCExceptionReporter:58 - - 不允許的操作: Streams type cannot be used in batching

    17:27:24,171 ERROR Sessionlmpl:2399 - Could not synchronize database state with session

    net.sf.hibernate.exception.GenericJDBCException:could not insert:[com.redsaga.hibernate.db.entity.TUser#6]

    ...

    ?

    觀察異常信息:streams type cannot be used in batching.這意味著Oracle JDBC不允許流操作以批量方式執(zhí)行(Oracle CLOB采用流機(jī)制作為數(shù)據(jù)讀寫(xiě)方式)

    這種錯(cuò)誤一般發(fā)生在hibernate.cfg.xml中的hibernate jdbc.batch_size設(shè)定大于0的情況,將hibernate.jdbc.batch_size修改為0即可消除。

    ?

    <hibernate-configuration>

    <session-factory>

    ???????????? ...

    ???????????? <property name='hibernate. jdbc.batch_size">0</property>

    ???????????? ...

    </session-factory>

    </hibernate-configuration>

    ?

    再次嘗試啟動(dòng)代碼,發(fā)現(xiàn)依然無(wú)法成功運(yùn)行,拋出異常如下:

    ?

    Hibernate: select hibernate_sequence.nextval from dual

    Hibernate: insert into T--USER? (name,? age,? image,resume,id) values(?,?,?,?,?)

    19:02:21,054 ERROR JDBCExceptionReporter:58 IO異常:Connection reset bypeer: socket write error

    19:02:21,054 ERROR JDBCExceptionReporter:58 I。異常:Connection reset by peer:socket write error

    19:02:21 064 ERROR JDBCExceptionReporter:58Io異常:Connection reset by peer: socket wrto error

    19:02:21,064 ERROR Sessionlrnpl:2399 Could not synchronize database state with session

    net.sf.hibernate.exception.GenericJDSCException:? could not insert:[com.redsaga.hibernate.db.entity.TUser#27]

    ...

    ?

    為什么會(huì)出現(xiàn)這樣的情況?

    問(wèn)題出在OracceBlob/Clob字段獨(dú)特的訪問(wèn)方式,Oracle Blob/Clob字段本身?yè)碛幸粋€(gè)游標(biāo)(cursor) , JDBC必須通過(guò)游標(biāo)對(duì)Blob/ Clob字段進(jìn)行操作,在Blob/Clob字段被創(chuàng)建之前,我們無(wú)法獲取其游標(biāo)句柄,這也就意味著,我們必須首先創(chuàng)建一個(gè)空Blob/Clob字段,再?gòu)倪@個(gè)空Blob/Clob字段獲取游標(biāo),寫(xiě)入我們所期望保存的數(shù)據(jù)。

    如果用JDBC代碼來(lái)表示這個(gè)過(guò)程,則得到如下代碼:

    ?

    //... 獲取JDBC連接

    dbconn.setAutoCommit(falee);

    // =======插入數(shù)據(jù),BLOB CLOB字段插入空值

    PreparedStatenent preStmt=

    dbconn.prepareStatement(

    ??? "insert into T_USER (name, age,? id,image,resume) values

    ???? (?,?,?,?,?)");

    preStmt.setString(1,"Shark");

    preStmt.setInt(2,20);

    preStmt.setInt(3,5);?

    // 通過(guò)oracle.sgl.BLOB/CLOB.empty_lob()方法構(gòu)造空Blob/Clob對(duì)象

    preStmt.setBlob(4 oracle.sgl.BLOB.empty_lob());

    preStmt.setClob(5,oracle.sgl.CLOB.empty_lob());

    preStmt.executeUpdate();

    preStmt.close():

    //========== 再次從庫(kù)表讀出,獲得Blob/Clob句柄

    preStmt=

    ? dbconn.prepareStatement(

    ????? "select? image,resume from T_USER where id=?for update');

    preStmt.setint(l,5);

    ResultSet rset=preStmt.executeQuery();

    // 注意我們這里需要引用Oracle原生BLOB定義,如果使用了Weblogic JDBC Vendor

    // 則應(yīng)使用weblogic.jdbc.vendor.oracle. OracleThinBLob/OracleThinCLOb

    rset.next();

    oracle.sql.BLOB imqBlob = (oracle.sql.BLOB) rset.getBlob(1);

    oracle.sql.CLOB resClob = (oracle.sql.CLOB) rset.getClob(2);

    //======= 將二進(jìn)創(chuàng)數(shù)據(jù)寫(xiě)入Blob

    FileInputStream inStream = new FileinputStream("c\\inimage.jpg");

    OutputStream outStream = imgBlob.getBinaryOutputStream();

    byte[] buf=new byte[10240];//10K 讀取緩存

    int len;

    while((len=inStream.read(buf))>0){

    ?? outStream.write(buf,0,len);

    }

    inStream.close();

    outStream.close():

    //======= 將字符串寫(xiě)入Clob

    resClob.putString(1 "This is my Glob"

    //======= Blob/Clob字段更新到數(shù)據(jù)序

    preStmt= dbconn.prepareStatement("update T_USER set? image=?,? resume=? where id=?");

    preStmt.setBlob(1,imgBlob);

    preStmt.setClob(2,resClob):

    preStmt.setlnt(3 5);

    preStmt.executeUpdate();

    preStmt.close():

    dbconn.commit();

    dbconn.close():

    ?

    上面的代碼說(shuō)明了OracleBlob/Clob字段操作的一般機(jī)制,那么,基于Hibernate的持久層實(shí)現(xiàn)中,應(yīng)該如何對(duì)Blob/Clob字段進(jìn)行處理?

    我們知道,Hibernate底層數(shù)據(jù)訪問(wèn)機(jī)制仍然是基于JDBC實(shí)現(xiàn),那么也就意味著我們必須在Hibernate中模擬JDBC的訪問(wèn)流程:

    TUser user=new TUser();

    user.setAge(new Integer(20));

    user.setName("Shark');

    user.setImage(Hibernate.createSlob(new byte [1])):

    user.setResume(Hibernate.createClob(" "));// 注意這里的參教是一個(gè)空格

    Transaction tx=session.beginTransaction();

    session.save(user):

    // 調(diào)用flush方法,強(qiáng)制Hibernate立即執(zhí)行insert sql

    session.flush();

    // 通過(guò)refresh方法,強(qiáng)制Hibernate執(zhí)行select for update

    session.refresh(user, LockMode.UPGRADE);

    // Blob寫(xiě)入實(shí)際內(nèi)容

    oracle.sql.BLOB blob=(oracle.sql.BLOB)user.getImage();

    OutputStream out=blob. getBinaryOutputStream();

    FileInputStream imgis=new FileInputStream("C:\\inimage.jpg");

    byte[] buf=new byte[10240];//10K 緩存

    int len;

    while((len=imgis.read(buf))>0){

    ? out.write(buf,0,len);

    }

    imgis.close();

    out.close();

    // Clob寫(xiě)入實(shí)際內(nèi)容

    oracle.sql.CLOB clob=(oracle.sgl.CLOB)? user.getResume();

    java.io.Writer writer = clob.getCharacterOutputStream();

    writer.write("this is my? resume');

    writer.close();

    session.save(user);

    tx.commit();

    實(shí)際應(yīng)用中,對(duì)于Clob字段,我們可以簡(jiǎn)單地將其映射為String類型,不過(guò)在這種情況下需要注意,Oracle Thin Driver對(duì)Clob字段支持尚有欠缺,當(dāng)Clob內(nèi)容超出4000字節(jié)時(shí)將無(wú)法讀取,而Oracle OCI Driver(需要在本地安裝Oracle客戶端組件)則可以成功地完成大容量Clob字段的操作。

    上面的代碼中,我們通過(guò)Session.save/flush/refresh方法的組合使用,實(shí)現(xiàn)了上面JDBC代碼中的Blob/Clob訪問(wèn)邏輯。

    Blob/Clob 字段的Hibernate保存實(shí)現(xiàn)如上所述,相對(duì)來(lái)講,讀取則沒(méi)有太多的障礙,之前的讀取代碼依然可以正常運(yùn)行。

    對(duì)于上面的實(shí)現(xiàn),相信大家都感覺(jué)到了一些Bad Smell,如果Blob/Clob字段普遍存在,那么我們的持久層邏輯中可能遍布如此復(fù)雜的數(shù)據(jù)存儲(chǔ)邏輯、并與數(shù)據(jù)庫(kù)原生類緊密禍

    如何解決這些問(wèn)題?

    回憶之前關(guān)于自定義數(shù)據(jù)類型的討論。通過(guò)自定義數(shù)據(jù)類型我們可以對(duì)數(shù)據(jù)的通用特征進(jìn)行抽象,那么,對(duì)于OracleBlob/Clob字段,我們是否可以也對(duì)其進(jìn)行抽象,并以其作為所有Oracle Blob/Clob字段的映射類型?

    下面的StringClobType實(shí)現(xiàn)了這一目標(biāo):

    public class StringClobType implements UserType{

    ??? private static final String ORACLE_DRIVER_NAME="Oracle JDBC driver";

    ?????? private static final int ORACLE_DRIVER_MAJOR_VERSION=9;

    ??? private static final int ORACLE_DRIVER_MINOR_VERSION=0;

    ??? public int[] sqlTypes(){

    ?????? return new int[] {Types.CLOB};

    ??? }

    ??? public Class returnedClass{

    ?????? return String.class;

    ??? }

    ??? public boolean equals(Object x, object y){

    ?????? return org.apache.commons.lang.ObjectUtils.equals(x, y);

    ??? }

    ??? public Object nullSafeGet(ResultSet rs, String[] names, Object owner)

    ??? throws HibernateException,SQLException{

    ?????? Clob clob=rs.getClob(names(O]);

    ?????? return(clob==null ? null:clob.getSubString(l,? (int) clob.length())):

    ??? }

    ??? public void nullSafeSet(PreparedStatement st Object value, int index)?

    ??? throws HibernateException, SQLException{

    ?????? DatabaseMetaData dbMetaData=st.getConnection().getMetaData();

    ?????? if (value==null)

    ?????????? st.setNull(index,? sqiTypes()(0));

    ?????? else

    //???????? 本實(shí)現(xiàn)僅僅適用于Oracle數(shù)據(jù)序9.0以上版本

    ?????? ??? if

    ?????????? (ORACLE_DRIVER_NAME.equals(dbMetaData.getDriverName( ))(

    ????????????? if((dbMetaData.getDriverMajorVersion()?

    ????????????????? ???>=ORACLE-DRIVER-MAJOR-VERSION)

    ????????????????? &&(dbMetaData.getDriverMinorVersion()??

    ???????????????????? >=ORACLE-DRIVER-MINOR-VERSION))

    ???????????????????????? try

    //??????????????? 通過(guò)動(dòng)態(tài)加載方式進(jìn)免編譯期對(duì)Oracle JDBC的依賴

    ???????????????????????? Class oracleClobClass=Class.forName('oracle.sgl.CLOB");

    //????????????????????????????? 動(dòng)態(tài)調(diào)用createTemporary方法

    ??????????????????????????????? Class partypes[]=new Class[3];

    ??????????????????????????????? partypes[0]=Connection.class;

    ??????????????????????????????? partypes[1]=Boolean.TYPE;

    ??????????????????????????????? partypes(2]=Integer.TYPE;

    ??????????????????????????????? Method createTemporaryMethod=

    ?????????????????????????????????? oracleClobClass.getDeclaredMethod(

    ????????????????????????????????????????? "createTemporaxy “,

    ????????????????????????????????????????? partypes);

    ??????????????????????????????? Field durationSessionField=

    ?????????????????????????????????? oracleClobClass.getField("DURATION-SESSION");

    ??????????????????????????????? Object arglist[]=new 0bject[3]:

    ?????????????????????????????????? Connection conn=

    ?????????????????????????????????????? st.getConnection().getMetaData().getConnection();

    //????????????????????????????? 數(shù)據(jù)庫(kù)連接類型必須為OracleConnection

    //????????????????????????????? 萊些應(yīng)用服務(wù)器會(huì)使用自帶Oracle JDBC Wrapper,如Weblogic

    //????????????????????????? ??? 這里需要特別注意

    ??????????????????????????????? Class oracleConnectionClass=

    ?????????????????????????????????? Class.forName("oracle.jdbc.OracleConnection");

    ??????????????????????????????? if(!oracleConnectionClass

    ?????????????????????????????????????? .isAssignableFrom(conn.getClass())){

    ?????????????????????????????????? throw new HibernateException(

    ????????????????????????????????????????? "Must be a oracle.jdbc.OracleConnection:.

    ????????????????????????????????????????? +conn.getClass().getName());

    ??????????????????????????????? }

    ??????????????????????????????? arglist[0] = conn;

    ??????????????????????????????? arglist(1] = Boolean.TRUE;

    ??????????????????????????????? arolist[2] = durationSessionField.get(null);

    ??????????????????????????????? Object tempClob =createTemporaryMethod.invoke(null,arglist);

    ??????????????????????????????? partypes=new Class[l];

    ??????????????????????????????? partypes[0]=Integer.TYPE;

    ??????????????????????????????? Method openMethod =oracleClobClass.getDeclaredMethod("open",partypes);

    ??????????????????????????????? Field modeReadWriteField =oracleClobClass.getField("MODE_READWRITE");

    ??????????????????????????????? arglist = new Object(l];

    ??????????????????????????????? arglis[0] = modeReadWriteField.get(null);

    ??????????????????????????????? openMethod.invoke(tempClob, arglist);

    ??????????????????????????????? Method getCharacterOutputStreamMethod=oracleClobClass.getDeclaredMethod("getCharacterOutputStream',null) ;

    //???????????????????????????????????? call the getCharacterOutpitStream method

    ?????????????????????????????????????? Writer tempClobWriter =(Writer)getCharacterOutputStreamMethod.invoke(tempClob,null);

    //???????????????????????????????????? 將參數(shù)寫(xiě)入Clob

    ?????????????????????????????????????? tempClobwriter.write((String) value);

    ?????????????????????????????????????? tempClobWriter.flush();

    ?????????????????????????????????????? tempClobWriter.Close();

    ??????????????????????????????????????

    //???????????????????????????????????? close? clob

    ?????????????????????????????????????? Method closeMethod=oracleClobClass.getDeclaredMethod("close", null);

    ?????????????????????????????????????? closeMethod.invoke(tempClob, null);

    ?????????????????????????????????????? st.setClob(index,? (Clob) tempClob);

    ??????????????????????????????? )catch? (ClassNotFoundException e){

    ?????????????????????????????????? throw new HibernateException("Unable to find a required class.\n"+e.getMessage()):

    ??????????????????????????????? }catch (NOSuchMethodException e){

    ?????????????????????????????????? throw new HibernateException("Unable to find a required method.\n"+e.getMessage()):

    ??????????????????????????????? }catch (NoSuchFieldException e){

    ?????????????????????????????????? throw new HibernateException("Unable to find a required field.\n"+e.getMessage());

    ??????????????????????????????? }catch (IllegalAccessException e){

    ?????????????????????????????????? throw new HibernateException("Unable to access a required method or field.\n"+e.getMessage());

    ?????????????????????????????????? catch (InvocationTargetException e){

    ?????????????????????????????????????? throw new HibernateException(e.getMessage());

    ?????????????????????????????????????? {? catch (IOException e){

    ????????????????????????????????????????? throw new HibernateException(e.getMessage());

    ?????????????????????????????????????? }

    ?????????????????????????????????????? else

    ?????????????????????????????????????? throw new HibernateException(

    ????????????????????????????????????????????? "No CLOBS support.Use driver version"

    ????????????????????????????????????????????? +ORACLE_DRIVER_MAJOR_VERSION

    ????????????????????????????????????????????? +" minor"

    ????????????????????????????????????????????? +ORACLE_DRIVER_MINOR_VERSION);

    ?????????????????????????????????????? }

    ?????????????????????????????????? }else

    ?????????????????????????????????? String str = (String)? value;

    ??? ??????????????????????????????? StrinaReader r = new StringReader(str);

    ?????????????????????????????????? St.setCharacterStream(index, r, str.length());

    ??????????????????????????????? }

    ??? }

    ??? public Object deepCopy(Object value){

    ?????? if(value==null)

    ?????????? return null;

    ?????? return new String((String)? value);

    ??? }

    ??? public boolean isMutable(){

    ?????? return false

    ??? }

    }

    上面這段代碼,重點(diǎn)在于nullSafeSet方法的實(shí)現(xiàn),nullSafeSet中通過(guò)Java Reflection機(jī)制,解除了編譯期的Oralce JDBC原生類依賴。同時(shí),借助Oracle JDBC提供的原生功能完成了Clob字段的寫(xiě)入,Clob字段的寫(xiě)入操作由于涉及特定數(shù)據(jù)庫(kù)內(nèi)部實(shí)現(xiàn)細(xì)節(jié),這里就不多費(fèi)唇舌,大家可參見(jiàn)Oracle JDBC Java Doc.

    這段代碼是由筆者根據(jù)Ali Ibrahim, Scott Miller的代碼修改而來(lái)的(原版請(qǐng)參見(jiàn)httpJ/www.hibemate org /56.html ),支持Oracle 9以上版本,Oracle 8對(duì)應(yīng)的實(shí)現(xiàn)請(qǐng)參見(jiàn)上述網(wǎng)址。

    同樣的道理,讀者可以根據(jù)以上例程,編寫(xiě)自己的ByteBlobType以實(shí)現(xiàn)byte[]Blob的映射。

    另外,此代碼必須運(yùn)行在最新版的Oracle JDBC Driver(筆者所用版本為Oracle9i9.2.0.5 for JDK1.4,如果使用9.2.0.3或之前版本則在新建l更卻刪除數(shù)據(jù)時(shí)可能會(huì)遇到“nomore data read from socket”錯(cuò)誤)

    ?


    評(píng)論

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2007-10-30 14:17 by libinglin
    很好,我正不知道用Hibernate如何存orcle的大對(duì)象呢,看了下,明白了

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2008-05-27 15:52 by roc
    兄臺(tái),保持文章更新啊。
    這篇帖子很有用處~~謝謝。

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2008-06-15 15:37 by 程波
    Caused by: java.sql.SQLException: 不允許的操作: streams type cannot be used in batching
    我用的ORALCE 報(bào)這個(gè)異常是怎么回事呢 ?

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2008-06-15 16:15 by 程波
    org.hibernate.lob.SerializableBlob cannot be cast to oracle.sql.BLOB
    怎么回事啊 樓主幫幫我啊

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2008-09-20 20:31 by Yvon
    謝謝博主的分享

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2010-01-12 15:51 by 落Nicety
    8錯(cuò)

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2011-09-27 12:44 by K仔
    很好很詳細(xì)!

    # re: Hibernate實(shí)現(xiàn)Clob和Blob對(duì)象的存取  回復(fù)  更多評(píng)論   

    2012-10-07 03:11 by 電風(fēng)扇的
    非常感謝

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 免费国产高清毛不卡片基地| 亚洲一区二区三区国产精品无码| 国产精品九九久久免费视频| 亚洲AV无码码潮喷在线观看| 国产91免费视频| 亚洲s码欧洲m码吹潮| 在线观看亚洲天天一三视| 亚洲精品免费视频| 亚洲AV无码成人网站在线观看| 亚洲va国产va天堂va久久| 黑人精品videos亚洲人| 我要看WWW免费看插插视频| 九九久久国产精品免费热6 | 免费观看91视频| 亚洲人成色99999在线观看| 亚洲精品少妇30p| 亚洲高清专区日韩精品| 成人国产mv免费视频| 国产精品免费AV片在线观看| 国产精品亚洲av色欲三区| 亚洲激情视频网站| 亚洲色精品vr一区二区三区| 国产午夜免费福利红片| 日韩人妻无码精品久久免费一| 四虎影视久久久免费| 亚洲国产日韩a在线播放| 激情小说亚洲图片| h视频在线观看免费| 久久国产精品免费观看| 国产精品怡红院永久免费| 久久国产乱子精品免费女| 永久在线免费观看| 99精品视频免费观看| 国产在线a免费观看| 无码精品人妻一区二区三区免费看| 4399影视免费观看高清直播| 成人a免费α片在线视频网站| 亚洲高清中文字幕免费| 国产在线a不卡免费视频| 免费看国产曰批40分钟| 亚洲熟妇无码AV在线播放 |