Spring的数据访问哲学
- Spring的目标之一就是允许我们在开发应用程序时,能够遵循面向对象(OO)原则中的“针对接口编程”。
- 为了避免持久化的逻辑分散到应用的各个组件中,最好将数据访问的功能放到一个或多个专注于此项任务的组件中。
- 这样的组件通常称为数据访问对象(data access object,DAO)或Repository。
- 为了避免应用与特定的数据访问策略耦合在一起,编写良好的Repository应该以接口的方式暴露功能。
- 下图展现了设计数据访问层的合理方式。
-
服务对象本身并不会处理数据访问,而是将数据访问委托给Repository。Repository接口确保其与服务对象的松耦合。
- 通过JDBC驱动程序定义的数据源
- 通过JNDI查找的数据源
- 连接池的数据源
- Spring应用程序经常部署在java EE应用服务器中,如WebSphere、JBoss或Tomcat这样的Web容器中。
- 这些服务器允许你配置通过JNDI获取数据源。这种配置的好处在于数据源完全可以在应用程序之外进行管理。
- 另外,在应用服务器中管理的数据源通常以池的方式组织,从而具备更好的性能。
使用JNDI数据源
基于JDBC驱动的数据源
- DriverManageDataSource:在每个连接请求时都会返回一个新建的连接,没有进行池化管理。
- SimpleDriverDataSource:与DriverManageDataSource的工作方式类似,但是它直接使用JDBC驱动,来解决在特定环境下的类加载问题。
- SingleConnectionDataSource:在每个连接请求时都会返回同一个连接。
使用数据源连接池
- 相对于持久层框架,JDBC能够让我们在更低的层次上处理数据,我们可以完全控制应用程序如何读取和管理数据。
- 但是JDBC也有问题,比如代码臃肿。因为你要负责处理与数据库访问相关的所有事情,其中包含管理数据库资源和处理异常。
- 上面的代码中存在大量的重复性的代码,这些代码是为了资源管理和处理异常而不得不添加。
- 在Spring中把这些为了资源管理和处理异常的重复性代码叫做样板代码。
- Spring的JDBC框架承担了资源管理和异常处理的工作,从而简化了JDBC代码,让我们只需编写从数据库读写数据的必需代码。
- JdbcTemplate:最基本的Spring JDBC模板,这个模板支持简单的JDBC数据库访问功能以及基于索引参数的查询。
- NamedParameterJdbcTemplate:使用该模板类执行查询时可以将值以命名参数的形式绑定到SQL中,而不是使用简单的索引参数。
JDBC模板
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource)
{
return new JdbcTemplate(dataSource);
}
在这里,DataSource是通过构造器参数注入进来的。这里所引用的dataSource bean可以是javax.sql.DataSource的任意实现。现在,可以将jdbcTemplate装配到Repository中并使用它来访问数据库。
@Repository
public class JdbcSpitterRepository implements SpitterRepository{
private JdbcOperations jdbcOperations;
@Inject
public JdbcSpitterRepository(JdbcOperations jdbcOperations)
{
this.jdbcOperations=jdbcOperations;
}
}
@Inject 标注的构造、成员字段和方法是可注入的
- @Repository注解表明它会在组件扫描时自动创建。它的构造器上使用了@Inject注解,因此在创建的时候,会自动获得一个JdbcOperations对象。
- JdbcOperations是一个接口,定义了JdbcTemplate所实现的操作。
- 通过注入JdbcOperations,而不是具体的JdbcTemplate,是为了保证JdbcSpitterRepository与JdbcTemplate保持松耦合。
- 作为另外一种组件扫描和自动装配的方案,我们可以将JdbcSpitterRepository显式声明为Spring中的bean,如下所示:
@Bean
public SpitterRepository spitterRepository(JdbcTemplate jdbcTemplate) {
return new JdbcSpitterRepository(jdbcTemplate,dataSource);
}
在Repository中具备可用的JdbcTemplate后,可以极大的简化程序:
- execute方法:可以用于执行任何SQL语句,一般用于执行DDL语句;
- update方法:update方法用于执行新增、修改、删除等语句;
- batchUpdate方法:batchUpdate方法用于执行批处理相关语句;
- query方法及queryForXXX方法: query方法及queryForXXX方法;
- call方法:用于执行存储过程、函数相关语句
jdbcTemplate.execute ("CREATE TABLE USER ( user_id integer, name varchar(100))");
int update(final String sql )
其中 sql 参数为需要传入的插入 sql 语句。
用法示例:
int update(String sql , Object[] args , int[] argTypes )
sql : 预处理 sql 语句; args:sql 需要注入的参数; argTypes : 需要注入的 sql 参数的 JDBC 类型。
用法示例:
int update(String sql , PreparedStatementSetter pss )
sql : 预处理 sql 语句; pss : 用于参数填充;
1.int [] batchUpdate (final String[] sql )
参数是一个 String 数组,存放多条 sql 语句;返回值是 int 数组,即每条 sql 更新影响的行数。
2.int [] batchUpdate (String sql , final BatchPreparedStatementSetter pss )
参数 sql :一条预处理 sql (如果是批量处理预处理 sql ,那么 sql 的格式就是固定的,只填充参数而已);第二个参数就是回调类
说明:批量执行多条sql
queryForObject (String sql , Class<T> requiredType ) ;
sql : 预处理 sql ; requiredType :查询单列结果的类型;
参数 requiredType 只能是 String , Integer 这种类型,不能是自定义的实体类型,只能返回一个值,不能映射对象

queryForObject (String sql , Object[] args , Class<T> requiredType )
说明:查询一个值(使用预处理sql,需要注入参数)
<T> T queryForObject(String sql, RowMapper<T> rowMapper)

<T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper)

1)<T> T queryForObject(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper);
2)<T> T queryForObject(String sql, RowMapper<T> rowMapper, Object... args);
List<Map<String, Object>> queryForList (String sql )
这个方法封装成 map 放入 list 中, key: 列名, value: 列的值

<T> List<T> queryForList (String sql , Class<T> elementType )
<T> List<T> queryForList (String sql , Object[] args , Class<T> elementType )
还有如下方式实现:
(1)<T> List<T> queryForList(String sql, Object[] args, int[] argTypes, Class<T> elementType);
(2)<T> List<T> queryForList(String sql, Class<T> elementType, Object... args);
<T> List<T> query(String sql , RowMapper <T> rowMapper )

<T> List<T> query(String sql , PreparedStatementSetter pss , RowMapper <T> rowMapper )

(1)<T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper);
(2)<T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper);
(3)<T> List<T> query(String sql, RowMapper<T> rowMapper, Object... args);