jdbctmplate底层源码及解析
一、回顾jdbc基础知识
-
jdbc是java语言用来规范客户端如何访问数据库的应用程序接口,提供了查询和更新数据库中数据的方法。
-
jdbc是面向关系型数据库的。
-
不同的数据库厂商有不同的jdbc的jar包。
-
jdbc基本步骤
- 加载驱动
- 获取Connection对象
- 获取执行sql的statement对象(推荐使用prepareStatement,(1)效率好(2)可以解决sql注入的问题。)
- 执行sql,获取结果
- 对结果进行处理
- 释放资源
二、回顾数据源DataSource
-
DataSource基本概念
- 负责与数据库的连接,当在应用程序中访问数据库时不必填写连接数据库的代码,直接引用DataSource获取连接数据库的Connection对象即可。
- 数据库连接池负责分配、管理和释放数据库连接,允许应用程序重复使用一个现有的数据库连接,而不用重新建立一个。
- 释放空闲时间超过最大空闲时间的数据库连接,避免因为没有释放连接而引起的数据库连接遗漏。
-
常见的数据库连接池:dbcp,c3p0,druid
-
druid使用步骤
-
导入依赖
-
提供db.properities
driverClassName = com.mysql.jdbc.Driver url = jdbc:mysql:///javaweb username = root password = root
-
使用druid创建DataSource
package com.rookie.util; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.IOException; import java.io.InputStream; import java.util.Properties; public class DruidUtils { private static DataSource dateSource = null; //静态代码块,类加载的时候就会执行 static{ try { //1.读取配置文件 InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("db.properties"); //2.将is导入properties Properties pp = new Properties(); pp.load(is); //3.创建连接池对象 dateSource = DruidDataSourceFactory.createDataSource(pp); } catch (Exception e) { e.printStackTrace(); } } public static DataSource getDateSource(){ return dateSource; } }
-
- 然后就可以使用dataSource获取数据库的连接对象Connection,执行sql操作。
三、使用JdbcTemplate
JdbcTemplate是spring对传统的jdbc的封装。
JdbcTemplate比较灵活,但是和ORM框架相比,JdbcTemplate功能则力不从心,学习JdbcTemplate是为了学习ORM框架做铺垫。
@Test
public void test4(){
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(DruidUtils.getDateSource());
//1.增删改
//因为id为主键,会自增,所以可以填NULL;不会出现主键冲突
jdbcTemplate.update("INSERT INTO ACCOUNT VALUES(NULL,?,?,?)","QWE","1000","0");
jdbcTemplate.update("UPDATE ACCOUNT SET NAME = ? WHERE ID = ?","ZXC","5");
jdbcTemplate.update("DELETE FROM ACCOUNT WHERE ID = ?","6");
//2.查询所有;<> 和 ()内都要填写
List<User> list = jdbcTemplate.query("SELECT * FROM ACCOUNT", new BeanPropertyRowMapper<User>(User.class));
list.forEach(user -> System.out.println(user));
//3.查询一条数据
User user = jdbcTemplate.queryForObject("SELECT * FROM ACCOUNT where id = ?", new BeanPropertyRowMapper<User>(User.class), "1");
System.out.println(user);
}
四、update流程简化总结
//把DataSource接收保存
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(DruidUtils.getDateSource());
//经过多次重载,内部调用update方法
//update执行了两件事(1.封装sql语句;2.封装参数)
jdbcTemplate.update("INSERT INTO ACCOUNT VALUES(NULL,?,?,?)","QWE","1000","0");
//通过判断,内部执行的是execute方法
{
获取数据库连接对象
初始化statement对象
通过回调函数执行update函数中的ps->{}里面的逻辑
//ps->{}包括
{
将prepareStatement对象和传入的参数进行封装
int rows = ps.executeUpdate(); 执行sql
return rows
}
}
总结:
jdbcTemplate的update方法:
- 先将sql语句和参数分别封装,封装之后会进行绑定(即将sql语句中的问号替换为传入的参数)
- 有了完整的sql语句之后,进行jdbc的基础操作
- 获取Connection对象(通过DataSource获得)
- 初始化prepareStatement对象
- 执行prepareStatement的executeUpdate方法
- 返回结果rows
- 释放数据库连接资源
五、query查询所有的流程
List<User> list = jdbcTemplate.query("SELECT * FROM ACCOUNT", new BeanPropertyRowMapper<User>(User.class));
BeanPropertyRowMapper的作用:
- 将结果集的数据封装到具体的对象中去,对象是根据刚开始传进BeanPropertyRowMapper的class来决定的
- 对象通过反射进行创建,然后通过内省的方式将对象的属性和结果集中的数据进行封装。
- 封装过程:
六、queryForObject的流程
query和queryForObject都会执行query()方法,传参和不传参的执行流程不一样,但是最终都会执行execute方法。
注:queryForObject查找不到数据或者查找到的数据数量大于1,都会抛出异常(因为在源码中将result集合的大小设定为了1)
//把DataSource接收保存
JdbcTemplate jdbcTemplate = new JdbcTemplate();
jdbcTemplate.setDataSource(DruidUtils.getDateSource());
//经过多次重载,内部调用query方法
//update执行了两件事(1.封装sql语句;2.封装参数)
User user = jdbcTemplate.queryForObject("SELECT * FROM ACCOUNT where id = ?", new BeanPropertyRowMapper<User>(User.class), "1");
//通过判断,内部执行的是execute方法
{
获取数据库连接对象
初始化statement对象
action实际对象是匿名内部类
{
将prepareStatement对象和传入的参数进行封装
rs = ps.executeQuery(); 执行sql
return rse.extractData(rs)
{
创建一个大小为1的集合
使用BeanPropertyRowMapper将结果集中的数据封装到一个指定的对象中(通过反射 + 内省 实现)
}
}
}