jdbcTemplate 详细使用

RowMapper:用于将结果集每行数据转换为需要的类型,用户需实现方法mapRow(ResultSet rs, int rowNum)来完成将每行数据转换为相应的类型。         

RowCallbackHandler:用于处理ResultSet的每一行结果,用户需实现方法processRow(ResultSet rs)来完成处理,在该回调方法中无需执行rs.next(),该操作由JdbcTemplate来执行,用户只需按行获取数据然后处理即可。

ResultSetExtractor:用于结果集数据提取,用户需实现方法extractData(ResultSet rs)来处理结果集,用户必须处理整个结果集;

//1.查询一行数据并返回int型结果

jdbcTemplate.queryForInt("select count(*) from test");

//2. 查询一行数据并将该行数据转换为Map返回

jdbcTemplate.queryForMap("select * from test where name='name5'");

//3.查询一行任何类型的数据,最后一个参数指定返回结果类型

jdbcTemplate.queryForObject("select count(*) from test", Integer.class);

//4.查询一批数据,默认将每行数据转换为Map     

jdbcTemplate.queryForList("select * from test");

//5.只查询一列数据列表,列类型是String类型,列名字是name

jdbcTemplate.queryForList("

select name from test where name=?", new Object[]{"name5"}, String.class);

//6.查询一批数据,返回为SqlRowSet,类似于ResultSet,但不再绑定到连接上

SqlRowSet rs = jdbcTemplate.queryForRowSet("select * from test");

其中下面这些查询方法支持多列结果集:

List query(String sql, RowMapper rowMapper)

Map queryForMap(String sql)

Object queryForObject(String sql, RowMapper rowMapper)

List queryForList(String sql)

其他不支持多列结果集的查询方法则会抛出IncorrectResultSetColumnCountException异常。

从上面的结果可以看出只有返回值类型为List的方法可以接收零到多行结果集而不抛出异常,

所以在使用query方法及queryForXXX方法时需要注意处理EmptyResultDataAccessException和IncorrectResultSizeDataAccessException这两个异常,

这两个异常反映出数据库表中数据可能出现了缺失或冗余。如果返回值不符合期望值时,则需要排查业务流程或者数据了。

最后我们来看看RowMapper接口,这个接口的实现类的功能是将结果集中的每一行数据封装成用户定义的结构,所以在查询方法中经常会被用到。

Spring框架为我们提供了BeanPropertyRowMapper/ParameterizedBeanPropertyRowMapper,ColumnMapRowMapper和SingleColumnRowMapper这三大便利类。

BeanPropertyRowMapper类与ParameterizedBeanPropertyRowMapper类的功能完全相同,当POJO对象和数据库表字段完全对应或者驼峰式与下划线式对应时,

该类会根据构造函数中传递的class来自动填充数据。只是ParameterizedBeanPropertyRowMapper类使用泛型需要JDK5+支持。这里需要注意虽然这两个类提供了便利,

但是由于使用反射导致性能下降,所以如果需要高性能则还是需要自己去实现RowMapper接口来包装数据。

ColumnMapRowMapper类返回一个List对象,对象中的每一个元素都是一个以列名为key的Map对象。

SingleColumnRowMapper类也返回一个List对象,对象中的每个元素是数据库中的某列的值。注意结果集必须是单列,不然会抛出IncorrectResultSetColumnCountException异常。

JdbcTemplate是core包的核心类。它替我们完成了资源的创建以及释放工作,从而简化了我们对JDBC的使用。它还可以帮助我们避免一些常见的错误,比如忘记关闭数据库连接。

JdbcTemplate将完成JDBC核心处理流程,比如SQL语句的创建、执行,而把SQL语句的生成以及查询结果的提取工作留给我们的应用代码。它可以完成SQL查询、更新以及调用存储过程,

可以对ResultSet进行遍历并加以提取。它还可以捕获JDBC异常并将其转换成org.springframework.dao包中定义的,通用的,信息更丰富的异常。

使用JdbcTemplate进行编码只需要根据明确定义的一组契约来实现回调接口。PreparedStatementCreator回调接口通过给定的Connection创建一个PreparedStatement,

包含SQL和任何相关的参数。CallableStatementCreateor实现同样的处理,只不过它创建的是CallableStatement。RowCallbackHandler接口则从数据集的每一行中提取值。

我们可以在一个service实现类中通过传递一个DataSource引用来完成JdbcTemplate的实例化,也可以在application context中配置一个JdbcTemplate bean,

来供service使用。需要注意的是DataSource在application context总是配制成一个bean,第一种情况下,DataSource bean将传递给service,

第二种情况下DataSource bean传递给JdbcTemplate bean。因为JdbcTemplate使用回调接口和SQLExceptionTranslator接口作为参数,所以一般情况下没有必要通过继承JdbcTemplate来定义其子类。

JdbcTemplate中使用的所有SQL将会以“DEBUG”级别记入日志(一般情况下日志的category是JdbcTemplate相应的全限定类名,不过如果需要对JdbcTemplate进行定制的话,可能是它的子类名)。

1. NamedParameterJdbcTemplate类

NamedParameterJdbcTemplate类增加了在SQL语句中使用命名参数的支持。在此之前,在传统的SQL语句中,参数都是用'?'占位符来表示的。NamedParameterJdbcTemplate类内部封装了一个普通的JdbcTemplate,

并作为其代理来完成大部分工作。下面的内容主要针对NamedParameterJdbcTemplate与JdbcTemplate的不同之处来加以说明,即如何在SQL语句中使用命名参数。

通过下面的例子我们可以更好地了解NamedParameterJdbcTemplate的使用模式(在后面我们还有更好的使用方式)。

// some JDBC-backed DAO class...

public int countOfActorsByFirstName(String firstName) {

String sql = "select count(0) from T_ACTOR where first_name = :first_name";

NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());

SqlParameterSource namedParameters = new MapSqlParameterSource("first_name", firstName);

return template.queryForInt(sql, namedParameters);

}

在上面例子中,sql变量使用了命名参数占位符“first_name”,与其对应的值存在namedParameters变量中(类型为MapSqlParameterSource)。

如果你喜欢的话,也可以使用基于Map风格的名值对将命名参数传递给NamedParameterJdbcTemplate(NamedParameterJdbcTemplate实现了NamedParameterJdbcOperations接口,

剩下的工作将由调用该接口的相应方法来完成,这里我们就不再赘述):

// some JDBC-backed DAO class...

public int countOfActorsByFirstName(String firstName) {

String sql = "select count(0) from T_ACTOR where first_name = :first_name";

NamedParameterJdbcTemplate template = new NamedParameterJdbcTemplate(this.getDataSource());

Map namedParameters = new HashMap();

namedParameters.put("first_name", firstName);

return template.queryForInt(sql, namedParameters);

}

另外一个值得一提的特性是与NamedParameterJdbcTemplate位于同一个包中的SqlParameterSource接口。在前面的代码片断中我们已经看到了该接口的实现

(即MapSqlParameterSource类),SqlParameterSource可以用来作为NamedParameterJdbcTemplate命名参数的来源。MapSqlParameterSource类是一个非常简单的实现,

它仅仅是一个java.util.Map适配器,当然其用法也就不言自明了(如果还有不明了的,可以在Spring的JIRA系统中要求提供更多的相关资料)。

SqlParameterSource接口的另一个实现--BeanPropertySqlParameterSource为我们提供了更有趣的功能。该类包装一个类似JavaBean的对象,所需要的命名参数值将由包装对象提供,

大家必须牢记一点:NamedParameterJdbcTemplate类内部包装了一个标准的JdbcTemplate类。如果你需要访问其内部的JdbcTemplate实例(比如访问JdbcTemplate的一些方法)

那么你需要使用getJdbcOperations()方法返回的JdbcOperations接口。(JdbcTemplate实现了JdbcOperations接口)。NamedParameterJdbcTemplate类是线程安全的,

该类的最佳使用方式不是每次操作的时候实例化一个新的NamedParameterJdbcTemplate,而是针对每个DataSource只配置一个NamedParameterJdbcTemplate实例

(比如在Spring IoC容器中使用Spring IoC来进行配置),然后在那些使用该类的DAO中共享该实例。

2.SimpleJdbcTemplate类

请注意该类所提供的功能仅适用于Java 5 (Tiger)。

SimpleJdbcTemplate类是JdbcTemplate类的一个包装器(wrapper),它利用了Java 5的一些语言特性,比如Varargs和Autoboxing。对那些用惯了Java 5的程序员,这些新的语言特性还是很好用的。

SimpleJdbcTemplate 类利用Java 5的语法特性带来的好处可以通过一个例子来说明。在下面的代码片断中我们首先使用标准的JdbcTemplate进行数据访问,接下来使用SimpleJdbcTemplate做同样的事情。

// classic JdbcTemplate-style...

public Actor findActor(long id) {

String sql = "select id, first_name, last_name from T_ACTOR where id = ?";

RowMapper mapper = new RowMapper() {

public Object mapRow(ResultSet rs, int rowNum) throws SQLException {

Actor actor = new Actor();

actor.setId(rs.getLong(Long.valueOf(rs.getLong("id"))));

actor.setFirstName(rs.getString("first_name"));

actor.setLastName(rs.getString("last_name"));

return actor;

}

};

// normally this would be dependency injected of course...

JdbcTemplate jdbcTemplate = new JdbcTemplate(this.getDataSource());

// notice the cast, and the wrapping up of the 'id' argument

// in an array, and the boxing of the 'id' argument as a reference type

return (Actor) jdbcTemplate.queryForObject(sql, mapper, new Object[] {Long.valueOf(id)});

}

下面是同一方法的另一种实现,惟一不同之处是我们使用了SimpleJdbcTemplate,这样代码显得更加清晰。

// SimpleJdbcTemplate-style...

public Actor findActor(long id) {

String sql = "select id, first_name, last_name from T_ACTOR where id = ?";

ParameterizedRowMapper<Actor> mapper = new ParameterizedRowMapper<Actor>() {

// notice the return type with respect to Java 5 covariant return types

public Actor mapRow(ResultSet rs, int rowNum) throws SQLException {

Actor actor = new Actor();

actor.setId(rs.getLong("id"));

actor.setFirstName(rs.getString("first_name"));

actor.setLastName(rs.getString("last_name"));

return actor;

}

};

// again, normally this would be dependency injected of course...

SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(this.getDataSource());

return simpleJdbcTemplate.queryForObject(sql, mapper, id);

}

11.3. 控制数据库连接

11.3.1. DataSourceUtils类

DataSourceUtils作为一个帮助类提供易用且强大的数据库访问能力, 我们可以使用该类提供的静态方法从JNDI获取数据库连接以及在必要的时候关闭之。 

它提供支持线程绑定的数据库连接(比如使用DataSourceTransactionManager 的时候,将把数据库连接绑定到当前的线程上)。

注:getDataSourceFromJndi(..)方法主要用于那些没有使用bean factory 或者application context的场合。如果使用application context,

那么最好是在JndiObjectFactoryBean中配置bean或者直接使用 JdbcTemplate实例。JndiObjectFactoryBean 

能够通过JNDI获取DataSource并将DataSource作为引用参数传递给其他bean。 这样,在不同的DataSource之间切换只需要修改配置文件即可, 

甚至我们可以用一个非JNDI的DataSource来替换FactoryBean定义!

11.3.2. SmartDataSource接口

SmartDataSource是DataSource 接口的一个扩展,用来提供数据库连接。使用该接口的类在指定的操作之后可以检查是否需要关闭连接。 

该接口在某些情况下非常有用,比如有些情况需要重用数据库连接。

11.3.3. AbstractDataSource类

AbstractDataSource是一个实现了DataSource 接口的abstract基类。它实现了DataSource接口的 一些无关痛痒的方法,如果你需要实现自己的DataSource,那么继承该类是个好主意。

11.3.4. SingleConnectionDataSource类

SingleConnectionDataSource是SmartDataSource接口 的一个实现,其内部包装了一个单连接。该连接在使用之后将不会关闭,很显然它不能在多线程 的环境下使用。

当客户端代码调用close方法的时候,如果它总是假设数据库连接来自连接池(就像使用持久化工具时一样), 你应该将suppressClose设置为true。 这样,通过该类获取的将是代理连接

(禁止关闭)而不是原有的物理连接。 需要注意的是,我们不能把使用该类获取的数据库连接造型(cast)为Oracle Connection之类的本地数据库连接。

SingleConnectionDataSource主要在测试的时候使用。 它使得测试代码很容易脱离应用服务器而在一个简单的JNDI环境下运行。 与DriverManagerDataSource不同的是,

它始终只会使用同一个数据库连接, 从而避免每次建立物理连接的开销。

11.3.5. DriverManagerDataSource类

DriverManagerDataSource类实现了SmartDataSource接口。在applicationContext.xml中可以使用 bean properties来设置JDBC Driver属性,该类每次返回的都是一个新的连接。

该类主要在测试以及脱离J2EE容器的独立环境中使用。它既可以用来在application context中作为一个DataSource bean,也可以在简单的JNDI环境下使用。

 由于Connection.close()仅仅只是简单的关闭数据库连接,因此任何能够获取DataSource的持久化代码都能很好的工作。不过使用JavaBean风格的连接池 (比如commons-dbcp)

 也并非难事。即使是在测试环境下,使用连接池也是一种比使用DriverManagerDataSource更好的做法。

11.3.6. TransactionAwareDataSourceProxy类

TransactionAwareDataSourceProxy作为目标DataSource的一个代理, 在对目标DataSource包装的同时,还增加了Spring的事务管理能力, 在这一点上,这个类的功能非常像J2EE服务器所提供的事务化的JNDIDataSource。

该类几乎很少被用到,除非现有代码在被调用的时候需要一个标准的 JDBC DataSource接口实现作为参数。 这种情况下,这个类可以使现有代码参与Spring的事务管理。

通常最好的做法是使用更高层的抽象 来对数据源进行管理,比如JdbcTemplate和DataSourceUtils等等。

11.3.7. DataSourceTransactionManager类

DataSourceTransactionManager类是PlatformTransactionManager接口的一个实现,用于处理单JDBC数据源。 它将从指定DataSource取得的JDBC连接绑定到当前线程,

因此它也支持了每个数据源对应到一个线程。我们推荐在应用代码中使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,而不是使用J2EE标准的DataSource.getConnection。

因为前者将抛出 unchecked的org.springframework.dao异常,而不是checked的SQLException异常。Spring Framework中所有的类(比如 JdbcTemplate)都采用这种做法。

如果不需要和这个 DataSourceTransactionManager类一起使用,DataSourceUtils 提供的功能跟一般的数据库连接策略没有什么两样,因此它可以在任何场景下使用。

DataSourceTransactionManager类支持定制隔离级别,以及对SQL语句查询超时的设定。 为了支持后者,应用代码必须使用JdbcTemplate或者在每次创建SQL语句时调用DataSourceUtils.applyTransactionTimeout方法。

在使用单个数据源的情形下,你可以用DataSourceTransactionManager来替代JtaTransactionManager, 因为DataSourceTransactionManager不需要容器支持JTA。

如果你使用DataSourceUtils.getConnection(DataSource)来获取 JDBC连接,二者之间的切换只需要更改一些配置。最后需要注意的一点就是JtaTransactionManager不支持隔离级别的定制!

用于查询的回调接口定义主要有以下三种: 

org.springframework.jdbc.core.ResultSetExtractor.  基本上属于JdbcTemplate内部使用的Callback接口,相对于下面两个Callback接口来说,ResultSetExtractor拥有更多的控制权,

因为使用它,你需要自行处理ResultSet: 

public interface ResultSetExtractor 

{ Object extractData(ResultSet rs) throws SQLException, DataAccessException; } 

在直接处理完ResultSet之后,你可以将处理后的结果以任何你想要的形式包装后返回。 

org.springframework.jdbc.core.RowCallbackHandler.  RowCallbackHandler相对于ResultSetExtractor来说,仅仅关注单行结果的处理,

处理后的结果可以根据需要存放到当前RowCallbackHandler对象内或者使用JdbcTemplate的程序上下文中,当然,这个完全是看个人爱好了。 RowCallbackHandler的定义如下: 

public interface RowCallbackHandler 

{ void processRow(ResultSet rs) throws SQLException; } 

org.springframework.jdbc.core.RowMapper.  ResultSetExtractor的精简版,功能类似于RowCallbackHandler,也只关注处理单行的结果,不过,处理后的结果会由ResultSetExtractor实现类进行组合。 RowMapper的接口定义如下: 

public interface RowMapper 

{ Object mapRow(ResultSet rs, int rowNum) throws SQLException; } 

为了说明这三种Callback接口的使用和相互之间的区别,我们暂且设定如下场景: 

数据库表customer中存在多行信息,对该表查询后,我们需要将每一行的顾客信息都映射到域对象Customer中,并以java.util.List的形式返回所有的查询结果。 

使用三种Callback接口作为参数的query方法的返回值不同: 

以ResultSetExtractor作为方法参数的query方法返回Object型结果,要使用查询结果,我们需要对其进行强制转型; 

以RowMapper接口作为方法参数的query方法直接返回List型的结果; 

以RowCallbackHandler作为方法参数的query方法,返回值为void; 

使用ResultSetExtractor作为Callback接口处理查询结果,我们需要自己声明集合类,自己遍历ResultSet,自己根据每行数据组装Customer对象,自己将组装后的Customer对象添加到集合类中,方法最终只负责将组装完成的集合返回; 

使用RowMapper比直接使用ResultSetExtractor要方便的多,只负责处理单行结果就行,现在,我们只需要将单行的结果组装后返回就行,剩下的工作,全部都是JdbcTemplate内部的事情了。 实际上,JdbcTemplae内部会使用一个ResultSetExtractor实现类来做其余的工作

JdbcTemplae内部使用的这个ResultSetExtractor实现类为org.springframework.jdbc.core.RowMapperResultSetExtractor, 它内部持有一个RowMapper实例的引用,当处理结果集的时候,会将单行数据的处理委派给其所持有的RowMapper实例,而其余工作它负责: 

public Object extractData(ResultSet rs) throws SQLException { 

List results = (this.rowsExpected > 0 ? new ArrayList(this.rowsExpected) : new ArrayList()); 

int rowNum = 0; 

while (rs.next()) { 

results.add(this.rowMapper.mapRow(rs, rowNum++)); 

return results; 

这下应该清楚为啥RowMapper为啥就处理单行结果就能完成ResultSetExtractor颇费周折的工作了吧?! 

RowCallbackHandler虽然与RowMapper同是处理单行数据,不过,除了要处理单行结果,它还得负责最终结果的组装和获取工作,在这里我们是使用当前上下文声明的List取得最终查询结果, 不过,我们也可以单独声明一个RowCallbackHandler实现类,

在其中声明相应的集合类,这样,我们可以通过该RowCallbackHandler实现类取得最终查询结果: 

public class GenericRowCallbackHandler implements RowCallbackHandler { 

private List collections = new ArrayList(); 

public void processRow(ResultSet rs) throws SQLException { 

Customer customer = new Customer(); 

customer.setFirstName(rs.getString(1)); 

customer.setLastName(rs.getString(2)); 

collections.add(customer); 

public List getResults() 

return collections; 

GenericRowCallbackHandler handler = new GenericRowCallbackHandler(); 

jdbcTemplate.query("select * from customer",handler()); 

List customerList = handler.getResults(); 

该使用方式是明了了,不过GenericRowCallbackHandler重用性不佳。 

RowCallbackHandler因为也是处理单行数据,所以,总得有人来做遍历ResultSet的工作,这个人其实也是一个ResultSetExtractor实现类, 它是JdbcTemplate一个内部静态类,名为RowCallbackHandlerResultSetExtractor,一看它的定义你就知道奥秘之所在了: 

private static class RowCallbackHandlerResultSetExtractor implements ResultSetExtractor { 

private final RowCallbackHandler rch; 

public RowCallbackHandlerResultSetExtractor(RowCallbackHandler rch) { 

this.rch = rch; 

public Object extractData(ResultSet rs) throws SQLException { 

while (rs.next()) { 

this.rch.processRow(rs); 

return null; 

总的来说,内部工作归根结底是由ResultSetExtractor做了,RowCallbackHandler和RowMapper只是为了帮助我们简化使用上的操作而已。 所以,实际使用中,RowCallbackHandler和RowMapper才是我们最常用的选择。

package jdbc;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.ColumnMapRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.PreparedStatementSetter;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.SingleColumnRowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import jdbc.model.Person;
import jdbc.service.PersonService;

@ContextConfiguration(locations = "classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class JunitTest {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	@Autowired
	private PersonService personService;

	@Test
	public void query1() {
		List<Person> a = jdbcTemplate.query("select * from person where id = ? or name = ?", new Object[] { 1, "张三" },
				new RowMapper<Person>() {
					@Override
					public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
						Person p = new Person();
						p.setId(rs.getInt("id"));
						p.setName(rs.getString("name"));
						p.setAge(rs.getInt("age"));
						p.setPass(rs.getString("pass"));
						return p;
					}
				});
		System.out.println(a);

		Map<String, Object> map = new HashMap<>();
		ArrayList<Integer> arr = new ArrayList<>();
		arr.add(1);
		arr.add(3);
		map.put("ids", arr);
		List<Person> b = namedParameterJdbcTemplate.query("select * from person where id IN (:ids)", map,
				new BeanPropertyRowMapper<>(Person.class));
		System.out.println(b);
	}

	@Test
	public void save1() {
		Person p = new Person();
		p.setId(5);
		p.setAge(11);
		p.setName("Ead");
		p.setPass("00000");
		jdbcTemplate.update("insert into person(id,name,age,pass) values(?,?,?,?)",
				new Object[] { p.getId(), p.getName(), p.getAge(), p.getPass() });
	}

	@Test
	public void save3() {
		Calendar c = Calendar.getInstance();
		jdbcTemplate.update("insert into testtime(time) values(?)", new Object[] { c.getTime() });
	}

	
	@Test
	public void save2() {
		Person p = new Person();
		p.setId(6);
		p.setAge(11);
		p.setName("Ead");
		p.setPass("00000");
		Person p1 = new Person();
		p1.setId(6);
		p1.setAge(11);
		p1.setName("Ead");
		p1.setPass("00000");
		List<Person> list = new ArrayList<>();
		list.add(p);
		jdbcTemplate.update("insert into person(name,age,pass) values(?,?,?)", new PreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps) throws SQLException {
				ps.setString(1, p.getName());
				ps.setInt(2, p.getAge());
				ps.setString(3, p.getPass());
			}
		});
		System.out.println(personService.getPersonList());

	}

	@Test
	public void update1() {
		Person p = new Person();
		p.setId(6);
		p.setAge(11);
		p.setName("Eada");
		p.setPass("232323");
		jdbcTemplate.update("update person set name=? where id=?", new PreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps) throws SQLException {
				ps.setString(1, p.getName());
				ps.setInt(2, p.getId());
			}
		});
	}

	@Test
	public void update2() {
		Person p = new Person();
		p.setId(6);
		p.setAge(11);
		p.setName("Eada");
		p.setPass("232323");
		jdbcTemplate.update("update person set name=? where id=?", new PreparedStatementSetter() {
			@Override
			public void setValues(PreparedStatement ps) throws SQLException {
				ps.setString(1, p.getName());
				ps.setInt(2, p.getId());
			}
		});
	}

	@Test
	public void delete() {
		jdbcTemplate.update("delete from person where id = ?", new Object[] { 5 },
				new int[] { java.sql.Types.INTEGER });
	}

	@Test
	public void queryForInt1() {
		int i = jdbcTemplate.queryForInt("select count(0) from person where name = ?", new Object[] { "zhu" });
		System.out.println(i);
	}

	@Test
	public void queryForObject2() {
		String p = jdbcTemplate.queryForObject("select name from person where id = 3", String.class);
		System.out.println(p);
	}

	@Test
	public void queryForObject3() { //
		Person p = (Person) jdbcTemplate.queryForObject("select * from person where id = 3", new RowMapper<Person>() {
			@Override
			public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
				Person user = new Person();
				user.setId(rs.getInt("id"));
				user.setName(rs.getString("name"));
				user.setPass(rs.getString("pass"));
				user.setAge(rs.getInt("age"));
				return user;
			}
		});
		System.out.println(p);
	}

	@Test
	public void queryForList2() {
		List<String> list = (List<String>) jdbcTemplate.queryForList("select name from person ", String.class);
		System.out.println(list);
	}

	@Test
	public void queryForList3() { // 不行
		List<Person> list = (List<Person>) jdbcTemplate.queryForList("select * from person ", Person.class);
		System.out.println(list);
	}

	@Test
	public void getPersonInfo() {
		List<Map<String, Object>> list = this.jdbcTemplate.queryForList("select * from person");
		System.out.println(list);
	}

	@Test
	public void testBeanPropertyRowMapper() { // 推荐,返回 对象list
		Collection<Integer> arr = new ArrayList<>();
		arr.add(2);
		arr.add(3);
		List<Person> result = jdbcTemplate.query("select * from person where id >?", new Object[] { 2 },
				new BeanPropertyRowMapper<Person>(Person.class));
		System.out.println(result);
	}

	@Test
	public void testColumnMapRowMapper() { // 返回对象map
		List<Map<String, Object>> result = jdbcTemplate.query("select * from person", new ColumnMapRowMapper());
		System.out.println(result);
	}

	@Test
	public void testSingleColumnRowMapper() { // 返回一列集合
		List<String> result1 = jdbcTemplate.query("select name from person", new SingleColumnRowMapper<String>());
		System.out.println(result1);
	}

	@Test
	public void list1() { // 查询结果
		List<Person> list = (List<Person>) jdbcTemplate.query("select * from person", new RowMapper<Person>() {
			@Override
			public Person mapRow(ResultSet rs, int rowNum) throws SQLException {
				Person user = new Person();
				user.setId(rs.getInt("id"));
				user.setAge(rs.getInt("age"));
				user.setName(rs.getString("name"));
				user.setPass(rs.getString("pass"));
				return user;
			}
		});
		System.out.println(list);
	}

	@Test
	public void batchUpdate() {
		List<Person> list = new ArrayList<>();
		Person p = new Person();
		p.setId(6);
		p.setAge(11);
		p.setName("Edddddddada");
		p.setPass("232323");
		list.add(p);
		int[] updateCounts = jdbcTemplate.batchUpdate("update person set name = ?, pass = ? where id = ?",
				new BatchPreparedStatementSetter() {
					@Override
					public void setValues(PreparedStatement ps, int i) throws SQLException {
						ps.setString(1, ((Person) list.get(i)).getName());
						ps.setString(2, ((Person) list.get(i)).getPass());
						ps.setLong(3, ((Person) list.get(i)).getId());
					}

					@Override
					public int getBatchSize() {
						return list.size();
					}
				});

		System.out.println(Arrays.toString(updateCounts));
	}

}
package jdbc;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;
import org.springframework.jdbc.core.RowCallbackHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import jdbc.model.Person;
import jdbc.service.PersonService;

@ContextConfiguration(locations = "classpath:beans.xml")
@RunWith(SpringJUnit4ClassRunner.class)
public class NamedParameterJdbcTemplateTest {

	@Autowired
	private JdbcTemplate jdbcTemplate;

	@Autowired
	private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

	@Autowired
	private PersonService personService;

	@Test
	public void testInsertSql() {
		String insertSql = "insert into person (name,age,pass) values(:name,:age,:pass);";
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("name", "Aily");
		paramMap.put("age", 22);
		paramMap.put("pass", "333");
		namedParameterJdbcTemplate.update(insertSql, paramMap);
	}

	@Test
	public void addStu() {

		String sql = "insert into person (name,age,pass) values(:name,:age,:pass)";

		Person p = new Person();
		p.setAge(11);
		p.setName("Edddad");
		p.setPass("000ddd00");

		SqlParameterSource ps = new BeanPropertySqlParameterSource(p);

		KeyHolder keyholder = new GeneratedKeyHolder();

		namedParameterJdbcTemplate.update(sql, ps, keyholder);
		int m = keyholder.getKey().intValue();

	}

	@Test
	public void testupdate() {
		String updatesql = "update person set age = :age where id > :id ";
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("id", 4);
		paramMap.put("age", 10);
		namedParameterJdbcTemplate.update(updatesql, paramMap);
	}

	@Test
	public void testupdate1() {
		String updatesql = "update person set age = ? where id > ? ";
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("id", 4);
		paramMap.put("age", 20);
		jdbcTemplate.batchUpdate(updatesql, new BatchPreparedStatementSetter() {
			@Override
			public int getBatchSize() {
				return paramMap.size();
			}

			@Override
			public void setValues(PreparedStatement ps, int i) throws SQLException {
				ps.setInt(1, (int) paramMap.get("age"));
				ps.setInt(2, (int) paramMap.get("id"));
			}
		});
	}

	@Test
	public void tes1queryq() {
		String selectSql = "select id,name from person where name=:name";
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("name", "Ead");
		List<Integer> result = new ArrayList<Integer>();
		namedParameterJdbcTemplate.query(selectSql, paramMap, new RowCallbackHandler() {
			@Override
			public void processRow(ResultSet rs) throws SQLException {
				result.add(rs.getInt("id"));
			}
		});
		System.out.println(result);
	}

	@Test
	public void tes1queryq1() {
		String selectSql = "select id,name from person where id IN (:ids)";
		Collection<Integer> arr = new ArrayList<>();
		arr.add(2);
		arr.add(3);
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("ids", arr);
		List<Integer> result = new ArrayList<Integer>();
		namedParameterJdbcTemplate.query(selectSql, paramMap, new RowCallbackHandler() {
			@Override
			public void processRow(ResultSet rs) throws SQLException {
				result.add(rs.getInt("id"));
			}
		});
		System.out.println(result);
	}

	@Test
	public void testquery2() {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("id", 4);
		String sql = "select name,age,pass from person  " + "where id > :id";
		List<Map<String, Object>> result = namedParameterJdbcTemplate.queryForList(sql, paramMap);
		for (Map<String, Object> map : result) {
			System.out.println("------------");
			System.out.println(map.get("name"));
			System.out.println(map.get("age"));
			System.out.println(map.get("pass"));
		}
		System.out.println(result);
	}

	@Test
	public void testdeleteSql() {
		String deleteSql = "delete from test where name=:name";
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("name", "Ead");
		namedParameterJdbcTemplate.update(deleteSql, paramMap);
	}

	@Test
	public void testBeanPropertyRowMapper() { // 推荐,返回 对象list
		List<Person> result = namedParameterJdbcTemplate.query("select * from person",
				new BeanPropertyRowMapper<Person>(Person.class));
		System.out.println(result);
	}

	/*-------------------三种结果集的查询使用------------*/

	@Test
	public void testResultSetExtractor() {
		List<Person> list = (List<Person>) jdbcTemplate.query("select * from person",
				new ResultSetExtractor<List<Person>>() {
					public List<Person> extractData(ResultSet rs) throws SQLException, DataAccessException {
						List<Person> ps = new ArrayList<>();
						while (rs.next()) {
							Person p = new Person();
							p.setId(rs.getInt("id"));
							p.setName(rs.getString("name"));
							p.setAge(rs.getInt("age"));
							p.setPass(rs.getString("pass"));
							ps.add(p);
						}
						return ps;
					}
				});
		System.out.println(list);// 返回整个查询结果
	}

	@Test
	public void testRowMapper() {
		List<Person> list = jdbcTemplate.query("select * from person", new RowMapper<Person>() {
			public Person mapRow(ResultSet rs, int rowNumber) throws SQLException {
				Person p = new Person();
				p.setId(rs.getInt("id"));
				p.setName(rs.getString("name"));
				p.setAge(rs.getInt("age"));
				p.setPass(rs.getString("pass"));
				return p;
			}
		});
		System.out.println(list);// 返回整个查询结果
	}

	@Test
	public void testRowCallbackHandler() {
		List<Person> list = new ArrayList<>();
		jdbcTemplate.query("select * from person", new RowCallbackHandler() {
			public void processRow(ResultSet rs) throws SQLException {
				Person p = new Person();
				p.setId(rs.getInt("id"));
				p.setName(rs.getString("name"));
				p.setAge(rs.getInt("age"));
				p.setPass(rs.getString("pass"));
				list.add(p);
			}
		});
		System.out.println(list);// 返回整个查询结果
	}

}
原文地址:https://www.cnblogs.com/liuzyw/p/5628082.html