JDBC及开源连接池Druid和C3P0的使用

1.JDBC

前面我们讲解了如何创建我们的第一个JDBC程序,接下来就详细的介绍我们的第一个JDBC程序

JDBC概述:JDBC是一种用于执行sql语句的java API,可以为多种关系数据库提供统一访问,它由一组java语言编写的类和接口组成,JDBC提供了一种基准,据此1就可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。

什么是数据库驱动

两个设备(应用)之间通信的桥梁

为什么要学习JDBC

没有JDBC的时候,如果现在要开发一套系统,使用java连接MySQL数据库,那么这时候java程序员需要了解MySQL驱动API,如果使用java连接Oracle数据库,那么这个时候java程序源需要了解Oracle数据库驱动API,后来,SUN公司就提供了一套统一的规范(接口),然后各个数据库生产商提供这套接口的实现,这套接口规范就是JDBC的规范了

JDBC的环境部署(以下JDBC操作的数据库都是这个数据库)

创建数据库:

create database my;

创建表:

-- 用户表 

CREATE TABLE user(
	 nid int not null auto_increment PRIMARY KEY,
	 username varchar(20),
	 password varchar(20),
	 role varchar(20)
);

-- 银行账户表

create table account(
nid int not null auto_increment PRIMARY key,
name varchar(20),
money int
);

添加数据:

//往用户表添加数据

insert into student(username, `password`, role) VALUES("luyi", "123", "student"), ("luer","321", "teacher")

//往银行账户表添加数据
insert into account(name, money) values("luyi", 1000), ("luer", 1000)

JDBC的使用步骤

1.加载驱动

2.获得连接

3.基本操作(增删改查)

4.释放资源

代码示例:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBCDemo {
	public static void main(String[] args) throws Exception {
		//加载驱动
		Class.forName("com.mysql.cj.jdbc.Driver");
		//获得连接
		Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my?serverTimezone=UTC", "root", "123");
		//获得执行sql的对象
		Statement statement = conn.createStatement();
		//编写sql语句
		String sql = "select * from user";
		//执行sql语句
		ResultSet rs = statement.executeQuery(sql);
		//遍及结果集
		while(rs.next()){
			System.out.println(rs.getInt("id") + " ");
			System.out.println(rs.getString("username") + " ");
			System.out.println(rs.getString("password") + " ");
			System.out.println(rs.getString("role") + " ");
		}
		
		//释放资源
		rs.close();
		statement.close();
		conn.close();
	}
}

2.JDBC的API详解

DriverManager:驱动管理类

  • registerDriver(Driver driver):该方法可以完成驱动的注册,但是实际开发中一般不会使用这个方法完成驱动的注册,因为通过查看源代码我们可以知道,在代码中有一段静态代码块,静态代码块已经调用了注册驱动的方法,所以如果我们手动调用该方法注册驱动,就会导致驱动被注册两次,实际开发中我们使用Class.forName("com.mysql.cj.jdbc.Driver"),通过加载这个类,然后执行静态代码块的代码,注册了驱动
  • getConnection(url, user, password):这个方法就是用来获得与数据库连接的,这个方法的三个参数,返回值是一个Connection实现类对象:
    • url:与数据库连接的路径:格式为jdbc:mysql://localhost:3306/mydb,如果连接的是本机,则可简写为jdbc:mysql:///mydb
      • jdbc:连接数据库的协议
      • mysql:是jdbc的子协议,我们用的是mysql数据
      • localhost:连接的MySQL数据库服务区的主机地址(连接本机的数据所以写出localhost,如果不是本机的数据库,就需要写上连接主机的ip地址)
      • 3306:MySQL数据库服务器的端口号
      • mydb:数据库名称
    • user:与数据库连接的用户名
    • password:与数据库连接的密码

Connection:与数据库连接的对象,是一个接口

Connection的实现类对象可以干嘛呢?

1.创建执行sql语句的对象:

  • createStatement():创建一个Statement对象,用于将sql语句发送到数据库
  • prepareCall(String sql):创建一个CallableStatement对象来调用数据库存储过程
  • prepareStatement(String sql):创建一个PreparedStatment对象来将参数化的sql语句发送到数据库,用于对sql进行预处理,解决sql注入漏洞

2.管理事务

  • setAutoCommit(boolean autoCommit):用于设置是否自动提交事务
  • commit():用于提交事务
  • rollback():事务回滚的方法

Statement:用于执行静态sql语句并返回它所生成结果的对象,一个接口

Statement的实现类对象可以干嘛呢?

1.执行sql:

  • boolean execute(String sql):执行查询,修改,添加,删除的sql语句,不经常使用
  • ResultSet executeQuery(String sql):执行查询语句,返回结果集ResultSet
  • int executeUpdate(String sql):执行修改,添加,删除的sql语句

2.执行批处理

  • void addBatch(String sql):将给定的sql命令添加到此Statement对象的当前命令列表中(添加批处理)
  • void clearBatch():清空此Statement对象的当前sql命令列表(删除批处理)
  • int[] executeBatch():将命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组(执行批处理)

ResultSet(结果集):表示的是数据库结果集的数据表,通常通过执行查询数据库的语句生成,是一个接口

1.结果集的遍历和获取:

  • next():将光标从当前位置向前移动一行
  • getXxx(int columnIndex):根据第几列第几列来获取数据
  • getXxx(String columnName):根据列名来获取数据

JDBC资源释放

概述:JDBC程序执行结束后,将与数据库进行交互的对象释放掉,通常是ResultSet,Statement,Connection,这几个对象中尤其是Connection对象是非常稀有的,这个对象一定要做到尽量晚创建,尽早释放掉

标准的释放代码应该写入finally代码中,而且需要手动将这几个对象置为空,以便及早被垃圾回收器发现,回收

标准的释放资源代码如下:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCDemo {
	public static void main(String[] args) {
		
		Connection conn = null;
		Statement statement = null;
		ResultSet rs = null;
		try{
			//加载驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			//获得连接
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my?serverTimezone=UTC", "root", "123");
			//获得执行sql的对象
			statement = conn.createStatement();
			//编写sql语句
			String sql = "select * from user";
			//执行sql语句
			rs = statement.executeQuery(sql);
			//遍及结果集
			while(rs.next()){
				System.out.println(rs.getInt("id") + " ");
				System.out.println(rs.getString("username") + " ");
				System.out.println(rs.getString("password") + " ");
				System.out.println(rs.getString("role") + " ");
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//标准的释放资源
			if(statement != null){
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				statement = null;
			}
			
			if(conn != null){
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				conn = null;
			}
			if(rs != null){
				try {
					rs.close();
				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				rs = null;
			}		
		}
	}
}

3.JDBC的CRUD操作

代码示例(对数据库进行增删改查):

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCDemo {
	public static void main(String[] args) {
		
		Connection conn = null;
		Statement statement = null;
		ResultSet rs = null;
		try{
			//加载驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			//获得连接
			conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/my?serverTimezone=UTC", "root", "123");
			//获得执行sql的对象
			statement = conn.createStatement();
			//编写sql语句
			String sql1 = "insert into user(username, password, role) value('卢一', '123', 'doctor')";//添加操作
			//String sql2 = "delete from user where username = 'luyi'";//删除操作
			//String sql3 = "update user set password = '666' where username = 'luer'";//修改操作
			String sql4 = "select * from user";//查询操作
			
			//增删改操作对应返回影响的行数
			int column = statement.executeUpdate(sql1);
			if(column > 0){
				System.out.println("操作成功");
			}
			
			/*//查询操作对应返回结果集
			 * //执行sql语句
			rs = statement.executeQuery(sql4);
			//遍及结果集
			while(rs.next()){
				System.out.print(rs.getInt("id") + " ");
				System.out.print(rs.getString("username") + " ");
				System.out.print(rs.getString("password") + " ");
				System.out.println(rs.getString("role"));
			}*/
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//标准的释放资源
			if(statement != null){
				try {
					statement.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				statement = null;
			}
			
			if(conn != null){
				try {
					conn.close();
				} catch (SQLException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				conn = null;
			}
			if(rs != null){
				try {
					rs.close();
				} catch (SQLException e1) {
					// TODO Auto-generated catch block
					e1.printStackTrace();
				}
				rs = null;
			}		
		}
	}
}

4.对JDBC的工具类的抽取以及提取配置信息到配置文件

从上面对JDBC的增删改查操作可以看出

1.工具类:

没有对象封装数据体现,只有方法,禁止了对象创建

2.配置文件:

  • 属性文件
    • 格式:扩展名是.properties
    • 内容:key=value:键值对形式出现
  • XML文件

示例代码:

//db.properties属性配置文件

driverClassName = com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/my?serverTimezone=UTC
username=root
password=123

//JDBCUtils.java

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的工具类
 */
public class JDBCUtils {
	/*
	 * 注册驱动的方法
	 */
	private static final String driverClassName;
	private static final String url;
	private static final String username;
	private 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();
		}
		driverClassName = properties.getProperty("driverClassName");
		url = properties.getProperty("url");
		username = properties.getProperty("username");
		password = properties.getProperty("password");
	}
	
	public static void loadDriver(){
		try {
			Class.forName(driverClassName);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/*
	 * 获得连接的方法
	 */
	public static Connection getConnection(){
		Connection conn = null;
		try {
			conn =  DriverManager.getConnection(url, username, password);
		} catch (SQLException e) {
			e.printStackTrace();
		}
		return conn;
	}
	
	/*
	 * 释放资源的方法
	 */
	public static void release(Statement stmt, Connection conn){
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				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(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			rs = null;
		}		
	}
}

//JDBCUtilsText

/*
 * JDBC工具类的测试类
 */
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

public class JDBCUtilsText {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			//获得连接
			conn = JDBCUtils.getConnection();
			//sql操作
			stmt = conn.createStatement();
			String sql = "select * from user";
			rs = stmt.executeQuery(sql);
			//遍历结果集
			while(rs.next()){
				System.out.print(rs.getString("username") + " ");
				System.out.print(rs.getString("password") + " ");
				System.out.println(rs.getString("role"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(rs, stmt, conn);
		}
		
		
	}
}

5.JDBC的SQL注入及解决方式

sql注入的概述:SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编写时的疏忽,通过SQL语句,实现无账号登录,甚至篡改数据库

sql注入攻击实例:

String sql = "select * from user_table where username=
' "+userName+" ' and password=' "+password+" '";

--当输入了上面的用户名和密码,上面的SQL语句变成:
SELECT * FROM user_table WHERE username=
'’or 1 = 1 -- and password='’

"""
--分析SQL语句:
--条件后面username=”or 1=1 用户名等于 ” 或1=1 那么这个条件一定会成功;

--然后后面加两个-,这意味着注释,它将后面的语句注释,让他们不起作用,这样语句永远都--能正确执行,用户轻易骗过系统,获取合法身份。
--这还是比较温柔的,如果是执行
SELECT * FROM user_table WHERE
username='' ;DROP DATABASE (DB Name) --' and password=''
--其后果可想而知…
"""

JDBC的SQL注入漏洞解决

需要采用PreparedStatement对象解决SQL注入漏洞,这个对象将SQL预先进行编译1,使用?作为占位符,?所代表的内容就是SQL所固定的,再次传入变量(包含SQL的关键字),这个时候也不会识别这些关键字

使用PrepareStatement对象进行增删改查:

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JDBCUtilsText {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			//获得连接
			conn = JDBCUtils.getConnection();
			
			//预编译sql操作
			
			//添加操作
			/*String sql1 = "insert into user(username, password, role) value(?, ?, ?)";
			pstmt = conn.prepareStatement(sql1);
			pstmt.setString(1, "赵露思");
			pstmt.setString(2, "888");
			pstmt.setString(3, "actor");*/
			
			//删除操作
			/*String sql2 = "delete from user where role = ?";
			pstmt.setString(1, "doctor");*/
			
			//修改操作
			String sql3 = "update user set password = ? where username = ?";
			pstmt = conn.prepareStatement(sql3);
			pstmt.setString(1, "000000");
			pstmt.setString(2, "赵露思");
			int column = pstmt.executeUpdate();
			if(column > 0){
				System.out.println("操作成功");
			}
			
			//查询操作
			/*String sql4 = "select * from user where username = ? and password = ?";
			pstmt = conn.prepareStatement(sql4);
			pstmt.setString(1, "luer");
			pstmt.setString(2, "666");
			rs = pstmt.executeQuery();
			if(rs.next()){
				System.out.println(rs.getString("username"));
				System.out.println(rs.getString("password"));
			}*/
			
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(rs, pstmt, conn);
		}
	}
}

6.JDBC的批处理

批量插入数据

import java.sql.Connection;
import java.sql.PreparedStatement;

public class JDBCDemo2 {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		try{
			JDBCUtils.loadDriver();
			conn = JDBCUtils.getConnection();
			String sql = "insert into user(username, password, role) values(?, '123', 'student')";
			pstmt = conn.prepareStatement(sql);
			
			for(int i = 1; i <= 10000; i ++){
				pstmt.setString(1, "luyi" + i);
				//添加到批处理
				pstmt.addBatch();
				//每添加1000条就执行一次批处理并释放
				if(i % 1000 == 0){
					//执行批处理
					pstmt.executeBatch();
					//清空批处理
					pstmt.clearBatch();
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils.release(pstmt, conn);
		}
		
	}
}

//注意:db.properiter属性文件中url需要传递一个参数表示允许批处理,修改后如下:
url=jdbc:mysql://localhost:3306/my?serverTimezone=UTC&rewriteBatchedStatements=true

7.JDBC的事务管理

事务的概念:事务是指逻辑上的一组操作,组成这组操作的各个逻辑单元要么全部成功,要么全部失败

JDBC的事务管理案例(银行转账案例):

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

public class AffairDemo {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			//获得连接
			conn = JDBCUtils.getConnection();
			//开启事务
			conn.setAutoCommit(false);
			//编写sql语句,用luyi账户给luer账户转账
			String sql = "update account set money = money + ? where name = ?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, -100);
			pstmt.setString(2, "luyi");
			//执行sql
			pstmt.executeUpdate();
			
			//使其报错
			int i = 1/0;
			
			//给luer账号加100
			pstmt.setInt(1, 100);
			pstmt.setString(2, "luer");
			pstmt.executeUpdate();
			//提交事务
			conn.commit();
		}catch(Exception e){
			//事务回滚
			try {
				conn.rollback();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			e.printStackTrace();
		}finally{
			JDBCUtils.release(pstmt, conn);
		}
	}
}

//如果没有添加事务,程序里面的这个报错就会使得luyi转账没了100,但是luer却没有收到这100块

8.连接池

概述:连接池是创建和管理一个连接的缓冲池的技术,这些连接准备好被任何需要它们的线程使用;连接对象创建和销毁是需要耗费时间的,在服务器初始化的时候就初始化一些连接,把这些连接放入到内存中,使用的时候可以从内存中获取,使用完成之后将连接放入连接池中,从内存中获取和归还的效率要远远高于创建和销毁的效率

自定义连接池

概述:通过实现DataSource接口实现自定义连接池

代码示例:

//MyDataSource.java

package cn.luyi.demo1;

/*
 * 自定义连接池
 */
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.sql.DataSource;

public class MyDataSource implements DataSource {
	//将一些连接存入到内存中,可以定义一个集合,用于存储连接对象,这个集合就相当于连接池
	private List<Connection> connList = new ArrayList<Connection>();
	//在初始化的时候提供一些连接,添加连接到内存中
	public MyDataSource(){
		//初始化连接
		for(int i = 1; i <= 3; i ++){
			connList.add(JDBCUtils.getConnection());
		}
	}
	//从连接池中获得连接的方法
	@Override
	public Connection getConnection() throws SQLException {
		Connection conn  = connList.remove(0);
		return conn;
	}
	/*
	 * 将连接归还到连接池的方法
	 */
	public void addBack(Connection conn){
		connList.add(conn);
	}
	
	@Override
	public PrintWriter getLogWriter() throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void setLogWriter(PrintWriter out) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void setLoginTimeout(int seconds) throws SQLException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public int getLoginTimeout() throws SQLException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public Logger getParentLogger() throws SQLFeatureNotSupportedException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public <T> T unwrap(Class<T> iface) throws SQLException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isWrapperFor(Class<?> iface) throws SQLException {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public Connection getConnection(String username, String password) throws SQLException { 
		return null;
	}


}

//MyDataSourceText.java

package cn.luyi.demo1;

/*
 * 连接池测试类
 */
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class MyDataSourceText {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		MyDataSource mdb = null;
		
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			//从连接池获取连接
			mdb = new MyDataSource();
			conn = mdb.getConnection();
			
			stmt = conn.createStatement();
			//编写sql语句
			String sql = "select * from user";
			//执行sql,获取结果集
			rs = stmt.executeQuery(sql);
			while(rs.next()){
				System.out.print(rs.getString("username")  + " ");
				System.out.print(rs.getString("password")  + " ");
				System.out.println(rs.getString("role"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//释放资源
			if(rs != null){
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			rs = null;
			
			if(stmt != null){
				try {
					stmt.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			stmt = null;
			
			//归还连接到连接池
			mdb.addBack(conn);
		}	
	}
}

以上是我们对自定义连接池的基本实现,但是我们的代码存在两点不合理的地方:

  • 使用接口的实现类完成构造,而不是接口来完成构造
  • 额外提供了连接归还连接池的方法,也正是因为有这个额外的方法,我们无法用接口来完成构造

那么,我们怎么样才能不提供额外的方法,还能实现连接归还连接池呢?

回想之前我们释放Connection时调用的是close方法,那我们是否有办法把close完成的释放资源的功能改为归还连接的功能呢?

答案是肯定的,把原有的close方法的逻辑改为归还连接,也就是增强一个类中的方法,我们有三种方法:

1.采用继承的方式,继承这种方法最简单,但是是有使用条件的:必须能够控制这个类的构造,也就是可以new这个类创建对象

2.采用装饰者模式:使用条件

  • 增强的类和被增强的类实现相同的接口
  • 在增强的类中获得被增强的类的引用

3.采用动态代理模式

采用装饰者模式实现把原有的close方法的逻辑改为归还连接代码示例:

	//ConnectionImpl.java
	
	package cn.luyi.demo1;
	
	/*
	 * 模板类
	 */
	import java.sql.Array;
	import java.sql.Blob;
	import java.sql.CallableStatement;
	import java.sql.Clob;
	import java.sql.Connection;
	import java.sql.DatabaseMetaData;
	import java.sql.NClob;
	import java.sql.PreparedStatement;
	import java.sql.SQLClientInfoException;
	import java.sql.SQLException;
	import java.sql.SQLWarning;
	import java.sql.SQLXML;
	import java.sql.Savepoint;
	import java.sql.Statement;
	import java.sql.Struct;
	import java.util.Map;
	import java.util.Properties;
	import java.util.concurrent.Executor;
	
	public class ConnectionImpl implements Connection{
	
		private Connection conn;
		public ConnectionImpl(Connection conn){
			super();
			this.conn = conn;
		}
		@Override
		public <T> T unwrap(Class<T> iface) throws SQLException {
			return conn.unwrap(iface);
		}
	
		@Override
		public boolean isWrapperFor(Class<?> iface) throws SQLException {
			return conn.isWrapperFor(iface);
		}
	
		@Override
		public Statement createStatement() throws SQLException {
			return conn.createStatement();
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql) throws SQLException {
			return conn.prepareStatement(sql);
		}
	
		@Override
		public CallableStatement prepareCall(String sql) throws SQLException {
			return conn.prepareCall(sql);
		}
	
		@Override
		public String nativeSQL(String sql) throws SQLException {
			return nativeSQL(sql);
		}
	
		@Override
		public void setAutoCommit(boolean autoCommit) throws SQLException {
			
		}
	
		@Override
		public boolean getAutoCommit() throws SQLException {
			return conn.getAutoCommit();
		}
	
		@Override
		public void commit() throws SQLException {
			conn.commit();
		}
	
		@Override
		public void rollback() throws SQLException {
			conn.rollback();
		}
	
		@Override
		public void close() throws SQLException {
			conn.close();
		}
	
		@Override
		public boolean isClosed() throws SQLException {
			return conn.isClosed();
		}
	
		@Override
		public DatabaseMetaData getMetaData() throws SQLException {
			return conn.getMetaData();
		}
	
		@Override
		public void setReadOnly(boolean readOnly) throws SQLException {
			conn.setReadOnly(readOnly);
		}
	
		@Override
		public boolean isReadOnly() throws SQLException {
			return conn.isReadOnly();
		}
	
		@Override
		public void setCatalog(String catalog) throws SQLException {
			conn.setCatalog(catalog);
		}
	
		@Override
		public String getCatalog() throws SQLException {
			return conn.getCatalog();
		}
	
		@Override
		public void setTransactionIsolation(int level) throws SQLException {
			conn.setTransactionIsolation(level);
		}
	
		@Override
		public int getTransactionIsolation() throws SQLException {
			return conn.getTransactionIsolation();
		}
	
		@Override
		public SQLWarning getWarnings() throws SQLException {
			return conn.getWarnings();
		}
	
		@Override
		public void clearWarnings() throws SQLException {
			conn.clearWarnings();
		}
	
		@Override
		public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
			return conn.createStatement();
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
				throws SQLException {
			return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
		}
	
		@Override
		public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
			return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
		}
	
		@Override
		public Map<String, Class<?>> getTypeMap() throws SQLException {
			return conn.getTypeMap();
		}
	
		@Override
		public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
			conn.setTypeMap(map);
		}
	
		@Override
		public void setHoldability(int holdability) throws SQLException {
			conn.setHoldability(holdability);
		}
	
		@Override
		public int getHoldability() throws SQLException {
			return conn.getHoldability();
		}
	
		@Override
		public Savepoint setSavepoint() throws SQLException {
			return conn.setSavepoint();
		}
	
		@Override
		public Savepoint setSavepoint(String name) throws SQLException {
			return conn.setSavepoint();
		}
	
		@Override
		public void rollback(Savepoint savepoint) throws SQLException {
			conn.rollback();
		}
	
		@Override
		public void releaseSavepoint(Savepoint savepoint) throws SQLException {
			conn.releaseSavepoint(savepoint);
		}
	
		@Override
		public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability)
				throws SQLException {
			return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency,
				int resultSetHoldability) throws SQLException {
			return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
		}
	
		@Override
		public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency,
				int resultSetHoldability) throws SQLException {
			return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
			return conn.prepareStatement(sql, autoGeneratedKeys);
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
			return conn.prepareStatement(sql, columnIndexes);
		}
	
		@Override
		public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
			return conn.prepareStatement(sql, columnNames);
		}
	
		@Override
		public Clob createClob() throws SQLException {
			return conn.createClob();
		}
	
		@Override
		public Blob createBlob() throws SQLException {
			return conn.createBlob();
		}
	
		@Override
		public NClob createNClob() throws SQLException {
			return conn.createNClob();
		}
	
		@Override
		public SQLXML createSQLXML() throws SQLException {
			return conn.createSQLXML();
		}
	
		@Override
		public boolean isValid(int timeout) throws SQLException {
			return conn.isValid(timeout);
		}
	
		@Override
		public void setClientInfo(String name, String value) throws SQLClientInfoException {
			conn.setClientInfo(name, value);
		}
	
		@Override
		public void setClientInfo(Properties properties) throws SQLClientInfoException {
			conn.setClientInfo(properties);
		}
	
		@Override
		public String getClientInfo(String name) throws SQLException {
			return getClientInfo(name);
		}
	
		@Override
		public Properties getClientInfo() throws SQLException {
			return conn.getClientInfo();
		}
	
		@Override
		public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
			return conn.createArrayOf(typeName, elements);
		}
	
		@Override
		public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
			return conn.createStruct(typeName, attributes);
		}
	
		@Override
		public void setSchema(String schema) throws SQLException {
			conn.setSchema(schema);
		}
	
		@Override
		public String getSchema() throws SQLException {
			return conn.getSchema();
		}
	
		@Override
		public void abort(Executor executor) throws SQLException {
			conn.abort(executor);
		}
	
		@Override
		public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
			conn.setNetworkTimeout(executor, milliseconds);
		}
	
		@Override
		public int getNetworkTimeout() throws SQLException {
			return conn.getNetworkTimeout();
		}
		
	}
	
	//MyConnectionWrapper.java
	package cn.luyi.demo1;
	
	/*
	 * 装饰者模式增强类中的close方法
	 */
	import java.sql.Connection;
	import java.sql.SQLException;
	import java.util.List;
	
	public class MyConnectionWrapper extends ConnectionImpl {
		private Connection conn;
		private List<Connection> connList;
		
		public MyConnectionWrapper(Connection conn, List<Connection> connList) {
			super(conn);
			this.conn = conn;
			this.connList = connList;
		}
		//增强了close方法:将释放资源功能改为归还连接功能
		@Override
		public void close() throws SQLException {
			connList.add(conn); 
		}
	}
	
	//MyDataSource.java
	
	package cn.luyi.demo1;
	
	/*
	 * 自定义连接池
	 */
	import java.io.PrintWriter;
	import java.sql.Connection;
	import java.sql.SQLException;
	import java.sql.SQLFeatureNotSupportedException;
	import java.util.ArrayList;
	import java.util.List;
	import java.util.logging.Logger;
	
	import javax.sql.DataSource;
	
	public class MyDataSource implements DataSource {
		//将一些连接存入到内存中,可以定义一个集合,用于存储连接对象,这个集合就相当于连接池
		private List<Connection> connList = new ArrayList<Connection>();
		//在初始化的时候提供一些连接,添加连接到内存中
		public MyDataSource(){
			//初始化连接
			for(int i = 1; i <= 3; i ++){
				connList.add(JDBCUtils.getConnection());
			}
		}
		//从连接池中获得连接的方法
		@Override
		public Connection getConnection() throws SQLException {
			Connection conn  = connList.remove(0);
			//使用装饰者模式把close重写为归还连接的方法
			MyConnectionWrapper connWrapper = new MyConnectionWrapper(conn, connList);
			return connWrapper;
		}
		
		
		@Override
		public PrintWriter getLogWriter() throws SQLException {
			// TODO Auto-generated method stub
			return null;
		}
	
		@Override
		public void setLogWriter(PrintWriter out) throws SQLException {
			// TODO Auto-generated method stub
			
		}
	
		@Override
		public void setLoginTimeout(int seconds) throws SQLException {
			// TODO Auto-generated method stub
			
		}
	
		@Override
		public int getLoginTimeout() throws SQLException {
			// TODO Auto-generated method stub
			return 0;
		}
	
		@Override
		public Logger getParentLogger() throws SQLFeatureNotSupportedException {
			// TODO Auto-generated method stub
			return null;
		}
	
		@Override
		public <T> T unwrap(Class<T> iface) throws SQLException {
			// TODO Auto-generated method stub
			return null;
		}
	
		@Override
		public boolean isWrapperFor(Class<?> iface) throws SQLException {
			// TODO Auto-generated method stub
			return false;
		}
	
		@Override
		public Connection getConnection(String username, String password) throws SQLException { 
			return null;
		}
	
	
	}
	
	
	
	//MyDataSourceText.java
	
	package cn.luyi.demo1;
	
	/*
	 * 连接池测试类
	 */
	import java.sql.Connection;
	import java.sql.ResultSet;
	import java.sql.SQLException;
	import java.sql.Statement;
	
	import javax.sql.DataSource;
	
	public class MyDataSourceText {
		public static void main(String[] args) {
			Connection conn = null;
			Statement stmt = null;
			ResultSet rs = null;
			DataSource mdb = null;
			
			try{
				//加载驱动
				JDBCUtils.loadDriver();
				//从连接池获取连接
				mdb = new MyDataSource();
				conn = mdb.getConnection();
				
				stmt = conn.createStatement();
				//编写sql语句
				String sql = "select * from user";
				//执行sql,获取结果集
				rs = stmt.executeQuery(sql);
				while(rs.next()){
					System.out.print(rs.getString("username")  + " ");
					System.out.print(rs.getString("password")  + " ");
					System.out.println(rs.getString("role"));
				}
			}catch(Exception e){
				e.printStackTrace();
			}finally{
				//释放资源
				JDBCUtils.release(rs, stmt, conn);
				
			}	
		}
	}

开源连接池Druid

Druid概述:Druid是阿里旗下的开源连接池产品,使用非常简单,可以与spring框架进行快速整合,在很多的开源网站上都可以找到它,下载它的jar包就可以使用了

Druid的使用(两种方式):

//db.properties

driverClassName = com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/my?serverTimezone=UTC&rewriteBatchedStatements=true
username=root
password=123

//DruidDemo.java

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;

import javax.sql.DataSource;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

public class DruidDemo {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			
			//使用Druid连接池获取Connection对象
			DruidDataSource dataSource = new DruidDataSource();
			/*//方式一:手动设置数据库连接的参数
			dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
			dataSource.setUrl("jdbc:mysql://localhost:3306/my?serverTimezone=UTC");
			dataSource.setUsername("root");
			dataSource.setPassword("123");
			conn = dataSource.getConnection();*/
			//方式二:从配置文件里读取
			Properties properties = new Properties();
			properties.load(new FileInputStream("src/db.properties"));
			DataSource datasource = DruidDataSourceFactory.createDataSource(properties);
			conn = datasource.getConnection();
			
			stmt = conn.createStatement();
			//编写sql语句
			String sql = "select * from user";
			//执行sql,获取结果集
			rs = stmt.executeQuery(sql);
			while(rs.next()){
				System.out.print(rs.getString("username")  + " ");
				System.out.print(rs.getString("password")  + " ");
				System.out.println(rs.getString("role"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//释放资源
			JDBCUtils.release(rs, stmt, conn);
			
		}

开源连接池C3P0

概述:C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate、Spring等,下载它的jar包就可以使用了,需要注意的是C3P0版本0.9.1之前是只有一个包的,而版本0.9.2之后就被分离了一个mchange-commons-java包出来,所以使用版本0.9.2以上就需要导入两个包

C3P0的连接池使用:

//c3p0-config.xml

<?xml version="1.0" encoding="utf-8"?>
<c3p0-config>
	<!-- 默认配置 -->
  <default-config>
    <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/my?serverTimezone=UTC</property>
    <property name="user">root</property>
    <property name="password">123</property>
    
    <property name="initialPoolSize">5</property>
    <property name="maxPoolSize">10</property>
    <property name="checkoutTimeout">3000</property>
  </default-config>

	<!-- 设置其他的配置 -->
  <named-config name="otherc3p0"> 
  </named-config>
</c3p0-config>

//C3P0Demo.java

package cn.luyi.demo1;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Demo {
	public static void main(String[] args) {
		Connection conn = null;
		Statement stmt = null;
		ResultSet rs = null;
		try{
			//加载驱动
			JDBCUtils.loadDriver();
			
			//使用C3P0连接池获取Connection对象
			/*//方式一:手动设置参数
			ComboPooledDataSource dataSource = new ComboPooledDataSource();
			dataSource.setDriverClass("com.mysql.jdbc.Driver");
			dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/my?serverTimezone=UTC");
			dataSource.setUser("root");
			dataSource.setPassword("123");
			conn = dataSource.getConnection();*/
			
			//方式二:使用配置文件
			ComboPooledDataSource dataSource = new ComboPooledDataSource();
			conn = dataSource.getConnection();
			
			stmt = conn.createStatement();
			//编写sql语句
			String sql = "select * from user";
			//执行sql,获取结果集
			rs = stmt.executeQuery(sql);
			while(rs.next()){
				System.out.print(rs.getString("username")  + " ");
				System.out.print(rs.getString("password")  + " ");
				System.out.println(rs.getString("role"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			//释放资源
			JDBCUtils.release(rs, stmt, conn);
			
		}
	}
}

连接池版的工具类

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.sql.DataSource;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class JDBCUtils2 {
	//创建一个连接池,但是这个连接池只需要创建一次即可
	private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
	
	/*
	 * 获得连接的方法
	 */
	public static Connection getConnection() throws SQLException{
		return dataSource.getConnection();
	}
	/*
	 * 获得连接池
	 */
	public static DataSource getDataSource(){
		return dataSource;
	}
	/*
	 * 释放资源的方法
	 */
	public static void release(Statement stmt, Connection conn){
		if(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				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(stmt != null){
			try {
				stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			stmt = null;
		}
		
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			}
			conn = null;
		}
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e1) {
				e1.printStackTrace();
			}
			rs = null;
		}		
	}
}

9.DBUtils

概述:Commons DbUtils是Apache组织提供的一个对JDBC进行简单封装的开源工具类库,使用它能够简化JDBC应用程序的开发,同时也不会影响程序的性能,下载它的jar包即可使用

为什么要学习DBUtils?

因为JDBC手写比较麻烦,而且有非常多的代码是类似的,比如获得连接,预编译SQL,释放资源登,那么可以将这些代码抽取出来放到工具类中,大大简化JDBC的编程

DBUtils核心类QueryRunner

有两套常用方法:

1.在一般情况下如果执行CRUD的操作:

  • QueryRunner(DataSource ds):带参构造方法
  • int update(String sql, Object...args):增删改操作
  • T query(String sql, ResultSetHandler rsh, Object...args):查询操作

2.如果有事务管理的话则用这一套:

  • QuerryRunner():无参构造方法
  • int update(Connection conn, String sql, Object...args):增删改操作
  • T query(Connection conn, String sql, ResultSetHandler rsh, Object...args):查询操作

批量处理方法:

  • int[] batch(Connection conn, String sql, Object[][] params)
  • int[] batch(String sql, Object[][] params)

DbUtils类

主要方法:

  • static void commitAndCloseQuietly(Connection conn):提交事务,会把异常也处理了
  • static void rollbackAndCloseQuiety(Connection conn):回滚事务,会把异常也处理了

代码示例1(DBUtils的增删改):

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.apache.commons.dbutils.QueryRunner;

public class DBUtilsDemo {
	public static void main(String[] args) {
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try{
			//insert();
			//delete();
			update();
			
		}catch(Exception e){
			e.printStackTrace();
		}finally{
			JDBCUtils2.release(rs, pstmt, conn);
		}
	}
	/*
	 *添加数据操作
	 */
	public static void insert() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		queryRunner.update("insert into user value(null, ?, ?, ?)", "黄伊", "123", "student");
	}
	/*
	 * 删除操作
	 */
	public static void delete() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		queryRunner.update("delete from user where username = ?", "luer");
	}
	/*
	 * 修改操作
	 */
	public static void update() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		queryRunner.update("update user set password = ? where username = ?", "520", "黄伊");
	}
}

代码示例2(DBUtils的查询操作):

//User.java
package cn.luyi.demo1;

public class User {
	private String username;
	private String password;
	private String role;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + ", role=" + role + "]";
	}
	
}

// DBUtilsDemo2.java
package cn.luyi.demo1;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;


public class DBUtilsDemo2 {
	public static void main(String[] args) throws SQLException {
		//querySingle();
		queryMany();
	}
	
	/*
	 * 单条查询
	 */
	public static void querySingle() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		User user = queryRunner.query("select * from user where username = ?", new ResultSetHandler<User>(){

			@Override
			public User handle(ResultSet rs) throws SQLException {
				User user = new User();
				if(rs.next()){
					user.setUsername(rs.getString("username"));
					user.setPassword(rs.getString("password"));
					user.setRole(rs.getString("role"));
				}
				return user;
			}
			
		}, "lusan");
		
		System.out.println(user);
	}
	/*
	 * 多条查询
	 */
	public static void queryMany() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		//用一个集合来装User对象
		List<User> list = queryRunner.query("select * from user", new ResultSetHandler<List<User>>(){
			
			@Override
			public List<User> handle(ResultSet rs) throws SQLException {
				//创建一个集合用于封装数据
				List<User> list = new ArrayList<User>();
				while(rs.next()){
					User user = new User();
					user.setUsername(rs.getString("username"));
					user.setPassword(rs.getString("password"));
					user.setRole(rs.getString("role"));
					list.add(user);
				}
				return list;
			}
		});
		for(User user : list){
			System.out.println(user);
		}
		
		}
}

ResultHandler的实例

前面我们通过使用DBUtils对数据库进行增删改查,可以看出确实省了很多代码,但是我们在使用查询时,仍然需要一个个手动封装数据到对象中,有没有什么办法可以帮我们封装好数据呢?答案是有的,ResultHandler的不同的实现类就帮我们做了这样的事情,接下来我们就来学习ResultHandler的实例吧

1.ArrayHandler和ArrayListHandler

  • ArrayHandler将一条记录封装到一个数组当中,这个数组就是Object[]
  • ArrayListHandler:将多条数据封装到一个装有Object[]的List集合中

代码示例:

import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ArrayHandler;
import org.apache.commons.dbutils.handlers.ArrayListHandler;

public class DBUtilsDemo3 {
	public static void main(String[] args) throws SQLException {
		//method1();
		method2();
	}
	/*
	 * ArrayHandler:将一条记录封装到一个Object数组中
	 */
	public static void method1() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		Object[] objs = queryRunner.query("select * from user where id = ?", new ArrayHandler(), 3);
		System.out.println(Arrays.toString(objs));
	}
	/*
	 * ArrayListHandler:将多条数据封装到一个装有Object数组的list集合中
	 */
	public static void method2() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		List<Object[]> list = queryRunner.query("select * from user", new ArrayListHandler());
		
		for(Object[] obj:list){
			System.out.println(Arrays.toString(obj));
		}
	}
}

2.BeanHandler和BeanListHandler

  • BeanHandler:将一条记录封装到一个javaBean中
  • BeanListHandler:将多条记录封装到一个装有javaBean的list集合中

代码示例:

//User.java

public class User {
	private String username;
	private String password;
	private String role;
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	@Override
	public String toString() {
		return "User [username=" + username + ", password=" + password + ", role=" + role + "]";
	}
	
}


//DBUtilsDemo4.java

import java.sql.SQLException;
import java.util.List;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;

public class DBUtilsDemo4 {
	public static void main(String[] args) throws SQLException {
		//method1();
		method2();
	}
	/*
	 * BeanHandler的使用
	 */
	public static void method1() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		User user = queryRunner.query("select * from user where id = ?", new BeanHandler<User>(User.class), 3);
		
		System.out.println(user);
	}
	
	/*
	 * BeanListHandler的使用
	 */
	public static void method2() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		List<User> list = queryRunner.query("select * from user", new BeanListHandler<User>(User.class));
		for(User user:list){
			System.out.println(user);
		}
	}
}

3.MapHandler和MapListHandler

  • MapHandler:将一条记录封装到一个集合中,Map的key是列名,Map的value就是表中列的记录
  • MapListHandler:将多条记录封装到一个装有Map的List集合中

代码示例:

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.MapListHandler;

public class DBUtilsDemo5 {
	public static void main(String[] args) throws SQLException {
		//method1();
		method2();
	}
	/*
	 * MapHandler的使用
	 */
	public static void method1() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		Map<String, Object> map = queryRunner.query("select * from user where id = ?", new MapHandler(), 3);
		
		System.out.println(map);
	}
	/*
	 * MapListHandler的使用
	 */
	public static void method2() throws SQLException{
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		List<Map<String, Object>> list = queryRunner.query("select * from user", new MapListHandler());
		
		for(Map<String, Object> map:list){
			System.out.println(map);
		}
	}
}

4.ColumnListHandler、ScalarHandler、KeyedHandler(了解)

  • ColumnListHandler:将数据中的某列封装到List集合中
  • ScalarHandler:将单个值进行封装
  • KeyedHandler:将一条记录封装到一个Map集合中,将多条记录封装到一个装有Map集合的Map集合中去,而且外面的Map的key是可以指定的

代码示例:

import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.dbutils.handlers.KeyedHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

public class DBUtilsDemo6 {
	public static void main(String[] args) throws SQLException {
		//method1();
		//method2();
		method3();
	}

	/*
	 * ColumnListHandler的使用
	 */
	public static void method1() throws SQLException {
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		List<Object> list = queryRunner.query("select username, password  from user", new ColumnListHandler<Object>("username"));
		for (Object obj : list) {
			System.out.println(obj);
		}
	}
	
	/*
	 * ScalarHandler的使用
	 */
	public static void method2() throws SQLException {
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		Object obj = queryRunner.query("select count(*) from user", new ScalarHandler<Object>());
		System.out.println(obj);
	}
	/*
	 * KeyedHandler的使用
	 */
	public static void method3() throws SQLException {
		QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
		//指定键为username
		Map<Object, Map<String, Object>> map = queryRunner.query("select * from user", new KeyedHandler<Object>("username"));
		for(Object key: map.keySet()){
			System.out.println(key + "---" + map.get(key));
		}
	}
}
原文地址:https://www.cnblogs.com/luyi001/p/13420171.html