标签
数据库
字数
1715 字
阅读时间
8 分钟
一、概述
Spring对数据库的操作在jdbc上面做了基本的封装,让开发者在操作数据库时只需关注SQL语句和查询 结果处理器,即可完成功能(当然,只使用JdbcTemplate,还不能摆脱持久层实现类的编写)。
在配合spring的IoC功能,可以把DataSource注册到JdbcTemplate之中。同时利用spring基于 aop的事务即可完成简单的数据库CRUD操作。
JdbcTemplate的限定命名为org.springframework.jdbc.core.JdbcTemplate。要使用 JdbcTemlate需要导入spring-jdbc和spring-tx两个坐标。
1.1 相关方法
JdbcTemplate实现了JdbcOperations接口,操作方法都定义在此接口中
JdbcTemplate主要提供以下五类方法:
execute方法: 可以用于执行任何SQL语句,一般用于执行DDL语句;
update方法及batchUpdate方法: update方法用于执行新增、修改、删除等语句;batchUpdate方法用于执行批处理相关语 句;
query方法及queryForXXX方法: 用于执行查询相关语句;
call方法: 用于执行存储过程、函数相关语句。1.2 NamedParameterJdbcTemplate
在经典的 JDBC 用法中, SQL 参数是用占位符 ? 表示,并且受到位置的限制. 定位参数的问题在于, 一旦参数的顺序发生变化, 就必须改变参数绑定.在 Spring JDBC 框架中, 绑定 SQL 参数的另一种选择 是使用具名参数(named parameter).
那么什么是具名参数?
具名参数: SQL 按名称(以冒号开头)而不是按位置进行指定. 具名参数更易于维护, 也提升了可读性. 具名 参数由框架类在运行时用占位符取代
具名参数只在 NamedParameterJdbcTemplate 中得到支持。
NamedParameterJdbcTemplate可以使 用全部jdbcTemplate方法。
NamedParameterJdbcTemplate里面封装了一个JdbcTemplate对象
二、使用示例
2.1 自定义JdbcTemplate
依赖
xml
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
</dependencies>自定义jdbcTemplate
java
package com.itheima.jdbc;
import com.itheima.jdbc.handler.ResultSetHandler;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* 自定义JdbcTemplate
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class JdbcTemplate {
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public JdbcTemplate(){
}
public JdbcTemplate(DataSource dataSource){
setDataSource(dataSource);
}
/**
* 用于执行增删改方法的
* @param sql 执行的SQL语句
* @param params 执行SQL所需的参数
* @return 影响数据库记录的行数
*/
public int update(String sql,Object... params){
//1.验证数据源是否有值
if(dataSource == null){
throw new NullPointerException("DataSource can not be null!");
}
//2.定义jdbc操作的相关对象
Connection conn = null;
PreparedStatement pstm = null;
int res = 0;
try{
//3.获取连接
conn = dataSource.getConnection();
//4.获取预处理对象
pstm = conn.prepareStatement(sql);
//5.获取参数的元信息
ParameterMetaData pmd = pstm.getParameterMetaData();
//6.获取sql域中参数的个数
int parameterCount = pmd.getParameterCount();
//7.判断sql语句中是否有参数
if(parameterCount > 0){
//判断是否提供了参数
if(params == null){
throw new IllegalArgumentException("Parameter can not be null!");
}
//判断是否个数匹配
if(parameterCount != params.length){
throw new IllegalArgumentException("Incorrect parameter size: expected "+String.valueOf(parameterCount)+", actual "+String.valueOf(params.length));
}
//参数校验通过,给占位符赋值
for(int i=0;i<parameterCount;i++){
pstm.setObject(i+1,params[i]);
}
}
//8.执行sql语句
res = pstm.executeUpdate();
}catch (Exception e){
e.printStackTrace();
}finally {
release(null,pstm,conn);
}
return res;
}
/**
* 执行查询方法
* @param sql 执行的语句
* @param rsh 处理结果集的封装,此处只是提供一个规范(接口),由使用者编写具体的实现
* @param params 执行语句所需的参数
* @return
*/
public Object query(String sql, ResultSetHandler rsh, Object... params){
//1.验证数据源是否有值
if(dataSource == null){
throw new NullPointerException("DataSource can not be null!");
}
//2.定义jdbc操作的相关对象
Connection conn = null;
PreparedStatement pstm = null;
ResultSet rs = null;
try{
//3.获取连接
conn = dataSource.getConnection();
//4.获取预处理对象
pstm = conn.prepareStatement(sql);
//5.获取参数的元信息
ParameterMetaData pmd = pstm.getParameterMetaData();
//6.获取sql域中参数的个数
int parameterCount = pmd.getParameterCount();
//7.判断sql语句中是否有参数
if(parameterCount > 0){
//判断是否提供了参数
if(params == null){
throw new IllegalArgumentException("Parameter can not be null!");
}
//判断是否个数匹配
if(parameterCount != params.length){
throw new IllegalArgumentException("Incorrect parameter size: expected "+String.valueOf(parameterCount)+", actual "+String.valueOf(params.length));
}
//参数校验通过,给占位符赋值
for(int i=0;i<parameterCount;i++){
pstm.setObject(i+1,params[i]);
}
}
//8.执行sql语句
rs = pstm.executeQuery();
//9.封装
return rsh.handle(rs);
}catch (Exception e){
throw new RuntimeException(e);
}finally {
release(rs,pstm,conn);
}
}
private void release(ResultSet rs,PreparedStatement pstm ,Connection conn){
if(rs != null){
try {
rs.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(pstm != null){
try {
pstm.close();
}catch (Exception e){
e.printStackTrace();
}
}
if(conn != null){
try {
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}自定义RowMapper
java
package com.itheima.jdbc.handler;
import java.sql.ResultSet;
/**
* 结果集的处理器
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public interface ResultSetHandler {
/**
* 处理结果集
* @param rs
* @return
*/
Object handle(ResultSet rs);
}提供不同实现
java
package com.itheima.jdbc.handler.impl;
import com.itheima.jdbc.handler.ResultSetHandler;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
/**
* 封装到实体类中的结果集处理器
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class BeanHandler<T> implements ResultSetHandler {
//定义封装哪个实体类的子接口
private Class<T> requiredType;
/**
* 当创建BeanHandler对象时,就需要提供封装到的实体类字节码
* @param requiredType
*/
public BeanHandler(Class requiredType){
this.requiredType = requiredType;
}
@Override
public Object handle(ResultSet rs) {
//1.定义返回值
T bean = null;
try{
//2.判断是否有结果集
if(rs.next()){
//3.实例化返回值对象
bean = requiredType.newInstance();
//4.获取结果集的元信息
ResultSetMetaData rsmd = rs.getMetaData();
//5.获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.遍历列的个数
for(int i=0;i<columnCount;i++){
//7.取出列的标题
String columnLabel = rsmd.getColumnLabel(i+1);
//8.取出当前列标题对应的数据内容
Object value = rs.getObject(columnLabel);
//9.借助java的内省机制,使用属性描述器填充
PropertyDescriptor pd = new PropertyDescriptor(columnLabel,requiredType);
//10.获取属性的写方法
Method method = pd.getWriteMethod();
//11.执行方法
method.invoke(bean,value);
}
}
}catch (Exception e){
e.printStackTrace();
}
return bean;
}
}java
package com.itheima.jdbc.handler.impl;
import com.itheima.jdbc.handler.ResultSetHandler;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;
/**
* @author 黑马程序员
* @Company http://www.itheima.com
*/
public class BeanListHandler<T> implements ResultSetHandler {
//定义封装哪个实体类的子接口
private Class<T> requiredType;
/**
* 当创建BeanHandler对象时,就需要提供封装到的实体类字节码
* @param requiredType
*/
public BeanListHandler(Class requiredType){
this.requiredType = requiredType;
}
@Override
public Object handle(ResultSet rs) {
//1.定义返回值
List list = new ArrayList<>();
T bean = null;
try{
//2.遍历结果集
while(rs.next()){
//3.实例化返回值对象
bean = requiredType.newInstance();
//4.获取结果集的元信息
ResultSetMetaData rsmd = rs.getMetaData();
//5.获取结果集的列数
int columnCount = rsmd.getColumnCount();
//6.遍历列的个数
for(int i=0;i<columnCount;i++){
//7.取出列的标题
String columnLabel = rsmd.getColumnLabel(i+1);
//8.取出当前列标题对应的数据内容
Object value = rs.getObject(columnLabel);
//9.借助java的内省机制,使用属性描述器填充
PropertyDescriptor pd = new PropertyDescriptor(columnLabel,requiredType);
//10.获取属性的写方法
Method method = pd.getWriteMethod();
//11.执行方法
method.invoke(bean,value);
}
//12.把填充好的bean封装到集合中
list.add(bean);
}
}catch (Exception e){
e.printStackTrace();
}
return list;
}
}