JDBC
今日任务
- 使用JDBC完成对分类表的CRUD的操作(JDBC的回顾)
- 使用DBCP,C3P0连接池完成基本数据库的操作(抽取工具类)
- 能够使用DBUtils完成CRUD的操作
教学导航
教学目标 |
掌握DBCP和C3P0连接池的使用并掌握连接池的原理. 能够使用DBUtils完成基本的CRUD的操作 |
教学方法 |
案例驱动法 |
1.1 使用JDBC完成对于分类的CRUD的操作-回顾JDBC
1.1.1 需求:
网上商城中对分类添加,修改,删除,查询的操作.使用JDBC完成对分类的CRUD的操作.
1.1.2 分析:
1.1.2.1 技术分析
【JDBC的回顾】
- JDBC的概念:
JDBC:Java Data Base Connectivity.
- 驱动:
- JDBC的开发步骤:
步骤一:注册驱动.
步骤二:获得连接.
步骤三:创建执行SQL语句对象.
步骤四:释放资源.
- JDBC的API的详解:
DriverManager:
* 注册驱动:
* 获得连接:
Connection:
* 获得执行SQL语句对象.
* Statement createStatement();
* PreparedStatement prepareStatement(String sql);
* CallableStatement prepareCall(String sql);
* 进行事务管理:
* setAutoCommit(boolean flag);
* commit();
* rollback();
Statement:
* 执行SQL语句:
* int executeUpate(String sql); --执行insert update delete语句.
* ResultSet executeQuery(String sql); --执行select语句.
* boolean execute(String sql); --执行select返回true 执行其他的语句返回false.
ResultSet:
* 遍历结果集:next();
* 获得结果集中的数据.getXXX(int c); getXXX(String name);
1.1.2.2 步骤分析
- 步骤一:创建Java项目,引入mysql的驱动包.
- 步骤二:编写程序
- 步骤三:注册驱动
- 步骤四:获得连接
- 步骤五:执行SQL
- 步骤六:释放资源
1.1.3 代码实现:
抽取工具类:
package com.itheima.jdbc.utils;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
/**
* JDBC的工具类
* @author apple
*
*/
public class JDBCUtils {
public static final String DRIVERCLASS;
public static final String URL;
public static final String USERNAME;
public static final String PASSWORD;
static{
// 获得属性文件中的数据.
Properties properties = new Properties();
try {
properties.load(new FileInputStream("src/db.properties"));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
DRIVERCLASS = properties.getProperty("jdbc.driverClass");
URL = properties.getProperty("jdbc.url");
USERNAME = properties.getProperty("jdbc.username");
PASSWORD = properties.getProperty("jdbc.password");
}
// 加载驱动:
public static void loadDriver(){
try {
Class.forName(DRIVERCLASS);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 获得连接:
public static Connection getConnection(){
loadDriver();
Connection conn = null;
try {
conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
// 释放资源:
public static void release(Statement stmt,Connection conn){
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
public static void release(ResultSet rs,Statement stmt,Connection conn){
if(rs!= null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
rs = null;
}
if(stmt != null){
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
stmt = null;
}
if(conn != null){
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
conn = null;
}
}
}
1.2 使用连接池改造JDBC的程序:
1.2.1 需求:
提升程序运行的效率,采用连接池对JDBC的部分的效率进行提升.
1.2.2 分析:
1.2.2.1 技术分析:
【连接池的概述】
- 为什么使用连接池
Connection对象在JDBC使用的时候.使用的时候就会去创建一个对象,使用结束以后就会将这个对象给销毁了.每次创建和销毁对象都是耗时操作.需要使用连接池对其进行优化.程序初始化的时候,初始化多个连接,将多个连接放入到池中(内存中).每次获取的时候,都可以直接从连接池中进行获取.使用结束以后,将连接归还到池中.
- 常见连接池:
DBCP :Apache.
C3P0 :
【连接池的原理】
在javax.sql.DataSource接口--连接池的接口
* 功能:初始化多个连接.把多个连接放入到内存中.
* 归还:将连接对象放回到内存中.
【自定义连接池--了解】
public class MyDataSource implements DataSource{
// 创建一个集合List集合.
List<Connection> list = new ArrayList<Connection>();
// 初始化连接池的时候,初始化5个连接.
public MyDataSource() {
for (int i = 1; i <= 5; i++) {
Connection conn = JDBCUtils.getConnection();
list.add(conn);
}
}
@Override
// 从连接池中获得连接
public Connection getConnection() throws SQLException {
if(list.size()==0){
for (int i = 1; i <= 3; i++) {
Connection conn = JDBCUtils.getConnection();
list.add(conn);
}
}
Connection conn = list.remove(0);
return conn;
}
// 归还连接:
public void addBack(Connection conn){
list.add(conn);
}
...
}
【自定义连接池中问题】
1.创建连接池的时候能不能面向接口编程.
2.额外增加连接池的方法,那么程序员需要记住这些方法.能不能不额外去提供一些方法.
***** 解决:就是要去增强Connection的close方法.
1.继承的方法:
* 继承的使用条件:能够控制这个类的构造.
2.装饰者模式:(*****)
* 装饰者模式的使用条件:
* 2.1增强的类和被增强的类实现相同的接口.
* 2.2在增强的类中能够获得被增强的类的引用.
* 接口中方法过多,只增强其中的一个方法.其他方法都需要原样调用原有方法.
3.动态代理:(*****)
* JDK的动态代理使用条件:
* 被代理的对象必须实现接口.
【使用开源连接池优化程序】
- DBCP连接池:
核心API:
@Test
/**
* DBCP的一个入门:手动设置参数
*/
public void demo1(){
Connection conn = null;
PreparedStatement pstmt = null;
// 创建连接池:
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///web07");
dataSource.setUsername("root");
dataSource.setPassword("1234");
try{
// 获得连接:
conn = dataSource.getConnection();
// 编写SQL语句.
String sql = "insert into category values (null,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "鞋靴箱包");
//执行SQL
pstmt.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
@Test
/**
* DBCP的带有配置文件的方式
*/
public void demo2(){
Connection conn = null;
PreparedStatement pstmt = null;
// 创建连接池:
try{
Properties properties = new Properties();
properties.load(new FileInputStream("src/dbcp.properties"));
DataSource dataSource = BasicDataSourceFactory.createDataSource(properties);
// 获得连接:
conn = dataSource.getConnection();
// 编写SQL语句.
String sql = "insert into category values (null,?)";
// 预编译SQL:
pstmt = conn.prepareStatement(sql);
// 设置参数:
pstmt.setString(1, "生活用品");
//执行SQL
pstmt.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(pstmt, conn);
}
}
DBCP的参数的设置:
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbc
username=root
password=1234
#<!-- 初始化连接 -->
initialSize=10
#最大连接数量
maxActive=50
#<!-- 最大空闲连接 -->
maxIdle=20
#<!-- 最小空闲连接 -->
minIdle=5
#<!-- 超时等待时间以毫秒为单位 6000毫秒/1000等于60秒 -->
maxWait=60000
- C3P0连接池的使用:
代码实现:
@Test
/**
* 手动设置参数的方式:
*/
public void demo1(){
Connection conn = null;
PreparedStatement stmt = null;
// System.err.println("");
try{
// 创建连接池:
ComboPooledDataSource dataSource = new ComboPooledDataSource();
// 设置参数:
dataSource.setDriverClass("com.mysql.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql:///web07");
dataSource.setUser("root");
dataSource.setPassword("1234");
conn = dataSource.getConnection();
// 编写SQL
String sql = "insert into category values (null,?)";
// 预编译SQL:
stmt = conn.prepareStatement(sql);
// 设置参数:
stmt.setString(1, "食品饮料");
stmt.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(stmt, conn);
}
}
@Test
/**
* 配置文件的方式:
*/
public void demo2(){
Connection conn = null;
PreparedStatement stmt = null;
// System.err.println("");
try{
// 创建连接池:
ComboPooledDataSource dataSource = new ComboPooledDataSource("mysql11111");
conn = dataSource.getConnection();
// 编写SQL
String sql = "insert into category values (null,?)";
// 预编译SQL:
stmt = conn.prepareStatement(sql);
// 设置参数:
stmt.setString(1, "食品饮料222");
stmt.executeUpdate();
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(stmt, conn);
}
}
【使用C3P0改写了工具类】
public class JDBCUtils2 {
private static final ComboPooledDataSource DATASOURCE =new ComboPooledDataSource();
public Connection getConnection(){
Connection conn = null;
try {
conn = DATASOURCE.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
...
}
1.3 DBUtils完成CRUD的操作
1.3.1 需求:
简化DAO的开发.
1.3.2 分析:
1.3.2.1 技术分析:
DBUtils
【概述】
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核心功能介绍
l QueryRunner中提供对sql语句操作的API.
l ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
l DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
【QueryRunner核心类】
l QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection
l update(String sql, Object... params) ,执行更新数据
l query(String sql, ResultSetHandler<T> rsh, Object... params) ,执行查询
【ResultSetHandler结果集处理类】
ArrayHandler |
将结果集中的第一条记录封装到一个Object[]数组中,数组中的每一个元素就是这条记录中的每一个字段的值 |
ArrayListHandler |
将结果集中的每一条记录都封装到一个Object[]数组中,将这些数组在封装到List集合中。 |
BeanHandler |
将结果集中第一条记录封装到一个指定的javaBean中。 |
BeanListHandler |
将结果集中每一条记录封装到指定的javaBean中,将这些javaBean在封装到List集合中 |
ColumnListHandler |
将结果集中指定的列的字段值,封装到一个List集合中 |
KeyedHandler |
将结果集中每一条记录封装到Map<String,Object>,在将这个map集合做为另一个Map的value,另一个Map集合的key是指定的字段的值。 |
MapHandler |
将结果集中第一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值 |
MapListHandler |
将结果集中每一条记录封装到了Map<String,Object>集合中,key就是字段名称,value就是字段值,在将这些Map封装到List集合中。 |
ScalarHandler |
它是用于单数据。例如select count(*) from 表操作。 |
【DbUtils】
closeQuietly(Connection conn) 关闭连接,如果有异常try后不抛。
commitAndCloseQuietly(Connection conn) 提交并关闭连接
rollbackAndCloseQuietly(Connection conn) 回滚并关闭连接