?
Dokumen ini menggunakan Manual laman web PHP Cina Lepaskan
絕大多數(shù)JDBC驅(qū)動(dòng)針對(duì)批量調(diào)用相同的prepared statement對(duì)象提供了性能提升。通過(guò)將這些更新操作封裝到一個(gè)批量操作中,可以大量減少與數(shù)據(jù)庫(kù)的操作頻繁度。 本章節(jié)將詳細(xì)描述使用JdbcTemplate或者SimpleJdbcTemplate進(jìn)行批量操作的流程。
JdbcTemplate的批量操作特性需要實(shí)現(xiàn)特定的接口BatchPreparedStatementSetter
來(lái)進(jìn)行的, 通過(guò)實(shí)現(xiàn)這個(gè)接口,并將其傳入batchUpdate
方法進(jìn)行調(diào)用。
這個(gè)接口有兩個(gè)方法需要實(shí)現(xiàn)。一個(gè)叫做getBatchSize
來(lái)提供當(dāng)前需要批量操作的數(shù)量。另外一個(gè)方法是setValues
允許你為prepared statement設(shè)置參數(shù)。這個(gè)方法將在整個(gè)過(guò)程中被調(diào)用的次數(shù),則取決于你在getBatchSize
中所指定的大小。
下面的示例展示了根據(jù)傳入的list參數(shù)更新actor表,而傳入的list同時(shí)作為批量操作的參數(shù)。
public class JdbcActorDao implements ActorDao { private JdbcTemplate jdbcTemplate; public void setDataSource(DataSource dataSource) { this.jdbcTemplate = new JdbcTemplate(dataSource); } public int[] batchUpdate(final List 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, ((Actor)actors.get(i)).getFirstName()); ps.setString(2, ((Actor)actors.get(i)).getLastName()); ps.setLong(3, ((Actor)actors.get(i)).getId().longValue()); } public int getBatchSize() { return actors.size(); } } ); return updateCounts; } // ... additional methods }
如果你是通過(guò)讀取文件進(jìn)行批量操作,那么你可能需要一個(gè)特定的批量操作的數(shù)量,不過(guò)最后一次的批量操作,你可能沒(méi)有那么多數(shù)量的記錄。
在這種情況下,你可以實(shí)現(xiàn)InterruptibleBatchPreparedStatementSetter
接口,從而允許你在某些情況中斷批量操作,isBatchExhausted
方法允許你指定一個(gè)終止批量操作的信號(hào)量。
SimpleJdbcTemplate
類(lèi)提供了另外一種批量操作的方式。無(wú)需實(shí)現(xiàn)一個(gè)特定的接口,你只需要提供所有在調(diào)用過(guò)程中要用到的參數(shù),框架會(huì)遍歷這些參數(shù)值,并使用內(nèi)置的prepared statement類(lèi)進(jìn)行批量操作。API將根據(jù)你是否使用命名參數(shù)而有所不同。對(duì)于使用命名參數(shù)的情況,你需要提供一個(gè)SqlParameterSource
的數(shù)組, 其中的每個(gè)元素將將作為批量操作的參數(shù)。
你可以使用SqlParameterSource.createBatch
方法,通過(guò)傳入一個(gè)JavaBean的數(shù)組或者一個(gè)包含了參數(shù)鍵值對(duì)的Map數(shù)組來(lái)創(chuàng)建這個(gè)數(shù)組。
下面的示例展示了使用命名參數(shù)進(jìn)行批量更新的方法:
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource); } public int[] batchUpdate(final List<Actor> actors) { SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(actors.toArray()); int[] updateCounts = simpleJdbcTemplate.batchUpdate( "update t_actor set first_name = :firstName, last_name = :lastName where id = :id", batch); return updateCounts; } // ... additional methods }
對(duì)于使用傳統(tǒng)的“?”作為參數(shù)占位符的情況,你可以傳入一個(gè)List,包含了所有需要進(jìn)行批量更新的對(duì)象。這樣的對(duì)象數(shù)組必須與每個(gè)SQL Statement的占位符以及他們?cè)赟QL Statement中出現(xiàn)的位置一一對(duì)應(yīng)。
下面是同樣的例子,使用的傳統(tǒng)的“?”作為參數(shù)占位符:
public class JdbcActorDao implements ActorDao { private SimpleJdbcTemplate simpleJdbcTemplate; public void setDataSource(DataSource dataSource) { this.simpleJdbcTemplate = new SimpleJdbcTemplate(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 = simpleJdbcTemplate.batchUpdate( "update t_actor set first_name = ?, last_name = ? where id = ?", batch); return updateCounts; } // ... additional methods }
所有的批量更新的方法都會(huì)返回一組int的數(shù)組,表示在整個(gè)操作過(guò)程中有多少記錄被批量更新。 這個(gè)數(shù)量是由JDBC驅(qū)動(dòng)所返回的,有時(shí)這個(gè)返回并不可靠,尤其對(duì)于某些JDBC驅(qū)動(dòng)只是簡(jiǎn)單的返回-2作為返回值。