精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Golang 數據庫事務實踐

數據庫
事務是很多業務的基礎,本文介紹了如何在Golang里實現數據庫事務操作,并以一個用戶注冊場景給出了完整實現。

Go 是一種年輕而強大的語言,專為編寫小型、簡單的服務而創建。但隨著時間推移,越來越多復雜應用和系統也在采用 Go 進行開發,這就出現了一些問題:如何處理事務?

為了深入探討這個問題,我們假設一個簡單的業務場景:用戶注冊。

作為一個系統,我希望在注冊時創建用戶和個人資料。

RDBMS/DBMS 的現代 Go 庫不像 C# 和 Java 的 Hibernate、Entity Framework 那樣強大,因此我們必須自己處理。為了實現用戶注冊業務場景,我們將創建并評估幾種處理事務的方法。

由于每種事務處理方法都必須與 sql.DB 和 sql.Tx 配合使用,因此需要引入接口來封裝對數據庫的訪問。

生成的應用有兩個域實體和一個用于訪問數據庫的 DB 低級接口。

package model

type User struct {
 Email string
}

type Profile struct {
 Name string
}
package transaction

type DB interface {
 QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row
 QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error)
 ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error)
 PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
}

準備工作完成后,就可以采用如下兩種方法。

1. 事務感知上下文

工作原理:transaction.Manager啟動事務并將其放入上下文。當存儲庫執行查詢時,助手會檢查上下文中是否有事務,并使用創建的事務來執行查詢,或者如果上下文為空,則不使用事務來執行查詢。

為了啟動事務,我們需要實體:Manager

package transaction

type Manager interface {
 Run(
  ctx context.Context,
  callback func(ctx context.Context) error,
 ) error
}

transaction.Manager 實現:

package transaction

import (
 "context"
 "database/sql"
 "github.com/pkg/errors"
 "go.uber.org/multierr"
)

type txKey string

var ctxWithTx = txKey("tx")

type SQLTransactionManager struct {
 db *sql.DB
}

func NewManager(db *sql.DB) *SQLTransactionManager {
 return &SQLTransactionManager{db: db}
}

func (m *SQLTransactionManager) Run(
 ctx context.Context,
 callback func(ctx context.Context) error,
) (rErr error) {
 tx, err := m.db.BeginTx(ctx, &sql.TxOptions{})
 if err != nil {
  return errors.WithStack(err)
 }

 defer func() {
  if rErr != nil {
   rErr = multierr.Combine(rErr, errors.WithStack(tx.Rollback()))
  }
 }()

 defer func() {
  if rec := recover(); rec != nil {
   if e, ok := rec.(error); ok {
    rErr = e
   } else {
    rErr = errors.Errorf("%s", rec)
   }
  }
 }()

 if err = callback(putTxToContext(ctx, tx)); err != nil {
  return err
 }

 return errors.WithStack(tx.Commit())
}

func ExtractTxFromContext(ctx context.Context) (*sql.Tx, bool) {
 tx := ctx.Value(ctxWithTx)

 if t, ok := tx.(*sql.Tx); ok {
  return t, true
 }

 return nil, false
}

func putTxToContext(ctx context.Context, tx *sql.Tx) context.Context {
 return context.WithValue(ctx, ctxWithTx, tx)
}

DB實現:

package storage

import (
 "brand/transaction/example1/transaction"
 "context"
 "database/sql"
)

type DB struct {
 db *sql.DB
}

func NewDB(db *sql.DB) *DB {
 return &DB{db: db}
}

func (d *DB) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row {
 tx, ok := transaction.ExtractTxFromContext(ctx)
 if !ok {
  return d.db.QueryRowContext(ctx, query, args...)
 }

 return tx.QueryRowContext(ctx, query, args...)
}

func (d *DB) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
 tx, ok := transaction.ExtractTxFromContext(ctx)
 if !ok {
  return d.db.QueryContext(ctx, query, args...)
 }

 return tx.QueryContext(ctx, query, args...)
}

func (d *DB) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {
 tx, ok := transaction.ExtractTxFromContext(ctx)
 if !ok {
  return d.db.ExecContext(ctx, query, args...)
 }

 return tx.ExecContext(ctx, query, args...)
}

func (d *DB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
 tx, ok := transaction.ExtractTxFromContext(ctx)
 if !ok {
  return d.db.PrepareContext(ctx, query)
 }

 return tx.PrepareContext(ctx, query)
}

RegistrationService 負責用戶注冊業務場景

package service

import (
 "brand/transaction/example1/model"
 "brand/transaction/example1/transaction"
 "context"
)

type UserRepository interface {
 Create(ctx context.Context, user *model.User) error
}

type ProfileRepository interface {
 Create(ctx context.Context, user *model.Profile) error
}

type RegistrationData struct {
 Email string
 Name  string
}

type RegistrationService struct {
 transactionManager transaction.Manager
 userRepository     UserRepository
 profileRepository  ProfileRepository
}

func NewRegistrationService(
 transactionManager transaction.Manager,
 userRepository UserRepository,
 profileRepository ProfileRepository,
) *RegistrationService {
 return &RegistrationService{
  transactionManager: transactionManager,
  userRepository:     userRepository,
  profileRepository:  profileRepository,
 }
}

func (s *RegistrationService) Register(ctx context.Context, data RegistrationData) error {
 return s.transactionManager.Run(ctx, func(ctx context.Context) error {
  if err := s.userRepository.Create(ctx, &model.User{
   Email: data.Email,
  }); err != nil {
   return err
  }

  if err := s.profileRepository.Create(ctx, &model.Profile{
   Name: data.Name,
  }); err != nil {
   return err
  }

  return nil
 })
}

User和ProfileRepository的實現:

package storage

import (
 "brand/transaction"
 "brand/transaction/example1/model"
 "context"
)

type ProfileRepository struct {
 db transaction.DB
}

func NewProfileRepository(db transaction.DB) *ProfileRepository {
 return &ProfileRepository{db: db}
}

func (r *ProfileRepository) Create(ctx context.Context, profile *model.Profile) error {
 _, err := r.db.ExecContext(ctx, "INSERT ...", profile.Name)

 return err
}
package storage

import (
 "brand/transaction"
 "brand/transaction/example1/model"
 "context"
)

type UserRepository struct {
 db transaction.DB
}

func NewUserRepository(db transaction.DB) *UserRepository {
 return &UserRepository{db: db}
}

func (r *UserRepository) Create(ctx context.Context, user *model.User) error {
 _, err := r.db.ExecContext(ctx, "INSERT ...", user.Email)

 return err
}

優點:

  • 簡單:存儲庫會自動使用由 TransactionManager 啟動的事務
  • 與存儲無關:客戶端代碼對存儲類型一無所知

缺點

  • 不符合Go的使用習慣
  • 控制較少:無法防止在事務中啟動事務,可能會產生意想不到的副作用,代碼審查時必須考慮到這一點

2. 事務感知存儲庫

工作原理:事務管理器啟動事務并將事務放入回調,存儲庫工廠方法使用事務創建自己。

為了啟動事務,我們需要實體:Manager

type Manager interface {
 Run(
  ctx context.Context,
  callback func(ctx context.Context, tx *sql.Tx) error,
 ) error
}

transaction.Manager 實現:

package transaction

import (
 "context"
 "database/sql"
 "github.com/pkg/errors"
 "go.uber.org/multierr"
)

type txKey string

var ctxWithTx = txKey("tx")

type SQLTransactionManager struct {
 db *sql.DB
}

func NewManager(db *sql.DB) *SQLTransactionManager {
 return &SQLTransactionManager{db: db}
}

func (m *SQLTransactionManager) Run(
 ctx context.Context,
 callback func(ctx context.Context, tx *sql.Tx) error,
) (rErr error) {
 tx, err := m.db.BeginTx(ctx, &sql.TxOptions{})
 if err != nil {
  return errors.WithStack(err)
 }

 defer func() {
  if rErr != nil {
   rErr = multierr.Combine(rErr, errors.WithStack(tx.Rollback()))
  }
 }()

 defer func() {
  if rec := recover(); rec != nil {
   if e, ok := rec.(error); ok {
    rErr = e
   } else {
    rErr = errors.Errorf("%s", rec)
   }
  }
 }()

 if err = callback(ctx, tx); err != nil {
  return err
 }

 return errors.WithStack(tx.Commit())
}

DB實現:

package storage

import (
 "context"
 "database/sql"
)

type DB struct {
 db *sql.DB
}

func NewDB(db *sql.DB) *DB {
 return &DB{db: db}
}

func (d *DB) QueryRowContext(ctx context.Context, query string, args ...any) *sql.Row {
 return d.db.QueryRowContext(ctx, query, args...)
}

func (d *DB) QueryContext(ctx context.Context, query string, args ...any) (*sql.Rows, error) {
 return d.db.QueryContext(ctx, query, args...)
}

func (d *DB) ExecContext(ctx context.Context, query string, args ...any) (sql.Result, error) {
 return d.db.ExecContext(ctx, query, args...)
}

func (d *DB) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
 return d.db.PrepareContext(ctx, query)
}

RegistrationService 負責用戶注冊業務場景

有兩種方法可以創建帶有事務的存儲庫:

  • 存儲庫帶有結構方法 WithTransaction(示例中使用了該方法)
  • 存儲庫工廠 userRepositoryFactory.CreateFromTransaction(tx)
package service

import (
 "brand/transaction/example2/model"
 "brand/transaction/example2/transaction"
 "context"
 "database/sql"
)

type UserRepository interface {
 Create(ctx context.Context, user *model.User) error
 WithTransaction(tx *sql.Tx) UserRepository
}

type ProfileRepository interface {
 Create(ctx context.Context, user *model.Profile) error
 WithTransaction(tx *sql.Tx) ProfileRepository
}

type RegistrationData struct {
 Email string
 Name  string
}

type RegistrationService struct {
 transactionManager transaction.Manager
 userRepository     UserRepository
 profileRepository  ProfileRepository
}

func NewRegistrationService(
 transactionManager transaction.Manager,
 userRepository UserRepository,
 profileRepository ProfileRepository,
) *RegistrationService {
 return &RegistrationService{
  transactionManager: transactionManager,
  userRepository:     userRepository,
  profileRepository:  profileRepository,
 }
}

func (s *RegistrationService) Register(ctx context.Context, data RegistrationData) error {
 return s.transactionManager.Run(ctx, func(ctx context.Context, tx *sql.Tx) error {
  userRepository := s.userRepository.WithTransaction(tx)
  profileRepository := s.profileRepository.WithTransaction(tx)

  if err := userRepository.Create(ctx, &model.User{
   Email: data.Email,
  }); err != nil {
   return err
  }

  if err := profileRepository.Create(ctx, &model.Profile{
   Name: data.Name,
  }); err != nil {
   return err
  }

  return nil
 })
}

User和ProfileRepository的實現:

package storage

import (
 "brand/transaction"
 "brand/transaction/example2/model"
 "brand/transaction/example2/service"
 "context"
 "database/sql"
)

type ProfileRepository struct {
 db transaction.DB
}

func NewProfileRepository(db transaction.DB) *ProfileRepository {
 return &ProfileRepository{db: db}
}

func (r *ProfileRepository) Create(ctx context.Context, profile *model.Profile) error {
 _, err := r.db.ExecContext(ctx, "INSERT ...", profile.Name)

 return err
}

func (r *ProfileRepository) WithTransaction(tx *sql.Tx) service.ProfileRepository {
 return NewProfileRepository(tx)
}
package storage

import (
 "brand/transaction"
 "brand/transaction/example2/model"
 "brand/transaction/example2/service"
 "context"
 "database/sql"
)

type UserRepository struct {
 db transaction.DB
}

func NewUserRepository(db transaction.DB) *UserRepository {
 return &UserRepository{db: db}
}

func (r *UserRepository) Create(ctx context.Context, user *model.User) error {
 _, err := r.db.ExecContext(ctx, "INSERT ...", user.Email)

 return err
}

func (r *UserRepository) WithTransaction(tx *sql.Tx) service.UserRepository {
 return NewUserRepository(tx)
}

優點:

  • 更明確:在注冊服務內部創建事務,可避免副作用

缺點:

  • 客戶端代碼知道存儲類型
  • 客戶端代碼負責創建新的存儲庫

我相信任何一種方法都能使代碼更易讀、更簡單,但建議使用第一種方法,從而可以隱藏存儲細節,使我們能夠在一個項目中使用多個存儲,而無需考慮實現和存儲細節。




package storage

import (
 "brand/transaction"
 "brand/transaction/example2/model"
 "brand/transaction/example2/service"
 "context"
 "database/sql"
)

type UserRepository struct {
 db transaction.DB
}

func NewUserRepository(db transaction.DB) *UserRepository {
 return &UserRepository{db: db}
}

func (r *UserRepository) Create(ctx context.Context, user *model.User) error {
 _, err := r.db.ExecContext(ctx, "INSERT ...", user.Email)

 return err
}

func (r *UserRepository) WithTransaction(tx *sql.Tx) service.UserRepository {
 return NewUserRepository(tx)
}
責任編輯:趙寧寧 來源: DeepNoMind
相關推薦

2020-11-18 10:16:52

數據庫回滾事務

2020-11-18 08:32:07

數據庫

2024-04-17 08:11:01

數據庫事務流程

2009-08-07 17:04:41

C#數據庫

2010-10-08 09:38:55

Android數據庫事

2009-09-24 14:12:22

Hibernate數據

2025-04-08 06:00:00

2021-04-09 08:21:25

數據庫索引數據

2020-11-23 14:16:42

Golang

2020-06-17 16:56:36

數據庫MySQL跨行事務

2017-08-22 17:10:45

數據庫MySQL事務模型

2017-06-22 16:00:07

數據庫NoSQL遷移實踐

2022-02-10 10:51:35

數據庫

2017-05-09 12:40:05

2013-10-08 09:54:41

數據庫安全數據庫管理

2023-06-30 13:22:19

2018-09-06 14:53:39

數據庫事務隔離隔離級別

2010-05-31 15:12:44

MySQL數據庫

2023-10-11 08:09:53

事務隔離級別
點贊
收藏

51CTO技術棧公眾號

a黄色片在线观看| www.日本久久久久com.| 91精品国产高清自在线| 网站一区二区三区| 亚洲国产精品午夜在线观看| 四虎影视精品永久在线观看| 一区二区三区四区电影| 欧美性高跟鞋xxxxhd| 成人网欧美在线视频| 精品人妻互换一区二区三区| 美洲精品一卡2卡三卡4卡四卡| 美女在线观看视频一区二区| 精品亚洲一区二区三区四区五区| 国产在线视频在线| 精品久久久久久亚洲综合网站| 日韩成人精品一区| 在线观看精品一区| 日韩国产在线一区| 在线视频精品免费| 精品无人区麻豆乱码久久久| 色婷婷综合视频在线观看| 国产麻豆乱码精品一区二区三区| 五月天丁香激情| 麻豆国产一区二区三区四区| 亚洲天堂精品在线观看| 成人在线视频网站| 日本一级免费视频| 午夜av成人| 国产清纯白嫩初高生在线观看91| 日韩av免费在线| www.狠狠爱| caoporn成人免费视频在线| 亚洲一区在线看| 精品久久久久久一区二区里番| 日本午夜精品理论片a级app发布| 久久福利综合| 亚洲色图13p| a在线观看免费视频| www中文字幕在线观看| 成人av在线资源| 欧美一区亚洲一区| 性欧美精品男男| 婷婷激情成人| 欧美中文字幕久久| 国产二区视频在线播放| 五月婷婷开心中文字幕| 久久久久.com| 日韩三级成人av网| 日本一卡二卡在线播放| 成人在线视频区| 亚洲国产精品久久艾草纯爱 | 欧洲精品久久久久毛片完整版| 婷婷开心激情综合| 欧美一区1区三区3区公司| 欧美brazzers| 一本一道久久综合狠狠老| 伊人精品在线观看| 丰满人妻一区二区三区免费视频棣| 91制片在线观看| 国产欧美日韩不卡| 日韩一区免费观看| 成人精品福利| 成人免费看视频| 国产精品久久久久99| 欧美卡一卡二卡三| 韩国在线视频一区| 在线观看日韩视频| 成年人视频软件| 都市激情久久| 欧美色倩网站大全免费| 日韩 欧美 视频| aaa日本高清在线播放免费观看| 国产精选一区二区三区| 国产97在线|亚洲| 久久久久久无码午夜精品直播| 视频在线在亚洲| 欧美劲爆第一页| 午夜黄色福利视频| 欧美午夜寂寞| 日韩免费高清av| 久久99爱视频| 伊人色综合一区二区三区影院视频 | 亚洲中国最大av网站| 欧美污视频久久久| 亚洲精品无码久久久| 蜜臀久久久久久久| 91在线在线观看| 伊人网中文字幕| 亚洲欧美bt| 久久久久久久一区二区三区| 国产精品视频久久久久久久| 欧美黄免费看| 久久精品99久久久香蕉| av小说在线观看| 久久中文字幕av| 一区国产精品视频| 九九视频在线免费观看| 忘忧草精品久久久久久久高清| 亚洲精品自拍第一页| 黄色裸体一级片| 亚洲日本免费| 高清欧美性猛交xxxx黑人猛交| 日韩在线一卡二卡| 日韩欧美三级| 97免费中文视频在线观看| 欧美xxxx黑人xyx性爽| 一区二区三区成人精品| 韩国美女主播一区| 97人妻一区二区精品免费视频| 日本91福利区| 国产精品免费视频久久久| 天天爽夜夜爽人人爽| 国产精品一区二区在线看| 欧美日韩免费精品| 男女在线观看视频| 欧美顶级少妇做爰| 亚洲三级在线观看视频| 亚州欧美在线| 亚洲人成免费电影| 久久精品国产亚洲AV无码麻豆| 欧美日韩在线大尺度| 欧美丰满片xxx777| 精品亚洲永久免费| 日韩视频三区| 亚洲sss综合天堂久久| 99精品久久久久久中文字幕 | 亚洲综合久久久| 在线观看av日韩| 在线国产成人影院| 欧美日韩一区二区欧美激情 | 国产女18毛片多18精品| 久久综合999| 色吧亚洲视频| 久久bbxx| 亚洲综合在线第一页| 久久人人爽av| 中文一区二区三区四区| 亚洲黄色www| 亚洲精品乱码久久久久久久久久久久| 伊人影院久久| 国产精彩精品视频| 国产又粗又猛又黄| 国产福利电影一区二区三区| 国产精品一区二区三区免费观看| 免费黄网在线观看| 亚洲午夜影视影院在线观看| 做a视频在线观看| 日本午夜一区| 欧美高清视频在线播放| 国产三级视频在线播放| 中文字幕佐山爱一区二区免费| 国产一区二区三区乱码| 日韩视频在线直播| 亚洲毛片在线免费观看| 国产一区在线观看免费| 日本不卡一区二区三区| 亚洲激情图片| av剧情在线观看| 亚洲高清一区二| 成人欧美一区二区三区黑人一 | japan高清日本乱xxxxx| 日日天天久久| 久久精品视频在线播放| 黄色一区二区视频| 国产不卡在线视频| 日本不卡免费新一二三区| 日韩电影免费观| 日韩一二在线观看| 中文字幕av久久爽一区| 奇米色一区二区| 亚洲最新免费视频| 日本中文字幕中出在线| 欧美亚洲一区二区在线| 涩视频在线观看| 在线观看日韩av电影| 免费国产在线精品一区二区三区| 1区2区3区在线视频| 欧美性色欧美a在线播放| 国产小视频你懂的| 国产成人啪午夜精品网站男同| 国产精品啪啪啪视频| 精品国产欧美日韩一区二区三区| 日韩网站免费观看| 成 人 黄 色 片 在线播放| 亚洲成a天堂v人片| 日本一区二区视频在线播放| 国产在线精品视频| 一本一本久久a久久精品综合妖精| 男人的天堂免费在线视频| 精品精品国产高清一毛片一天堂| 久久一级免费视频| 福利一区二区在线| 美女av免费在线观看| 色777狠狠狠综合伊人| 国产伦精品一区二区三区视频黑人| 97成人资源| 欧美裸体xxxx极品少妇| 国产男男gay体育生白袜| 亚洲国产另类av| 91成人在线免费视频| 国产成人无遮挡在线视频| 国产精品第12页| 最新国产一区| 国产精品aaa| 羞羞视频在线免费国产| 亚洲少妇中文在线| 国产91麻豆视频| 亚洲五月六月丁香激情| 妺妺窝人体色WWW精品| 国产福利精品一区二区| www.天天射.com| av不卡在线| 可以在线看黄的网站| 国产真实有声精品录音| 国产成人精品亚洲精品| 久草在线视频网站| 色噜噜国产精品视频一区二区| 一级一级黄色片| 亚洲国产人成综合网站| 波兰性xxxxx极品hd| 91免费在线播放| 国产精品69页| 亚洲精品1区| 成人午夜视频免费观看| 都市激情久久| 91欧美视频网站| 成人黄色免费网站| 日韩亚洲在线观看| 黄色在线播放| 欧美久久一区二区| 欧美超碰在线观看| 疯狂做受xxxx欧美肥白少妇| 日韩精品电影一区二区| 成人高清视频在线| 三上悠亚 电影| 国模大尺度一区二区三区| 成人国产在线看| 小处雏高清一区二区三区| 91在线在线观看| 999精品嫩草久久久久久99| 欧美—级高清免费播放| 成人片在线看| 久久久精品免费视频| 午夜视频在线观看免费视频| 在线成人av网站| 波多野结衣视频网址| 色综合久久久久综合| 美女又爽又黄免费视频| 中文字幕一区二区在线观看| 女人扒开双腿让男人捅 | 亚洲国产老妈| 精品日韩在线播放| 欧美男人操女人视频| 国产精品一 二 三| 精品久久对白| 91久久精品日日躁夜夜躁国产| 成人午夜在线| 成人福利在线视频| 精品三级久久久| 成人三级在线| 国产麻豆一区| 91精品国产乱码久久久久久蜜臀| а√天堂8资源中文在线| 中文综合在线观看| 天天综合网在线观看| 欧美日韩国产区一| 九九精品免费视频| 在线免费精品视频| 夜夜狠狠擅视频| 色哟哟国产精品| 国产成人av免费| 欧美高清视频一二三区| 精品人妻无码一区二区三区蜜桃一| 欧美电影免费提供在线观看| 天堂av中文字幕| 一区二区三区四区精品| 国产精品刘玥久久一区| 久久久久久97| 台湾佬中文娱乐久久久| 成人天堂噜噜噜| 日韩美女毛片| 一区二区日本伦理| 激情久久五月| 日本中文字幕高清| 国产成人亚洲综合a∨婷婷图片| 少妇饥渴放荡91麻豆| 成人av免费观看| 国产美女免费网站| 亚洲九九爱视频| 免费成人深夜夜行网站| 亚洲成人一区在线| 日本视频www色| 精品久久久久久久久久久久包黑料| 美丽的姑娘在线观看免费动漫| 亚洲精品久久久一区二区三区| 国产人妖在线播放| 日韩精品中文字幕有码专区 | 国产精品电影院| 日本少妇性高潮| 91精品视频网| 国产一区二区在线视频观看| 亚洲第一页自拍| 欧美日韩在线看片| 热99在线视频| av电影一区| 国产91色在线|亚洲| 日韩黄色大片网站| 尤物av无码色av无码| 一本色道久久综合亚洲精品高清| av亚洲天堂网| 久久久久亚洲综合| www久久久久久久| 亚洲在线视频网站| 91丨九色丨蝌蚪丨对白| 日韩高清av一区二区三区| 18视频在线观看网站| 国产精品一区二区性色av| 99久久久国产精品免费调教网站| 国产精品免费在线| 欧美久久九九| 成人亚洲免费视频| 国产精品免费视频网站| 一区二区成人免费视频| 亚洲午夜精品久久久久久久久| 中文字幕一区二区三区波野结| 日韩精品视频在线播放| aaa在线播放视频| 不卡一区二区三区视频| 日韩电影在线观看完整免费观看| 99中文字幕在线观看| 久久精品国产久精国产爱| 一区二区三区人妻| 成人免费在线播放视频| 中文字幕av无码一区二区三区| 精品视频在线播放免| 三级在线观看视频| 国产精品我不卡| 亚洲福利国产| 亚洲黄色小说在线观看| 91免费精品国自产拍在线不卡| 久久久美女视频| 欧美变态凌虐bdsm| 午夜伦理在线视频| www.一区二区三区| 亚洲午夜av| 久久精品无码专区| 亚洲福利视频导航| 香港三日本三级少妇66| 欧美在线观看一区二区三区| 果冻天美麻豆一区二区国产| www.xxx麻豆| 91女神在线视频| 超碰在线免费97| 精品国产拍在线观看| 国产精品亚洲一区二区在线观看| 欧美精品一区二区性色a+v| 国产美女在线精品| 久久免费播放视频| 日韩电影免费观看在线观看| 成人免费直播| 一本色道久久综合亚洲精品婷婷| 久久97超碰国产精品超碰| 久久精品综合视频| 欧美午夜片欧美片在线观看| 美女做暖暖视频免费在线观看全部网址91| 国产成人精品一区二区三区| 日韩欧美中字| 性xxxxxxxxx| 懂色aⅴ精品一区二区三区蜜月| 免费看男男www网站入口在线| 国产精品免费在线免费| 99精品电影| 制服丝袜av在线| 色噜噜狠狠色综合欧洲selulu| 亚洲精品97久久中文字幕无码| 国自产精品手机在线观看视频| 亚洲激情播播| 亚洲熟妇无码一区二区三区导航| 精品一区二区综合| 久久精品波多野结衣| 日韩精品亚洲元码| 日本免费成人| www精品久久| 国产欧美综合在线观看第十页| 一级α片免费看刺激高潮视频| 欧美黑人性生活视频| 蜜桃视频欧美| 三级av免费看| 中文字幕在线播放不卡一区| 亚洲av无码一区二区乱子伦| 91av国产在线| 亚洲va在线| 97伦伦午夜电影理伦片| 舔着乳尖日韩一区| 二区三区在线| 国产精品对白刺激| 欧美福利影院| 谁有免费的黄色网址| 精品美女一区二区| 韩国精品视频在线观看|