本专栏将从基础开始,循序渐进,讲解数据库的基本概念以及使用,希望大家都能够从中有所收获,也请大家多多支持。
专栏地址: 数据库必知必会
相关软件地址:软件地址
如果文章知识点有错误的地方,请指正!大家一起学习,一起进步。
文章目录
1 DBUtils
1.1 DBUtils的概述
DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能
1.2 DBUtils的常用API介绍
-
创建QueryRunner对象的API
public QueryRunner(DataSource ds)
,提供数据源(连接池),DBUtils底层自动维护连接connection -
QueryRunner执行增删改的SQL语句的API
int update(String sql, Object... params)
,执行增删改的SQL语句, params参数就是可变参数,参数个数取决于语句中问号的个数eg: qr.update(“insert into user values(null,?,?,?)”,“zs”,“123456”,“张三”);
-
执行查询的SQL语句的API
query(String sql, ResultSetHandler<T> rsh, Object... params)
,其中ResultSetHandler是一个接口,表示结果集处理者
小结
DBUtils: Apache开发的一个数据库工具包, 用来简化JDBC操作数据库的步骤
1.3 JavaBean
JavaBean说白了就是一个类, 用来封装数据用的
-
JavaBean要求
- 私有字段
- 提供公共的get/set方法
- 无参构造
- 建议满参构造
- 实现Serializable
-
字段和属性
- 字段: 全局/成员变量 eg:
private String username
- 属性: 去掉get或者set首字母变小写 eg:
setUsername-去掉set->Username-首字母变小写->username
一般情况下,我们通过IDEA直接生成的set/get
- 字段: 全局/成员变量 eg:
小结
- JavaBean用来封装数据用的
- 字段和属性
- 字段: 全局/成员变量 eg:
private String username
- 属性: 去掉get或者set首字母变小写 eg:
setUsername-去掉set->Username-首字母变小写->username
- 字段: 全局/成员变量 eg:
1.4 使用DBUtils完成增删改
步骤
- 拷贝jar包
- 创建QueryRunner()对象,传入dataSource
- 调用update()方法
实现
public class UpdateTest {
// 插入记录
@Test
public void insert() throws Exception {
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用update方法
String sql = "insert into user values(null,?,?,?)";
int rows = qr.update(sql, "tianqi", "123456", "田七");
System.out.println("受影响的行数:" + rows);
}
// 删除记录 删除id为4的记录
@Test
public void delete() throws Exception {
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用update方法
String sql = "delete from user where id = ?";
int rows = qr.update(sql, 4);
System.out.println("受影响的行数:" + rows);
}
// 修改记录 修改id为5的记录
@Test
public void update() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用update方法
String sql = "update user set password = ? where id = ?";
int rows = qr.update(sql,"abcd",3);
System.out.println("受影响的行数:" + rows);
}
}
小结
- 创建QueryRuner()对象, 传入DataSource
- 调用update(String sql, Object…params)
1.5 使用DBUtils完成查询
目标
- 掌握使用DBUtils完成查询
步骤
- 拷贝jar包
- 创建QueryRunner()对象 传入DataSource
- 调用query(sql, resultSetHandler,params)方法
1.5.1 ResultSetHandler结果集处理类介绍
public queryRunner(DataSource ds);
query(String sql, ResultSetHandler rsh, Object… params) 执行查询语句
参数ResultSetHandler是一个接口,表示结果集处理者(对查询结果的封装):
ResultSetHandler接口的实现类:
ArrayHandler
:适合查询结果是一条记录的,会把这条记录的数据封装到一个Object数组中
ArrayListHandler
:适合查询结果是多条记录的,会把每条记录的数据封装到一个Object数组中,然后把这些数组添加到List集合中
BeanHandler
:适合查询结果是一条记录的,会把这条记录的数据封装到一个javaBean对象中
BeanListHandler
:适合查询结果是多条记录的,会把每条记录的数据封装到一个javaBean对象中,然后把这些javaBean对象添加到List集合中
ColumnListHandler
:适合查询结果是单列多行的,会把该列的所有数据存储到List集合中
KeyedHandle
:适合查询结果是多条记录的,会把每条记录的数据封装到一个Map集合中,然后把这些Map集合添加到另一个Map集合中
MapHandler
:适合查询结果是一条记录的,会把这条记录的数据封装到一个Map集合中
MapListHandler
:适合查询结果是多条记录的,会把每条记录的数据封装到一个Map集合中,然后把这些Map集合添加到List集合中
ScalarHandler
:适合查询结果是单个值的,会把这个值封装成一个对象
代码实现
1.5.1.1 查询一条数据封装到JavaBean对象中(使用BeanHandler)
@Test
public void select1() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query(sql,resultSetHandler,args)方法
String sql = "select * from user where id = ?";
User user = qr.query(sql, new BeanHandler<User>(User.class), 3);
System.out.println(user);
}
1.5.1.2 查询多条数据封装到List中(使用BeanListHandler)
@Test
public void select2() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select * from user";
List<User> list = qr.query(sql, new BeanListHandler<User>(User.class));
for (User user : list) {
System.out.println(user);
}
}
1.5.1.3 查询一条数据,封装到Map对象中(使用MapHandler)
// 查询一条数据,封装到Map对象中(使用MapHandler)
// 列名作为key,列中的值作为value
@Test
public void select3() throws Exception {
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select * from user where id = ?";
Map<String, Object> map = qr.query(sql, new MapHandler(), 3);
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
}
/*
password:123
nickname:aaa
id:3
username:wangwu
*/
1.5.1.4 查询多条数据,封装到List Map 对象中(使用MapListHandler)
// 查询多条数据,封装到List<Map>对象中(使用MapListHandler)
@Test
public void select4() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select * from user";
List<Map<String, Object>> list = qr.query(sql, new MapListHandler());
for (Map<String, Object> map : list) {
// map--->每条记录
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
System.out.println("=================================================");
}
}
1.5.1.5 查询单个数据(使用ScalarHandler())
// 查询单个数据(使用ScalarHandler())
@Test
public void select5() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select count(*) from user";
Long count = (Long) qr.query(sql, new ScalarHandler());
System.out.println("记录数:"+count);
}
1.5.1.6 查询单列多个值(使用ArrayListHandler)
// 查询单列多个值(ArrayListHandler)
// 单列多值: 每列的数据封装成一个数组,再把所有的数组存储到List集合中
// 多条记录: 每条记录的数据封装成一个数组,再把所有的数组存储到List集合中
@Test
public void select6() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select username from user";
List<Object[]> list = qr.query(sql, new ArrayListHandler());
for (Object[] arr : list) {
System.out.println(Arrays.toString(arr));
}
}
1.5.1.7 查询一条记录(使用ArrayHandler)
// 查询一条记录(ArrayHandler)
// 一条记录封装成一个数组,数组中的元素就是每列的值
@Test
public void select7() throws Exception{
// 1.创建QueryRunner对象,传入连接池
QueryRunner qr = new QueryRunner(C3P0Utils.getDataSource());
// 2.调用query方法
String sql = "select * from user where id = ?";
Object[] arr = qr.query(sql, new ArrayHandler(), 3);
System.out.println(Arrays.toString(arr));
}
小结
-
步骤
- 创建QueryRunner() 对象传入DataSource
- 调用query(sql,ResultSetHandler, params…)
-
ResultSetHandler
- BeanHandler() 查询一条记录封装到JavaBean对象
- BeanListHandler() 查询多条记录封装到List list
- ScalarHandler() 封装单个记录的 eg:统计数量
- ColumnListHandler() 封装单列多行记录
- MapHandler() 查询一条记录封装到Map对象
- MapListHandler() 查询多条记录封装到List
- ArrayHandler() 查询一条记录封装到数组中
原理: 使用了反射+内省
-
注意实现
封装到JavaBean条件, 查询出来的数据的列名必须和JavaBean属性一致
2 自定义DBUtils
我们要自定义DBUtils, 就需要知道列名, 参数个数等, 这些可以通过数据库的元数据库进行获得.元数据在建立框架和架构方面是特别重要的知识,我们可以使用数据库的元数据来创建自定义JDBC工具包, 模仿DBUtils.
2.1 什么是元数据
元数据(MetaData),即定义数据的数据。打个比方,就好像我们要想搜索一首歌的歌词(歌词本身是数据),而我们可以通过歌名,作者,专辑等信息来搜索,那么这些歌名,作者,专辑等等就是这首歌的元数据。因此数据库的元数据就是一些注明数据库信息的数据。
歌曲:aa
作词:bb
演唱: cc
时长: dd
…
简单来说: 数据库的元数据就是 数据库、表、列的定义信息。
① 由PreparedStatement对象的getParameterMetaData ()方法获取的是ParameterMetaData对象。
② 由ResultSet对象的getMetaData()方法获取的是ResultSetMetaData对象。
2.1.1 ParameterMetaData
概述
ParameterMetaData是由preparedStatement对象通过getParameterMetaData方法获取而来,ParameterMetaData
可用于获取有关PreparedStatement
对象和其预编译sql语句
中的一些信息. eg:参数个数,获取指定位置占位符的SQL类型
获得ParameterMetaData:
`ParameterMetaData parameterMetaData = preparedStatement.getParameterMetaData ()`
2.1.2 ParameterMetaData相关的API
- int getParameterCount(); 获得参数个数
- int getParameterType(int param) 获取指定参数的SQL类型。 (注:MySQL不支持获取参数类型)
实例代码
package com.hashnode.test;
import com.hashnode.utils.C3P0Utils;
import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
public class Test1_参数元数据 {
public static void main(String[] args) throws Exception{
/*
ParameterMetaData类:
概述: 是一个参数元数据类,可以用来获取参数的元数据
使用:
1.获取参数元数据类对象
PreparedStatement对象调用getParameterMetaData()方法
2.获取参数的元数据
ParameterMetaData相关的API
- int getParameterCount(); 获得参数个数
- int getParameterType(int param) 获取指定参数的SQL类型。 (注:MySQL不支持获取参数类型)
*/
// 1.获取连接
Connection connection = C3P0Utils.getConnection();
// 2.预编译sql语句
String sql = "select * from user where username = ? and password = ?";
PreparedStatement ps = connection.prepareStatement(sql);
// 3.通过PreparedStatement对象获取参数元数据对象
ParameterMetaData pmd = ps.getParameterMetaData();// 参数元数据对象
// 4.获取参数个数元数据 参数个数就是参数的元数据
int count = pmd.getParameterCount();
System.out.println("sql语句的参数个数:"+count);// 2
// 5.获取参数类型元数据 参数类型也是参数的元数据 MySQL不支持获取参数类型
// int parameterType = pmd.getParameterType(1);
// System.out.println(parameterType);
// String typeName = pmd.getParameterTypeName(1);
// System.out.println(typeName);
}
}
2.1.3 ResultSetMetaData
概述
ResultSetMetaData是由ResultSet对象通过getMetaData方法获取而来,ResultSetMetaData
可用于获取有关ResultSet
对象中列的类型和属性的信息。
获得ResultSetMetaData:
`ResultSetMetaData resultSetMetaData = resultSet.getMetaData()`
2.1.3.1 resultSetMetaData 相关的API
- getColumnCount(); 获取结果集中列项目的个数
- getColumnName(int column); 获得数据指定列的列名
- getColumnTypeName();获取指定列的SQL类型
- getColumnClassName();获取指定列SQL类型对应于Java的类型
实例代码
public class Test2_结果集元数据 {
public static void main(String[] args) throws Exception {
/*
ResultSetMetaData类:
概述:是一个结果集元数据类,可以用来获取结果集的元数据
使用:
1.获取结果集元数据类的对象
ResultSet的对象调用getMetaData()方法
2.获取结果集的元数据
ResultSetMetaData 相关的API
- getColumnCount(); 获取结果集中列项目的个数
- getColumnName(int column); 获得数据指定列的列名
- getColumnTypeName();获取指定列的SQL类型
- getColumnClassName();获取指定列SQL类型对应于Java的类型
*/
// 1.获取连接
Connection connection = C3P0Utils.getConnection();
// 2.预编译sql语句
String sql = "select * from user where username = ? and password = ?";
PreparedStatement ps = connection.prepareStatement(sql);
// 3.设置参数
ps.setString(1, "zs");
ps.setString(2, "123456");
// 4.执行sql语句
ResultSet resultSet = ps.executeQuery();
// 5.获取结果集的元数据对象
ResultSetMetaData rsmd = resultSet.getMetaData();
// 1.获取列的数量
int columnCount = rsmd.getColumnCount();
System.out.println("列的个数:" + columnCount);//4
// 2.获取列的名字
for (int i = 1; i <= columnCount; i++) {
System.out.println(rsmd.getColumnName(i));
}
System.out.println("==================================");
// 3.获取列的MySQL类型
for (int i = 1; i <= columnCount; i++) {
System.out.println(rsmd.getColumnTypeName(i));
}
System.out.println("==================================");
// 4.获取列在Mysql中的类型对应于java中的类型
for (int i = 1; i <= columnCount; i++) {
System.out.println(rsmd.getColumnClassName(i));
}
}
}
小结
- 元数据: 描述数据的数据. mysql元数据: 用来定义数据库, 表 ,列信息的 eg: 参数的个数, 列的个数, 列的类型…
- mysql元数据:
- ParameterMetaData
- ResultSetMetaData
2.2 自定义DBUtils增删改
需求
- 模仿DBUtils, 完成增删改的功能
分析
- 创建MyQueryRunner类, 定义dataSource, 提供有参构造方法
- 定义int update(String sql, Object…params)方法
0.非空判断
1.从dataSource里面获得connection
2.根据sql语句创建预编译sql语句对象
3.获得参数元数据对象, 获得参数的个数
4.遍历, 从params取出值, 依次给参数? 赋值
5.执行
6.释放资源
实现
public class MyQueryRunner {
private DataSource dataSource;
public MyQueryRunner(DataSource dataSource) {
this.dataSource = dataSource;
}
public MyQueryRunner() {
}
/**
* 增删改的方法
* @param sql
* @param args
* @return rows
*/
public int update(String sql,Object... args) throws Exception{
// 非空判断
// 连接池为空
if (dataSource == null){
throw new RuntimeException("连接池不能为null");
}
if (sql == null){
throw new RuntimeException("sql语句不能为空");
}
// 1.获得连接
Connection connection = dataSource.getConnection();
// 2.预编译sql语句
PreparedStatement ps = connection.prepareStatement(sql);
// 3.设置参数
// 3.1 获得参数元数据类的对象
ParameterMetaData pmd = ps.getParameterMetaData();
// 3.2 根据参数元数据类的对象,获取参数个数(元数据)
int count = pmd.getParameterCount();
// 3.3 给参数赋值
for (int i = 0; i < count; i++) {
ps.setObject(i+1,args[i]);
}
// 4.执行sql语句
int rows = ps.executeUpdate();
// 5.释放资源
C3P0Utils.release(null,ps,connection);
// 6.返回影响的行数
return rows;
}
}