日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

聊一聊Spring事務失效的12種場景

來源: 責編: 時間:2024-09-10 09:47:39 202觀看
導讀前言對于從事java開發(fā)工作的同學來說,spring的事務肯定再熟悉不過了。在某些業(yè)務場景下,如果一個請求中,需要同時寫入多張表的數據。為了保證操作的原子性(要么同時成功,要么同時失敗),避免數據不一致的情況,我們一般都會用到

gTW28資訊網——每日最新資訊28at.com

前言

對于從事java開發(fā)工作的同學來說,spring的事務肯定再熟悉不過了。gTW28資訊網——每日最新資訊28at.com

在某些業(yè)務場景下,如果一個請求中,需要同時寫入多張表的數據。為了保證操作的原子性(要么同時成功,要么同時失敗),避免數據不一致的情況,我們一般都會用到spring事務。gTW28資訊網——每日最新資訊28at.com

確實,spring事務用起來賊爽,就用一個簡單的注解:@Transactional,就能輕松搞定事務。我猜大部分小伙伴也是這樣用的,而且一直用一直爽。gTW28資訊網——每日最新資訊28at.com

但如果你使用不當,它也會坑你于無形。gTW28資訊網——每日最新資訊28at.com

今天我們就一起聊聊,事務失效的一些場景,說不定你已經中招了。不信,讓我們一起看看。gTW28資訊網——每日最新資訊28at.com

gTW28資訊網——每日最新資訊28at.com

一、事務不生效

1.訪問權限問題

眾所周知,java的訪問權限主要有四種:private、default、protected、public,它們的權限從左到右,依次變大。gTW28資訊網——每日最新資訊28at.com

但如果我們在開發(fā)過程中,把有某些事務方法,定義了錯誤的訪問權限,就會導致事務功能出問題,例如:gTW28資訊網——每日最新資訊28at.com

@Servicepublic class UserService {        @Transactional    private void add(UserModel userModel) {         saveData(userModel);         updateData(userModel);    }}

我們可以看到add方法的訪問權限被定義成了private,這樣會導致事務失效,spring要求被代理方法必須是public的。gTW28資訊網——每日最新資訊28at.com

說白了,在AbstractFallbackTransactionAttributeSource類的computeTransactionAttribute方法中有個判斷,如果目標方法不是public,則TransactionAttribute返回null,即不支持事務。gTW28資訊網——每日最新資訊28at.com

protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {    // Don't allow no-public methods as required.    if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {      return null;    }    // The method may be on an interface, but we need attributes from the target class.    // If the target class is null, the method will be unchanged.    Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);    // First try is the method in the target class.    TransactionAttribute txAttr = findTransactionAttribute(specificMethod);    if (txAttr != null) {      return txAttr;    }    // Second try is the transaction attribute on the target class.    txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());    if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {      return txAttr;    }    if (specificMethod != method) {      // Fallback is to look at the original method.      txAttr = findTransactionAttribute(method);      if (txAttr != null) {        return txAttr;      }      // Last fallback is the class of the original method.      txAttr = findTransactionAttribute(method.getDeclaringClass());      if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {        return txAttr;      }    }    return null;  }

也就是說,如果我們自定義的事務方法(即目標方法),它的訪問權限不是public,而是private、default或protected的話,spring則不會提供事務功能。gTW28資訊網——每日最新資訊28at.com

2. 方法用final修飾

有時候,某個方法不想被子類重新,這時可以將該方法定義成final的。普通方法這樣定義是沒問題的,但如果將事務方法定義成final,例如:gTW28資訊網——每日最新資訊28at.com

@Servicepublic class UserService {    @Transactional    public final void add(UserModel userModel){        saveData(userModel);        updateData(userModel);    }}

我們可以看到add方法被定義成了final的,這樣會導致事務失效。gTW28資訊網——每日最新資訊28at.com

為什么?gTW28資訊網——每日最新資訊28at.com

如果你看過spring事務的源碼,可能會知道spring事務底層使用了aop,也就是通過jdk動態(tài)代理或者cglib,幫我們生成了代理類,在代理類中實現的事務功能。gTW28資訊網——每日最新資訊28at.com

但如果某個方法用final修飾了,那么在它的代理類中,就無法重寫該方法,而添加事務功能。gTW28資訊網——每日最新資訊28at.com

注意:如果某個方法是static的,同樣無法通過動態(tài)代理,變成事務方法。gTW28資訊網——每日最新資訊28at.com

3.方法內部調用

有時候我們需要在某個Service類的某個方法中,調用另外一個事務方法,比如:gTW28資訊網——每日最新資訊28at.com

@Servicepublic class UserService {    @Autowired    private UserMapper userMapper;      public void add(UserModel userModel) {        userMapper.insertUser(userModel);        updateStatus(userModel);    }    @Transactional    public void updateStatus(UserModel userModel) {        doSameThing();    }}

我們看到在事務方法add中,直接調用事務方法updateStatus。從前面介紹的內容可以知道,updateStatus方法擁有事務的能力是因為spring aop生成代理了對象,但是這種方法直接調用了this對象的方法,所以updateStatus方法不會生成事務。gTW28資訊網——每日最新資訊28at.com

由此可見,在同一個類中的方法直接內部調用,會導致事務失效。gTW28資訊網——每日最新資訊28at.com

那么問題來了,如果有些場景,確實想在同一個類的某個方法中,調用它自己的另外一個方法,該怎么辦呢?gTW28資訊網——每日最新資訊28at.com

(1) 新加一個Service方法

這個方法非常簡單,只需要新加一個Service方法,把@Transactional注解加到新Service方法上,把需要事務執(zhí)行的代碼移到新方法中。具體代碼如下:gTW28資訊網——每日最新資訊28at.com

@Servciepublic class ServiceA {   @Autowired   prvate ServiceB serviceB;   public void save(User user) {         queryData1();         queryData2();         serviceB.doSave(user);   } } @Servcie public class ServiceB {    @Transactional(rollbackFor=Exception.class)    public void doSave(User user) {       addData1();       updateData2();    } }

(2)在該Service類中注入自己

如果不想再新加一個Service類,在該Service類中注入自己也是一種選擇。具體代碼如下:gTW28資訊網——每日最新資訊28at.com

@Servciepublic class ServiceA {   @Autowired   prvate ServiceA serviceA;   public void save(User user) {         queryData1();         queryData2();         serviceA.doSave(user);   }   @Transactional(rollbackFor=Exception.class)   public void doSave(User user) {       addData1();       updateData2();    } }

可能有些人可能會有這樣的疑問:這種做法會不會出現循環(huán)依賴問題?gTW28資訊網——每日最新資訊28at.com

答案:不會。gTW28資訊網——每日最新資訊28at.com

其實spring ioc內部的三級緩存保證了它,不會出現循環(huán)依賴問題。gTW28資訊網——每日最新資訊28at.com

(3)通過AopContent類

在該Service類中使用AopContext.currentProxy()獲取代理對象gTW28資訊網——每日最新資訊28at.com

上面的方法2確實可以解決問題,但是代碼看起來并不直觀,還可以通過在該Service類中使用AOPProxy獲取代理對象,實現相同的功能。具體代碼如下:gTW28資訊網——每日最新資訊28at.com

@Servciepublic class ServiceA {   public void save(User user) {         queryData1();         queryData2();         ((ServiceA)AopContext.currentProxy()).doSave(user);   }   @Transactional(rollbackFor=Exception.class)   public void doSave(User user) {       addData1();       updateData2();    } }

4.未被spring管理

在我們平時開發(fā)過程中,有個細節(jié)很容易被忽略。即使用spring事務的前提是:對象要被spring管理,需要創(chuàng)建bean實例。gTW28資訊網——每日最新資訊28at.com

通常情況下,我們通過@Controller、@Service、@Component、@Repository等注解,可以自動實現bean實例化和依賴注入的功能。gTW28資訊網——每日最新資訊28at.com

如果有一天,你匆匆忙忙的開發(fā)了一個Service類,但忘了加@Service注解,比如:gTW28資訊網——每日最新資訊28at.com

//@Servicepublic class UserService {    @Transactional    public void add(UserModel userModel) {         saveData(userModel);         updateData(userModel);    }    }

從上面的例子,我們可以看到UserService類沒有加@Service注解,那么該類不會交給spring管理,所以它的add方法也不會生成事務。gTW28資訊網——每日最新資訊28at.com

5.多線程調用

在實際項目開發(fā)中,多線程的使用場景還是挺多的。如果spring事務用在多線程場景中,會有問題嗎?gTW28資訊網——每日最新資訊28at.com

@Slf4j@Servicepublic class UserService {    @Autowired    private UserMapper userMapper;    @Autowired    private RoleService roleService;    @Transactional    public void add(UserModel userModel) throws Exception {        userMapper.insertUser(userModel);        new Thread(() -> {            roleService.doOtherThing();        }).start();    }}@Servicepublic class RoleService {    @Transactional    public void doOtherThing() {        System.out.println("保存role表數據");    }}

從上面的例子中,我們可以看到事務方法add中,調用了事務方法doOtherThing,但是事務方法doOtherThing是在另外一個線程中調用的。gTW28資訊網——每日最新資訊28at.com

這樣會導致兩個方法不在同一個線程中,獲取到的數據庫連接不一樣,從而是兩個不同的事務。如果想doOtherThing方法中拋了異常,add方法也回滾是不可能的。gTW28資訊網——每日最新資訊28at.com

如果看過spring事務源碼的朋友,可能會知道spring的事務是通過數據庫連接來實現的。當前線程中保存了一個map,key是數據源,value是數據庫連接。gTW28資訊網——每日最新資訊28at.com

private static final ThreadLocal<Map<Object, Object>> resources =  new NamedThreadLocal<>("Transactional resources");

我們說的同一個事務,其實是指同一個數據庫連接,只有擁有同一個數據庫連接才能同時提交和回滾。如果在不同的線程,拿到的數據庫連接肯定是不一樣的,所以是不同的事務。gTW28資訊網——每日最新資訊28at.com

6.表不支持事務

周所周知,在mysql5之前,默認的數據庫引擎是myisam。gTW28資訊網——每日最新資訊28at.com

它的好處就不用多說了:索引文件和數據文件是分開存儲的,對于查多寫少的單表操作,性能比innodb更好。gTW28資訊網——每日最新資訊28at.com

有些老項目中,可能還在用它。gTW28資訊網——每日最新資訊28at.com

在創(chuàng)建表的時候,只需要把ENGINE參數設置成MyISAM即可:gTW28資訊網——每日最新資訊28at.com

CREATE TABLE `category` (  `id` bigint NOT NULL AUTO_INCREMENT,  `one_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,  `two_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,  `three_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,  `four_category` varchar(20) COLLATE utf8mb4_bin DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin

myisam好用,但有個很致命的問題是:不支持事務。gTW28資訊網——每日最新資訊28at.com

如果只是單表操作還好,不會出現太大的問題。但如果需要跨多張表操作,由于其不支持事務,數據極有可能會出現不完整的情況。gTW28資訊網——每日最新資訊28at.com

此外,myisam還不支持行鎖和外鍵。gTW28資訊網——每日最新資訊28at.com

所以在實際業(yè)務場景中,myisam使用的并不多。在mysql5以后,myisam已經逐漸退出了歷史的舞臺,取而代之的是innodb。gTW28資訊網——每日最新資訊28at.com

有時候我們在開發(fā)的過程中,發(fā)現某張表的事務一直都沒有生效,那不一定是spring事務的鍋,最好確認一下你使用的那張表,是否支持事務。gTW28資訊網——每日最新資訊28at.com

7.未開啟事務

有時候,事務沒有生效的根本原因是沒有開啟事務。gTW28資訊網——每日最新資訊28at.com

你看到這句話可能會覺得好笑。gTW28資訊網——每日最新資訊28at.com

開啟事務不是一個項目中,最最最基本的功能嗎?gTW28資訊網——每日最新資訊28at.com

為什么還會沒有開啟事務?gTW28資訊網——每日最新資訊28at.com

沒錯,如果項目已經搭建好了,事務功能肯定是有的。gTW28資訊網——每日最新資訊28at.com

但如果你是在搭建項目demo的時候,只有一張表,而這張表的事務沒有生效。那么會是什么原因造成的呢?gTW28資訊網——每日最新資訊28at.com

當然原因有很多,但沒有開啟事務,這個原因極其容易被忽略。gTW28資訊網——每日最新資訊28at.com

如果你使用的是springboot項目,那么你很幸運。因為springboot通過DataSourceTransactionManagerAutoConfiguration類,已經默默的幫你開啟了事務。gTW28資訊網——每日最新資訊28at.com

你所要做的事情很簡單,只需要配置spring.datasource相關參數即可。gTW28資訊網——每日最新資訊28at.com

但如果你使用的還是傳統(tǒng)的spring項目,則需要在applicationContext.xml文件中,手動配置事務相關參數。如果忘了配置,事務肯定是不會生效的。gTW28資訊網——每日最新資訊28at.com

具體配置如下信息:gTW28資訊網——每日最新資訊28at.com

<!-- 配置事務管理器 --> <bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="transactionManager">     <property name="dataSource" ref="dataSource"></property> </bean> <tx:advice id="advice" transaction-manager="transactionManager">     <tx:attributes>         <tx:method name="*" propagatinotallow="REQUIRED"/>    </tx:attributes> </tx:advice> <!-- 用切點把事務切進去 --> <aop:config>     <aop:pointcut expressinotallow="execution(* com.susan.*.*(..))" id="pointcut"/>     <aop:advisor advice-ref="advice" pointcut-ref="pointcut"/> </aop:config>

默默的說一句,如果在pointcut標簽中的切入點匹配規(guī)則,配錯了的話,有些類的事務也不會生效。gTW28資訊網——每日最新資訊28at.com

二、事務不回滾

1.錯誤的傳播特性

其實,我們在使用@Transactional注解時,是可以指定propagation參數的。gTW28資訊網——每日最新資訊28at.com

該參數的作用是指定事務的傳播特性,spring目前支持7種傳播特性:gTW28資訊網——每日最新資訊28at.com

  • REQUIRED 如果當前上下文中存在事務,那么加入該事務,如果不存在事務,創(chuàng)建一個事務,這是默認的傳播屬性值。
  • SUPPORTS 如果當前上下文存在事務,則支持事務加入事務,如果不存在事務,則使用非事務的方式執(zhí)行。
  • MANDATORY 如果當前上下文中存在事務,否則拋出異常。
  • REQUIRES_NEW 每次都會新建一個事務,并且同時將上下文中的事務掛起,執(zhí)行當前新建事務完成以后,上下文事務恢復再執(zhí)行。
  • NOT_SUPPORTED 如果當前上下文中存在事務,則掛起當前事務,然后新的方法在沒有事務的環(huán)境中執(zhí)行。
  • NEVER 如果當前上下文中存在事務,則拋出異常,否則在無事務環(huán)境上執(zhí)行代碼。
  • NESTED 如果當前上下文中存在事務,則嵌套事務執(zhí)行,如果不存在事務,則新建事務。

如果我們在手動設置propagation參數的時候,把傳播特性設置錯了,比如:gTW28資訊網——每日最新資訊28at.com

@Servicepublic class UserService {    @Transactional(propagation = Propagation.NEVER)    public void add(UserModel userModel) {        saveData(userModel);        updateData(userModel);    }}

我們可以看到add方法的事務傳播特性定義成了Propagation.NEVER,這種類型的傳播特性不支持事務,如果有事務則會拋異常。gTW28資訊網——每日最新資訊28at.com

目前只有這三種傳播特性才會創(chuàng)建新事務:REQUIRED,REQUIRES_NEW,NESTED。gTW28資訊網——每日最新資訊28at.com

2.自己吞了異常

事務不會回滾,最常見的問題是:開發(fā)者在代碼中手動try...catch了異常。比如:gTW28資訊網——每日最新資訊28at.com

@Slf4j@Servicepublic class UserService {        @Transactional    public void add(UserModel userModel) {        try {            saveData(userModel);            updateData(userModel);        } catch (Exception e) {            log.error(e.getMessage(), e);        }    }}

這種情況下spring事務當然不會回滾,因為開發(fā)者自己捕獲了異常,又沒有手動拋出,換句話說就是把異常吞掉了。gTW28資訊網——每日最新資訊28at.com

如果想要spring事務能夠正常回滾,必須拋出它能夠處理的異常。如果沒有拋異常,則spring認為程序是正常的。gTW28資訊網——每日最新資訊28at.com

3.手動拋了別的異常

即使開發(fā)者沒有手動捕獲異常,但如果拋的異常不正確,spring事務也不會回滾。gTW28資訊網——每日最新資訊28at.com

@Slf4j@Servicepublic class UserService {        @Transactional    public void add(UserModel userModel) throws Exception {        try {             saveData(userModel);             updateData(userModel);        } catch (Exception e) {            log.error(e.getMessage(), e);            throw new Exception(e);        }    }}

上面的這種情況,開發(fā)人員自己捕獲了異常,又手動拋出了異常:Exception,事務同樣不會回滾。gTW28資訊網——每日最新資訊28at.com

因為spring事務,默認情況下只會回滾RuntimeException(運行時異常)和Error(錯誤),對于普通的Exception(非運行時異常),它不會回滾。gTW28資訊網——每日最新資訊28at.com

4.自定義了回滾異常

在使用@Transactional注解聲明事務時,有時我們想自定義回滾的異常,spring也是支持的。可以通過設置rollbackFor參數,來完成這個功能。gTW28資訊網——每日最新資訊28at.com

但如果這個參數的值設置錯了,就會引出一些莫名其妙的問題,例如:gTW28資訊網——每日最新資訊28at.com

@Slf4j@Servicepublic class UserService {        @Transactional(rollbackFor = BusinessException.class)    public void add(UserModel userModel) throws Exception {       saveData(userModel);       updateData(userModel);    }}

如果在執(zhí)行上面這段代碼,保存和更新數據時,程序報錯了,拋了SqlException、DuplicateKeyException等異常。而BusinessException是我們自定義的異常,報錯的異常不屬于BusinessException,所以事務也不會回滾。gTW28資訊網——每日最新資訊28at.com

即使rollbackFor有默認值,但阿里巴巴開發(fā)者規(guī)范中,還是要求開發(fā)者重新指定該參數。gTW28資訊網——每日最新資訊28at.com

這是為什么呢?gTW28資訊網——每日最新資訊28at.com

因為如果使用默認值,一旦程序拋出了Exception,事務不會回滾,這會出現很大的bug。所以,建議一般情況下,將該參數設置成:Exception或Throwable。gTW28資訊網——每日最新資訊28at.com

5.嵌套事務回滾多了

public class UserService {    @Autowired    private UserMapper userMapper;    @Autowired    private RoleService roleService;    @Transactional    public void add(UserModel userModel) throws Exception {        userMapper.insertUser(userModel);        roleService.doOtherThing();    }}@Servicepublic class RoleService {    @Transactional(propagation = Propagation.NESTED)    public void doOtherThing() {        System.out.println("保存role表數據");    }}

這種情況使用了嵌套的內部事務,原本是希望調用roleService.doOtherThing方法時,如果出現了異常,只回滾doOtherThing方法里的內容,不回滾 userMapper.insertUser里的內容,即回滾保存點。。但事實是,insertUser也回滾了。gTW28資訊網——每日最新資訊28at.com

why?gTW28資訊網——每日最新資訊28at.com

因為doOtherThing方法出現了異常,沒有手動捕獲,會繼續(xù)往上拋,到外層add方法的代理方法中捕獲了異常。所以,這種情況是直接回滾了整個事務,不只回滾單個保存點。gTW28資訊網——每日最新資訊28at.com

怎么樣才能只回滾保存點呢?gTW28資訊網——每日最新資訊28at.com

@Slf4j@Servicepublic class UserService {    @Autowired    private UserMapper userMapper;    @Autowired    private RoleService roleService;    @Transactional    public void add(UserModel userModel) throws Exception {        userMapper.insertUser(userModel);        try {            roleService.doOtherThing();        } catch (Exception e) {            log.error(e.getMessage(), e);        }    }}

可以將內部嵌套事務放在try/catch中,并且不繼續(xù)往上拋異常。這樣就能保證,如果內部嵌套事務中出現異常,只回滾內部事務,而不影響外部事務。gTW28資訊網——每日最新資訊28at.com

三、其他

1.大事務問題

在使用spring事務時,有個讓人非常頭疼的問題,就是大事務問題。gTW28資訊網——每日最新資訊28at.com

通常情況下,我們會在方法上@Transactional注解,填加事務功能,比如:gTW28資訊網——每日最新資訊28at.com

@Servicepublic class UserService {        @Autowired     private RoleService roleService;        @Transactional    public void add(UserModel userModel) throws Exception {       query1();       query2();       query3();       roleService.save(userModel);       update(userModel);    }}@Servicepublic class RoleService {        @Autowired     private RoleService roleService;        @Transactional    public void save(UserModel userModel) throws Exception {       query4();       query5();       query6();       saveData(userModel);    }}

但@Transactional注解,如果被加到方法上,有個缺點就是整個方法都包含在事務當中了。gTW28資訊網——每日最新資訊28at.com

上面的這個例子中,在UserService類中,其實只有這兩行才需要事務:gTW28資訊網——每日最新資訊28at.com

roleService.save(userModel);update(userModel);

在RoleService類中,只有這一行需要事務:gTW28資訊網——每日最新資訊28at.com

saveData(userModel);

現在的這種寫法,會導致所有的query方法也被包含在同一個事務當中。gTW28資訊網——每日最新資訊28at.com

如果query方法非常多,調用層級很深,而且有部分查詢方法比較耗時的話,會造成整個事務非常耗時,而從造成大事務問題。gTW28資訊網——每日最新資訊28at.com

gTW28資訊網——每日最新資訊28at.com

2.編程式事務

上面聊的這些內容都是基于@Transactional注解的,主要說的是它的事務問題,我們把這種事務叫做:聲明式事務。gTW28資訊網——每日最新資訊28at.com

其實,spring還提供了另外一種創(chuàng)建事務的方式,即通過手動編寫代碼實現的事務,我們把這種事務叫做:編程式事務。例如:gTW28資訊網——每日最新資訊28at.com

@Autowired   private TransactionTemplate transactionTemplate;      ...      public void save(final User user) {         queryData1();         queryData2();         transactionTemplate.execute((status) => {            addData1();            updateData2();            return Boolean.TRUE;         })   }

在spring中為了支持編程式事務,專門提供了一個類:TransactionTemplate,在它的execute方法中,就實現了事務的功能。gTW28資訊網——每日最新資訊28at.com

相較于@Transactional注解聲明式事務,我更建議大家使用,基于TransactionTemplate的編程式事務。主要原因如下:gTW28資訊網——每日最新資訊28at.com

  • 避免由于spring aop問題,導致事務失效的問題。
  • 能夠更小粒度的控制事務的范圍,更直觀。

建議在項目中少使用@Transactional注解開啟事務。但并不是說一定不能用它,如果項目中有些業(yè)務邏輯比較簡單,而且不經常變動,使用@Transactional注解開啟事務開啟事務也無妨,因為它更簡單,開發(fā)效率更高,但是千萬要小心事務失效的問題。gTW28資訊網——每日最新資訊28at.com

本文鏈接:http://m.www897cc.com/showinfo-26-112728-0.html聊一聊Spring事務失效的12種場景

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 面試官:你對插件化有什么了解?

下一篇: SpringBoot與XXL-JOB高效定時任務管理指南

標簽:
  • 熱門焦點
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
欧美色大人视频| 久久九九国产| 亚洲最新色图| 亚洲婷婷综合久久一本伊一区| 亚洲综合导航| 久久人人97超碰国产公开结果 | 久久精品夜色噜噜亚洲aⅴ| 久久综合网hezyo| 欧美日韩国产综合新一区| 国产精品久久久久av免费| 国产一区二区成人| 亚洲人成在线观看网站高清| 亚洲精品资源| 狠狠入ady亚洲精品| 亚洲欧洲精品一区二区三区不卡| 亚洲网站视频福利| 久久一二三区| 欧美亚州在线观看| 伊伊综合在线| 亚洲一区二区三区四区五区黄| 久久精品一区二区国产| 亚洲欧美中文在线视频| 久久综合九九| 国产精品国产三级国产aⅴ入口| 欧美激情亚洲自拍| 国产精品视频福利| 亚洲人成人一区二区三区| 亚洲欧美自拍偷拍| 欧美激情亚洲综合一区| 国产亚洲欧美日韩一区二区| 日韩性生活视频| 久久久久综合网| 国产精品嫩草99a| 亚洲激情国产| 国内精品久久久久久久果冻传媒| 国产精品久久久久久福利一牛影视| 欧美日韩综合精品| 永久555www成人免费| 亚洲欧美成人综合| 欧美日韩精品欧美日韩精品| 激情综合五月天| 亚洲激情偷拍| 久久本道综合色狠狠五月| 欧美视频中文一区二区三区在线观看 | 国产精品午夜久久| 日韩视频免费| 蜜臀av在线播放一区二区三区 | 亚洲片区在线| 久久人人爽国产| 国产日韩欧美一区| 亚洲网站在线| 欧美三级在线播放| 亚洲免费高清| 欧美国产欧美亚洲国产日韩mv天天看完整| 国产亚洲精品成人av久久ww| 亚洲影院在线| 国产精品国产三级国产专播精品人| 最新成人在线| 免费中文日韩| 在线看片第一页欧美| 久久久蜜臀国产一区二区| 欧美成人三级在线| 一区二区三区在线高清| 性高湖久久久久久久久| 国产精品久久久久av| 在线视频日韩| 欧美三区美女| 中文日韩在线| 欧美涩涩网站| 亚洲图片在区色| 国产精品久久久久久超碰| 亚洲美女精品成人在线视频| 欧美国产日韩一区二区三区| 亚洲国产高清自拍| 欧美成人精品不卡视频在线观看 | 国产精品一区二区你懂的| 在线成人黄色| 久久久国产精品一区二区中文 | 欧美风情在线观看| 亚洲精品免费网站| 欧美精品情趣视频| 亚洲另类在线一区| 欧美日韩免费观看一区三区| 夜夜嗨av色一区二区不卡| 欧美日韩在线不卡一区| 亚洲无限av看| 国产免费观看久久黄| 久久国产福利国产秒拍| 国内激情久久| 久久综合九色综合欧美狠狠| 亚洲第一天堂av| 欧美激情女人20p| 一本久久a久久精品亚洲| 国产精品videosex极品| 亚洲欧美日韩精品一区二区| 国产日韩欧美三级| 久久久久免费视频| 亚洲国产精品一区二区久 | 在线成人www免费观看视频| 欧美成人小视频| 日韩午夜精品| 国产精品毛片a∨一区二区三区| 午夜精品美女自拍福到在线| 国产资源精品在线观看| 麻豆91精品91久久久的内涵| 亚洲精品欧美精品| 国产精品国码视频| 久久精品二区亚洲w码| 亚洲国产精品免费| 欧美日韩中文字幕在线| 午夜在线电影亚洲一区| 影音先锋久久| 欧美日韩午夜剧场| 亚洲欧美资源在线| 有码中文亚洲精品| 欧美日韩高清不卡| 欧美一区二区三区免费观看| 在线播放一区| 国产精品分类| 久久久亚洲国产美女国产盗摄| 亚洲精品乱码久久久久久久久| 国产精品久久国产精麻豆99网站| 久久九九99| 99精品国产在热久久下载| 国产农村妇女毛片精品久久莱园子 | 国产麻豆成人精品| 国内精品久久久久影院色| 久久一区二区三区四区| 亚洲三级国产| 欧美一区二区在线| 国产精品国产精品| 国产精品最新自拍| 国产啪精品视频| 亚洲成人资源网| 亚洲视频欧洲视频| 亚洲欧美国产一区二区三区| 亚洲尤物在线视频观看| 欧美1区2区视频| 国产精品夜夜夜| 亚洲国产精品va在看黑人| 在线亚洲国产精品网站| 欧美精品免费在线观看| 亚洲欧美精品| 欧美成人中文| 国产精品久久久久av| 欧美理论电影在线播放| 一区二区三区久久久| 欧美影院成人| 欧美成人精品一区二区| 一区二区三区久久网| 韩曰欧美视频免费观看| 欧美三级视频在线播放| 久久久水蜜桃| 一区二区久久久久| 韩国v欧美v日本v亚洲v| 欧美裸体一区二区三区| 国产亚洲综合精品| 亚洲精品乱码久久久久久黑人 | 国产精品jizz在线观看美国| 午夜国产精品视频| 欧美另类一区二区三区| 这里只有精品在线播放| 国产日产欧美一区| 欧美日韩国产bt| 久久综合伊人| 欧美亚洲日本国产| 亚洲少妇自拍| 国产精品一区一区| 久久久久国产精品厨房| 国产精品啊v在线| 先锋影音久久| 韩日欧美一区| 欧美一区二区三区视频在线观看| 国产精品国产三级国产专区53 | 久久久国产精彩视频美女艺术照福利| 亚洲国产另类久久精品| 欧美日韩一区二区三区视频| 最新国产乱人伦偷精品免费网站| 欧美va亚洲va日韩∨a综合色| 这里只有视频精品| 亚洲国产天堂久久综合网| 好吊日精品视频| 欧美视频免费| 亚洲永久免费视频| 亚洲欧美日韩在线观看a三区 | 亚洲一区二区三区中文字幕 | 久久综合图片| 久久精品免费| 久久国产精品久久久久久| 性欧美video另类hd性玩具| 亚洲女优在线| 午夜精品av| 欧美特黄一级| 欧美日韩免费在线| 欧美日韩成人精品| 欧美日韩不卡合集视频| 欧美日韩p片| 欧美日韩一区二区三区四区五区| 欧美日本国产| 欧美日韩亚洲视频| 欧美体内she精视频| 国产精品成人一区二区网站软件| 欧美天堂亚洲电影院在线播放| 欧美日韩一区国产|