C3P0
使用步骤:1.添加(c3p0-0.9.1.2) jar 包
2.编写配置文件 c3p0-config.xml (文件名字固定,位置固定在src下面),系统会自动读取配置文件
配置文件
<?xml version="1.0" encoding="UTF-8"?> <c3p0-config> <default-config> <property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql://localhost:3306/db3</property> <property name="user">root</property> <property name="password">123456</property> <property name="automaticTestTable">con_test</property> <property name="checkoutTimeout">30000</property> <property name="idleConnectionTestPeriod">30</property> <property name="initialPoolSize">10</property> <property name="maxIdleTime">30</property> <property name="maxPoolSize">100</property> <property name="minPoolSize">10</property> <property name="maxStatements">200</property> <user-overrides user="test-user"> <property name="maxPoolSize">10</property> <property name="minPoolSize">1</property> <property name="maxStatements">0</property> </user-overrides> </default-config> <!-- This app is massive! --> <named-config name="intergalactoApp"> <property name="acquireIncrement">50</property> <property name="initialPoolSize">100</property> <property name="minPoolSize">50</property> <property name="maxPoolSize">1000</property> <!-- intergalactoApp adopts a different approach to configuring statement caching --> <property name="maxStatements">0</property> <property name="maxStatementsPerConnection">5</property> <!-- he's important, but there's only one of him --> <user-overrides user="master-of-the-universe"> <property name="acquireIncrement">1</property> <property name="initialPoolSize">1</property> <property name="minPoolSize">1</property> <property name="maxPoolSize">5</property> <property name="maxStatementsPerConnection">50</property> </user-overrides> </named-config> </c3p0-config>
3.编写工具类
package com.qianfeng.util; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import com.mchange.v2.c3p0.ComboPooledDataSource; /* * 注意事项: * 1.系统会自动读取c3p0-config.xml文件:a.文件的名字要固定-c3p0-config.xml b.文件的位置也是固定的--src下面 * 2.一般会自己创建xml配置文件,按照要求创建即可. * 3.优势:又有不需要自己关联配置文件,所以使用更方便 */ public class C3P0Util { //1.创建池子(数据源)---创建了数据源之后,系统会自动添加连接 private static ComboPooledDataSource dataSource = new ComboPooledDataSource();//使用文件中默认的值 //private static ComboPooledDataSource dataSource = new ComboPooledDataSource("initergalactoApp");//使用c3p0-config.xml配置文件中的named-config节点中name属性的值 //向池子中添加连接---系统会自动读取c3p0-config.xml文件:a.文件的名字要固定-c3p0-config.xml b.文件的位置也是固定的--src下面 //2.获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } //获取数据源 public static ComboPooledDataSource getDataSource() { return dataSource; } //3.释放连接 public static void release(Connection conn,PreparedStatement statement,ResultSet set) { if (conn != null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (statement != null) { try { statement.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (set != null) { try { set.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
DBUtils
- 作用:
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作。可以少写代码。
1.对于数据表的读操作,他可以把结果转换成List,Array,Set等java集合,便于程序员操作;
2.对于数据表的写操作,也变得很简单(只需写sql语句)
3.可以使用数据源,使用JNDI,数据库连接池等技术来优化性能--重用已经构建好的数据库连接对象
- DBUtils的三个核心对象
QueryRunner类
ResultSetHandler接口
DBUtils类
QueryRunner类
QueryRunner中提供对sql语句操作的API.
它主要有三个方法
query() 用于执行select
update() 用于执行insert update delete
batch() 批处理
ResultSetHandler接口
用于定义select操作后,怎样封装结果集.
DbUtils类
它就是一个工具类,定义了关闭资源与事务处理的方法
- DBUtils快速入门
步骤:导入jar包 (commons-dbutils-1.4.jar)(c3p0与mysql驱动jar也要导入)
创建QueryRunner对象
使用query方法执行select语句
使用ResultSetHandler封装结果集
使用DBUtils类释放资源
- QueryRunner对象
new QueryRunner(); 它的事务可以手动控制。
也就是说此对象调用的方法(如:query、update、batrch)参数中要有Connection对象。
new QueryRunner(DataSource ds); 它的事务是自动控制的。一个sql一个事务。
此对象调用的方法(如:query、update、batrch)参数中无需Connection对象。
代码:
public void test2() throws SQLException{ //写sql语句 String sql = "insert into user(id,name,password) values(?,?,?)"; //第一种:使用的是无参的QueryRunner()方法----为了更加方便的使用事务,因为可以直接获取到Connection对象 //1.创建干活的的对象--QueryRunner QueryRunner qRunner = new QueryRunner(); //2.获取连接对象 Connection connection = C3P0Util.getConnection(); //3.调用update()方法实现对数据库的访问 int num = qRunner.update(connection, sql,6,"马六","345"); if (num >0) { System.out.println("增加成功"); }else { System.out.println("增加失败"); } //第二种:使用的是有参的QueryRunner()方法--参数是数据源 //1.创建干活儿的对象并绑定数据源 // QueryRunner qRunner2 = new QueryRunner(C3P0Util.getDataSource()); // //2.调用update()方法 // int num2 = qRunner2.update(sql,7,"马六1","3451"); // if (num2 >0) { // System.out.println("增加成功"); // }else { // System.out.println("增加失败"); // } } //批量增加--只能同时执行一种操作 @Test public void test3() throws SQLException{ QueryRunner qRunner2 = new QueryRunner(C3P0Util.getDataSource()); //创建一个二维数组装 数据 Object[][] params = new Object[3][]; for (int i = 0; i < params.length; i++) { params[i] = new Object[]{i+8,"bingbing"+i,"333"+i}; } //写sql语句 String sql = "insert into user(id,name,password) values(?,?,?)"; int[] nums = qRunner2.batch(sql, params); }
- ResultSetHandler接口
ResultSetHandler下的所有结果处理器
package com.qianfeng.test; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.enterprise.inject.New; import org.apache.commons.dbutils.QueryRunner; import org.apache.commons.dbutils.ResultSetHandler; import org.apache.commons.dbutils.handlers.ArrayHandler; import org.apache.commons.dbutils.handlers.ArrayListHandler; import org.apache.commons.dbutils.handlers.BeanHandler; import org.apache.commons.dbutils.handlers.BeanListHandler; import org.apache.commons.dbutils.handlers.ColumnListHandler; import org.apache.commons.dbutils.handlers.KeyedHandler; import org.apache.commons.dbutils.handlers.MapHandler; import org.apache.commons.dbutils.handlers.MapListHandler; import org.apache.commons.dbutils.handlers.ScalarHandler; import org.junit.Test; import com.qianfeng.domain.User; import com.qianfeng.util.C3P0Util; public class TestDemo2 { /* * ResultSetHandler接口 */ @SuppressWarnings("unchecked") //@Test //获取全部的数据 public void test1() throws SQLException{ QueryRunner qRunner2 = new QueryRunner(C3P0Util.getDataSource()); ResultSetHandler handler = new ResultSetHandler<List<User>>() { /* * 这是真正处理数据的方法 * 参数就是得到的结果集 * 这个方法会被自动调用 */ @Override public List<User> handle(ResultSet set) throws SQLException { List<User> list = new ArrayList<User>(); while (set.next()) { User user = new User(); user.setName(set.getString("name")); user.setPassword(set.getString("password")); list.add(user); } return list; } }; List<User> list = qRunner2.query("select * from user", handler); System.out.println(list); } //@Test //返回所有的数据--将记录装入模型,将模型装入list public void test2() throws SQLException{ QueryRunner qRunner2 = new QueryRunner(C3P0Util.getDataSource()); //<对应模型的类>(模型的字节码文件) List<User> list = qRunner2.query("select * from user", new BeanListHandler<User>(User.class)); System.out.println(list); } @Test //返回一条记录-得到的是模型 public void test3() throws SQLException{ QueryRunner qRunner2 = new QueryRunner(C3P0Util.getDataSource()); User user = qRunner2.query("select * from user where id=?", new BeanHandler<User>(User.class),1); System.out.println(user); } //取一条记录 //ArrayHandler:只能返回一个记录,并且没有存储到javabean中,默认返回的是第一个记录 //@Test public void test13() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); // Object[] objects = qRunner.query("select * from user", new ArrayHandler()); for (Object object : objects) { System.out.println(object); } } //取多条记录 //ArrayListHandler:可以返回查到的多行记录,将一条记录的每个字段存储到一个数组中,再将这些数组放入一个集合中,并返回 //@Test public void test4() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); List<Object[]> list = qRunner.query("select * from user", new ArrayListHandler()); for (Object[] objects : list) { for (Object object : objects) { System.out.print(object+" "); } System.out.println(); } } //ColumnListHandler:根据指定的列数,取某一列的数据,封装到list中返回 //@Test public void test5() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); //参数的意思是:指定查询的列号---从1开始计数 List<Object> list = qRunner.query("select * from user", new ColumnListHandler(2)); for (Object object : list) { System.out.print(object+" "); } } //KeyedHandler:可以取多条记录,每一条记录被封装在了map中,然后再将所有的map对象放在一个大的map中,让每条记录中的某个字段充当外层map的key //注意:如果充当key的字段有重复,和面的记录会将前面所有的记录覆盖 //@Test public void test6() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); Map<Object, Map<String, Object>> map=qRunner.query("select * from user", new KeyedHandler(5)); for(Map.Entry<Object, Map<String, Object>> en:map.entrySet()){ Object key = en.getKey(); Map<String, Object> subMap = en.getValue(); for(Map.Entry<String, Object> suben:subMap.entrySet()){ String subkey = suben.getKey(); Object value = suben.getValue(); System.out.print(subkey+"="+value+" "); } System.out.println(" key="+key); } } //只能取一条记录 //MapHandler:将一条记录的字段和对应的值封装到一个map中,返回,默认取的是第一行 //@Test public void test7() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); Map<String, Object> map = qRunner.query("select * from user", new MapHandler()); for(String key:map.keySet()){ System.out.print(key+"="+map.get(key)+" "); } } //MapHandler:将一条记录的字段和对应的值封装到一个map中,再将所有的map放到一个list中并返回 //@Test public void test8() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); List<Map<String, Object>> list = qRunner.query("select * from user", new MapListHandler()); for (Map<String, Object> map : list) { for(String key:map.keySet()){ System.out.print(key+"="+map.get(key)+" "); } System.out.println(); } } //取第一行的某一列的值 //ScalarHandler:适合取单行单列的数据 @Test public void test9() throws SQLException{ QueryRunner qRunner = new QueryRunner(C3P0Util.getDataSource()); //参数:代表第一行对应的行号,取这个列下的数据,若果不写,默认取第一列 //Object object = qRunner.query("select * from user", new ScalarHandler(3)); //与聚合函数联合使用,参数可以取的列是select后面可以获取的列数 Object object1 = qRunner.query("select *,count(*) from user", new ScalarHandler(6)); System.out.println(object1); } }
DBCP
使用步骤:添加jar包 commons-dbcp-1.4.jar commons-pool-1.5.6.jar
添加属性资源文件
编写数据源工具类
- 资源文件
driver=com.mysql.jdbc.Driver url=jdbc:mysql://localhost:3306/db6 user=root password=971125 initSize=3 maxSize=3
- 编写工具类
package com.qianfeng.dbcp; import java.io.IOException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp.BasicDataSourceFactory; /* * 1.导入三方架包 * 2.编写配置文件:配置文件的类型必须是properties,名字随意,位置随意 * 3.创建DBCPUtil工具类 */ public class DBCPUtil { //1.创建数据源 private static DataSource dataSource; //2.连接配置文件 static{ Properties properties = new Properties(); try { //获取配置信息,将内容保存到properties对象里面 properties.load(DBCPUtil.class.getClassLoader().getResourceAsStream("dbcpconfig.properties")); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } //得到连接池对象,将配置信息指定给连接池对象 try { dataSource = BasicDataSourceFactory.createDataSource(properties); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } //3.获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } //4.释放连接 public static void release(Connection conn,PreparedStatement statement,ResultSet set) { if (conn != null) { try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (statement != null) { try { statement.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (set != null) { try { set.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
数据库连接池
- 基本原理
在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。如外部使用者可通过getConnection方法获取数据库连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
- 作用
①资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以级数据库临时进程、线程的数量)
②更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池内备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
③新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接技术。
④统一的连接管理,避免数据库连接泄露
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露
- 编写标准的数据源
自定义数据库连接池要实现javax.sql.DataSource接口,一般都叫数据源。
- 编写数据源时遇到的问题及解决办法
a.装饰设计模式:使用频率很高
目的:改写已存在的类的某个方法或某些方法,装饰设计模式(包装模式)
口诀:
1、编写一个类,实现与被包装类相同的接口。(具备相同的行为)
2、定义一个被包装类类型的变量。
3、定义构造方法,把被包装类的对象注入,给被包装类变量赋值。
4、对于不需要改写的方法,调用原有的方法。
5、对于需要改写的方法,写自己的代码。
b.默认适配器:装饰设计模式一个变体
- 常用的数据源有 DBCP ,C3P0
区别一:
DBCP(DataBase connection pool):是 apache 上的一个 java 连接池项目。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展
区别二:
DBCP没有自动的去回收空闲连接的功能,C3P0有自动回收空闲连接功能
区别三:
DBCP连接池的持续运行的稳定性还是可以,不过速度稍慢,在大并发量的压力下稳定性有所下降
C3P0连接池的持续运行的稳定性相当不错,在大并发量的压力下稳定性也有一定保证