使用连接池改造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方法,原有的销毁变为归还!!!

  • 如何增强Connectionclose方法:

* 增强一个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的更多相关文章

  1. java学习笔记—c3p0连接池与元数据分析(42)

    第一步:导入c3p0包 第二步:在classpath目录下,创建一个c3p0-config.xml <?xml version="1.0" encoding="UT ...

  2. java学习笔记—标准连接池的实现(27)

    javax.sql.DataSource. Java.sql.* DataSource 接口由驱动程序供应商实现.共有三种类型的实现: 基本实现 - 生成标准的 Connection 对象 – 一个D ...

  3. Junit 注解 类加载器 .动态代理 jdbc 连接池 DButils 事务 Arraylist Linklist hashset 异常 哈希表的数据结构,存储过程 Map Object String Stringbufere File类 文件过滤器_原理分析 flush方法和close方法 序列号冲突问题

    Junit 注解 3).其它注意事项: 1).@Test运行的方法,不能有形参: 2).@Test运行的方法,不能有返回值: 3).@Test运行的方法,不能是静态方法: 4).在一个类中,可以同时定 ...

  4. openresty 学习笔记四:连接mysql和进行相关操作

    openresty 学习笔记四:连接mysql和进行相关操作 毕竟redis是作为缓存,供程序的快速读写,虽然reidis也可以做持久化保存,但还是需要一个做数据存储的数据库.比如首次查询数据在red ...

  5. openresty 学习笔记三:连接redis和进行相关操作

    openresty 学习笔记三:连接redis和进行相关操作 openresty 因其非阻塞的调用,令服务器拥有高性能高并发,当涉及到数据库操作时,更应该选择有高速读写速度的redis进行数据处理.避 ...

  6. JavaWeb学习笔记总结 目录篇

    JavaWeb学习笔记一: XML解析 JavaWeb学习笔记二 Http协议和Tomcat服务器 JavaWeb学习笔记三 Servlet JavaWeb学习笔记四 request&resp ...

  7. javaweb学习笔记整理补课

    javaweb学习笔记整理补课 * JavaWeb: * 使用Java语言开发基于互联网的项目 * 软件架构: 1. C/S: Client/Server 客户端/服务器端 * 在用户本地有一个客户端 ...

  8. JUC源码学习笔记5——线程池,FutureTask,Executor框架源码解析

    JUC源码学习笔记5--线程池,FutureTask,Executor框架源码解析 源码基于JDK8 参考了美团技术博客 https://tech.meituan.com/2020/04/02/jav ...

  9. 超全面的JavaWeb笔记day18<事务&连接池&DBUtils>

    1.事务 ACID 原子性 一致性 隔离性 持久性 mysql中开启和关闭事务 开启事务:START TRANSACTION 结束事务 提交事务:COMMIT 回滚事务:ROLLBACK JDBC中开 ...

随机推荐

  1. pl sql 查询显示乱码解决方法——设置环境变量NLS_LANG

    用oracle进行查询的时候,有的时候会出现查询结果为乱码的情况,此时要设置一个环境变量NLS_LANG. 此变量的值如何获得呢?运行下面sql语句就可以获得: select userenv('lan ...

  2. [认证授权] 2.OAuth2(续) & JSON Web Token

    0. RFC6749还有哪些可以完善的? 0.1. 撤销Token 在上篇[认证授权] 1.OAuth2授权中介绍到了OAuth2可以帮我们解决第三方Client访问受保护资源的问题,但是只提供了如何 ...

  3. 通过php动态传数据到highcharts

    1:在平时工作中,在对数据进行展示的时候,是直接通过后台提供的接口来获取json串,用来展示.今天别人问怎么在本地演示一下请求的动态数据. 2:在本地搭建环境,我用的WampServer,下载地址:h ...

  4. Xcode的Architectures、Valid Architectures和Build Active Architecture Only属性(原创)

    最近xcode升级了5.1版本,升级之后程序报关于要适配arm64机器的错.之前对xcode的参数配置,一直不是很了解,但实现先面对问题了,就调查了一下并解决它. 一个一个来吧. Architectu ...

  5. 前端开发必须说的那些事之——同源策略(same origin policy)

    同源策略指的是三个相同 协议相同 域名相同 端口相同 如https://www.baidu.com/hahah.html这个网址来说 https是使用的协议,www.baidu.com是域名,端口号默 ...

  6. 用 js 的 selection range 操作选择区域内容和图片

    原创文章,转载请注明出处并保留地址.原文地址:http://www.cnblogs.com/muge10/p/6723894.html 最近在做编辑器相关的东西,遇到一个需求,用户在编辑器中插入或者粘 ...

  7. 论.net平台的切身感触(惑)

    这篇博客只是作者客观看法,不喜勿喷,条条大路通罗马,路不同风景也不一样,接下来的路该怎么走? 简介:作者.net程序员一枚,工作已有四年,接触过.net平台winform,webform,mvc的开发 ...

  8. 前端魔法堂:解秘FOUC

    前言  对于问题多多的IE678,FOUC(flash of unstyled content)--浏览器样式闪烁是一个不可忽视的话题,但对于ever green的浏览器就不用理会了吗?下面尝试较全面 ...

  9. MySQL最常用数值函数

    数值函数: 用来处理很多数值方面的运算,使用数值函数,可以免去很多繁杂的判断求值的过程,能够大大提高用户的工作效率. 1.ABS(x):返回 x 的绝对值 mysql> select abs(- ...

  10. Extjs6(特别篇)——项目自带例子main.js拆分详解

    本文基于extjs6.0.0 一.拆分代码来看看 1.主页面main是个tab页: 写一些页面的依赖: 标明页面的controller和viewModel Ext.define('Learning.v ...