【JAVAWEB学习笔记】10_JDBC连接池&DBUtils
使用连接池改造JDBC的工具类:
1.1.1 需求:
传统JDBC的操作,对连接的对象销毁不是特别好.每次创建和销毁连接都是需要花费时间.可以使用连接池优化的程序.
* 在程序开始的时候,可以创建几个连接,将连接放入到连接池中.用户使用连接的时候,可以从连接池中进行获取.用完之后,可以将连接归还连接池.
1.1.2 分析:
1.1.2.1 技术分析:
【自定义连接池】(了解)
* SUN公司提供了一个连接池的接口.(javax.sql.DataSource).
* 定义一个连接池:实现这个接口.
* 使用List集合存放多个连接的对象.
【自定义连接池的代码】
public class MyDataSource implements DataSource{
// 创建一个List集合用于存放多个连接对象.
private List<Connection> list = new ArrayList<Connection>();
// 在程序开始的时候,初始化几个连接,将连接存放到list中.
public MyDataSource() {
// 初始化3个连接:
for(int i=1;i<=3;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.如果使用自定义连接池,那么需要额外记住自定义连接池中的API.
2.能不能使用面向接口的编程方式.
- 解决:
不额外提供API方法,就可以解决上述两个问题!!!
能不能还调用Connection的close方法.能不能增强Connection的close方法,原有的销毁变为归还!!!
- 如何增强Connection的close方法:
* 增强一个Java类中的某个方法有几种方式???
* 一种方式:继承的方式.
* 能够控制这个类的构造的时候,才可以使用继承.
* 二种方式:装饰者模式方式.
* 包装对象和被包装的对象都要实现相同的接口.
* 包装的对象中需要获得到被包装对象的引用.
***** 缺点:如果接口的方法比较多,增强其中的某个方法.其他的功能的方法需要原有调用.
* 三种方式:动态代理的方式.
* 被增强的对象实现接口就可以.
【继承和装饰者的案例】
/**
* 继承的方式增强一个类中某个方法:
*/
class Man{
public void run(){
System.out.println("跑....");
}
}
class SuperMan extends Man{
public void run(){
// super.run();
System.out.println("飞....");
}
}
/**
* 使用装饰者的方式完成类的方法的增强
*/
interface Waiter{
public void server();
}
class Waiteress implements Waiter{
@Override
public void server() {
System.out.println("服务...");
}
}
class WaiteressWrapper implements Waiter{
private Waiter waiter;
public WaiteressWrapper(Waiter waiter) {
this.waiter = waiter;
}
@Override
public void server() {
System.out.println("微笑...");
// this.waiter.server();
}
}
【使用装饰者模式增强Connection的close方法】
public class MyConnection implements Connection{
private Connection conn;
private List<Connection> list;
public MyConnection(Connection conn,List<Connection> list) {
this.conn = conn;
this.list = list;
}
@Override
public void close() throws SQLException {
list.add(conn);
}
...
}
连接池的getConnection方法:
@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);
MyConnection
myConn = new MyConnection(conn, list);
return myConn;
}
【常见的开源的数据库连接池】:
- DBCP:
DBCP(DataBase
connection pool),数据库连接池。是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件。单独使用dbcp需要2个包:commons-dbcp.jar,commons-pool.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据库连接时直接到连接池中申请一个就行,用完后再放回去。
- C3P0:
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
- Tomcat内置连接池:
【DBCP连接池的使用】
第一步:引入DBCP连接池的jar包.
第二步:编写DBCP代码:
* 手动设置参数:
* 配置文件设置参数:
【DBCP连接池的使用】
@Test
/**
* 手动方式:
*/
public void demo1(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
BasicDataSource dataSource = new
BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///web_07");
dataSource.setUsername("root");
dataSource.setPassword("123");
try{
// 获得连接:
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from
category";
// 预编译SQL:
stmt = conn.prepareStatement(sql);
// 执行SQL:
rs = stmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("cid")+" "+rs.getString("cname"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs,stmt, conn);
}
}
@Test
/**
* 配置文件方式:
*/
public void demo2(){
Connection conn = null;
PreparedStatement stmt = null;
ResultSet rs = null;
Properties properties = new Properties();
try{
properties.load(new
FileInputStream("src/dbcpconfig.properties"));
DataSource dataSource =
BasicDataSourceFactory.createDataSource(properties);
// 获得连接:
conn = dataSource.getConnection();
// 编写SQL:
String sql = "select * from
category";
// 预编译SQL:
stmt = conn.prepareStatement(sql);
// 执行SQL:
rs = stmt.executeQuery();
while(rs.next()){
System.out.println(rs.getInt("cid")+" "+rs.getString("cname"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(rs,stmt, conn);
}
}
【C3P0连接池的使用】
第一步:引入C3P0连接池的jar包.
第二步:编写代码:
* 手动设置参数:
* 配置文件设置参数:
【C3P0改造工具类】
public
class JDBCUtils2 {
private static final ComboPooledDataSource
DATA_SOURCE =new ComboPooledDataSource();
/**
* 获得连接的方法
*/
public static Connection getConnection(){
Connection conn = null;
try {
conn = DATA_SOURCE.getConnection();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
...
ResultSetHandler
我们知道在执行select语句之后得到的是ResultSet,然后我们还需要对ResultSet进行转换,得到最终我们想要的数据。你可以希望把ResultSet的数据放到一个List中,也可能想把数据放到一个Map中,或是一个Bean中。
DBUtils提供了一个接口ResultSetHandler,它就是用来ResultSet转换成目标类型的工具。你可以自己去实现这个接口,把ResultSet转换成你想要的类型。
DBUtils提供了很多个ResultSetHandler接口的实现,这些实现已经基本够用了,我们通常不用自己去实现ResultSet接口了。
l MapHandler:单行处理器!把结果集转换成Map<String,Object>,其中列名为键!
l MapListHandler:多行处理器!把结果集转换成List<Map<String,Object>>;
l BeanHandler:单行处理器!把结果集转换成Bean,该处理器需要Class参数,即Bean的类型;
l BeanListHandler:多行处理器!把结果集转换成List<Bean>;
l ColumnListHandler:多行单列处理器!把结果集转换成List<Object>,使用ColumnListHandler时需要指定某一列的名称或编号,例如:new
ColumListHandler(“name”)表示把name列的数据放到List中。
l ScalarHandler:单行单列处理器!把结果集转换成Object。一般用于聚集查询,例如select
count(*) from tab_student。
Map处理器

Bean处理器

Column处理器

Scalar处理器

QueryRunner之查询
QueryRunner的查询方法是:
public <T> T query(String sql, ResultSetHandler<T> rh, Object… params)
public <T> T query(Connection con, String sql, ResultSetHandler<T> rh, Object… params)
query()方法会通过sql语句和params查询出ResultSet,然后通过rh把ResultSet转换成对应的类型再返回。
|
@Test public void fun1() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student where number=?"; Map<String,Object> map = qr.query(sql, new MapHandler()[ThinkPad1] , "S_2000"); System.out.println(map); } @Test public void fun2() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Map<String,Object>> list = qr.query(sql, new MapListHandler()[ThinkPad2] ); for(Map<String,Object> map : list) { System.out.println(map); } } @Test public void fun3() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student where number=?"; Student stu = qr.query(sql, new BeanHandler<Student>(Student.class)[ThinkPad3] , "S_2000"); System.out.println(stu); } @Test public void fun4() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Student> list = qr.query(sql, new BeanListHandler<Student>(Student.class));[ThinkPad4] for(Student stu : list) { System.out.println(stu); } } @Test public void fun5() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select * from tab_student"; List<Object> list = qr.query(sql, new ColumnListHandler("name")[ThinkPad5] ); for(Object s : list) { System.out.println(s); } } @Test public void fun6() throws SQLException { DataSource ds = JdbcUtils.getDataSource(); QueryRunner qr = new QueryRunner(ds); String sql = "select count(*) from tab_student"; Number number = (Number)qr.query(sql, new ScalarHandler()[ThinkPad6] ); int cnt = number.intValue();[ThinkPad7] System.out.println(cnt); } |
[ThinkPad1]把一行记录转换成一个Map,其中键为列名称,值为列值
[ThinkPad2]把转换集转换成List<Map>,其中每个Map对应一行记录
[ThinkPad3]把结果集转换成一个Bean对象,在使用BeanHandler时需要指定Class,即Bean的类型
[ThinkPad4]把结果集转换成List<Bean>,其中每个Bean对应一行记录
[ThinkPad5]多行单例处理器,即获取name列数据
[ThinkPad6]单行单列处理器,一般用于聚合查询,在使用ScalarHandler时可以指定列名,如果不指定,默认为第1列。
[ThinkPad7]对聚合函数的查询结果,有的驱动返回的是Long,有的返回的是BigInteger,所以这里我们把它转换成Number,Number是Long和BigInteger的父类!然后我们再调用Number的intValue()或longValue()方法就OK了。
【JAVAWEB学习笔记】10_JDBC连接池&DBUtils的更多相关文章
- java学习笔记—c3p0连接池与元数据分析(42)
第一步:导入c3p0包 第二步:在classpath目录下,创建一个c3p0-config.xml <?xml version="1.0" encoding="UT ...
- java学习笔记—标准连接池的实现(27)
javax.sql.DataSource. Java.sql.* DataSource 接口由驱动程序供应商实现.共有三种类型的实现: 基本实现 - 生成标准的 Connection 对象 – 一个D ...
- Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题
Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...
- openresty 学习笔记四:连接mysql和进行相关操作
openresty 学习笔记四:连接mysql和进行相关操作 毕竟redis是作为缓存,供程序的快速读写,虽然reidis也可以做持久化保存,但还是需要一个做数据存储的数据库.比如首次查询数据在red ...
- openresty 学习笔记三:连接redis和进行相关操作
openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...
- JavaWeb学习笔记总结 目录篇
JavaWeb学习笔记一: XML解析 JavaWeb学习笔记二 Http协议和Tomcat服务器 JavaWeb学习笔记三 Servlet JavaWeb学习笔记四 request&resp ...
- javaweb学习笔记整理补课
javaweb学习笔记整理补课 * JavaWeb: * 使用Java语言开发基于互联网的项目 * 软件架构: 1. C/S: Client/Server 客户端/服务器端 * 在用户本地有一个客户端 ...
- JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析
JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...
- 超全面的JavaWeb笔记day18<事务&连接池&DBUtils>
1.事务 ACID 原子性 一致性 隔离性 持久性 mysql中开启和关闭事务 开启事务:START TRANSACTION 结束事务 提交事务:COMMIT 回滚事务:ROLLBACK JDBC中开 ...
随机推荐
- Androidstudio2.0.0汉化教程及汉化包。
()Eric为大家带来Androidstudio2.0.0的简单汉化教程,许多小伙伴喜欢使用中文版的AS那么没有中文的AS只能靠自己汉化取得更好的体验. 第一步下载AS2.0.0汉化包,我有链接给大家 ...
- 老李推荐:第4章3节《MonkeyRunner源码剖析》ADB协议及服务: ADB协议概览
老李推荐:第4章3节<MonkeyRunner源码剖析>ADB协议及服务: ADB协议概览 poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试, ...
- SQL语句中的日期查询
我们先创建一个表: CREATE TABLE `student` ( `id` INT NOT NULL AUTO_INCREMENT , `name` VARCHAR(10) NULL COMMEN ...
- ajax第三步
ajaxSend()函数用于设置当AJAX请求即将被发送时执行的回调函数. 这是一个全局AJAX事件函数,用于为任何AJAX请求的ajaxSend事件绑定事件处理函数.当AJAX请求即将被发送时,将触 ...
- zookeeper入门与实践
概述 Zookeeper是Hadoop的一个子项目,它是分布式系统中的协调系统,可提供的服务主要有:配置服务.名字服务.分布式同步.组服务等. 它有如下的一些特点: 简单 Zookeeper的核心是一 ...
- git教程(简单的带你学好git)
刚开始使用的时候没有找到好的资源学习,下面这个资源不错,大家可以参考学习. http://www.liaoxuefeng.com/wiki/0013739516305929606dd183612485 ...
- Linux-进程描述(2)之进程标识符与进程位置
在上一篇文章中详细介绍了task_struct结构体内的常见成员,然后我们就来看一下具体内容.每个进程都把它的信息放在 task_struct 这个数据结构中,task_struct 包含了这些内容: ...
- select 训练
--1.查询"c001"课程比"c002"课程成绩高的所有学生的学号:SELECT b.sno FROM (SELECT * FROM sc WHERE cno ...
- 分享一本书<<谁都不敢欺负你>>
有些人,不管在工作还是生活上,总是被人欺负. 分享这本书给大家,能给大家带来正能量.你强大了,就没人敢欺负你. 有的时候,感到为什么倒霉的总是我?为什么我的命运是这样?为什么总欺负我? 也许有很多人会 ...
- 【转】QQ传输文件原理参考(来自互联网)
QQ的文件发送是怎样的过程呢?通常,发送文件的计算机首先要通过消息服务器将其IP地址发送给接收计算机,当接收计算机同意接收的确认消息反馈到消息服务器后,消息服务器将据此设置好文件传输对话.随即,发送计 ...