spring3: 对JDBC的支持 之 Spring提供的其它帮助 SimpleJdbcInsert/SimpleJdbcCall/SqlUpdate/JdbcTemplate 生成主键/批量处理
7.4 Spring提供的其它帮助
7.4.1 SimpleJdbc方式
Spring JDBC抽象框架提供SimpleJdbcInsert和SimpleJdbcCall类,这两个类通过利用JDBC驱动提供的数据库元数据来简化JDBC操作。
1、SimpleJdbcInsert: 用于插入数据,根据数据库元数据进行插入数据,本类用于简化插入操作,提供三种类型方法:execute方法用于普通插入、executeAndReturnKey及executeAndReturnKeyHolder方法用于插入时获取主键值、executeBatch方法用于批处理。
@Test
public void testSimpleJdbcInsert() {
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
Map<String, Object> args = new HashMap<String, Object>();
args.put("name", "name5");
insert.compile();
//1.普通插入
insert.execute(args);
Assert.assertEquals(1, jdbcTemplate.queryForInt("select count(*) from test"));
//2.插入时获取主键值
insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
insert.setGeneratedKeyName("id");
Number id = insert.executeAndReturnKey(args);
Assert.assertEquals(1, id);
//3.批处理
insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
insert.setGeneratedKeyName("id");
int[] updateCount = insert.executeBatch(new Map[] {args, args, args});
Assert.assertEquals(1, updateCount[0]);
Assert.assertEquals(5, jdbcTemplate.queryForInt("select count(*) from test"));
}
- new SimpleJdbcInsert(jdbcTemplate) : 首次通过DataSource对象或JdbcTemplate对象初始化SimpleJdbcInsert;
- insert.withTableName("test") : 用于设置数据库表名;
- args : 用于指定插入时列名及值,如本例中只有name列名,即编译后的sql类似于“insert into test(name) values(?)”;
- insert.compile() : 可选的编译步骤,在调用执行方法时自动编译,编译后不能再对insert对象修改;
- 执行: execute方法用于执行普通插入;executeAndReturnKey用于执行并获取自动生成主键(注意是Number类型),必须首先通过setGeneratedKeyName设置主键然后才能获取,如果想获取复合主键请使用setGeneratedKeyNames描述主键然后通过executeReturningKeyHolder获取复合主键KeyHolder对象;executeBatch用于批处理;
2、SimpleJdbcCall: 用于调用存储过程及自定义函数,本类用于简化存储过程及自定义函数调用。
@Test
public void testSimpleJdbcCall1() {
//此处用mysql,因为hsqldb调用自定义函数和存储过程一样
SimpleJdbcCall call = new SimpleJdbcCall(getMysqlDataSource());
call.withFunctionName("FUNCTION_TEST");
call.declareParameters(new SqlOutParameter("result", Types.INTEGER));
call.declareParameters(new SqlParameter("str", Types.VARCHAR));
Map<String, Object> outVlaues = call.execute("test");
Assert.assertEquals(4, outVlaues.get("result"));
}
- new SimpleJdbcCall(getMysqlDataSource()) :通过DataSource对象或JdbcTemplate对象初始化SimpleJdbcCall;
- withFunctionName("FUNCTION_TEST") : 定义自定义函数名;自定义函数sql语句将被编译为类似于{?= call …}形式;
- declareParameters : 描述参数类型,使用方式与StoredProcedure对象一样;
- 执行: 调用execute方法执行自定义函数;
@Test
public void testSimpleJdbcCall2() {
//调用hsqldb自定义函数得使用如下方式
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);
call.withProcedureName("FUNCTION_TEST");
call.declareParameters(new SqlReturnResultSet("result",
new ResultSetExtractor<Integer>() {
@Override
public Integer extractData(ResultSet rs)
throws SQLException, DataAccessException {
while(rs.next()) {
return rs.getInt(1);
}
return 0;
}}));
call.declareParameters(new SqlParameter("str", Types.VARCHAR));
Map<String, Object> outVlaues = call.execute("test");
Assert.assertEquals(4, outVlaues.get("result"));
}
调用hsqldb数据库自定义函数与调用mysql自定义函数完全不同,详见StoredProcedure中的解释。
@Test
public void testSimpleJdbcCall3() {
SimpleJdbcCall call = new SimpleJdbcCall(jdbcTemplate);
call.withProcedureName("PROCEDURE_TEST");
call.declareParameters(new SqlInOutParameter("inOutName", Types.VARCHAR));
call.declareParameters(new SqlOutParameter("outId", Types.INTEGER));
SqlParameterSource params =
new MapSqlParameterSource().addValue("inOutName", "test");
Map<String, Object> outVlaues = call.execute(params);
Assert.assertEquals("Hello,test", outVlaues.get("inOutName"));
Assert.assertEquals(0, outVlaues.get("outId"));
}
与自定义函数调用不同的是使用withProcedureName来指定存储过程名字;其他参数描述等完全一样。
7.4.2 控制数据库连接
Spring JDBC通过DataSource控制数据库连接,即通过DataSource实现获取数据库连接。
Spring JDBC提供了一下DataSource实现:
- DriverManagerDataSource :简单封装了DriverManager获取数据库连接;通过DriverManager的getConnection方法获取数据库连接;
- SingleConnectionDataSource :内部封装了一个连接,该连接使用后不会关闭,且不能在多线程环境中使用,一般用于测试;
- LazyConnectionDataSourceProxy :包装一个DataSource,用于延迟获取数据库连接,只有在真正创建Statement等时才获取连接,因此再说实际项目中最后使用该代理包装原始DataSource从而使得只有在真正需要连接时才去获取。
第三方提供的DataSource实现主要有C3P0、Proxool、DBCP等,这些实现都具有数据库连接池能力。
DataSourceUtils: Spring JDBC抽象框架内部都是通过它的getConnection(DataSource dataSource)方法获取数据库连接,releaseConnection(Connection con, DataSource dataSource) 用于释放数据库连接,DataSourceUtils用于支持Spring管理事务,只有使用DataSourceUtils获取的连接才具有Spring管理事务。
7.4.3 获取自动生成的主键
有许多数据库提供自动生成主键的能力,因此我们可能需要获取这些自动生成的主键,JDBC 3.0标准支持获取自动生成的主键,且必须数据库支持自动生成键获取。
1 )JdbcTemplate 获取自动生成主键方式:
@Test
public void testFetchKey1() throws SQLException {
final String insertSql = "insert into test(name) values('name5')";
KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
jdbcTemplate.update(new PreparedStatementCreator() {
@Override
public PreparedStatement createPreparedStatement(Connection conn)
throws SQLException {
return conn.prepareStatement(insertSql, new String[]{"ID"});
}}, generatedKeyHolder);
Assert.assertEquals(0, generatedKeyHolder.getKey());
}
使用JdbcTemplate的update(final PreparedStatementCreator psc, final KeyHolder generatedKeyHolder)方法执行需要返回自动生成主键的插入语句,其中psc用于创建PreparedStatement并指定自动生成键,如“prepareStatement(insertSql, new String[]{"ID"})”;generatedKeyHolder是KeyHolder类型,用于获取自动生成的主键或复合主键;如使用getKey方法获取自动生成的主键。
2 )SqlUpdate 获取自动生成主键方式:
@Test
public void testFetchKey2() {
final String insertSql = "insert into test(name) values('name5')";
KeyHolder generatedKeyHolder = new GeneratedKeyHolder();
SqlUpdate update = new SqlUpdate();
update.setJdbcTemplate(jdbcTemplate);
update.setReturnGeneratedKeys(true);
//update.setGeneratedKeysColumnNames(new String[]{"ID"});
update.setSql(insertSql);
update.update(null, generatedKeyHolder);
Assert.assertEquals(0, generatedKeyHolder.getKey());
}
SqlUpdate获取自动生成主键方式和JdbcTemplate完全一样,可以使用setReturnGeneratedKeys(true)表示要获取自动生成键;也可以使用setGeneratedKeysColumnNames指定自动生成键列名。
3 )SimpleJdbcInsert : 前边示例已介绍,此处就不演示了。
7.4.4 JDBC批量操作
JDBC批处理用于减少与数据库交互的次数来提升性能,Spring JDBC抽象框架通过封装批处理操作来简化批处理操作
1 )JdbcTemplate 批处理: 支持普通的批处理及占位符批处理;
@Test
public void testBatchUpdate1() {
String insertSql = "insert into test(name) values('name5')";
String[] batchSql = new String[] {insertSql, insertSql};
jdbcTemplate.batchUpdate(batchSql);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
直接调用batchUpdate方法执行需要批处理的语句即可。
@Test
public void testBatchUpdate2() {
String insertSql = "insert into test(name) values(?)";
final String[] batchValues = new String[] {"name5", "name6"};
jdbcTemplate.batchUpdate(insertSql, new BatchPreparedStatementSetter() {
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
ps.setString(1, batchValues[i]);
}
@Override
public int getBatchSize() {
return batchValues.length;
}
});
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
JdbcTemplate还可以通过batchUpdate(String sql, final BatchPreparedStatementSetter pss)方法进行批处理,该方式使用预编译语句,然后通过BatchPreparedStatementSetter实现进行设值(setValues)及指定批处理大小(getBatchSize)。
2 )NamedParameterJdbcTemplate 批处理: 支持命名参数批处理;
@Test
public void testBatchUpdate3() {
NamedParameterJdbcTemplate namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(jdbcTemplate);
String insertSql = "insert into test(name) values(:myName)";
UserModel model = new UserModel();
model.setMyName("name5");
SqlParameterSource[] params = SqlParameterSourceUtils.createBatch(new Object[] {model, model});
namedParameterJdbcTemplate.batchUpdate(insertSql, params);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
通过batchUpdate(String sql, SqlParameterSource[] batchArgs)方法进行命名参数批处理,batchArgs指定批处理数据集。SqlParameterSourceUtils.createBatch用于根据JavaBean对象或者Map创建相应的BeanPropertySqlParameterSource或MapSqlParameterSource。
3) SimpleJdbcTemplate 批处理: 已更简单的方式进行批处理;
@Test
public void testBatchUpdate4() {
SimpleJdbcTemplate simpleJdbcTemplate = new SimpleJdbcTemplate(jdbcTemplate);
String insertSql = "insert into test(name) values(?)";
List<Object[]> params = new ArrayList<Object[]>();
params.add(new Object[]{"name5"});
params.add(new Object[]{"name5"});
simpleJdbcTemplate.batchUpdate(insertSql, params);
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
本示例使用batchUpdate(String sql, List<Object[]> batchArgs)方法完成占位符批处理,当然也支持命名参数批处理等。
4 )SimpleJdbcInsert 批处理:
@Test
public void testBatchUpdate5() {
SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);
insert.withTableName("test");
Map<String, Object> valueMap = new HashMap<String, Object>();
valueMap.put("name", "name5");
insert.executeBatch(new Map[] {valueMap, valueMap});
Assert.assertEquals(2, jdbcTemplate.queryForInt("select count(*) from test"));
}
如代码所示,使用executeBatch(Map<String, Object>[] batch)方法执行批处理。
spring3: 对JDBC的支持 之 Spring提供的其它帮助 SimpleJdbcInsert/SimpleJdbcCall/SqlUpdate/JdbcTemplate 生成主键/批量处理的更多相关文章
- spring3: 对JDBC的支持 之 关系数据库操作对象化
7.3.1 概述 所谓关系数据库对象化其实就是用面向对象方式表示关系数据库操作,从而可以复用. Spring JDBC框架将数据库操作封装为一个RdbmsOperation,该对象是线程安全的.可复 ...
- spring mvc 插入一条数据 返回该数据的主键编号
import org.springframework.jdbc.core.PreparedStatementCreator; import org.springframework.jdbc.suppo ...
- Spring boot jpa 设定MySQL数据库的自增ID主键值
内容简介 本文主要介绍在使用jpa向数据库添加数据时,如果表中主键为自增ID,对应实体类的设定方法. 实现步骤 只需要在自增主键上添加@GeneratedValue注解就可以实现自增,如下图: 关键代 ...
- 跟我学Spring3(9.1):Spring的事务之数据库事务概述
原文出处: 张开涛 9.1 数据库事务概述 事务首先是一系列操作组成的工作单元,该工作单元内的操作是不可分割的,即要么所有操作都做,要么所有操作都不做,这就是事务. 事务必需满足ACID(原子性.一致 ...
- 跟我学Spring3(9.2):Spring的事务之事务管理器
原文出处: 张开涛9.2.1 概述 Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口PlatformTransactionManage ...
- 开涛spring3(7.4) - 对JDBC的支持 之 7.4 Spring提供的其它帮助
7.4 Spring提供的其它帮助 7.4.1 SimpleJdbc方式 Spring JDBC抽象框架提供SimpleJdbcInsert和SimpleJdbcCall类,这两个类通过利用JDB ...
- 1.Spring对JDBC整合支持
1.Spring对JDBC整合支持 Spring对DAO提供哪些支持 1)Spring对DAO异常提供统一处理 2)Spring对DAO编写提供支持的抽象类 3)提高编程效率,减少DAO编码量 Spr ...
- 8.Spring对JDBC的支持和事务
1.Spring对JDBC的支持 DAO : Spring中对数据访问对象(DAO)的支持旨在简化Spring与数据访问技术的操作,使JDBC.Hibernate.JPA和JDO等采用统一的方式访问 ...
- Spring3之JDBC
Spring提供了统一的数据访问异常层次体系,所涉及到的大部分异常类型都定义在org.springframework.dao包中,出于这个体系中所有异常类型均以org.springframework. ...
随机推荐
- 12.php中无比坑爹的构造函数。
当你在php类中,写一个构造方法时,记得,一定要用__这是两个下划线,而不是一个.......... <?php class Car { // function _construct() { / ...
- XML 之快速入门
XML 简介 - XML, 即可扩展标记语言(eXtensible Markup Language), 是一种标记语言. - 标记型语言: 使用标签进行操作 - 可扩展: XML 的标签可以自定义 - ...
- 设计4个线程,其中2个对num进行加操作,另两个对num进行减操作
/** * 设计4个线程,其中2个对num进行加操作,另两个对num进行减操作 */ public class ThreadTest { private int j; public static vo ...
- Python 一键同步windows和linux数据(基于pscp.exe)
outline 项目中需要把 windows server 上的数据同步到 linux server,方法很多,这里记录下自己采用的一种比较简单的方法. 准备工作 首先确保你 windows serv ...
- django博客项目2.建立 Django 博客应用
建立博客应用 我们已经建立了 Django 博客的项目工程,并且成功地运行了它.不过到目前为止这一切都还只是 Django 为我们创建的项目初始内容,Django 不可能为我们初始化生成博客代码,这些 ...
- action接收请求参数
一.采用基本类型接收请求参数(get/post)在Action类中定义与请求参数同名的属性,struts2便能接收自动接收请求参数并赋给同名属性. action的代码: public class Pa ...
- CWM是什么?
CWM [1] (CommonWarehouseMetamodel公共仓库元模型)是OMG组织在数据仓库系统中定义了一套完整的元模型体系结构,用于数据仓库构建和应用的元数据建模.公共仓库元模型指定的 ...
- (转)RTP-H264封包分析
rtp(H264)第一个包(单一NAL单元模式)————-sps 80 {V=10,p=0,x=0,cc=0000} 60 {m=0,pt=110 0000} 53 70{sequence numbe ...
- 什么是 jQuery 和jQuery的基本选择器,层级选择器,基本筛选器
jQuery是什么? [1] jQuery由美国人John Resig创建,至今已吸引了来自世界各地的众多 javascript高手加入其team. [2] jQuery是继prototype ...
- python提示AttributeError: 'NoneType' object has no attribute 'append'
在写python脚本时遇到AttributeError: 'NoneType' object has no attribute 'append' a=[] b=[1,2,3,4] a = a.appe ...