日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

Spring 4 官方文档学习(十)数据访问之JDBC

發布時間:2023/12/10 javascript 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Spring 4 官方文档学习(十)数据访问之JDBC 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說明:未修訂版,閱讀起來極度困難

?

1、Spring框架JDBC的介紹

?

Spring JDBC - who does what?

動作Spring
定義連接參數?
打開連接?
指定SQL語句?
聲明參數,提供參數值?
準備、執行語句?
迭代結果(如果有)?
操作每個迭代?
處理任何異常?
處理事務?
關閉連接、語句、結果集?

一句話,Spring框架負責所有的低級別細節操作。

?

1.1、選擇JDBC數據庫訪問的路徑

所有的路徑都需要兼容JDBC 2.0的驅動,部分特性可能需要JDBC 3.0 的驅動。

JdbcTemplate 是經典的Spring JDBC 路徑,最流行。最低級的路徑,所有其他的底層都是用一個JdbcTemplate。

NamedParameterJdbcTemplate 封裝了一個JdbcTemplate,使用帶名字的參數取代了傳統的JDBC 占位符(?)。該路徑,提供了更好的文檔,當你有很多參數時,更易于使用。

SimpleJdbcInsert和SimpleJdbcCall 優化了數據庫元數據,限制了必要數據的數量。該路徑簡化了編碼,你只要提供表名或procedure并提供參數和列匹配的映射即可。這只有在數據庫提供了足夠的元數據時才起作用。否則需要顯式的提供足夠的數據。

RDBM Objects 包括 MappingSqlQuery、SqlUpdate和StoredProcedure,要求在數據訪問層初始化時創建可復用的、線程安全的對象。

?

1.2、package層級

Spring框架的JDBC抽象框架由四個不同的包組成:core、datasource、object以及support。

?

org.springframework.jdbc.core 包含JdbcTemplate類和其各種回調接口,以及一組相關的類。子包jdbc.core.simple包含了SimpleJdbcInsert 和 SimpleJdbcCall類。子包jdbc.core.namedparam 包含了NamedParameterJdbcTemplate類和相關支持類。

?

jdbc.datasource包含了簡化DataSource使用的工具類,以及各種簡單的DataSource實現(可以用于Java EE 容器之外的測試和運行)。子包jdbc.datasource.embedded支持使用Java數據庫引擎創建內嵌的數據庫,如HSQL、H2、Derby。

?

jdbc.object包含了代表RDBMS查詢、更新,以及stored-procedure(存儲過程)。

This approach is modeled by JDO, although objects returned by queries are naturally disconnected from the database. This higher level of JDBC abstraction depends on the lower-level abstraction in the org.springframework.jdbc.core package.

?

The org.springframework.jdbc.support package provides SQLException translation functionality and some utility classes. Exceptions thrown during JDBC processing are translated to exceptions defined in the org.springframework.dao package. This means that code using the Spring JDBC abstraction layer does not need to implement JDBC or RDBMS-specific error handling. All translated exceptions are unchecked, which gives you the option of catching the exceptions from which you can recover while allowing other exceptions to be propagated to the caller.

?

2、使用JDBC核心類來控制基本的JDBC處理和錯誤處理

2.1、JdbcTemplate

處理資源的創建和釋放。執行core JDBC工作流的基本任務,例如語句的創建和執行,讓應用代碼只需要提供SQL和抽取結果即可。

?

當你使用JdbcTemplate時,你只需要實現回調接口們。PreparedStatementCreator回調接口會根據給定的Connection和SQL以及任何必要的參數來創建預處理語句。CallableStatementCreator接口也是一樣,只不過是創建callable語句。RowCallbackHandler接口會從ResultSet的每一行中提取值。

?

JdbcTemplate能在DAO實現內使用,使用DataSource實例化。

在Spring IoC容器中,DataSource總是需要被配置的!

JdbcTemplate使用例子:

本部分提供了一些JdbcTemplate的使用例子。沒有詳盡的列出JdbcTemplate的所有功能,具體見javadoc。

查詢(SELECT)

int rowCount = this.jdbcTemplate.queryForObject("select count(*) from t_actor", Integer.class); int countOfActorsNamedJoe = this.jdbcTemplate.queryForObject("select count(*) from t_actor where first_name = ?", Integer.class, "Joe"); String lastName = this.jdbcTemplate.queryForObject("select last_name from t_actor where id = ?",new Object[]{1212L}, String.class); // 將結果映射到domain object Actor actor = this.jdbcTemplate.queryForObject("select first_name, last_name from t_actor where id = ?",new Object[]{1212L},new RowMapper<Actor>() {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;}}); // 將查詢結果映射到一組domain objects。和上面相比,實際上只有等號左邊變化了。 List<Actor> actors = this.jdbcTemplate.query("select first_name, last_name from t_actor",new RowMapper<Actor>() {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;}});

或者,上面的可以這樣寫:

public List<Actor> findAllActors() {return this.jdbcTemplate.query( "select first_name, last_name from t_actor", new ActorMapper()); }private static final class ActorMapper implements RowMapper<Actor> {public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {Actor actor = new Actor();actor.setFirstName(rs.getString("first_name"));actor.setLastName(rs.getString("last_name"));return actor;} }

使用JdbcTemplate更新 (INSERT/UPDATE/DELETE) --可以都使用update(..)

this.jdbcTemplate.update("insert into t_actor (first_name, last_name) values (?, ?)","Leonor", "Watling"); this.jdbcTemplate.update("update t_actor set last_name = ? where id = ?","Banjo", 5276L); this.jdbcTemplate.update("delete from actor where id = ?",Long.valueOf(actorId));

其他JdbcTemplate操作--可以使用execute(..)執行任意SQL

this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");

調用一個簡單的存儲過程:

this.jdbcTemplate.update("call SUPPORT.REFRESH_ACTORS_SUMMARY(?)",Long.valueOf(unionId));

?

JdbcTemplate 最佳實踐

JdbcTemplate 實例 是線程安全的!就是說,你只需要定義一個實例即可,隨便注入并使用!

通常的實踐是配置一個DataSource,然后將其注入到DAO類中。JdbcTemplate通過setDataSource(..)創建:

public class JdbcCorporateEventDao implements CorporateEventDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}// JDBC-backed implementations of the methods on the CorporateEventDao follow... }

相應配置文件:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><bean id="corporateEventDao" class="com.example.JdbcCorporateEventDao"><property name="dataSource" ref="dataSource"/></bean><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><context:property-placeholder location="jdbc.properties"/></beans>

或者,使用注解配合自動掃描。

@Repository public class JdbcCorporateEventDao implements CorporateEventDao {private JdbcTemplate jdbcTemplate;@Autowiredpublic void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}// JDBC-backed implementations of the methods on the CorporateEventDao follow... } <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!-- Scans within the base package of the application for @Component classes to configure as beans --><context:component-scan base-package="org.springframework.docs.test" /><bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></bean><context:property-placeholder location="jdbc.properties"/></beans>

如果使用Spring的JdbcDaoSupport類,可以讓你的DAO類繼承它,然后自動繼承了setDataSource(..)方法。

只有在訪問多個數據庫時才需要創建多個JdbcTemplate實例!

?

2.2、NamedParameterJdbcTemplate

// some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActorsByFirstName(String firstName) {String sql = "select count(*) from T_ACTOR where first_name = :first_name";SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName); // thisreturn this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); } // some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActorsByFirstName(String firstName) {String sql = "select count(*) from T_ACTOR where first_name = :first_name";Map<String, String> namedParameters = Collections.singletonMap("first_name", firstName); // 換成map了,一樣return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); }

還可以,從domain object中獲取參數 -- 不是寫入domain object!!!如下:

public class Actor {private Long id;private String firstName;private String lastName;public String getFirstName() {return this.firstName;}public String getLastName() {return this.lastName;}public Long getId() {return this.id;}// setters omitted... } // some JDBC-backed DAO class... private NamedParameterJdbcTemplate namedParameterJdbcTemplate;public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource); }public int countOfActors(Actor exampleActor) { // 這里// notice how the named parameters match the properties of the above 'Actor' classString sql = "select count(*) from T_ACTOR where first_name = :firstName and last_name = :lastName";SqlParameterSource namedParameters = new BeanPropertySqlParameterSource(exampleActor); // 這里return this.namedParameterJdbcTemplate.queryForObject(sql, namedParameters, Integer.class); }

?

2.3、SQLExceptionTranslator

一個接口,其實現類能夠在SQLExceptions和Spring自己的org.springframework.dao.DataAccessException之間轉換。其實現可以是泛型的也可以是具體的。

?

SQLErrorCodeSQLExceptionTranslator 是默認使用的實現。

?

?

2.4、執行語句

執行一個SQL語句只需要少量的代碼。

import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate;public class ExecuteAStatement {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public void doExecute() {this.jdbcTemplate.execute("create table mytable (id integer, name varchar(100))");} }

2.5、運行查詢

一些查詢方法返回單個值。使用queryForObject(..)從一行中獲取一個計數或特定的值。后者將返回的JDBC類型轉成指定的Java類型。如果類型轉換無效,會拋出InvalidDataAccessApiUsageException異常。

import javax.sql.DataSource; import org.springframework.jdbc.core.JdbcTemplate;public class RunAQuery {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int getCount() { // 返回intreturn this.jdbcTemplate.queryForObject("select count(*) from mytable", Integer.class);}public String getName() { // 返回Stringreturn this.jdbcTemplate.queryForObject("select name from mytable", String.class);} }

除了單個結果的查詢方法,有幾個方法返回一個列表。最泛型的方法是queryForList(..),會返回List<Map<col_name_type, col_value_type>>。如下:

private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource); }public List<Map<String, Object>> getList() {return this.jdbcTemplate.queryForList("select * from mytable"); }

返回結果類似這樣:

[{name=Bob, id=1}, {name=Mary, id=2}]

2.6、更新數據庫

下面的例子示意了更新某個特定主鍵對應的列。參數值可以通過變參數或數組傳入。primitive類型會自動裝箱。

import javax.sql.DataSource;import org.springframework.jdbc.core.JdbcTemplate;public class ExecuteAnUpdate {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public void setName(int id, String name) {this.jdbcTemplate.update("update mytable set name = ? where id = ?", name, id);} }

?

2.7、獲取自動生成的鍵 auto-generated keys -- 就是mybatis的<selectKey>

JDBC 3.0標準支持使用update()方法獲取數據庫生成的主鍵。該方法使用一個PreparedStatementCreator作為其第一個參數。另一個參數是一個KeyHolder,其包含了update成功時生成的key。

下面的例子在Oracle中可以正常工作,但在其他平臺上可能無法工作。

final String INSERT_SQL = "insert into my_test (name) values(?)"; final String name = "Rob";KeyHolder keyHolder = new GeneratedKeyHolder(); jdbcTemplate.update(new PreparedStatementCreator() {public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {PreparedStatement ps = connection.prepareStatement(INSERT_SQL, new String[] {"id"});ps.setString(1, name);return ps;}},keyHolder);// keyHolder.getKey() now contains the generated key

?

3、控制數據庫連接

3.1、DataSource

Spring通過一個DataSource來獲取到數據庫的連接。DataSource是JDBC標準的一部分,是一個連接工廠。它允許容器或框架隱藏連接池和事務管理。

當使用Spring的JDBC層,你是從JNDI獲取一個data source,或者,你使用第三方連接池實現來配置自己的data source。流行的連接池實現包括DBCP和C3P0. Spring中的實現僅用于測試目的,不提供pooling功能。

?

本部分使用Spring的DriverMangerDataSource實現和幾個其他實現。

DriverMangerDataSource 僅用于測試目的!

DriverManagerDataSource dataSource = new DriverManagerDataSource(); // 實際工作中不要使用這個!!! dataSource.setDriverClassName("org.hsqldb.jdbcDriver"); dataSource.setUrl("jdbc:hsqldb:hsql://localhost:"); dataSource.setUsername("sa"); dataSource.setPassword(""); <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/>

下例示意了針對DBCP和C3P0的基本的連接和配置:

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><property name="driverClassName" value="${jdbc.driverClassName}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><property name="driverClass" value="${jdbc.driverClassName}"/><property name="jdbcUrl" value="${jdbc.url}"/><property name="user" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/> </bean><context:property-placeholder location="jdbc.properties"/>

3.2、DataSourceUtils

幫助類,提供了靜態方法從JNDI獲取連接,以及關閉連接(如有必要)。支持線程綁定的連接,例如DataSourceTransactionManager。

3.3、SmartDataSource

擴展了DataSource接口,允許類使用它查詢連接是否應該在某操作之后被關閉。如果你明確會復用一個連接,它會很有效率的。

3.4、AbstractDataSource

是Spring DataSource實現的抽象類。

3.5、SingleConnectionDataSource

是SmartDataSource的實現,封裝了一個單獨的Connection,每次使用都不會關閉,所以不具備多線程功能。

測試類。

3.6、DriverManagerDataSource

是標準DataSource的實現,通過bean properties配置簡單的JDBC驅動,每次返回一個新的Connection!

在測試情況以及Java EE容器之外的環境下很有用。 -- 不要在生產環境中使用!

3.7、TransactionAwareDataSourceProxy

是對目標DataSource的代理,封裝了目標DataSource to add awareness of Spring-managed transactions。從這個角度看,類似于一個Java EE服務器提供的事務性的JNDIDataSource。

-- 很少很少用到這個類!

3.8、DataSourceTransactionManager

是PlatformTransactionManager的單JDBC datasources的實現。它將一個特定data source的JDBC連接綁定到當前執行的線程,允許每個data source一個線程。

需要代碼使用DataSourceUtils.getConnection(DataSource)代替DataSource.getConnection來獲取JDBC連接。它會拋出unchecked org.springframework.dao 異常,而不是SQLExceptions。所有的框架類如JdbcTemplate都隱式的使用這種策略。

?

DataSourceTransactionManager 支持自定義隔離級別、超時時間(用于每個JDBC語句查詢)。為了支持后者,代碼中應該使用JdbcTemplate或者DataSourceUtils.applyTransactionTimeout(..)方法來為每個創建的語句設置超時時間。

?

該實現可以替代JtaTransactionManager -- 在單資源的情況下,因為此時不需要容器支持JTA。二者的切換僅僅是配置的問題。

?

3.9、NativeJdbcExtractor

有時候,你需要訪問供應商獨有的JDBC方法,而非標準JDBC API。這時你可以使用NativeJdbcExtractor配置你的JdbcTemplate或者OracleLobHandler。

NativeJdbcExtractor 有不同變體:

  • SimpleNativeJdbcExtractor
  • C3P0NativeJdbcExtractor
  • CommonsDbcpNativeJdbcExtractor
  • JBossNativeJdbcExtractor
  • WebLogicNativeJdbcExtractor
  • WebSphereNativeJdbcExtractor
  • XAPoolNativeJdbcExtractor

多數情況下,針對為封裝的Connection對象,只需要使用SimpleNativeJdbcExtractor。

?

4、JDBC 批處理操作

當你的批處理需要調用相同的預處理語句時,多數JDBC驅動提供了性能改進。

4.1、使用JdbcTemplate進行基本的批處理操作

JdbcTemplate批處理需要實現BatchPreparedStatementSetter接口的兩個方法,并將其作為第二個參數傳入你的batchUpdate(..)方法。使用getBatchSize()方法來提供當前batch的尺寸。使用setValues(..)方法來為預處理語句的參數設置。 該方法會被調用n次 -- 你在getBatchSize()方法中設置的次數。例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, " +"last_name = ? where id = ?",new BatchPreparedStatementSetter() {public void setValues(PreparedStatement ps, int i) throws SQLException {ps.setString(1, actors.get(i).getFirstName());ps.setString(2, actors.get(i).getLastName());ps.setLong(3, actors.get(i).getId().longValue());}public int getBatchSize() {return actors.size();}});return updateCounts;}// ... additional methods }

如果你在處理一個更新stream或者從文件中讀取的stream,可能會預先設置一個batch size,但最后的batch可能不會滿足batch size。這種情況下,可以使用InterruptibleBatchPreparedStatementSetter接口,其isBatchExhausted()方法允許你判斷批處理的結束。

?

4.2、針對對象列表的批處理操作

JdbcTemplate和NamedParameterJdbcTemplate 都有另一種提供batch update的方法。不需要實現特定的batch接口,只需要以列表形式提供所有的參數值。框架會遍歷這些值并使用一個內部的預處理語句SETTER。其API視你使用的命名參數不同而不同。For the named parameters you provide an array of SqlParameterSource, one entry for each member of the batch. You can use the SqlParameterSource.createBatch method to create this array, passing in either an array of JavaBeans or an array of Maps containing the parameter values.

例子(使用命名參數):

public class JdbcActorDao implements ActorDao {private NamedParameterTemplate namedParameterJdbcTemplate; //public void setDataSource(DataSource dataSource) {this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray());int[] updateCounts = namedParameterJdbcTemplate.batchUpdate("update t_actor set first_name = :firstName, last_name = :lastName where id = :id",batch);return updateCounts;}// ... additional methods }

使用JDBC的占位符:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[] batchUpdate(final List<Actor> actors) {List<Object[]> batch = new ArrayList<Object[]>();for (Actor actor : actors) {Object[] values = new Object[] {actor.getFirstName(),actor.getLastName(),actor.getId()};batch.add(values);}int[] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, last_name = ? where id = ?", // ? 占位符 batch);return updateCounts;}// ... additional methods }

上面兩個例子最后都會返回一個int數組,每個值都代表一條語句執行后影響的行數。如果不可用,會返回-2

?

4.3、多個批處理的批處理操作

當批處理非常大時,你可能想將其拆分成幾個小的批處理。當然,你可以使用上面的方法,多次調用batchUpdate方法即可,但這里有一個更方便的方法。該方法除了使用SQL語句,還需要一個對象的集合 -- 包含了參數、每個batch中update的數量、以及一個ParameterizedPreparedStatementSetter 來為參數設值。框架會遍歷提供的值,并將update調用拆分成指定大小的batch中。

例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);}public int[][] batchUpdate(final Collection<Actor> actors) {int[][] updateCounts = jdbcTemplate.batchUpdate("update t_actor set first_name = ?, last_name = ? where id = ?",actors,100, // this, size of each batchnew ParameterizedPreparedStatementSetter<Actor>() { // thispublic void setValues(PreparedStatement ps, Actor argument) throws SQLException {ps.setString(1, argument.getFirstName());ps.setString(2, argument.getLastName());ps.setLong(3, argument.getId().longValue());}});return updateCounts;}// ... additional methods }

最終結果是int數組的數組。不再解釋。

?

5、使用SimpleJdbc類來簡化JDBC操作

SimpleJdbcInsert和SimpleJdbcCall類利用了可以從JDBC驅動獲取的數據庫的元數據,從而提供了簡化的配置。

?

5.1、使用SimpleJdbcInsert 插入數據

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor; // thispublic void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor"); // here!!! }public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(3);parameters.put("id", actor.getId());parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());insertActor.execute(parameters);}// ... additional methods }

5.2、使用SimpleJdbcInsert獲取自動生成的鍵

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor") // here.usingGeneratedKeyColumns("id"); // here }public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(2);parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());Number newId = insertActor.executeAndReturnKey(parameters); // here actor.setId(newId.longValue());}// ... additional methods }

如果返回多個自動生成的鍵,可以使用executeAndReturnKeyHolder,這會返回一個KeyHolder。

?

5.3、為SimpleJdbcInsert指定列

就是限制插入的列。

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingColumns("first_name", "last_name") // here.usingGeneratedKeyColumns("id");}public void add(Actor actor) {Map<String, Object> parameters = new HashMap<String, Object>(2);parameters.put("first_name", actor.getFirstName());parameters.put("last_name", actor.getLastName());Number newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

5.4、使用SqlParameterSource提供參數值

使用Map提供參數值很不錯,但不是最方便的。Spring提供了一組SqlParameterSource接口的實現,很不錯。第一個是BeanPropertySqlParameterSource,適用于JavaBean類。例子:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingGeneratedKeyColumns("id");}public void add(Actor actor) {SqlParameterSource parameters = new BeanPropertySqlParameterSource(actor); // hereNumber newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

另一個是MapSqlParameterSource,重裝了一個Map,但提供了更方便的addValue方法--可以鏈式編程!如下:

public class JdbcActorDao implements ActorDao {private JdbcTemplate jdbcTemplate;private SimpleJdbcInsert insertActor;public void setDataSource(DataSource dataSource) {this.jdbcTemplate = new JdbcTemplate(dataSource);this.insertActor = new SimpleJdbcInsert(dataSource).withTableName("t_actor").usingGeneratedKeyColumns("id");}public void add(Actor actor) {SqlParameterSource parameters = new MapSqlParameterSource() // this.addValue("first_name", actor.getFirstName()) // 鏈式編程.addValue("last_name", actor.getLastName()); // 鏈式編程Number newId = insertActor.executeAndReturnKey(parameters);actor.setId(newId.longValue());}// ... additional methods }

?

5.5、使用SimpleJdbcCall調用存儲過程

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-1

?

5.6、為SimpleJdbcCall顯式聲明參數

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-2

?

5.7、如何定義SqlParameter

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-params

為了SimpleJdbc類還有RDBMS的操作類定義參數,可以使用SqlParameter或其任一子類。通常需要在構造器中指定參數名和SQL類型。SQL類型使用java.sql.Types中的常量。

new SqlParameter("in_id", Types.NUMERIC),new SqlOutParameter("out_first_name", Types.VARCHAR),

略。。。

?

5.8、使用SimpleJdbcCall調用stored function

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-3

?

5.9、從SimpleJdbcCall返回ResultSet/REF 游標

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-simple-jdbc-call-4

?

6、將JDBC操作模型化為Java對象

org.springframework.jdbc.object

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-object

6.1、SqlQuery

6.2、MappingSqlQuery

6.3、SqlUpdate

6.4、StoredProcedure

?

?

7、參數和數據值處理的常見問題

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-parameter-handling

7.1、為參數提供SQL type信息

一般,Spring是基于傳入的參數類型決定參數的SQL type。但還可以顯式的提供SQL type。有時候為了正確設置NULL值,這樣做很有必要。

有以下幾種方式:

  • JdbcTemplate的很多update和query方法會接收一個額外的參數:int數組形式。該數組用于表明相應參數的SQL類型,其值來自java.sql.Types類的常量。
  • 還可以使用SqlParameterValue類來封裝需要額外信息的參數值。為每個值創建一個實例,將SQL type和參數值傳入構造器。You can also provide an optional scale parameter for numeric values.
  • 當使用命名參數時,使用SqlParameterSource類的子類:BeanPropertySqlParameterSource 或 MapSqlParameterSource。它們都有為任意命名參數值注冊SQL type的方法。

7.2、處理BLOB 和 CLOB對象

你可以在數據庫中存儲圖像、其他二進制數據,還有大量的文本。這些大對象稱為:BLOB(Binary Large Object) -- 針對二進制數據;CLOB (Character Large Object) -- 針對字符數據。在Spring中你可以使用JdbcTemplate處理這些大對象 (In Spring you can handle these large objects by using the JdbcTemplate directly and also when using the higher abstractions provided by RDBMS Objects and the SimpleJdbc classes.)。所有這些途徑都是用了LobHandler接口的實現。LobHandler可以訪問LobCreator類以創建新的LOB對象--使用getLobCreator()方法,從而插入數據庫。

LobCreator/LobHandler 為LOB的輸入輸出提供下列支持:

  • BLOB
    • byte[] -- getBlobAsBytes, setBlobAsBytes
    • InputStream -- getBlobAsBinaryStream, setBlobAsBinaryStream
  • CLOB
    • String -- getClobAsString, setClobAsString
    • InputStream -- getClobAsAsciiStream, setClobAsAsciiStream
    • Reader -- getClobAsCharacterStream, setClobAsCharacterStream

?

下面的例子使用了JdbcTemplate以及AbstractLobCreatingPreparedStatementCallback的一個實現。它實現了setValues方法,該方法提供了一個LobCreator可以為LOB列設值。

下面的例子假定已經有一個變量lobHandler,且已經設置成DefaultLobHandler的實例。

final File blobIn = new File("spring2004.jpg"); final InputStream blobIs = new FileInputStream(blobIn); final File clobIn = new File("large.txt"); final InputStream clobIs = new FileInputStream(clobIn); final InputStreamReader clobReader = new InputStreamReader(clobIs); jdbcTemplate.execute("INSERT INTO lob_table (id, a_clob, a_blob) VALUES (?, ?, ?)",new AbstractLobCreatingPreparedStatementCallback(lobHandler) { // 1protected void setValues(PreparedStatement ps, LobCreator lobCreator) throws SQLException {ps.setLong(1, 1L);lobCreator.setClobAsCharacterStream(ps, 2, clobReader, (int)clobIn.length()); // 2lobCreator.setBlobAsBinaryStream(ps, 3, blobIs, (int)blobIn.length()); // 3}} ); blobIs.close(); clobReader.close();

  • Pass in the lobHandler that in this example is a plain DefaultLobHandler.
  • Using the method setClobAsCharacterStream, pass in the contents of the CLOB.
  • Using the method setBlobAsBinaryStream, pass in the contents of the BLOB.
  • If you invoke the setBlobAsBinaryStream, setClobAsAsciiStream, or setClobAsCharacterStream method on the LobCreator returned from DefaultLobHandler.getLobCreator(), you can optionally specify a negative value for the contentLength argument. If the specified content length is negative, the DefaultLobHandler will use the JDBC 4.0 variants of the set-stream methods without a length parameter; otherwise, it will pass the specified length on to the driver.

    上面的例子是寫入LOB數據,下面看看讀取LOB數據:

    List<Map<String, Object>> l = jdbcTemplate.query("select id, a_clob, a_blob from lob_table",new RowMapper<Map<String, Object>>() {public Map<String, Object> mapRow(ResultSet rs, int i) throws SQLException {Map<String, Object> results = new HashMap<String, Object>();String clobText = lobHandler.getClobAsString(rs, "a_clob"); // 1 results.put("CLOB", clobText); byte[] blobBytes = lobHandler.getBlobAsBytes(rs, "a_blob"); // 2 results.put("BLOB", blobBytes); return results; } });

    Using the method getClobAsString, retrieve the contents of the CLOB.

    Using the method getBlobAsBytes, retrieve the contents of the BLOB.

    ?

    7.3、為IN語句傳入值列表

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-in-clause

    ?

    7.4、為存儲過程的調用處理復雜類型

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-complex-types

    ?

    8、內嵌數據庫支持

    原生支持HSQL, H2, Derby。可以擴展。

    8.1、為什么使用內嵌數據庫?

    開發階段很有用,因為其輕量級特性。易配置,啟動快,便于測試,以及快速的改進SQL。

    8.2、使用Spring XML創建內嵌數據庫

    如果想將內嵌數據庫實例暴露到Spring的ApplicationContext中作為一個bean,需要使用spring-jdbc命名空間的embedded-database標簽:

    <jdbc:embedded-database id="dataSource" generate-name="true"><jdbc:script location="classpath:schema.sql"/><jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database>上面的配置會創建一個內嵌的HSQL數據庫,并執行schema.sql和test-data.sql中的SQL語句。

    另外,作為最佳實踐,內嵌數據庫會被賦予一個獨特的生成的名字。內嵌數據庫在Spring容器中是一種javax.sql.DataSource類型的bean,可以注入任何dao中。

    8.3、編碼式創建一個內嵌數據庫

    類似這樣:

    EmbeddedDatabase db = new EmbeddedDatabaseBuilder() // 這貨.generateUniqueName(true).setType(H2).setScriptEncoding("UTF-8").ignoreFailedDrops(true).addScript("schema.sql").addScripts("user_data.sql", "country_data.sql").build();// perform actions against the db (EmbeddedDatabase extends javax.sql.DataSource) db.shutdown()

    還可以這樣:

    @Configuration public class DataSourceConfig {@Beanpublic DataSource dataSource() {return new EmbeddedDatabaseBuilder().generateUniqueName(true).setType(H2).setScriptEncoding("UTF-8").ignoreFailedDrops(true).addScript("schema.sql").addScripts("user_data.sql", "country_data.sql").build();} }

    8.4、選擇內嵌數據庫類型

    使用HSQL

    Spring支持HSQL 1.8.0及以上版本。如果沒有指定,默認就是HSQL。需要指定的話,將embedded-database標簽的type屬性設值為HSQL即可。

    如果使用builder API,調用setType(EmbeddedDatabaseType.HSQL) 即可。

    其他:H2,Derby。類似HSQL。

    8.5、使用內嵌數據庫測試數據訪問邏輯

    public class DataAccessIntegrationTestTemplate {private EmbeddedDatabase db;@Beforepublic void setUp() {// creates an HSQL in-memory database populated from default scripts// classpath:schema.sql and classpath:data.sqldb = new EmbeddedDatabaseBuilder().generateUniqueName(true).addDefaultScripts().build();}@Testpublic void testDataAccess() {JdbcTemplate template = new JdbcTemplate(db);template.query( /* ... */ );}@Afterpublic void tearDown() {db.shutdown();}}

    Embedded databases provide a lightweight way to test data access code. The following is a data access integration test template that uses an embedded database. Using a template like this can be useful for one-offs when the embedded database does not need to be reused across test classes. However, if you wish to create an embedded database that is shared within a test suite, consider using the Spring TestContext Framework and configuring the embedded database as a bean in the Spring ApplicationContext as described in Section 19.8.2, “Creating an embedded database using Spring XML” and Section 19.8.3, “Creating an embedded database programmatically”.

    8.6、為內嵌數據庫生成一個唯一的名字

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-unique-names

    8.7、擴展內嵌數據庫支持

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-embedded-database-extension

    ?

    ?

    9、初始化一個DataSource

    org.springframework.jdbc.datasource.init包提供了初始化已有DataSource的支持。內嵌數據庫支持 提供了為一個應用創建和初始化一個DataSource的選項,但是,有時候你需要在服務器或者其他地方初始化一個實例。

    9.1、使用Spring XML初始化一個數據庫

    <jdbc:initialize-database data-source="dataSource"><jdbc:script location="classpath:com/foo/sql/db-schema.sql"/><jdbc:script location="classpath:com/foo/sql/db-test-data.sql"/> </jdbc:initialize-database>

    該數據庫初始化器的默認行為是無條件的執行提供的腳本。這通常不是你想要的,例如,如果你要針對一個已有數據的數據庫進行初始化。偶然刪除數據的可能可以通過以下常見模式(先創建表,再插入數據,如果已經存在表,那第一步就會失敗)來降低。

    ?

    然而,為了獲取針對已有數據的創建和刪除的更多控制,XML命名空間提供了一些額外的選項。第一個選項就是切換是否初始化。這可以根據環境來設置(例如從系統properties中獲取一個boolean值),如下:

    <jdbc:initialize-database data-source="dataSource"enabled="#{systemProperties.INITIALIZE_DATABASE}"><jdbc:script location="..."/> </jdbc:initialize-database>

    The second option to control what happens with existing data is to be more tolerant of failures. 你可以控制初始化器的能力,讓其在執行scripts中的SQL時忽略特定錯誤。例如:

    <jdbc:initialize-database data-source="dataSource" ignore-failures="DROPS"><jdbc:script location="..."/> </jdbc:initialize-database>

    上面的例子是說,有時候我們期望scripts能夠在一個空的數據庫上執行 ,scripts中的一些DROP語句會執行失敗。這些失敗的SQL DROP語句會被忽略,但其他失敗會導致異常。當你的SQL dialect不支持 DROP ... IF EXISTS ,但你又想在重建數據前無條件的清除所有測試數據時,這會很有用。

    ignore-failures 選項,可以被設置為NONE(默認)、DROPS、或 ALL。

    每個語句都應以分號間隔,或者完全不使用分號,而用換行代替。你可以控制它:

    <jdbc:initialize-database data-source="dataSource" separator="@@"><jdbc:script location="classpath:com/foo/sql/db-schema.sql" separator=";"/><jdbc:script location="classpath:com/foo/sql/db-test-data-1.sql"/><jdbc:script location="classpath:com/foo/sql/db-test-data-2.sql"/> </jdbc:initialize-database>

    上面是用 @@作為通用的分隔符,又給db-schema.sql設置了分號分隔符。

    如果需要更多控制,使用DataSourceInitializer即可。

    ?

    依賴數據庫的其他組件的初始化

    http://docs.spring.io/spring/docs/current/spring-framework-reference/html/jdbc.html#jdbc-client-component-initialization

    數據庫初始化器依賴于一個DataSource實例,且會執行在其初始化回調(類似@PostConstruct)中提供的scripts。如果其他beans依賴相同的data source,并也在初始化回調中使用它,那么可能會導致問題,因為數據還沒有初始化!常見的例子是在應用啟動時就迫切的初始化并加載數據的緩存。

    圍繞這個問題,你有兩個選擇:改變你的緩存初始化策略,不要迫切初始化,而是延遲初始化,或者確保數據庫初始化器已經初始化了。

    第一個選擇可能很簡單 -- 如果你負責這個應用。一些建議:

    • 讓緩存懶初始化--第一次使用時再初始化。
    • 讓你的緩存或者初始化緩存的組件實現Lifecycle或SmartLifecycle。當應用上下文啟動時,SmartLifecyle會被自動啟動--如果它的autoStartup被設置了,可以在該上下文中手動調用ConfigurableApplicationContext.start()來啟動Lifecycle
    • 使用ApplicationEvent或類似的觀察者機制來觸發緩存初始化。ContextRefreshedEvent通常是個很有用的鉤子。

    第二個選擇可能同樣簡單。一些建議:

    • 依賴Spring BeanFactory的默認行為--beans以注冊順序被初始化。你可以很簡單的安排順序--一組<import/>,讓數據庫放在前面。
    • 分離DataSource和使用其的業務組件,通過將它們放在不同的ApplicationContext實例中來控制它們的啟動順序。--例如,父上下文包含DataSource,子上下文包含業務組件。這種結構在Spring web應用中很常見,但可用于更多地方。

    轉載于:https://www.cnblogs.com/larryzeal/p/5997550.html

    總結

    以上是生活随笔為你收集整理的Spring 4 官方文档学习(十)数据访问之JDBC的全部內容,希望文章能夠幫你解決所遇到的問題。

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

    国产精品美女久久久网av | 亚洲高清国产视频 | 久久九九视频 | 色播亚洲婷婷 | 国产69精品久久99不卡的观看体验 | 欧美精品三级在线观看 | 国产电影黄色av | 国产白浆在线观看 | 日本中文在线 | 91九色视频国产 | 精品人人人 | 国产欧美综合视频 | 狠狠久久综合 | 国产成人免费网站 | 97色狠狠| 精品一区精品二区高清 | 91麻豆精品国产91久久久无需广告 | 久久 一区 | 亚洲毛片在线观看. | 97在线看 | 国产精品99蜜臀久久不卡二区 | 日韩欧美一级二级 | 在线 欧美 日韩 | 国产精品视频免费观看 | 99精品久久久久久久 | 国产vs久久 | 最近更新的中文字幕 | 99激情网| www.夜夜操.com| 欧美最新另类人妖 | 在线观看中文字幕亚洲 | 精品一区欧美 | 久久成人一区二区 | 亚洲精品视频在线观看免费 | 美女网站黄免费 | 日韩欧美在线视频一区二区三区 | 狠色在线| 久久精品欧美日韩精品 | 欧美视频99| 日韩欧美亚州 | av三级av | 国产精品一区在线观看你懂的 | 日本久久久久 | 国产午夜精品理论片在线 | 97视频免费 | 99高清视频有精品视频 | 免费在线观看成人av | 最近中文字幕视频网 | 久草在线资源观看 | 久久美女免费视频 | 91免费高清观看 | 91精品入口 | 久久久91精品国产一区二区三区 | 成人羞羞视频在线观看免费 | 国产不卡av在线 | 日韩免费在线观看网站 | 免费视频18 | 国产精品久久久久久模特 | 亚洲成人精品在线 | 国产高清视频在线播放一区 | 久久国内免费视频 | 国产精品理论片 | 手机在线欧美 | 久久99网站 | 中文字幕高清在线 | 国产在线不卡一区 | 黄色软件在线观看 | 激情av五月婷婷 | 国产精品区免费视频 | 亚洲综合欧美激情 | 日韩精品一区二区在线观看视频 | 婷婷成人亚洲综合国产xv88 | 成人久久网 | 97超碰在线免费观看 | 久久精品三级 | 精品高清美女精品国产区 | 久久视频精品在线观看 | 久草久草在线 | 亚洲精品影视在线观看 | 成人av电影免费在线观看 | 免费在线观看的av网站 | 黄色小说视频网站 | 中文字幕在线精品 | 五月婷婷免费 | 久久97久久97精品免视看 | 国产一区二区在线免费 | 色婷婷综合久久久 | 久久艹综合 | 日韩成人高清在线 | 丁香视频五月 | 特级黄色片免费看 | 香蕉久久久久久av成人 | 精品伦理一区二区三区 | 欧美一区二区三区激情视频 | 久久高清片 | 精品不卡视频 | 在线免费国产 | 人人干在线观看 | 狠狠干夜夜爱 | 美女黄视频免费 | 免费网站在线观看人 | 特级毛片在线 | 精品一区三区 | 国产精品免费观看国产网曝瓜 | 亚洲综合在线发布 | 欧美在线free | 日韩欧美国产精品 | 日韩免费网址 | 五月婷婷综合在线 | 久久不卡国产精品一区二区 | 一区二区三区视频网站 | 精品国产一区二区三区蜜臀 | 91欧美精品 | 免费看特级毛片 | 成年人在线电影 | 成人av电影免费观看 | 菠萝菠萝在线精品视频 | 91精品国自产拍天天拍 | 国产一区二区成人 | 91在线网址 | 免费视频资源 | 国产成人精品免费在线观看 | 日韩av午夜在线观看 | av成人动漫| 国产精品不卡一区 | 国内视频在线 | 在线观看91 | 四虎影视成人永久免费观看视频 | 91精品国产网站 | 亚洲欧美视频 | 成人免费观看av | 亚洲欧美精品一区 | 久草com | www免费网站在线观看 | 久久不卡电影 | 国产91电影在线观看 | 色婷婷激情四射 | 亚洲乱码久久久 | 波多野结衣在线播放一区 | 久久爱资源网 | 婷婷久久综合网 | 久久久性 | 中文字幕av在线免费 | 免费黄在线观看 | 中文字幕高清免费日韩视频在线 | 992tv又爽又黄的免费视频 | av看片网 | а天堂中文最新一区二区三区 | www黄色com | 国产91电影在线观看 | 激情xxxx| 四川妇女搡bbbb搡bbbb搡 | 日韩精品一区二区三区第95 | 久久怡红院 | 国产精品久久久久久爽爽爽 | 在线免费性生活片 | 天天天综合网 | 91福利国产在线观看 | 免费黄色a级毛片 | 精品久久久久久久久久久久久久久久久久 | 免费观看版 | 麻豆果冻剧传媒在线播放 | 成人欧美亚洲 | 久久九九影视网 | 国产亚洲精品久久久久久无几年桃 | 国产精品女 | 久久综合婷婷综合 | 久久激情片 | 91麻豆精品国产自产在线游戏 | 四虎在线免费视频 | 久热免费在线 | 99精品网站 | 中文字幕在线免费 | 国产午夜在线观看 | 日韩色综合网 | 国产精品福利在线观看 | 在线视频观看成人 | 黄色com | 狠狠干婷婷色 | av色综合网 | 精品国产伦一区二区三区 | 中文在线字幕免费观 | 亚洲男人天堂2018 | av高清在线观看 | 成人免费大片黄在线播放 | 国产一级一片免费播放放a 一区二区三区国产欧美 | 国产视频精选 | 久久久www成人免费精品张筱雨 | 91在线观看视频 | 国产日韩亚洲 | 精品毛片在线 | 久草在线免费色站 | 国产色在线,com | 日韩二级毛片 | 亚洲精品视频www | 91麻豆精品国产91 | 涩涩网站在线 | 久久视频在线观看中文字幕 | 高潮毛片无遮挡高清免费 | av中文字幕在线播放 | 久久69精品久久久久久久电影好 | 九九热视频在线 | 夜夜骑首页 | 天天插日日操 | 草樱av| 欧美一二三视频 | 97视频资源| 亚洲成人家庭影院 | 东方av在| 国产精品一区二区在线免费观看 | 天天操,夜夜操 | 欧美日韩在线第一页 | 成人av亚洲 | 97国产精品亚洲精品 | 中文在线免费观看 | 在线小视频国产 | 又黄又爽又刺激的视频 | 日韩av高潮 | 久久久在线| 嫩草91影院 | 超碰97中文 | 中文av网 | 一区二区三区在线观看免费视频 | 96国产在线| 日韩三级免费观看 | 国产1区2区| 青草视频免费观看 | 中文字幕免费观看视频 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 国产午夜精品一区二区三区在线观看 | 亚洲电影网站 | 最近最新中文字幕视频 | 国产中年夫妇高潮精品视频 | 欧美精品第一 | 亚洲视频在线视频 | 麻豆91在线看 | 成人在线免费观看网站 | 亚洲精品午夜久久久 | 国产色爽 | 久久久久麻豆v国产 | 久久久久免费精品 | 亚洲成人午夜av | 在线免费观看视频一区二区三区 | 丁香花在线视频观看免费 | 国产成人精品福利 | 亚洲视频一区二区三区在线观看 | 亚洲日本成人 | 欧美淫aaa免费观看 日韩激情免费视频 | 在线亚洲欧美日韩 | 一区二区三区四区在线免费观看 | 激情五月婷婷激情 | 亚洲精品午夜久久久久久久久久久 | 青草视频在线看 | 97视频网址| 国产高清视频在线观看 | 最新超碰| 91在线九色 | 在线观看精品国产 | 国产免费一区二区三区网站免费 | 久久视奸 | 水蜜桃亚洲一二三四在线 | 国模精品一区二区三区 | 欧美一级电影 | 午夜视频福利 | 日韩av黄 | 国产在线超碰 | 黄色大片中国 | 日韩免费看视频 | 日韩视频图片 | 欧美va在线观看 | 人人澡人人添人人爽一区二区 | 午夜精品久久久久久 | 久久国产成人午夜av影院潦草 | 久久丝袜视频 | 亚洲丝袜一区 | 精品久久久久久国产91 | 麻豆91小视频 | 正在播放久久 | 亚洲黄色片 | 精品黄色视 | 久久激情日本aⅴ | 在线观看免费观看在线91 | 精品福利在线 | 黄色软件在线观看免费 | 亚洲永久精品在线观看 | 亚洲另类视频在线 | 欧美日韩中文在线 | 日韩网站中文字幕 | 亚洲视频精品在线 | 欧美性生活免费看 | 亚洲精品乱码久久久久久9色 | 久亚洲精品 | 国产免费小视频 | 91日韩精品 | 日韩在线电影观看 | 69精品在线观看 | 亚洲 在线 | 久久黄色免费视频 | 中文av网 | 久久久久二区 | 热久久国产精品 | 亚洲h色精品| 天天狠狠操 | 国产精品免费av | 国产欧美精品xxxx另类 | 国产精品国产三级国产aⅴ9色 | 亚洲精品黄色在线观看 | 欧美另类xxxx| 日韩av一区二区三区四区 | 久草在线高清视频 | 91亚洲国产 | 欧美aaa一级| 精品久久91 | 人人看人人| 日韩电影在线观看一区二区三区 | 成人av网站在线观看 | 亚洲精品在线观看av | 天天干,天天插 | 国产婷婷vvvv激情久 | 日韩精品在线播放 | 99久久精品无码一区二区毛片 | 狠狠干狠狠色 | 亚洲专区一二三 | 婷婷丁香花五月天 | 欧美日韩免费视频 | 久久久国内精品 | 中文字幕成人 | 久久久黄色免费网站 | 极品嫩模被强到高潮呻吟91 | 国产精品久久久久久久久久了 | 伊人日日干 | 99久久久久久久久 | 国产字幕在线看 | 亚洲欧洲精品视频 | 成人av一区二区兰花在线播放 | 国产成人三级 | 中文字幕欧美日韩va免费视频 | 精品二区久久 | 婷婷久操| 草久电影 | 欧美做受高潮1 | 国产精品久久久久影院 | 日韩在线观看一区 | 99精品小视频 | 手机看片午夜 | 黄色三级在线观看 | 正在播放五月婷婷狠狠干 | 日韩理论视频 | 午夜骚影 | 中文字幕免费久久 | 狠狠久久综合 | 精品美女在线观看 | 蜜臀aⅴ国产精品久久久国产 | 日韩免费在线一区 | 韩日精品在线 | 中文字幕在线观看第一页 | 正在播放国产91 | 国产精品视频免费观看 | 一级一级一片免费 | 国产精品欧美一区二区 | 99爱精品在线 | 国精产品999国精产品视频 | 日本在线观看中文字幕 | 久久99久久99精品 | 亚洲特级片 | 粉嫩一二三区 | 久久人人97超碰com | 六月丁香在线观看 | 国产最顶级的黄色片在线免费观看 | 1区2区3区在线观看 三级动图 | 日韩视频中文字幕 | 99亚洲国产 | 国产精彩视频 | 日韩免费不卡av | 亚洲成av人片在线观看无 | 人人澡超碰碰97碰碰碰软件 | 六月丁香在线观看 | www视频免费在线观看 | 亚洲成年人免费网站 | 国产精品美女久久久久久免费 | 天天干夜夜操视频 | 午夜免费福利视频 | 成人av.com | 日韩午夜精品福利 | 国产精品视频永久免费播放 | 可以免费看av | 92精品国产成人观看免费 | 国产精品麻豆欧美日韩ww | 久久国产精品99久久久久久进口 | 欧美日韩视频一区二区三区 | 97成人在线| 久久美女视频 | 激情欧美网 | 久久天天躁狠狠躁夜夜不卡公司 | 国产1级视频 | 欧美韩国日本在线 | 91精品国产三级a在线观看 | 欧美在线观看小视频 | 欧美国产日韩一区二区三区 | 九九涩涩av台湾日本热热 | 免费网站在线观看人 | 在线观看www视频 | 操高跟美女 | 国产精品麻豆91 | 国产精品免费看 | 天天干天天插 | 成人免费视频网址 | 黄色三级久久 | 免费看污网站 | 国产成人亚洲在线观看 | 免费av观看网站 | 国产精品久久久久免费观看 | 91久久爱热色涩涩 | 伊人中文字幕在线 | 99精品视频在线观看视频 | 免费能看的黄色片 | 88av视频 | 黄色av在| 91精品一 | 日韩在线观看视频一区二区三区 | 欧美一级黄色网 | 国产资源免费 | 日本高清免费中文字幕 | 色婷婷激情 | 西西44人体做爰大胆视频 | 香蕉在线影院 | 久草网在线| 成人av在线观 | 黄色av网站在线观看 | 激情网婷婷 | 美女黄网久久 | 特级西西444www高清大视频 | 色视频在线免费 | 香蕉视频在线网站 | 免费观看黄 | 久久不射电影网 | 99在线热播精品免费99热 | 日韩网 | 久久综合九色综合97婷婷女人 | 久久激情精品 | 九九激情视频 | 国产精品美女久久久久久久 | 一区二区成人国产精品 | 国产精品精品国产 | 免费的国产精品 | 亚洲一区日韩精品 | av免费成人| 午夜精品久久久久久久99婷婷 | 99久久99久久免费精品蜜臀 | 国产二级视频 | 中国老女人日b | 精品国产免费一区二区三区五区 | 亚洲v精品 | 97视频在线观看成人 | 亚洲欧美日韩精品久久久 | 国产成人精品电影久久久 | 久久1区 | 欧美有色| 久久国语露脸国产精品电影 | 成人免费一区二区三区在线观看 | 日韩欧美网站 | 天天操天天是 | 99热在线观看免费 | 99视频偷窥在线精品国自产拍 | 三级黄色大片在线观看 | 五月天天色 | 日韩特级黄色片 | 久久这里只有精品9 | 国产精品第一视频 | 日韩在线免费电影 | 中文字幕色在线视频 | 国产日韩视频在线播放 | 狠狠色狠狠综合久久 | 成人九九视频 | 中日韩免费视频 | 91完整视频 | 91麻豆精品国产91 | 激情综合网五月 | 国产精品视频永久免费播放 | 色婷婷骚婷婷 | 永久免费观看视频 | 国产免费高清视频 | 97视频免费 | 国产一区二区在线播放 | 久久精品日产第一区二区三区乱码 | 久久精品国产成人 | 在线观看成人国产 | 成人国产电影在线观看 | 免费观看国产视频 | 亚洲免费专区 | 国产一区二区高清 | 奇米网在线观看 | 国产精品永久久久久久久久久 | 国产精品久久久久影院日本 | 日韩在线国产 | 国产精品一区二区吃奶在线观看 | 日本美女xx | 波多野结衣精品 | 99视频在线精品免费观看2 | 91女人18片女毛片60分钟 | 欧美成人精品欧美一级乱 | 91在线看黄| 最新精品国产 | 在线观看www. | 免费观看av网站 | 久久99国产综合精品 | 亚洲精品国产第一综合99久久 | 一级黄网| 久草视频免费 | 久久久久北条麻妃免费看 | 欧美成人久久 | 亚洲综合射 | 国产精品久久久久久久久久尿 | 久热久草在线 | 男女全黄一级一级高潮免费看 | 日韩精品欧美专区 | 国内久久久久 | 激情婷婷在线 | 日韩精品一区在线观看 | 国产拍揄自揄精品视频麻豆 | 中文字幕在线观看第一区 | 中国一级片免费看 | 亚洲精品视频免费看 | 美女在线观看av | 欧洲av在线 | 亚洲精品mv在线观看 | 天天综合操 | ww亚洲ww亚在线观看 | 日韩精品免费一线在线观看 | 99免费精品视频 | 久久久久久久久久免费视频 | 五月婷婷.com| 玖玖视频精品 | 狠狠操狠狠干天天操 | 久久avav| 91精品秘密在线观看 | 国产免码va在线观看免费 | 91精品国自产在线观看欧美 | 日本最大色倩网站www | 在线成人小视频 | 天天爽天天碰狠狠添 | 91精品视频免费看 | 超碰在线亚洲 | 狠狠ri| 九九九热精品免费视频观看 | 国产在线第三页 | 日韩精品高清不卡 | 国产在线播放一区二区 | 97人人网 | 波多野结衣在线播放一区 | 婷婷丁香激情 | 亚洲黄色片在线 | 国产精彩视频一区 | 久精品视频在线观看 | 国产区精品视频 | 久久伦理 | 成人久久久电影 | 色精品视频 | 精品国产片 | 中文字幕免费高清 | 国产特级毛片aaaaaa高清 | 一区二区三区免费在线观看视频 | 国产精品女教师 | 麻豆 videos| 亚洲另类视频 | 四虎在线免费 | 中文字幕在线有码 | 亚洲视频精品在线 | 手机av片| 国产麻豆视频免费观看 | 人人舔人人 | 97超碰影视 | 亚洲第一av在线播放 | 亚洲日韩中文字幕 | 91人人爽人人爽人人精88v | 日韩美女免费线视频 | 色wwww| 丁香五月亚洲综合在线 | 黄色av网站在线观看免费 | 91精品秘密在线观看 | 一区二区三区在线影院 | 日本久久精 | 国产性天天综合网 | www狠狠| 成年人国产视频 | 久草手机视频 | 亚洲精品色视频 | 天天躁日日躁狠狠躁av麻豆 | 国产精品99久久免费黑人 | 免费瑟瑟网站 | 17videosex性欧美 | 亚洲国产精品第一区二区 | 久久久91精品国产一区二区三区 | 四虎影视国产精品免费久久 | 亚洲精品综合欧美二区变态 | 在线香蕉视频 | 精品91| 91av官网 | 欧美一区在线观看视频 | 国产免费区 | 2024国产精品视频 | 国产在线精 | 天天色天天射天天综合网 | 97夜夜澡人人双人人人喊 | 免费在线观看污 | 国产三级久久久 | 久久色亚洲| 五月天婷婷综合 | 最近2019年日本中文免费字幕 | 91网站观看| 91chinesexxx| 久久视频二区 | 天天插天天狠天天透 | 午夜精品导航 | 一区二区三区中文字幕在线 | 中文字幕日韩高清 | 久久国产精品一区二区三区 | 五月天激情综合网 | av韩国在线| 一区二区成人国产精品 | 97国产精品一区二区 | 涩涩在线 | 中文字幕一二 | 久久伊人婷婷 | 国产精品免费麻豆入口 | 国产福利免费在线观看 | 日韩三级免费 | 国产一级特黄毛片在线毛片 | 美国av片在线观看 | 日韩av午夜 | 91精品国产九九九久久久亚洲 | 亚洲精品在线观看不卡 | 国产91精品一区二区绿帽 | 香蕉久草在线 | 97成人资源站 | 中文字幕免费高清在线观看 | 91精品一区二区三区蜜桃 | 色老板在线 | 欧美aa一级| 91探花系列在线播放 | 欧美日韩精品电影 | 日韩一区二区三区免费视频 | 久久手机免费观看 | 成人av高清 | 成人一级免费电影 | 一区二区男女 | 在线你懂 | 欧美无极色 | 日韩电影久久 | 国产黄色大片 | 亚洲永久精品在线观看 | www.久久免费视频 | 日韩最新在线 | 国产在线精品视频 | 天天在线视频色 | 黄色av免费在线 | 久久久久久久久久久久久国产精品 | 国产午夜精品免费一区二区三区视频 | 蜜臀久久99精品久久久无需会员 | 97视频总站| 精品特级毛片 | 久久久久久久久精 | 综合久久婷婷 | 国产精品入口麻豆www | 日韩成人一级大片 | 欧美国产日韩激情 | 91精品国产91热久久久做人人 | 欧美成人精品欧美一级乱黄 | 久久激情影院 | 中文字幕日韩精品有码视频 | 手机av资源 | 99热这里只有精品8 久久综合毛片 | 天天舔天天搞 | 免费看一级一片 | 青春草视频 | 国内精品美女在线观看 | 夜夜高潮夜夜爽国产伦精品 | 成人网在线免费视频 | 国产一区二区在线播放 | 国产精品亚洲视频 | 91完整版在线观看 | 国产专区免费 | 欧美一级片在线 | 午夜视频在线观看网站 | 激情欧美日韩一区二区 | 99爱视频在线观看 | 亚洲国产美女精品久久久久∴ | 97品白浆高清久久久久久 | 三级av网站| 国产一级二级三级在线观看 | 亚洲日b视频 | 亚洲精品高清一区二区三区四区 | 91污污视频在线观看 | 91精品久久久久久粉嫩 | 欧美少妇xx| 免费看搞黄视频网站 | 在线观看911视频 | 一区二区精品视频 | 国产又粗又猛又爽又黄的视频免费 | 国产精品国产三级国产 | 欧美巨大| 免费视频久久 | 人人插人人舔 | 天天夜操| 久久久久久久免费看 | 91精品一区国产高清在线gif | 中文字幕 国产视频 | 91最新在线观看 | 狠狠综合久久av | 粉嫩高清一区二区三区 | 男女啪啪网站 | 婷婷久久综合九色综合 | 五月天中文字幕mv在线 | 九七在线视频 | 亚洲精品免费看 | 国产1区2 | 亚洲精品在线视频播放 | 九九热国产 | 91香蕉视频色版 | 欧美日韩视频免费 | 亚洲精品三级 | 久久草在线免费 | 九九免费观看视频 | 99久久日韩精品免费热麻豆美女 | 亚洲国产日本 | 草莓视频在线观看免费观看 | 久久久久国产精品免费免费搜索 | 人人爱人人舔 | 日韩高清观看 | 成人一级片在线观看 | 久久综合久久综合这里只有精品 | 久久亚洲欧美 | 国产一区网址 | 色多多污污在线观看 | 免费成人看片 | 国内免费的中文字幕 | 人人爽人人 | 人人爽人人插 | 精品视频www | 亚洲无毛专区 | 日韩中文字幕免费视频 | 久久人人爽av| 婷婷九九| 在线观看av免费观看 | 婷婷亚洲最大 | 一区二区三区在线不卡 | 91porny九色91啦中文 | 超碰在线网 | 99精品系列| 97视频人人免费看 | 99久久久久免费精品国产 | 91精品久久久久久综合五月天 | 国产精品久久久久高潮 | 99久久国产免费,99久久国产免费大片 | 亚洲精品男女 | 最新中文字幕在线观看视频 | 国产69精品久久久久99尤 | 亚洲国产精品影院 | 少妇bbb好爽| 国产精品久久婷婷六月丁香 | 97品白浆高清久久久久久 | 国产美女网 | 精品一区二区在线免费观看 | 欧美视频www| 中文在线免费观看 | 久久国产福利 | 国产高清精 | 久久99精品国产麻豆婷婷 | 日韩中文字幕91 | 激情综合国产 | 夜色资源站国产www在线视频 | 国产在线观看免费 | 最新久久免费视频 | 免费视频色 | 全久久久久久久久久久电影 | 国产手机在线播放 | 在线观看v片 | 国内精品久久久 | 久久超级碰 | 国产美女视频免费观看的网站 | 永久精品视频 | 人人爱人人射 | www.狠狠干 | 久草视频免费 | 成人亚洲免费 | 国产精品资源 | 国产成人精品一区二三区 | 欧美激情视频久久 | 中文字幕一区二区三区四区视频 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 91尤物国产尤物福利在线播放 | 日韩免费在线观看 | 午夜国产福利在线观看 | 国产精品区一区 | 成人国产精品入口 | 亚洲激情在线视频 | 亚洲专区欧美 | 最近日本中文字幕a | 成人午夜精品福利免费 | 日韩高清在线一区 | 色婷婷国产精品一区在线观看 | 99精品在线视频观看 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 欧美久草视频 | 2021国产在线视频 | 国产97在线播放 | 日韩天天综合 | 97人人澡人人添人人爽超碰 | 四虎影视成人 | 国产美女精品久久久 | 国产精品久久久久久久99 | 中文字幕在线看视频国产中文版 | 免费看污网站 | 国产黄色精品在线 | 91精品国产成| av资源在线看 | 91精品国产欧美一区二区 | 五月天国产 | 在线观看免费高清视频大全追剧 | 亚洲精品在线免费 | 婷婷性综合 | 97精品国产97久久久久久久久久久久 | 久久不射电影院 | 日韩二区精品 | 91麻豆.com| 国产一线在线 | 国产精品99久久免费观看 | 精品久久久免费 | 成人免费视频播放 | 丰满少妇在线观看 | 日韩av高清在线观看 | 日操干| 菠萝菠萝蜜在线播放 | 日韩精品一区二区三区高清免费 | 91av在线精品 | 激情丁香综合五月 | 国产精品99久久久久久大便 | www99久久 | 成人av一区二区兰花在线播放 | 99久久99久久免费精品蜜臀 | 日韩免费视频线观看 | 免费观看完整版无人区 | 日韩欧美在线影院 | 日本久久久精品视频 | 国产午夜精品免费一区二区三区视频 | 欧美一区二区三区在线播放 | 久久五月婷婷综合 | 人人爽人人爽人人片av免 | 亚洲成年人av | 日韩在线观看视频中文字幕 | 男女靠逼app | 国产高清亚洲 | 久青草影院 | 婷婷综合视频 | 日韩特黄一级欧美毛片特黄 | 人人插人人| 成人午夜精品福利免费 | 国产a级精品 | 久久99国产精品久久99 | 日韩电影一区二区在线 | 人人爽人人看 | 精品久久五月天 | 中文字幕在线观看不卡 | 欧美久久久久久久久中文字幕 | 亚洲视频在线免费观看 | 黄a在线看| 91av在线视频免费观看 | 波多野结衣在线观看一区 | 国产视频黄 | 在线看小早川怜子av | 欧美另类色图 | 亚洲爽爽网 | 亚洲激情免费 | 黄色免费观看 | 一级黄色片在线播放 | 六月婷婷网 | 色吊丝av中文字幕 | 成人黄视频 | 国产成人精品一区二 | 992tv成人免费看片 | 韩日电影在线观看 | 久青草视频在线观看 | 国产午夜一区二区 | 久久观看最新视频 | 在线观看亚洲国产 | 啪啪av在线 | 精品视频国产一区 | 久青草视频 | 亚洲国产大片 | 特黄一级毛片 | 玖玖视频精品 | 狠狠躁夜夜躁人人爽超碰91 | 中文字幕在线观看播放 | www.久久久.cum | 久久精品欧美视频 | 视频一区二区免费 | 色综合天天色 | 欧美日韩高清免费 | 免费看的毛片 | 91传媒在线观看 | 午夜黄色影院 | 91精品一区二区三区久久久久久 | 伊人永久 | 高清久久久| 日韩一区二区三区高清免费看看 | 91精品视频观看 | 欧美久久九九 | 日韩91在线 | 有码中文字幕 | 四虎国产精 | 91久久久久久久 | 99精品国产兔费观看久久99 | 成人性生交大片免费看中文网站 | 五月丁香 | 亚洲欧洲国产精品 | 亚洲午夜久久久久久久久久久 | 波多野结衣小视频 | 久久国产影视 | 日日爱夜夜爱 | av在线收看 | 亚洲综合色视频在线观看 | 91人人爱 | 2017狠狠干| 一级全黄毛片 | 国语自产偷拍精品视频偷 | 99精品视频在线免费观看 | 国产精品一区二区三区四 | 欧美尹人| 国产999久久久 | 超碰在线免费97 | 成 人 免费 黄 色 视频 | 亚洲91精品在线观看 | 日韩视频免费观看高清 | 天干啦夜天干天干在线线 | 99精品视频免费看 | 国产一区二区久久精品 | 国产精品ssss在线亚洲 | 99亚洲国产 | 亚洲国产999| 五月天激情婷婷 | 久久97久久97精品免视看 | 在线播放国产精品 | 黄色国产成人 | 国产香蕉久久精品综合网 | 免费黄色av电影 | 精品视频免费久久久看 | 青青五月天 | 精品人人人人 | 91亚洲精品久久久中文字幕 | 久久久亚洲麻豆日韩精品一区三区 | 免费91在线观看 | 亚洲精品日韩在线观看 | 国产日韩中文字幕 | 国产中文字幕久久 | 久久免费黄色大片 | 免费在线成人av电影 | 蜜臀久久99精品久久久无需会员 | 亚洲专区在线 | 精品久久一级片 | 欧美成人黄色片 | 丝袜美腿在线视频 | 久草网站在线观看 | 开心色停停 | 国产日韩高清在线 | 国内一级片在线观看 | www.久草视频 | 午夜久久成人 | 精品国产成人av在线免 | 精品亚洲男同gayvideo网站 | 亚洲一区免费在线 | 午夜视频二区 | 又黄又爽又刺激视频 | 深夜免费福利视频 | 伊人婷婷网 | 美女视频一区 | 国产永久免费高清在线观看视频 | 亚洲精品日韩在线观看 | 中文字幕av日韩 | 国产九九九视频 | 7777精品伊人久久久大香线蕉 | 日韩视频免费 | 久久视频在线 | 国产一在线精品一区在线观看 | 久久成熟 | 久草电影免费在线观看 | 婷婷综合五月天 | 麻豆一精品传二传媒短视频 | 亚洲japanese制服美女 | 国产亚洲视频中文字幕视频 | www.天天射 | 成 人 黄 色 片 在线播放 | 亚洲一区动漫 | 在线观看亚洲专区 | 手机在线看永久av片免费 | www.色综合.com| 久久久久网址 | 麻豆国产露脸在线观看 | 国产精品美女www爽爽爽视频 |