日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

MyBatis-16MyBatis动态SQL之【支持多种数据库】

發布時間:2025/3/21 数据库 50 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis-16MyBatis动态SQL之【支持多种数据库】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  • 概述
  • 配置
    • 1.MyBatis全局配置文件增加
    • 2.映射文件中的標簽調整包含databaseId屬性
  • 示例
    • 增加個查詢當前時間的接口
    • 編寫映射文件
    • 單元測試
  • 注意事項

概述

MyBatis-15MyBatis動態SQL之【bind】 bind標簽并不能解決更換數據庫帶來的所有問題。 那么還有沒其他的方式來支持不同的數據庫呢 ?

答案是 使用if標簽以及由MyBatis提供的databaseIdProvider數據庫廠商標識配置

MyBatis可以根據不同的數據庫廠商執行不同的SQL,這種多廠商的支持是基于映射語句中的databaseId屬性。 MyBatis會加載不帶databaseId屬性和帶有匹配當前數據庫databaseId屬性的所有語句。 如果同時找到了帶有databaseId和不帶databaseId的相同語句,則不帶databaseId的將被舍棄。


配置

1.MyBatis全局配置文件增加

為了支持多廠商數據庫,需要在MyBatis全局配置文件中加入databaseIdProvider配置 <databaseIdProvider type="DB_VENDOR"/>

也可以通過實現接口 org.apache.ibatis.mapping.DatabaseIdProvider 并在 mybatis-config.xml 中注冊來構建自己的 DatabaseIdProvider

DB_VENDOR會通過DatabaseMetaData#getDatabaseProductName()返回的字符串進行設置, 通常情況下這個字符串比較長而且相同產品的不同版本會返回不同的值,通常會設置屬性別名使其變短。

<!-- 多數據庫支持 --><databaseIdProvider type="DB_VENDOR"><property name ="SQL Server" value="sqlserver"/><property name ="DB2" value ="db2"/><property name ="Oracle" value ="oracle"/><property name ="MySQL" value ="mysql"/><property name ="PostgreSQL" value ="postgresql"/><property name ="Derby" value ="derby"/><property name ="HSQL" value ="hsqldb"/><property name ="H2" value ="h2"/></databaseIdProvider>

上述列舉了常見的數據庫產品名稱,在有property配置時,databaseId將被設置為第一個能匹配數據庫產品名稱的屬性鍵對應的值,如果沒有匹配則置為null .

DB_VENDOR的匹配策略為DatabaseMetaData#getDatabaseProductName()返回的字符串包含property中name部分的值即可匹配。

數據庫產品名一般由選擇的當前數據庫的JDBC驅動所決定,只要找到對應數據庫DatabaseMetaData的實現類,一般在getDatabaseProductName()方法中就可以直接找到該值。
任何情況下都可以通過調用DatabaseMetaData#getDatabaseProductName()來獲取具體的值

完整的mybatis-config.xml如下

<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration><!-- 引入外部屬性文件 ,必須放在第一位--><properties resource="db.properties"/><settings><!-- 通過logImpl屬性指定使用LOG4J輸出日志,mybatis默認使用log4j作為輸出日志信息。 --><setting name="logImpl" value="LOG4J" /><!-- 通過配置這個屬性為true可以自動將下畫線方式命名的數據庫列映射到java對象駝峰式命名屬性中<setting name="mapUnderscoreToCamelCase" value="true"/>--></settings><!-- typeAliases元素下配置了一個包的別名,通常確定一個類的時候需要使用全限定名,比如 com.artisan.mybatis.simple.mapper.model.Country--><typeAliases><package name="com.artisan.mybatis.simple.model" /></typeAliases><!-- 和spring整合后 environments配置將廢除--><environments default="development"><environment id="development"><!-- 使用jdbc事務管理--><transactionManager type="JDBC"/><!-- 數據庫連接池--><dataSource type="UNPOOLED"><property name="driver" value="${jdbc.driver}" /><property name="url" value="${jdbc.url}" /><property name="username" value="${jdbc.username}" /><property name="password" value="${jdbc.password}" /></dataSource></environment></environments><!-- 多數據庫支持 --><databaseIdProvider type="DB_VENDOR" ><property name ="SQL Server" value="sqlserver"/><property name ="DB2" value ="db2"/><property name ="Oracle" value ="oracle"/><property name ="MySQL" value ="mysql"/><property name ="PostgreSQL" value ="postgresql"/><property name ="Derby" value ="derby"/><property name ="HSQL" value ="hsqldb"/><property name ="H2" value ="h2"/></databaseIdProvider><mappers><!-- 配置具體的mapper --><mapper resource="com/artisan/mybatis/simple/mapper/CountryMapper.xml" /><!-- 逐一配置,比較繁瑣,容易遺漏,接口方式不推薦<mapper resource="com/artisan/mybatis/xml/mapper/UserMapper.xml"/><mapper resource="com/artisan/mybatis/xml/mapper/UserRoleMapper.xml"/><mapper resource="com/artisan/mybatis/xml/mapper/RoleMapper.xml"/><mapper resource="com/artisan/mybatis/xml/mapper/PrivilegeMapper.xml"/><mapper resource="com/artisan/mybatis/xml/mapper/RolePrivilegeMapper.xml"/>--><!-- 推薦:通過包的方式配置,mybatis會先查找對應包下的所有的接口 --><package name="com.artisan.mybatis.xml.mapper"/></mappers> </configuration>

注意databaseIdProvider節點的位置。


2.映射文件中的標簽調整包含databaseId屬性

除了增加上述配置之外,映射文件也需要調整,關鍵在于下面幾個映射文件的標簽中含有的databaseId屬性

  • select
  • insert
  • update
  • delete
  • selectKey
  • sql

示例

舉個簡單的例子,查詢當前時間

我們知道 mysql中的語句為

select now() from dual

oracle中為

select sysdate from dual

增加個查詢當前時間的接口

結合mybatis全局配置文件中的 mappers-package節點,在com.artisan.mybatis.xml.mapper包中增加接口

MultiDBMapper.java

package com.artisan.mybatis.xml.mapper;public interface MultiDBMapper {String getSysTime();}

編寫映射文件

MultiDBMapper.xml

<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <!-- 當Mapper接口和XML文件關聯的時候, namespace的值就需要配置成接口的全限定名稱 --> <mapper namespace="com.artisan.mybatis.xml.mapper.MultiDBMapper"><select id="getSysTime" resultType="String" databaseId="mysql">select now() from dual</select><select id="getSysTime" resultType="String" databaseId="oracle">select 'oralce-'||to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual </select></mapper>

單元測試

package com.artisan.mybatis.xml.mapper;import java.io.InputStream; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.util.Properties;import org.apache.ibatis.session.SqlSession; import org.junit.Test;public class MultiDBMapperTest extends BaseMapperTest {public String getDatabaseProductName() {String productName = null;try {String dbfile = "db.properties";InputStream in = ClassLoader.getSystemResourceAsStream(dbfile);Properties p = new Properties();p.load(in);Class.forName(p.getProperty("jdbc.driver"));String url = p.getProperty("jdbc.url");String user = p.getProperty("jdbc.username");String pass = p.getProperty("jdbc.password");Connection con = DriverManager.getConnection(url, user, pass);DatabaseMetaData dbmd = con.getMetaData();productName = dbmd.getDatabaseProductName();System.out.println("數據庫名稱是:" + productName);} catch (Exception e) {e.printStackTrace();}return productName;}@Testpublic void getSysTimeTest() {// 獲取數據庫名稱getDatabaseProductName();// 獲取SqlSessionSqlSession sqlSession = getSqlSession();// 獲取MultiDBMapperMultiDBMapper multiDBMapper = sqlSession.getMapper(MultiDBMapper.class);// 調用接口方法String sysTime = multiDBMapper.getSysTime();System.out.println("當前時間:" + sysTime);sqlSession.close();}}

日志

2018-04-27 16:05:57,730 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-27 16:05:57,730 INFO [main] (BaseMapperTest.java:29) - reader close successfully 數據庫名稱是:MySQL 2018-04-27 16:05:57,819 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: select now() from dual 2018-04-27 16:05:57,929 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: 2018-04-27 16:05:57,959 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: now() 2018-04-27 16:05:57,959 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 2018-04-27 16:05:57.0 2018-04-27 16:05:57,969 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 當前時間:2018-04-27 16:05:57.0

當基于不同的數據庫運行時,MyBatis會根據配置找到合適的SQL去執行。


注意事項

我們在上面演示了基于databaseId的基本用法,實際在工作中,大部分的SQL還是相同的,沒有必要寫成2個。這樣會導致大量重復的SQL。

數據庫的更換可能只會引起某個SQL語句的部分不同, 可以使用if標簽配合默認的上下文中的_databaseId參數去實現。

我們用前幾篇博文的例子來演示下

改造前

<select id="selectSysUsersAdvancedWithWhere" resultType="com.artisan.mybatis.xml.domain.SysUser">SELECTa.id,a.user_name userName,a.user_password userPassword,a.user_email userEmail,a.user_info userInfo,a.head_img headImg,a.create_time createTimeFROMsys_user a<where><if test="userName != null and userName != '' ">and user_name like concat('%',#{userName},'%')</if><if test="userEmail != null and userEmail != '' ">and user_email = #{userEmail}</if></where></select>

改造后

<!-- 多數據庫的支持 BEGIN --><select id="selectSysUsersAdvancedMulitDB" resultType="com.artisan.mybatis.xml.domain.SysUser">SELECTa.id,a.user_name userName,a.user_password userPassword,a.user_email userEmail,a.user_info userInfo,a.head_img headImg,a.create_time createTimeFROMsys_user a<where><if test="userName != null and userName != '' "><if test="_databaseId == 'mysql' ">and user_name like concat('%',#{userName},'%')</if><if test="_databaseId == 'oracle' ">and user_name like '%'||#{username}||'%'</if></if><if test="userEmail != null and userEmail != '' ">and user_email = #{userEmail}</if></where></select><!-- 多數據庫的支持 END -->

增加個接口方法,方便區分測試

/*** * * @Title: selectSysUsersAdvancedMulitDB* * @Description: selectSysUsersAdvancedMulitDB* * @param sysUser* @return* * @return: List<SysUser>*/List<SysUser> selectSysUsersAdvancedMulitDB(SysUser sysUser);

單元測試

@Testpublic void selectSysUsersAdvancedMulitDBTest() {logger.info("selectSysUsersAdvancedMulitDBTest");// 獲取SqlSessionSqlSession sqlSession = getSqlSession();List<SysUser> userList = null;try {// 獲取UserMapper接口UserMapper userMapper = sqlSession.getMapper(UserMapper.class);logger.info("===========1.當用戶只輸入用戶名時,需要根據用戶名模糊查詢===========");// 模擬前臺傳參 1.當用戶只輸入用戶名時,需要根據用戶名模糊查詢SysUser sysUser = new SysUser();sysUser.setUserName("ad");// 調用selectSysUserByAdvancedCondition,根據查詢條件查詢用戶userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);// 根據數據庫sys_user表中的記錄,可以匹配到admin, 期望userList不為空Assert.assertNotNull(userList);// 根據查詢條件,期望只有1條數據Assert.assertTrue(userList.size() == 1);logger.info("userList:" + userList);// 為了測試 匹配多條記錄的情況,我們將id=1001這條數據的userName 由test 改為artisansysUser.setUserName("i");// 調用selectSysUserByAdvancedCondition,根據查詢條件查詢用戶userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);// 根據數據庫sys_user表中的記錄,可以匹配到admin和artisan, 期望userList不為空Assert.assertNotNull(userList);// 根據查詢條件,期望只有2條數據Assert.assertTrue(userList.size() == 2);logger.info("userList:" + userList);logger.info("===========2.當用戶只輸入郵箱使,根據郵箱進行完全匹配===========");// 模擬前臺傳參 2.當用戶只輸入郵箱使,根據郵箱進行完全匹配sysUser.setUserEmail("admin@artisan.com");userList = userMapper.selectSysUsersAdvanced(sysUser);Assert.assertNotNull(userList);Assert.assertTrue(userList.size() == 1);logger.info(userList);sysUser.setUserEmail("1admin@artisan.com");userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);Assert.assertTrue(userList.size() == 0);logger.info("===========3.當用戶同時輸入用戶名和密碼時,用這兩個條件查詢匹配的用戶===========");// 模擬組合查詢條件,存在記錄的情況sysUser.setUserName("i");sysUser.setUserEmail("admin@artisan.com");userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);Assert.assertNotNull(userList);Assert.assertEquals("admin@artisan.com", sysUser.getUserEmail());Assert.assertTrue(userList.size() == 1);logger.info(userList);logger.info("===========4.當用戶同時輸入無法匹配的用戶名和密碼===========");// 模擬組合查詢條件,不存在記錄的情況sysUser.setUserName("x");sysUser.setUserEmail("admin@artisan.com");userList = userMapper.selectSysUsersAdvancedMulitDB(sysUser);Assert.assertTrue(userList.size() == 0);logger.info(userList);} catch (Exception e) {e.printStackTrace();} finally {sqlSession.close();logger.info("sqlSession close successfully ");}}

日志

2018-04-27 16:22:51,822 INFO [main] (BaseMapperTest.java:26) - sessionFactory bulit successfully 2018-04-27 16:22:51,826 INFO [main] (BaseMapperTest.java:29) - reader close successfully 2018-04-27 16:22:51,827 INFO [main] (UserMapperTest.java:934) - selectSysUsersAdvancedMulitDBTest 2018-04-27 16:22:51,857 INFO [main] (UserMapperTest.java:943) - ===========1.當用戶只輸入用戶名時,需要根據用戶名模糊查詢=========== 2018-04-27 16:22:51,987 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') 2018-04-27 16:22:52,086 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: ad(String) 2018-04-27 16:22:52,157 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime 2018-04-27 16:22:52,157 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0 2018-04-27 16:22:52,167 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-04-27 16:22:52,167 INFO [main] (UserMapperTest.java:953) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理員用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]] 2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') 2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String) 2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime 2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0 2018-04-27 16:22:52,177 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1001, artisan, 123456, test@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0 2018-04-27 16:22:52,177 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 2 2018-04-27 16:22:52,187 INFO [main] (UserMapperTest.java:964) - userList:[SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理員用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018], SysUser [id=1001, userName=artisan, userPassword=123456, userEmail=test@artisan.com, userInfo=測試用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]] 2018-04-27 16:22:52,187 INFO [main] (UserMapperTest.java:966) - ===========2.當用戶只輸入郵箱使,根據郵箱進行完全匹配=========== 2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE 1=1 and user_name like concat('%',?,'%') and user_email = ? 2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), admin@artisan.com(String) 2018-04-27 16:22:52,187 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime 2018-04-27 16:22:52,187 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0 2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-04-27 16:22:52,187 INFO [main] (UserMapperTest.java:972) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理員用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]] 2018-04-27 16:22:52,187 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), 1admin@artisan.com(String) 2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 0 2018-04-27 16:22:52,197 INFO [main] (UserMapperTest.java:978) - ===========3.當用戶同時輸入用戶名和密碼時,用這兩個條件查詢匹配的用戶=========== 2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 2018-04-27 16:22:52,197 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: i(String), admin@artisan.com(String) 2018-04-27 16:22:52,197 TRACE [main] (BaseJdbcLogger.java:151) - <== Columns: id, userName, userPassword, userEmail, userInfo, headImg, createTime 2018-04-27 16:22:52,207 TRACE [main] (BaseJdbcLogger.java:151) - <== Row: 1, admin, 123456, admin@artisan.com, <<BLOB>>, <<BLOB>>, 2018-04-13 21:12:47.0 2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 1 2018-04-27 16:22:52,207 INFO [main] (UserMapperTest.java:987) - [SysUser [id=1, userName=admin, userPassword=123456, userEmail=admin@artisan.com, userInfo=管理員用戶, headImg=[18, 49, 35, 18, 48], createTime=Fri Apr 13 21:12:47 BOT 2018]] 2018-04-27 16:22:52,207 INFO [main] (UserMapperTest.java:989) - ===========4.當用戶同時輸入無法匹配的用戶名和密碼=========== 2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Preparing: SELECT a.id, a.user_name userName, a.user_password userPassword, a.user_email userEmail, a.user_info userInfo, a.head_img headImg, a.create_time createTime FROM sys_user a WHERE user_name like concat('%',?,'%') and user_email = ? 2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - ==> Parameters: x(String), admin@artisan.com(String) 2018-04-27 16:22:52,207 DEBUG [main] (BaseJdbcLogger.java:145) - <== Total: 0 2018-04-27 16:22:52,207 INFO [main] (UserMapperTest.java:995) - [] 2018-04-27 16:22:52,217 INFO [main] (UserMapperTest.java:1001) - sqlSession close successfully

總結

以上是生活随笔為你收集整理的MyBatis-16MyBatis动态SQL之【支持多种数据库】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 女人看黄色网 | 性高跟丝袜xxxxhd | 一区在线不卡 | 中文字幕婷婷 | 色94色欧美sute亚洲线路二 | 日韩在线免费观看av | 夜夜操av | 亚欧洲乱码视频 | 欧美h在线观看 | 国产91综合一区在线观看 | 天堂视频免费在线观看 | 完全免费在线视频 | 久久九九国产精品 | 黄色激情四射 | 国产亚洲一区二区在线 | 成年人的黄色片 | 九九热在线免费观看 | 18视频在线观看娇喘 | 欧美a天堂 | 久草视频在线观 | 欧美午夜寂寞影院 | 国产a一级| 三级全黄的视频 | 欧美一级特黄视频 | 国产精品永久免费观看 | 污视频在线免费观看 | 天天干天天色综合 | 精品无码人妻一区 | 久久久激情视频 | 欧美123| 色就是色亚洲色图 | 国产精品一区二区人妻喷水 | 天天操天天干天天插 | 中文字幕线人 | 女人的洗澡毛片毛多 | 久久精品无码Av中文字幕 | 欧美黄色大片视频 | 国产精品嫩草影院桃色 | 丰满双乳秘书被老板狂揉捏 | 午夜视频在线 | 国产jk精品白丝av在线观看 | 操操干干 | 超碰97久久| 亚洲一区二区国产 | 美女主播在线观看 | 91伦理在线 | 不卡的在线视频 | 婷婷中文| 日日摸日日添日日碰9学生露脸 | 成人av在线播放网站 | 亚洲免费色 | a毛片视频| 亚洲国产欧美日韩 | 国精品人妻无码一区二区三区喝尿 | 无码一区二区三区免费 | 日韩乱码人妻无码中文字幕 | www.com欧美| 男人添女人荫蒂国产 | ass精品国模裸体欣赏pics | 91av在线播放 | 在线观看国产三级 | 成人αv| 仙踪林av| 狼人久久 | 少妇被黑人到高潮喷出白浆 | 爱情岛论坛亚洲自拍 | 好吊妞精品 | 蜜桃av免费 | 国产一区二区av在线 | 免费视频一二三区 | 精品日本一区二区三区在线观看 | 爱情岛论坛永久入址在线 | √8天堂资源地址中文在线 欧美精品在线一区二区 | 帮我拍拍漫画全集免费观看 | 久久无码精品丰满人妻 | 免费三级网 | 欧美日韩色片 | 蜜臀av性久久久久蜜臀aⅴ四虎 | 免费av黄色 | 欧美aⅴ| 国产成人免费在线视频 | 国产欧美一区二区三区国产幕精品 | 中文人妻熟女乱又乱精品 | 深夜网站在线观看 | 国产噜噜噜噜噜久久久久久久久 | 视频丨9l丨白浆 | 波多野结衣影院 | 五月婷婷综合在线 | 少妇又色又紧又爽又刺激视频 | 欧美日韩一区二区三区在线播放 | 视频一区在线免费观看 | 午夜毛片电影 | 青青操91 | 国产激情久久久久 | 亚洲xxxx视频 | 成人免费视频一区二区 | 精品久久久久久久久久久国产字幕 | 欧美女人天堂 | 中国久久 |