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(7.4) - 对JDBC的支持 之 7.4 Spring提供的其它帮助的更多相关文章

  1. 开涛spring3(7.5) - 对JDBC的支持 之 7.5 集成Spring JDBC及最佳实践

    7.5 集成Spring JDBC及最佳实践 大多数情况下Spring JDBC都是与IOC容器一起使用.通过配置方式使用Spring JDBC. 而且大部分时间都是使用JdbcTemplate类(或 ...

  2. 开涛spring3(6.9) - 对JDBC的支持 之 7.1 概述

    7.1  概述 7.1.1  JDBC回顾 传统应用程序开发中,进行JDBC编程是相当痛苦的,如下所示: //cn.javass.spring.chapter7. TraditionalJdbcTes ...

  3. 开涛spring3(7.3) - 对JDBC的支持 之 7.3 关系数据库操作对象化

    7.3.1  概述 所谓关系数据库对象化其实就是用面向对象方式表示关系数据库操作,从而可以复用. Spring JDBC框架将数据库操作封装为一个RdbmsOperation,该对象是线程安全的.可复 ...

  4. 开涛spring3(7.2) - 对JDBC的支持 之 7.2 JDBC模板类

    7.2  JDBC模板类 7.2.1  概述 Spring JDBC抽象框架core包提供了JDBC模板类,其中JdbcTemplate是core包的核心类,所以其他模板类都是基于它封装完成的,JDB ...

  5. 开涛spring3(8.1) - 对ORM的支持 之 8.1 概述

    8.1  概述 8.1.1  ORM框架 ORM全称对象关系映射(Object/Relation Mapping),指将Java对象状态自动映射到关系数据库中的数据上,从而提供透明化的持久化支持,即把 ...

  6. 开涛spring3(1) - Spring概述

    1.1.1  Spring是什么 Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发.应用程序是由 ...

  7. 开涛spring3(12.1) - 零配置 之 12.1 概述

    12.1  概述 12.1.1  什么是零配置 在SSH集成一章中大家注意到项目结构和包结构是不是很有规律,类库放到WEB-INF/lib文件夹下,jsp文件放到WEB-INF/jsp文件夹下,web ...

  8. 开涛spring3(9.2) - Spring的事务 之 9.2 数据库事务概述

    9.2.1  概述 Spring框架支持事务管理的核心是事务管理器抽象,对于不同的数据访问框架(如Hibernate)通过实现策略接口 PlatformTransactionManager,从而能支持 ...

  9. 开涛spring3(12.3) - 零配置 之 12.3 注解实现Bean定义

    12.3  注解实现Bean定义 12.3.1  概述 前边介绍的Bean定义全是基于XML方式定义配置元数据,且在[12.2注解实现Bean依赖注入]一节中介绍了通过注解来减少配置数量,但并没有完全 ...

随机推荐

  1. JDBC基础学习(一)—JDBC的增删改查

    一.数据的持久化     持久化(persistence): 把数据保存到可掉电式存储设备中以供之后使用.大多数情况下,数据持久化意味着将内存中的数据保存到硬盘上加以固化,而持久化的实现过程大多通过各 ...

  2. 前端代码组织优化--小demo(进阶你的思路)

    事出必有因 最近在看老项目的代码,一个富客户端的js代码,几千行的代码,全是function(){} var...的垂直布局,真的是要感动的哭了. 一开始都是这样,想实现什么功能,不管三七二十一,fu ...

  3. PHPCMS笔记第二弹

    熟练地使用PHPCMS可以插入模板,将静态站转变为动态站也更加方便,多加练习还是有好处的 将index.html的头和尾拆分出来,分别放在header.html和footer.html文件夹中,这三个 ...

  4. 易汇金在线支付接口实例。ecshop和shopex,shopnc,iwebshop下完美无错(最新)

    最近为客户的一个在线商城做了一个易汇金在线支付的接口.跟大家分享一下. 1 首先可以模仿其他的接口,比如支付宝,财付通等的接口,构建模块功能文件和语言文件. 功能模块构建: /includes/mod ...

  5. 转账示例(一):Dao层面实现(本例采用QueryRunner来执行sql语句,数据源为C3P0)

    缺点:Dao层面把Service层面的操作完成了,不利于后期的代码修改和重构 1.自行创建C3P0Util account数据库 2.jar包 3.Dao层面 接口: package com.lear ...

  6. 【one day one linux】find 用法详解小记

    find命令的功能很强大,查找文件的选项很多,所以这是一个很实用并且很常用的linux命令.但是他有个缺点就是搜索的时候比较慢的.而与之相对的有一个locate命令. find的命令格式 find   ...

  7. C#网络程序设计(1)网络编程常识与C#常用特性

        网络程序设计能够帮我们了解联网应用的底层通信原理!     (1)网络编程常识: 1)什么是网络编程 只有主要实现进程(线程)相互通信和基本的网络应用原理性(协议)功能的程序,才能算是真正的网 ...

  8. Java Comparator的范型类型推导问题

    问题 在项目中,有一处地方需要对日期区间进行排序 我需要以日期区间的开始日为第一优先级,结束日为第二优先级进行排序 代码 我当时写的代码如下: List<Pair<LocalDate, L ...

  9. JavaScript巧学巧用

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 由于工作和生活上的一些变化,最近写文章的频率有点下降了,实在不好意思,不过相信不久就会慢慢恢复过来, ...

  10. androidStudio通过svn进行版本控制

    andoridStudio配置使用svn(以windows为例) 1.先安装svn客户端程序,TortoiseSVN,注意安装过程中要勾选command line client tools(默认是不安 ...