1、在DAO中使用JdbcTemplate
(1)在Spring配置文件中配置DAO一般分为4个步骤:
- 定义DataSource;
- 定义JdbcTemplate;
- 声明一个抽象的<bean/>,以便所有DAO复用配置JdbcTemplate属性的配置;
- 配置具体的DAO。
(2)为了避免每个DAO都引入JdbcTemplate,Spring提供了JdbcDaoSupport,JdbcDaoSupport在内部定义了JdbcTemplate,开发者可以通过扩展JdbcDaoSupport定义自己的Dao,这是早期的做法。但是随着注解配置逐渐成为潮流,通过扩展JdbcDaoSupport就显得不合时宜了。因为直接继承JdbcDaoSupport无法对JdbcTemplate成员变量使用@Autowired注解。
所以推荐做法是自己定义一个BaseDao,在BaseDao中定义JdbcTemplate成员,并打上@Autowired注解。
2、基本的数据操作
2.1、更改数据
(1)JdbcTemplate内部通过PreparedStatement执行SQL语句,所以我们可以使用绑定参数的SQL语句,而且我们也应该尽量使用可绑定参数的SQL语句,以便数据库可以复用SQL的执行计划。
示例如下:
(2)我们通过update(String sql,Object[] args)方法为SQL语句的占位符绑定参数时,并没有显示指定对应字段的数据类型,此时Spring直接让PreparedStatement根据参数的类型进行“猜测”。然而更好的一种做法是使用
int update(String sql,Object[] args,int[] argTypes)显式指定每个占位符所对应的字段数据类型。示例如下:
(3)除了以上2个update方法,还有以下几个方法:
2.2、返回数据库表的自增主键值
(1)JDBC3.0允许将主键绑定至返回结果集,示例如下:
2.3、批量更改数据
示例如下:
2.4、查询多行数据
(1)Spring使用RowCallbackHandler处理查询结果集。示例如下:
(2)Spring还提供了一个和RowCallbackHandler功能上类似的RowMapper<T>接口,使用RowMapper<T>映射多行结果的示例如下:
(3)RowCallbackHandler和RowMapper<T>的比较
Spring中解释RowCallbackHandler的实现类是有状态的,而RowMapper<T>的实现类是无状态的。所以在多线程环境下,RowCallbackHandler不能复用,而RowMapper<T>可以复用。另外,通过JDBC查询返回ResultSet结果集时,JDBC不会一次性将所有匹配数据全部加载到JVM中,而是只返回一批次数据(返回的批次数据由JDBC驱动决定,如Oracle的JDBC驱动,默认返回10行)。当通过Result#next()游标滚动结果集超过数据范围时,JDBC再获取一批数据。这样以一种“批量化+串行化”的方式避免大结果集时JVM内存过大开销。
当使用RowMapper<T>处理大结果集时,RowMapper<T>会一次性把所有结果集都封装进List<T>,占用大量JVM内存,引发内存溢出,这时应该使用RowCallbackHandler接口。
2.5、查询单值数据
(1)获取int、long类型的方法如下:
- int queryForInt(String sql,Object[] args,int[] argTypes);
- long queryForLong(String sql,Object[] args,int[] argTypes);
(2)其他类型单值查询接口如下:
(3)我们在编写SQL语句时,一般用大写字母表述关键字和函数,而用小写字母编写表名、字段名等非语义元素
2.6、操作Blob数据类型
3、自增键和行集
3.1、自增建的作用
(1)Spring运行用户在应用层产生主键值,为此定义了org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer接口,提供2种产生主键的方案:
- 通过序列产生主键;
- 通过表产生主键。
(2)DataFieldMaxValueIncrementer类继承图如下:
3.2、获取主键方式
(1)代码示例如下:
(2)通过Oracle中的序列获取主键
create sequence
seq_post_id
increment by 1
start with 1;
调整Spring的配置,使用
OracleSequenceMaxValueIncrementer
作为主键产生器:
<bean id="incre" class="org.springframework.jdbc.support.incrementer.OracleSequenceMaxValueIncrementer"
p:incrementerName="
seq_post_id"
p:dataSource-ref="
dataSource">
(3)通过MySql表获取主键
在MySql中创建一张用户维护t_post主键的t_post_id表:
create table t_post_id(sequence_id int) type=MYISAM;
insert into t_post_id values(0);
由于主键维护表的并发访问量很大,所以最好将其声明为MYISAM类型,Spring配置如下:
<bean id="incre" class="org.springframework.jdbc.support.incrementer.MySQLMaxValueIncrementer"
p:incrementerName="t_post_id"
p:columnName="sequence_id"
p:cacheSize="10"
p:dataSource-ref="
dataSource">
其中:cacheSize决定一次返回的主键个数,当调用MySQLMaxValueIncrementer#nextIntValue()时,第一次MySQLMaxValueIncrementer使t_post_id表的sequence_id字段递增10,后续的9次调用都是从缓存中获取主键值。
4、其他类型的JdbcTemplate
4.1、NamedParameterJdbcTemplate
(1)在低版本的Spring中,用户使用?占位符,需要指定索引,如果增加和减少必须维护索引位置,这种编程模式被认为是弱稳定的。
NamedParameterJdbcTemplate模板类支持命名参数变量的SQL,它位于org.springframework.jdbc.core.namedparam包中,该包中还定义了一个用于承载命名参数的SqlParameterSource接口,该接口有2个实现类:
在SQL语句中声明命名参数的格式是“:paramName”
4.2、SimpleJdbcTemplate
SimpleJdbcTemplate是特殊时期过渡性产物,以后可能会剔除,建议不要使用。
5、以OO方式访问数据库
除了通过JdbcTemplate完成访问数据库的操作,Spring还提供了把一个查询操作封装一个类。
5.1、使用MappingSqlQuery查询数据
(1)
SqlQuery是一个可重用、线程安全的类,它封装了一个SQL查询。
(2)我们常使用其子类MappingSqlQuery,示例如下:
(3)使用MappingSqlQuery一般分为以下3个步骤:
- 定义子类,在子类中声明SQL语句并定义行数据映射逻辑。
- 声明子类的变量并实例化该类。
- 使用MappingSqlQuery的方法执行数据查询操作。
(4)父类SqlQuery的一些方法
5.2、使用SqlUpdate更新数据
5.3、使用StoredProcedure执行存储过程
5.4、使用SqlFunction类查询并返回一个单行结果集