1 JDBC概述

Java DataBase Connectivity,Java数据库连接,一种执行SQL的Java API,为多种关系数据库提供统一访问规范,由一组Java语言编写的类和接口组成。
数据库驱动:各个数据库生产商提供的JDBC实现类。使用统一的JDBC规范,不用专门去了解各个数据库的驱动API。
JDBC 可做三件事:与数据库建立连接、发送SQL、处理结果。

2 JDBC常用方法及增删改查

2.1 JDBC的开发步骤
先导入对应数据库的jar包 mysql-connector-java-5.0.8-bin.jar
  创建lib目录,用于存放当前项目需要的所有jar包
  选择jar包,右键执行build path / Add to Build Path

  1. 加载驱动
  2. 获得连接
  3. 获得语句执行平台statement
  4. 执行sql
  5. 处理结果
  6. 释放资源
  1. import org.junit.Test;
  2. public class JDBCDemo1 {
  3. @Test
  4. public void demo1() throws Exception{
  5. // 1.加载驱动
  6. Class.forName("com.mysql.jdbc.Driver");
  7. // 2.获得连接
  8. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/web_test3", "root", "abc");       //url如果连接的是本机的路径,可以简化为jdbc:mysql:///web_test3 (3个///)
  9. // 3.基本操作:执行SQL
  10. // 3.1获得执行SQL语句的对象
  11. Statement statement = conn.createStatement();
  12. // 3.2编写SQL语句:
  13. String sql = "select * from user";
  14. // 3.3执行SQL:
  15. ResultSet rs = statement.executeQuery(sql);
  16. // 3.4遍历结果集:
  17. while(rs.next()){
  18. System.out.print(rs.getInt("id")+" ");
  19. System.out.print(rs.getString("username")+" ");
  20. System.out.print(rs.getString("password")+" ");
  21. System.out.print(rs.getString("nickname")+" ");
  22. System.out.print(rs.getInt("age"));
  23. System.out.println();
  24. }
  25. // 4.释放资源
  26. rs.close();
  27. statement.close();
  28. conn.close();
  29. }
  30. }

2 JDBC常用类/接口:

DriverManager类:注册JDBC驱动,获取Connection对象(数据库链接对象,每个Connection代表一个物理连接会话)。
Class.forName("com.mysql.jdbc.Driver");
Connection接口:获取执行SQL的Statement对象,并包含多个用于控制事务的方法。

  1. Statement createStatement() throws SQLException;             //返回一个Statement对象,用来将SQL语句发送到数据库;
  2. PreparedStatement prepareStatement(String sql)throws SQLException;  //返回预编译的Statement对象,即将SQL语句提交到数据库进行预编译;
  3. CallableStatement prepareCall(String sql) throws SQLException;     //返回CallableStatement对象,用于调用存储过程。
  4.    //以上都返回用于执行sql语句的Statement对象,PreparedStatement和CallableStatement是Statement的子类,只有获得了Statement之后才可以执行sql语句;
  5.  
  6. void setAutoCommit(boolean autoCommit) throws SQLException;  //关闭自动提交,打开事务;
  7. void rollback() throws SQLException;               //回滚事务,并释放Connection对象当前持有的数据库锁;
  8. void commit() throws SQLException;               //提交事务,并释放Connection对象当前持有的数据库锁;
  9. void setTransactionIsolation(int level) throws SQLException;     //设置事务的隔离级别;
  10. Savepoint setSavepoint() throws SQLException;          //创建一个保存点;
  11. Savepoint setSavepoint(String name) throws SQLException;     //以指定名字来创建一个保存点;
  12. void rollback(Savepoint savepoint) throws SQLException;      //将事务回滚到指定的保存点;

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

  1. ResultSet executeQuery(String sql) throws SQLException;//执行查询语句,返回查询结果对应ResultSet对象。该方法只能用于执行查询语句。
  2. int executeUpdate(String sql) throws SQLException;//执行inset/update/delete语句,返回受影响的行数;也可以执行create/alter/drop/truncate语句,并返回0;
  3. boolean execute(String sql) throws SQLException;//执行任意sql语句。若执行后第一个结果为ResultSet对象,则返回true;
  4. //若执行后第一个结果为受影响的行数或无结果,则返回false;
  5.  
  6. void addBatch(String sql);//将给定的 SQL 命令添加到此 Statement 对象的当前命令列表中。
  7. void clearBatch();//清空此Statement对象当前的SQL命令列表。
  8. int[] executeBatch();//将一批命令提交给数据库来执行,如果全部命令执行成功,则返回更新计数组成的数组。

注意:如果 addBatch() -> executeBatch() 很慢,需要启动批处理操作rewriteBatchedStatements=true,即在数据库连接URL后面加上这个参数:String dbUrl =  "jdbc:mysql://localhost:3306/User? rewriteBatchedStatements=true";该参数将多条sql分成若干个报文发送到mysql服务器,并在最后加上commit操作。

ResultSet接口:结果集对象,包含查询结果,可以通过列索引或列名获得列数据。

  1. boolean next();//将光标从当前位置向前移动一行
  2. int getInt(int columnIndex);//获取结果集当前行指定列
  3. int getInt(String columnLabel);//获取结果集当前行指定列
  4. long getLong(int columnIndex);//获取结果集当前行指定列
  5. long getLong(String columnLabel);//获取结果集当前行指定列
  6. String getString(int columnIndex);//获取结果集当前行指定列
  7. String getString(String columnLabel);//获取结果集当前行指定列
  8.  
  9. //示例代码:
  10. while(resultSet.next()){
  11. System.out.println(resultSet.getInt("id"))
  12. System.out.println(resultSet.getString("ename"))
  13. System.out.println(resultSet.getString("nickname"))
  14. }

3 JDBC的资源释放

JDBC程序执行结束后,需要将与数据库进行交互的对象释放掉,通常是ResultSet,Statement,Connection。尤其是Connection对象,一定要做到晚创建,早释放。
如果把所有关闭语句写在同一个try块里面,一旦前面的关闭语句抛异常,后面的关闭语句就无法执行,所以要给每个关闭语句一个try块。
最后为了保证资源能够释放,还有在每个关闭语句的后面加一个finally,在finally里给要关闭的资源赋值为空。这样即使关闭过程中抛异常不能及时关闭,但是由于赋值为空,没有引用该资源,在垃圾回收的时候也能够回收。

  1. if(rs !=null){ try {
  2. rs.close();
  3. } catch (SQLException e) {
  4. e.printStackTrace();
  5. }finally
  6. rs = null;
  7. }
  8.  
  9. if(statement !=null){
  10. try {
  11. statement.close();
  12. } catch (SQLException e) {
  13. e.printStackTrace();
  14. }finally
  15. statement = null;
  16. }
  17.  
  18. if(conn !=null){
  19. try {
  20. conn.close();
  21. } catch (SQLException e) {
  22. e.printStackTrace();
  23. }finally
  24. conn = null;
  25. }

2.2 JDBC的增删改查

  1. public void demo1(){
  2. Connection conn = null;
  3. Statement stmt = null;
  4. try{
  5. Class.forName("com.mysql.jdbc.Driver");
  6. conn = DriverManager.getConnection("jdbc:mysql:///web_test3", "root", "abc");
  7. stmt = conn.createStatement();
  8.  
  9. //增加一条数据
  10. String sql = "insert into user values (null,'eee','123','阿黄',21)";
  11. int num = stmt.executeUpdate(sql);
  12. if(num > 0){
  13. System.out.println("保存用户成功!!!");
  14. }
  15. /*
  16. //删除、修改类似
  17.  
  18. //查询一条或多条多条
  19. String sql = "select * from user";
  20. rs = stmt.executeQuery(sql);
  21. while(rs.next()){
  22. System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));
  23. }
  24.  
  25. */
  26. }catch(Exception e){
  27. e.printStackTrace();
  28. }finally{
  29. // 资源释放:略
  30. }
  31. }

3 JDBC的工具类的抽取

  1. public class JDBCUtils {
  2. private static final String driverClassName;
  3. private static final String url;
  4. private static final String username;
  5. private static final String password;
  6.  
  7. // 获取属性文件中的内容:
  8. static{
  9. driverClassName="com.mysql.jdbc.Driver";
  10. url="jdbc:mysql:///web_test3";
  11. username="root";
  12. password="abc";
  13. }
  14. /*
  15. static{
  16. // 获取属性文件中的内容:
  17. Properties properties = new Properties();
  18. try {
  19. properties.load(new FileInputStream("src/db.properties"));
  20. } catch (FileNotFoundException e) {
  21. e.printStackTrace();
  22. } catch (IOException e) {
  23. e.printStackTrace();
  24. }
  25.  
  26. driverClassName=properties.getProperty("driverClassName");
  27. url=properties.getProperty("url");
  28. username=properties.getProperty("username");
  29. password=properties.getProperty("password");
  30. }
  31. */
  32.  
  33. /**
  34. * 注册驱动的方法
  35. */
  36. public static void loadDriver(){
  37. try {
  38. Class.forName(driverClassName);
  39. } catch (ClassNotFoundException e) {
  40. e.printStackTrace();
  41. }
  42. }
  43.  
  44. /**
  45. * 获得连接的方法
  46. */
  47. public static Connection getConnection(){
  48. Connection conn = null;
  49. try{
  50. // 将驱动一并注册:
  51. loadDriver();
  52. // 获得连接
  53. conn = DriverManager.getConnection(url,username, password);
  54. }catch(Exception e){
  55. e.printStackTrace();
  56. }
  57. return conn;
  58. }
  59.  
  60. /**
  61. * 释放资源的方法
  62. */
  63. public static void release(Statement stmt,Connection conn){
  64. if(stmt != null){
  65. try {
  66. stmt.close();
  67. } catch (SQLException e) {
  68. e.printStackTrace();
  69. }
  70.  
  71. stmt = null;
  72. }
  73. if(conn != null){
  74. try {
  75. conn.close();
  76. } catch (SQLException e) {
  77. e.printStackTrace();
  78. }
  79. conn = null;
  80. }
  81. }
  82.  
  83. public static void release(ResultSet rs,Statement stmt,Connection conn){
  84. // 资源释放:
  85. if(rs != null){
  86. try {
  87. rs.close();
  88. } catch (SQLException e) {
  89. e.printStackTrace();
  90. }
  91.  
  92. rs = null;
  93. }
  94. if(stmt != null){
  95. try {
  96. stmt.close();
  97. } catch (SQLException e) {
  98. e.printStackTrace();
  99. }
  100.  
  101. stmt = null;
  102. }
  103. if(conn != null){
  104. try {
  105. conn.close();
  106. } catch (SQLException e) {
  107. e.printStackTrace();
  108. }
  109. conn = null;
  110. }
  111. }
  112. }

测试工具类:

  1. public void demo1(){
  2. Connection conn = null;
  3. Statement stmt = null;
  4. ResultSet rs = null;
  5. try{
  6. conn = JDBCUtils.getConnection();
  7. stmt = conn.createStatement();
  8. String sql = "select * from user";
  9. rs = stmt.executeQuery(sql);
  10. while(rs.next()){
  11. System.out.println(rs.getInt("id")+" "+rs.getString("username")+" "+rs.getString("password"));
  12. }
  13. }catch(Exception e){
  14. e.printStackTrace();
  15. }finally{
  16. JDBCUtils.release(rs, stmt, conn);
  17. }
  18. }

4  用 properties 文件配置JDBC信息

1 开发中获得连接的4个参数(驱动、URL、用户名、密码)通常都存在配置文件中,方便后期维护,程序如果需要更换数据库,只需要修改配置文件即可。
使用properties文件要求:
  1.文件位置:任意,建议src下
  2.文件内容:一行一组数据,格式是“key=value”
    a)key命名自定义,如果是多个单词,习惯使用点分隔。例如:jdbc.driver
    b)value值不支持中文,如果需要使用非英文字符,将进行unicode转换

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/mydb
  3. user=root
  4. password=root

2 加载properties配置文件

  1. public class JDBCUtils {
  2.  
  3. private static String driver;
  4. private static String url;
  5. private static String user;
  6. private static String password;
  7. // 静态代码块
  8. static {
  9. try {
  10. // 1 使用Properties处理流
  11. // 使用load()方法加载指定的流
  12. Properties props = new Properties();
  13. Reader is = new FileReader("db.properties");
  14. props.load(is);
  15. // 2 使用getProperty(key),通过key获得需要的值,
  16. driver = props.getProperty("driver");
  17. url = props.getProperty("url");
  18. user = props.getProperty("user");
  19. password = props.getProperty("password");
  20. } catch (Exception e) {
  21. throw new RuntimeException(e);
  22. }
  23. }
  24.  
  25. /**
  26. * 获得连接
  27. */
  28. public static Connection getConnection() {
  29. try {
  30. // 1 注册驱动
  31. Class.forName(driver);
  32. // 2 获得连接
  33. Connection conn = DriverManager.getConnection(url, user, password);
  34. return conn;
  35. } catch (Exception e) {
  36. throw new RuntimeException(e);
  37. }
  38. }
  39. }

5 SQL 注入

输入一个存在的用户名 userName,再输入任意密码:XXX' OR 'a' = 'a'时,
SELECT * FROM Table WHERE Name = 'userName' AND PassWord = 'XXX' OR 'a' = 'a';
此时绕过了密码校验成功登录,这便是SQL注入问题。

为此,可以使用PreparedStatement将SQL预先进行编译,使用?作为占位符。当传入变量(包含SQL的关键字)时,不会识别 or 这些关键字。

  1. public class UserDao {
  2.  
  3. public boolean login(String username,String password){
  4. Connection conn = null;
  5. PreparedStatement pstmt = null;
  6. ResultSet rs = null;
  7. // 定义一个变量:
  8. boolean flag = false;
  9. try{
  10. conn = JDBCUtils.getConnection();
  11. String sql = "select * from user where username = ? and password = ?";
  12. // 预编译SQL
  13. pstmt = conn.prepareStatement(sql);
  14. // 设置参数:
  15. pstmt.setString(1, username);
  16. pstmt.setString(2, password);
  17. rs = pstmt.executeQuery();
  18. if(rs.next()){
  19. flag = true;
  20. }
  21. }catch(Exception e){
  22. e.printStackTrace();
  23. }finally{
  24. JDBCUtils.release(rs, pstmt, conn);
  25. }
  26. return flag;
  27. }

6 JDBC批处理

Statement接口:void addBatch(String sql)
PreparedStatement接口重写了addBatch()方法:void addBatch()

  1. public void demo1(){
  2. Connection conn = null;
  3. Statement stmt = null;
  4. try{
  5. // 获得连接:
  6. conn = JDBCUtils.getConnection();
  7. // 创建执行批处理对象:
  8. stmt = conn.createStatement();
  9. // 编写一批SQL语句:
  10. String sql1 = "create database test1";
  11. String sql2 = "use test1";
  12. String sql3 = "create table user(id int primary key auto_increment,name varchar(20))";
  13. String sql4 = "insert into user values (null,'aaa')";
  14. String sql5 = "insert into user values (null,'bbb')";
  15. String sql6 = "insert into user values (null,'ccc')";
  16. String sql7 = "update user set name = 'mmm' where id = 2";
  17. String sql8 = "delete from user where id = 1";
  18. // 添加到批处理
  19. stmt.addBatch(sql1);
  20. stmt.addBatch(sql2);
  21. stmt.addBatch(sql3);
  22. stmt.addBatch(sql4);
  23. stmt.addBatch(sql5);
  24. stmt.addBatch(sql6);
  25. stmt.addBatch(sql7);
  26. stmt.addBatch(sql8);
  27. // 执行批处理:
  28. stmt.executeBatch();
  29. }catch(Exception e){
  30. e.printStackTrace();
  31. }finally{
  32. JDBCUtils.release(stmt, conn);
  33. }
  34. }
  35.  
  36. //批量插入(使用PreparedStatement)
  37. @Test
  38. /**
  39. * 批量插入记录:
  40. * * 默认情况下MySQL批处理没有开启的,需要在url后面拼接一个参数即可。
  41. */
  42. public void demo2(){
  43. // 记录开始时间:
  44. long begin = System.currentTimeMillis();
  45. Connection conn = null;
  46. PreparedStatement pstmt = null;
  47. try{
  48. conn = JDBCUtils.getConnection();
  49. String sql = "insert into user values (null,?)";
  50. pstmt = conn.prepareStatement(sql);
  51. for(int i=1;i<=10000;i++){
  52. pstmt.setString(1, "name"+i);
  53. pstmt.addBatch();
  54. if(i % 1000 == 0){
  55. pstmt.executeBatch();
  56. pstmt.clearBatch();
  57. }
  58. }
  59. }catch(Exception e){
  60. e.printStackTrace();
  61. }finally{
  62. JDBCUtils.release(pstmt, conn);
  63. }
  64. long end = System.currentTimeMillis();
  65. System.out.println((end-begin));
  66. }

7 JDBC事务管理

例如在转账操作中,如果没有添加事务管理,可能出现 a b 账户互相转账后,两账户总额跟操作前不相等的情况,此时需要给转账功能添加事务管理。

  1. public void demo1(){
  2. Connection conn = null;
  3. PreparedStatement pstmt = null;
  4. try{
  5. conn = JDBCUtils.getConnection();
  6. // 1 开启事务
  7. conn.setAutoCommit(false);
  8. String sql = "update account set money = money + ? where name = ?";
  9. pstmt = conn.prepareStatement(sql);
  10. pstmt.setDouble(1, -1000);
  11. pstmt.setString(2, "aaa");
  12. pstmt.executeUpdate();
  13.  
  14. int i = 1 / 0;
  15.  
  16. pstmt.setDouble(1, 1000);
  17. pstmt.setString(2, "bbb");
  18. pstmt.executeUpdate();
  19.  
  20. // 2 提交事务:
  21. conn.commit();
  22. }catch(Exception e){
  23. // 3 回滚事务:
  24. try {
  25. conn.rollback();
  26. } catch (SQLException e1) {
  27. e1.printStackTrace();
  28. }
  29. e.printStackTrace();
  30. }finally{
  31. JDBCUtils.release(pstmt, conn);
  32. }
  33. }

8 DBUtils简介

为简化JDBC开发,可以使用DBUtils,DBUtils封装了对JDBC的操作,是JDBC的简化开发工具包。使用需要导入commons-dbutils-1.6.jar。
Dbutils三个核心功能
    QueryRunner      提供对sql语句操作的API,用来执行SQL语句的对象
    ResultSetHandler接口   定义select后怎样封装结果集.
    DbUtils类        工具类,定义了关闭资源与事务处理的方法
1 QueryRunner
    无事务管理:
      int update(String sql,Object… args);:增、删、改
      T query(String sql,ResultSetHandler rsh,Object… args);:查询
    有事务管理:
      int update(Connection conn, String sql, Object... params) :增、删、改           
      T query(Connection conn, String sql, ResultSetHandler<T> rsh, Object... params) :查询
query(Connection con,String sql,ResultSetHandler r, Object..params)
  ResultSetHandler r   结果集的处理方式,传递ResultSetHandler接口实现类
  Object..params     SQL语句中的?占位符
  注意: query方法返回值,返回的是T 泛型, 具体返回值类型,跟随结果集处理方式变化

  1. //增加
  2. public void demo1() throws SQLException{
  3. // 创建核心类:QueryRunner:
  4. QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
  5. queryRunner.update("insert into account values (null,?,?)", "ddd",10000);
  6. }
  7.  
  8. //删除
  9. public void demo3() throws SQLException{
  10. QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
  11. queryRunner.update("delete from account where id = ?", 3);
  12. }
  13. //修改
  14. public void demo2() throws SQLException{
  15. QueryRunner queryRunner = new QueryRunner(JDBCUtils2.getDataSource());
  16. queryRunner.update("update account set name=?,money=? where id =?", "eee",20000,4);
  17. }  
  1. //增加
  2. public void insert(){
  3. try {
  4. //获取一个QueryRunner对象,用来执行SQL语句
  5. QueryRunner queryRunner = new QueryRunner();
  6.  
  7. String sql = "INSERT INTO zhangwu(name,money,parent) VALUES(?,?,?)";
  8. Object[] params = {"股票收入", 5500, "收入"};
  9. Connection conn = JDBCUtils.getConnection();
  10. int line = queryRunner.update(conn,sql,params);// 用来完成表数据的增加、删除、更新操作
  11. //结果集处理
  12. System.out.println("line = " + line);
  13.  
  14. } catch (SQLException e) {
  15. throw new RuntimeException(e);
  16. }
  17. }
  18. //删除
  19. public void delete(){
  20. try {
  21. QueryRunner queryRunner = new QueryRunner();
  22. String sql = "DELETE FROM zhangwu WHERE name = ?";
  23. Object[] params = {"股票收入"};
  24. Connection conn = JDBCUtils.getConnection();
  25. int line = queryRunner.update(conn, sql, params);
  26. System.out.println("line="+line);
  27.  
  28. } catch (SQLException e) {
  29. throw new RuntimeException(e);
  30. }
  31. }
  32. //修改
  33. public void update(){
  34. try {
  35. QueryRunner queryRunner = new QueryRunner();
  36. String sql = "UPDATE zhangwu SET money = money+1000 WHERE name=?";
  37. Object[] params = {"股票收入"};
  38. Connection conn = JDBCUtils.getConnection();
  39. int line = queryRunner.update(conn, sql, params);
  40. System.out.println("line="+line);
  41.  
  42. } catch (SQLException e) {
  43. throw new RuntimeException(e);
  44. }
  45. }

QueryRunner的两个构造方法
第一种:不带connection参数
QueryRunner queryRunner = new QueryRunner();
这种情况下,调用update或query方法时,需要传入对应的connection参数
queryRunner.update(conn, sql,params);
conn.close();
DBUtils调用这种带connection参数的方法时,
只会关闭preparedstatement和resultset对象,不会关闭conneciton对象,
一些情况下,没有手动关闭,可能会导致连接池满了,访问数据库是处于一直等待的状态。
就是为了其他方法来调用这个conneciton,所以这种连接数据库的方法适合操作事务。
第二种:带connection参数
QueryRunner queryRunner = new QueryRunner(dataSource);
将dataSource传递进去,这样update或query方法内部就调用this.getconnection方法来从这个数据源获得连接,
queryRunner.update( sql,params);
操作完后,就关闭conneciton,preparedstatement和resultset对象.
事务是自动控制的,一条SQL语句一个事务,不需要人为的控制。
2 ResultSetHandler  

  ArrayHandler        将结果集的第一条记录封装到Object[]数组中,数组中的每一个元素就是这条记录中每一个字段的值
  ArrayListHandler     将结果集的每一条记录都封装到Object[]数组中,数组封装到List集合中。
  BeanHandler        将结果集第一条记录封装到javaBean中。
  BeanListHandler     将结果集每一条记录封装到javaBean中,javaBean封装到List集合中
  ColumnListHandler    将结果集指定的列的字段值,封装到一个List集合中
  ScalarHandler      用于单数据。例如select count(*) from 表操作。
  MapHandler       将结果集第一行封装到Map集合中,Key 列名, Value 该列数据
  MapListHandler       将结果集第一行封装到Map集合中,Key 列名, Value 该列数据,Map集合存储到List集合

  1)JavaBean
JavaBean就是一个类,在开发中常用封装数据。具有如下特性
1.需要实现接口:java.io.Serializable ,通常实现接口这步骤省略了,不会影响程序。
2.提供私有字段:private 类型 字段名;
3.提供getter/setter方法:
4.提供无参构造
示例:

  1. public class ZhangWu {
  2. private int id;
  3. private String name;
  4. private double money;
  5. private String parent;
  6.  
  7. public ZhangWu() {
  8. super();
  9. }
  10. public int getId() {
  11. return id;
  12. }
  13. public void setId(int id) {
  14. this.id = id;
  15. }
  16. public String getName() {
  17. return name;
  18. }
  19. public void setName(String name) {
  20. this.name = name;
  21. }
  22. public double getMoney() {
  23. return money;
  24. }
  25. public void setMoney(double money) {
  26. this.money = money;
  27. }
  28. public String getParent() {
  29. return parent;
  30. }
  31. public void setParent(String parent) {
  32. this.parent = parent;
  33. }
  34.  
  35. @Override
  36. public String toString() { //该方法可以省略
  37. return "ZhangWu [id=" + id + ", name=" + name + ", money=" + money + ", parent=" + parent + "]";
  38. }
  39. }

3 ResultSetHandler使用案例

  1. public class ArrayHandlerDemo {
  2.  
  3. public void method(){
  4. try {
  5. //获取QueryRunner对象
  6. QueryRunner qr = new QueryRunner();
  7. //执行SQL语句
  8. String sql = "SELECT * FROM zhangwu";
  9. Object[] params = {};
  10. Connection conn = JDBCUtils.getConnection();
  11. Object[] objArray = qr.query(conn, sql, new ArrayHandler(), params);
  12. //结果集的处理
  13. System.out.println( Arrays.toString(objArray) );
  14.  
  15. conn.close();
  16. } catch (SQLException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21.  
  22. //ArrayListHandlerDemo
  23. String sql = "SELECT * FROM zhangwu WHERE money>?";
  24. Object[] params = {2000};
  25. Connection conn = JDBCUtils.getConnection();
  26. List<Object[]> list = qr.query(conn, sql, new ArrayListHandler(), params);
  27. for (Object[] objArray : list) {
  28. System.out.println( Arrays.toString(objArray) );
  29. }
  30.  
  31. //BeanHandlerDemo
  32. String sql = "SELECT * FROM zhangwu WHERE id=?";
  33. Object[] params = {1};
  34. Connection conn = JDBCUtils.getConnection();
  35. ZhangWu zw = qr.query(conn, sql, new BeanHandler<ZhangWu>(ZhangWu.class), params);
  36. System.out.println(zw);
  37.  
  38. //BeanListHandlerDemo
  39. String sql = "SELECT * FROM zhangwu WHERE money>?";
  40. Object[] params = {2000};
  41. Connection conn = JDBCUtils.getConnection();
  42. List<ZhangWu> list = qr.query(conn, sql, new BeanListHandler<ZhangWu>(ZhangWu.class), params);
  43. for (ZhangWu zw : list) {
  44. System.out.println(zw);
  45. }
  46.  
  47. //ColumnListHandlerDemo
  48. String sql = "SELECT name FROM zhangwu WHERE money>?";
  49. Object[] params = {2000};
  50. Connection conn = JDBCUtils.getConnection();
  51. List<String> list = qr.query(conn, sql, new ColumnListHandler<String>(), params);
  52. for (String str : list) {
  53. System.out.println(str);
  54. }
  55.  
  56. //ScalarHandlerDemo
  57. String sql = "SELECT MAX(money) FROM zhangwu";
  58. Object[] params = {};
  59. Connection conn = JDBCUtils.getConnection();
  60. Double max = qr.query(conn, sql, new ScalarHandler<Double>(), params);
  61. System.out.println("max=" + max);
  1. /*
  2. * 结果集第一种处理方法, ArrayHandler
  3. * 将结果集的第一行存储到对象数组中 Object[]
  4. */
  5. public static void arrayHandler()throws SQLException{
  6. QueryRunner qr = new QueryRunner();
  7. String sql = "SELECT * FROM sort";
  8. //调用方法query执行查询,传递连接对象,SQL语句,结果集处理方式的实现类
  9. //返回对象数组
  10. Object[] result = qr.query(con, sql, new ArrayHandler());
  11. for(Object obj : result){
  12. System.out.print(obj);
  13. }
  14. }
  15.  
  16. /*
  17. * 结果集第二种处理方法,ArrayListHandler
  18. * 将结果集的每一行,封装到对象数组中, 出现很多对象数组
  19. * 对象数组存储到List集合
  20. */
  21. public static void arrayListHandler()throws SQLException{
  22. QueryRunner qr = new QueryRunner();
  23. String sql = "SELECT * FROM sort";
  24. //调用query方法,结果集处理的参数上,传递实现类ArrayListHandler
  25. //方法返回值 每行是一个对象数组,存储到List
  26. List<Object[]> result= qr.query(con, sql, new ArrayListHandler());
  27.  
  28. //集合的遍历
  29. for( Object[] objs : result){
  30. //遍历对象数组
  31. for(Object obj : objs){
  32. System.out.print(obj+" ");
  33. }
  34. System.out.println();
  35. }
  36. }
  37.  
  38. /*
  39. * 结果集第三种处理方法,BeanHandler
  40. * 将结果集的第一行数据,封装成JavaBean对象
  41. * 注意: 被封装成数据到JavaBean对象, Sort类必须有空参数构造
  42. */
  43. public static void beanHandler()throws SQLException{
  44. QueryRunner qr = new QueryRunner();
  45. String sql = "SELECT * FROM sort ";
  46. //调用方法,传递结果集实现类BeanHandler
  47. //BeanHandler(Class<T> type)
  48. Sort s = qr.query(con, sql, new BeanHandler<Sort>(Sort.class));
  49. System.out.println(s);
  50. }
  51.  
  52. /*
  53. * 结果集第四种处理方法, BeanListHandler
  54. * 结果集每一行数据,封装JavaBean对象
  55. * 多个JavaBean对象,存储到List集合
  56. */
  57. public static void beanListHander()throws SQLException{
  58. QueryRunner qr = new QueryRunner();
  59. String sql = "SELECT * FROM sort ";
  60. //调用方法query,传递结果集处理实现类BeanListHandler
  61. List<Sort> list = qr.query(con, sql, new BeanListHandler<Sort>(Sort.class));
  62. for(Sort s : list){
  63. System.out.println(s);
  64. }
  65. }
  66.  
  67. /*
  68. * 结果集第五种处理方法,ColumnListHandler
  69. * 结果集,指定列的数据,存储到List集合
  70. * List<Object> 每个列数据类型不同
  71. */
  72. public static void columnListHandler()throws SQLException{
  73. QueryRunner qr = new QueryRunner();
  74. String sql = "SELECT * FROM sort ";
  75. //调用方法 query,传递结果集实现类ColumnListHandler
  76. //实现类构造方法中,使用字符串的列名
  77. List<Object> list = qr.query(con, sql, new ColumnListHandler<Object>("sname"));
  78. for(Object obj : list){
  79. System.out.println(obj);
  80. }
  81. }
  82.  
  83. /*
  84. * 结果集第六种处理方法,ScalarHandler
  85. * 对于查询后,只有1个结果
  86. */
  87. public static void scalarHandler()throws SQLException{
  88. QueryRunner qr = new QueryRunner();
  89. String sql = "SELECT COUNT(*) FROM sort";
  90. //调用方法query,传递结果集处理实现类ScalarHandler
  91. long count = qr.query(con, sql, new ScalarHandler<Long>());
  92. System.out.println(count);
  93. }
  94.  
  95. /*
  96. * 结果集第七种处理方法,MapHandler
  97. * 将结果集第一行数据,封装到Map集合中
  98. * Map<键,值> 键:列名 值:这列的数据
  99. */
  100. public static void mapHandler()throws SQLException{
  101. QueryRunner qr = new QueryRunner();
  102. String sql = "SELECT * FROM sort";
  103. //调用方法query,传递结果集实现类MapHandler
  104. //返回值: Map集合,Map接口实现类, 泛型
  105. Map<String,Object> map = qr.query(con, sql, new MapHandler());
  106. //遍历Map集合
  107. for(String key : map.keySet()){
  108. System.out.println(key+".."+map.get(key));
  109. }
  110. }
  111.  
  112. /*
  113. * 结果集第八种处理方法,MapListHandler
  114. * 将结果集每一行存储到Map集合,键:列名,值:数据
  115. * Map集合过多,存储到List集合
  116. */
  117. public static void mapListHandler()throws SQLException{
  118. QueryRunner qr = new QueryRunner();
  119. String sql = "SELECT * FROM sort";
  120. //调用方法query,传递结果集实现类MapListHandler
  121. //返回值List集合, 存储的是Map集合
  122. List<Map<String,Object>> list = qr.query(con, sql, new MapListHandler());
  123. //遍历集合list
  124. for( Map<String,Object> map : list ){
  125. for(String key : map.keySet()){
  126. System.out.print(key+"..."+map.get(key));
  127. }
  128. System.out.println();
  129. }
  130.  
  131. }

9 连接池

9.1 DBCP连接池

Java提供了数据库连接池公共接口:javax.sql.DataSource,各厂商需要让自己的连接池实现这个接口,这样程序可以方便地切换不同厂商的连接池。

DBCP是tomcat内置开源连接池,提供了DataSource接口的实现类:BasicDataSource类
需要的jar包:
mysql-connector-java-5.1.37-bin.jar:数据库驱动
commons-dbutils-1.6.jar:提供QueryRunner类方便进行增删改查操作
commons-dbcp-1.4.jar:
commons-pool-1.5.6.jar:提供高效的数据库连接池技术
BasicDataSource类的使用:

  1. //使用DBCP实现数据库的连接池
  2. public class JDBCUtils{
  3. //创建出BasicDataSource类对象
  4. private static BasicDataSource datasource = new BasicDataSource();
  5.  
  6. static{
  7. datasource.setDriverClassName("com.mysql.jdbc.Driver");
  8. datasource.setUrl("jdbc:mysql://localhost:3306/day33_user");
  9. datasource.setUsername("root");
  10. datasource.setPassword("123");
  11. datasource.setInitialSize(10);//初始化的连接数
  12. datasource.setMaxActive(8);//最大连接数量
  13. datasource.setMaxIdle(5);//最大空闲数
  14. datasource.setMinIdle(1);//最小空闲
  15. }
  16.  
  17. //定义静态方法,返回BasicDataSource类的对象
  18. public static DataSource getDataSource(){
  19. return datasource;
  20. }
  21. }

常见配置
必须项
  driverClassName   数据库驱动名称
  url         数据库的地址
  username      用户名
  password      密码
基本项(扩展)
  maxActive   最大连接数量
  minIdle    最小空闲连接
  maxIdle    最大空闲连接
  initialSize   初始化连接
测试连接池:

  1. /*
  2. * 测试写好的工具类,
  3. * 提供的是一个DataSource接口的数据源
  4. * QueryRunner类构造方法,接收DataSource接口的实现类
  5. * 后面,调用方法update,query,无需传递他们Connection连接对象
  6. */
  7.  
  8. public class QueryRunnerDemo{
  9. public static void main(String[] args) {
  10. select();
  11. }
  12. //定义2个方法,实现数据表的添加,数据表查询
  13. //QueryRunner类对象,写在类成员位置
  14. private static QueryRunner qr = new QueryRunner(JDBCUtils.getDataSource());
  15.  
  16. //数据表查询
  17. public static void select(){
  18. String sql = "SELECT * FROM sort";
  19. try{
  20. List<Object[]> list = qr.query(sql, new ArrayListHandler());
  21. for(Object[] objs : list){
  22. for(Object obj : objs){
  23. System.out.print(obj+"\t");
  24. }
  25. System.out.println();
  26. }
  27. }catch(SQLException ex){
  28. throw new RuntimeException("数据查询失败");
  29. }
  30. }
  31.  
  32. }

9.2 C3P0连接池

C3P0是一个开源JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。
C3P0与DBCP区别:DBCP没有自动回收空闲连接的功能,C3P0有
C3P0连接池的使用:

  1. /**
  2. * 1 手动设置参数的方式:
  3. */
  4. public void demo1(){
  5. Connection conn = null;
  6. PreparedStatement pstmt = null;
  7. ResultSet rs = null;
  8. try{
  9. // 获得连接:从连接池中获取:
  10. // 创建连接池:
  11. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  12. // 设置连接参数:
  13. dataSource.setDriverClass("com.mysql.jdbc.Driver");
  14. dataSource.setJdbcUrl("jdbc:mysql:///web_test4");
  15. dataSource.setUser("root");
  16. dataSource.setPassword("abc");
  17.  
  18. conn = dataSource.getConnection();
  19. String sql = "select * from account";
  20. pstmt = conn.prepareStatement(sql);
  21. rs = pstmt.executeQuery();
  22. while(rs.next()){
  23. System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
  24. }
  25. }catch(Exception e){
  26. e.printStackTrace();
  27. }finally{
  28. JDBCUtils.release(rs, pstmt, conn);
  29. }
  30. }
  1. /**
  2. * 2 采用配置文件的方式:
  3. */
  4. public void demo2(){
  5. Connection conn = null;
  6. PreparedStatement pstmt = null;
  7. ResultSet rs = null;
  8. try{
  9. // 获得连接:从连接池中获取:
  10. // 创建连接池://创建连接池默认去类路径下查找c3p0-config.xml
  11. ComboPooledDataSource dataSource = new ComboPooledDataSource();
  12. // 从连接池中获得连接:
  13. conn = dataSource.getConnection();
  14. String sql = "select * from account";
  15. pstmt = conn.prepareStatement(sql);
  16. rs = pstmt.executeQuery();
  17. while(rs.next()){
  18. System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
  19. }
  20. }catch(Exception e){
  21. e.printStackTrace();
  22. }finally{
  23. JDBCUtils.release(rs, pstmt, conn);
  24. }
  25. }
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <c3p0-config>
  3. <!-- c3p0-config.xml -->
  4. <default-config>
  5. <property name="driverClass">com.mysql.jdbc.Driver</property>
  6. <property name="jdbcUrl">jdbc:mysql:///web_test4</property>
  7. <property name="user">root</property>
  8. <property name="password">abc</property>
  9.  
  10. <property name="initialPoolSize">5</property>
  11. <property name="minPoolSize">5</property>
  12. <property name="maxPoolSize">20</property>
  13. </default-config>
  14.  
  15. </c3p0-config>

C3P0详细配置:

  1. <?xml version="1.0" encoding="gbk"?>
  2. <c3p0-config>
  3. <!--默认配置,如果获取连接池时没有指定名称,则使用默认配置信息-->
  4. <default-config>
  5. <!--连接url-->
  6. <property name="jdbcUrl">jdbc:mysql://localhost:3306/mydb1</property>
  7.  
  8. <!--数据库驱动类-->
  9. <property name="driverClass">com.mysql.jdbc.Driver</property>
  10.  
  11. <!--用户名。Default: null-->
  12. <property name="user">root</property>
  13. <!--密码。Default: null-->
  14. <property name="password"></property>
  15.  
  16. <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->
  17. <property name="acquireIncrement">3</property>
  18.  
  19. <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->
  20. <property name="acquireRetryAttempts">30</property>
  21.  
  22. <!--两次连接中间隔时间,单位毫秒。Default: 1000 -->
  23. <property name="acquireRetryDelay">1000</property>
  24.  
  25. <!--连接关闭时默认将所有未提交的操作回滚。Default: false -->
  26. <property name="autoCommitOnClose">false</property>
  27.  
  28. <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
  29. 属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
  30. 使用。Default: null-->
  31. <property name="automaticTestTable">Test</property>
  32.  
  33. <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
  34. 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
  35. 获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->
  36. <property name="breakAfterAcquireFailure">false</property>
  37.  
  38. <!--当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
  39. SQLException,如设为0则无限期等待。单位毫秒。Default: 0 -->
  40. <property name="checkoutTimeout">100</property>
  41.  
  42. <!--通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
  43. Default: com.mchange.v2.c3p0.impl.DefaultConnectionTester-->
  44. <property name="connectionTesterClassName"></property>
  45.  
  46. <!--指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
  47. Default: null-->
  48. <property name="factoryClassLocation">null</property>
  49.  
  50. <!--Strongly disrecommended. Setting this to true may lead to subtle and bizarre bugs.
  51. (文档原文)作者强烈建议不使用的一个属性-->
  52. <property name="forceIgnoreUnresolvedTransactions">false</property>
  53.  
  54. <!--每60秒检查所有连接池中的空闲连接。Default: 0 -->
  55. <property name="idleConnectionTestPeriod">60</property>
  56.  
  57. <!--初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->
  58. <property name="initialPoolSize">3</property>
  59.  
  60. <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->
  61. <property name="maxIdleTime">60</property>
  62.  
  63. <!--连接池中保留的最大连接数。Default: 15 -->
  64. <property name="maxPoolSize">15</property>
  65.  
  66. <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
  67. 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
  68. 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->
  69. <property name="maxStatements">100</property>
  70.  
  71. <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0 -->
  72. <property name="maxStatementsPerConnection"></property>
  73.  
  74. <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
  75. 通过多线程实现多个操作同时被执行。Default: 3-->
  76. <property name="numHelperThreads">3</property>
  77.  
  78. <!--当用户调用getConnection()时使root用户成为去获取连接的用户。主要用于连接池连接非c3p0
  79. 的数据源时。Default: null-->
  80. <property name="overrideDefaultUser">root</property>
  81.  
  82. <!--与overrideDefaultUser参数对应使用的一个参数。Default: null-->
  83. <property name="overrideDefaultPassword">password</property>
  84.  
  85. <!--定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意:
  86. 测试的表必须在初始数据源的时候就存在。Default: null-->
  87. <property name="preferredTestQuery">select id from test where id=1</property>
  88.  
  89. <!--用户修改系统配置参数执行前最多等待300秒。Default: 300 -->
  90. <property name="propertyCycle">300</property>
  91.  
  92. <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的
  93. 时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable
  94. 等方法来提升连接测试的性能。Default: false -->
  95. <property name="testConnectionOnCheckout">false</property>
  96.  
  97. <!--如果设为true那么在取得连接的同时将校验连接的有效性。Default: false -->
  98. <property name="testConnectionOnCheckin">true</property>
  99.  
  100. <!--早期的c3p0版本对JDBC接口采用动态反射代理。在早期版本用途广泛的情况下这个参数
  101. 允许用户恢复到动态反射代理以解决不稳定的故障。最新的非反射代理更快并且已经开始
  102. 广泛的被使用,所以这个参数未必有用。现在原先的动态反射与新的非反射代理同时受到
  103. 支持,但今后可能的版本可能不支持动态反射代理。Default: false-->
  104. <property name="usesTraditionalReflectiveProxies">false</property>
  105.  
  106. </default-config>
  107. <!--指定配置名称的配置信息-->
  108. <named-config name="dumbTestConfig">
  109.  
  110. </named-config>
  111. </c3p0-config>

9.3 Druid连接池

阿里旗下开源连接池产品,使用简单,可以与Spring框架进行快速整合
1 Druid的使用:

  1. /**
  2. * 1 手动设置参数的方式
  3. */
  4. public void demo1(){
  5. Connection conn = null;
  6. PreparedStatement pstmt = null;
  7. ResultSet rs = null;
  8. try{
  9. // 使用连接池:
  10. DruidDataSource dataSource = new DruidDataSource();
  11. // 手动设置数据库连接的参数:
  12. dataSource.setDriverClassName("com.mysql.jdbc.Driver");
  13. dataSource.setUrl("jdbc:mysql:///web_test4");
  14. dataSource.setUsername("root");
  15. dataSource.setPassword("abc");
  16. // 获得连接:旧方式
  17. //conn = JDBCUtils.getConnection();
  18. conn = dataSource.getConnection();
  19.  
  20. String sql = "select * from account";
  21. pstmt = conn.prepareStatement(sql);
  22. rs = pstmt.executeQuery();
  23. while(rs.next()){
  24. System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
  25. }
  26. }catch(Exception e){
  27. e.printStackTrace();
  28. }finally{
  29. JDBCUtils.release(rs, pstmt, conn);
  30. }
  31. }
  1. /**
  2. * 2 配置方式设置参数
  3. * Druid配置方式可以使用属性文件配置的。
  4. * 文件名称没有规定但是属性文件中的key要一定的。
  5. */
  6. public void demo2(){
  7. Connection conn = null;
  8. PreparedStatement pstmt = null;
  9. ResultSet rs = null;
  10. try{
  11. // 使用连接池:
  12. // 从属性文件中获取:
  13. Properties properties = new Properties();
  14. properties.load(new FileInputStream("src/druid.properties"));
  15. DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
  16. // 获得连接:旧方式
  17. //conn = JDBCUtils.getConnection();
  18. conn = dataSource.getConnection();
  19.  
  20. String sql = "select * from account";
  21. pstmt = conn.prepareStatement(sql);
  22. rs = pstmt.executeQuery();
  23. while(rs.next()){
  24. System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
  25. }
  26. }catch(Exception e){
  27. e.printStackTrace();
  28. }finally{
  29. JDBCUtils.release(rs, pstmt, conn);
  30. }
  31. }

2 Druid监控及慢sql记录:
https://www.cnblogs.com/telwanggs/p/7484854.html

9.4 自定义连接池

步骤:
  1 编写一个类实现DataSource接口
  2 重写getConnection方法
  3 初始化多个连接在内存中
  4 编写归还连接的方法

  1. //自定义连接池
  2. public class MyDataSource implements DataSource {
  3. // 将一些连接存入到内存中,可以定义一个集合,用于存储连接对象。
  4. private List<Connection> connList = new ArrayList<Connection>();
  5.  
  6. // 在初始化的时候提供一些连接
  7. public MyDataSource() {
  8. // 初始化连接:
  9. for(int i = 1;i<=3;i++){
  10. // 向集合中存入连接:
  11. connList.add(JDBCUtils.getConnection());
  12. }
  13. }
  14.  
  15. // 从连接池中获得连接的方法
  16. @Override
  17. public Connection getConnection() throws SQLException {
  18. Connection conn = connList.remove(0);
  19. // 增强连接:
  20. MyConnectionWrapper connWrapper = new MyConnectionWrapper(conn, connList);
  21. return connWrapper;
  22. }
  23.  
  24. // 编写一个归还连接的方法:
  25. /*public void addBack(Connection conn){
  26. connList.add(conn);
  27. }*/
  28.  
  29. @Override
  30. public PrintWriter getLogWriter() throws SQLException {
  31. // TODO Auto-generated method stub
  32. return null;
  33. }
  34.  
  35. @Override
  36. public int getLoginTimeout() throws SQLException {
  37. // TODO Auto-generated method stub
  38. return 0;
  39. }
  40.  
  41. @Override
  42. public Logger getParentLogger() throws SQLFeatureNotSupportedException {
  43. // TODO Auto-generated method stub
  44. return null;
  45. }
  46.  
  47. @Override
  48. public void setLogWriter(PrintWriter arg0) throws SQLException {
  49. // TODO Auto-generated method stub
  50.  
  51. }
  52.  
  53. @Override
  54. public void setLoginTimeout(int arg0) throws SQLException {
  55. // TODO Auto-generated method stub
  56.  
  57. }
  58.  
  59. @Override
  60. public boolean isWrapperFor(Class<?> arg0) throws SQLException {
  61. // TODO Auto-generated method stub
  62. return false;
  63. }
  64.  
  65. @Override
  66. public <T> T unwrap(Class<T> arg0) throws SQLException {
  67. // TODO Auto-generated method stub
  68. return null;
  69. }
  70.  
  71. @Override
  72. public Connection getConnection(String arg0, String arg1) throws SQLException {
  73. // TODO Auto-generated method stub
  74. return null;
  75. }
  76.  
  77. }

测试自定义连接池:

  1. public class DataSourceDemo1 {
  2.  
  3. @Test
  4. /**
  5. * 测试自定义连接池
  6. */
  7. public void demo1(){
  8. Connection conn = null;
  9. PreparedStatement pstmt = null;
  10. ResultSet rs = null;
  11. DataSource dataSource = null;
  12. try{
  13. // 获得连接:
  14. // conn = JDBCUtils.getConnection();
  15. // 从连接池中获得连接:
  16. dataSource = new MyDataSource();
  17. conn = dataSource.getConnection();
  18. String sql = "select * from account";
  19. pstmt = conn.prepareStatement(sql);
  20. rs = pstmt.executeQuery();
  21. while(rs.next()){
  22. System.out.println(rs.getInt("id")+" "+rs.getString("name")+" "+rs.getDouble("money"));
  23. }
  24. }catch(Exception e){
  25. e.printStackTrace();
  26. }finally{
  27. JDBCUtils.release(rs, pstmt, conn);
  28. // 归还连接:
  29. // dataSource.addBack(conn);
  30. }
  31. }
  32. }

使用装饰者增强Connection中的close方法:将原有的close方法的逻辑改为归还(增强一个类中的方法) 
装饰者模式使用条件:
  1、增强类和被增强类实现相同的接口
  2、在增强的类中获得被增强的类的引用

  1. public class MyConnectionWrapper extends ConnectionWrapper{
  2.  
  3. private Connection conn;
  4. private List<Connection> connList;
  5.  
  6. public MyConnectionWrapper(Connection conn,List<Connection> connList) {
  7. super(conn);
  8. this.conn = conn;
  9. this.connList= connList;
  10. }
  11.  
  12. // 增强某个方法:
  13. @Override
  14. public void close() throws SQLException {
  15. // super.close();
  16. // 归还连接:
  17. connList.add(conn);
  18. }
  19.  
  20. }

JDBC 和连接池的更多相关文章

  1. c3p0、dbcp、tomcat jdbc pool 连接池配置简介及常用数据库的driverClass和驱动包

    [-] DBCP连接池配置 dbcp jar包 c3p0连接池配置 c3p0 jar包 jdbc-pool连接池配置 jdbc-pool jar包 常用数据库的driverClass和jdbcUrl ...

  2. jdbc数据连接池dbcp要导入的jar包

    jdbc数据连接池dbcp要导入的jar包 只用导入commons-dbcp-x.y.z.jarcommons-pool-a.b.jar

  3. 关于JDBC和连接池我学到的(转载保存)

    1.JDBC数据库连接池的必要性 在使用开发基于数据库的web程序时,传统的模式基本是按以下步骤: 在主程序(如servlet.beans)中建立数据库连接. 进行sql操作 断开数据库连接. 这种模 ...

  4. JDBC之 连接池

    JDBC之 连接池 有这样的一种现象: 用java代码操作数据库,需要数据库连接对象,一个用户至少要用到一个连接.现在假设有成千上百万个用户,就要创建十分巨大数量的连接对象,这会使数据库承受极大的压力 ...

  5. JDBC数据源连接池(4)---自定义数据源连接池

    [续上文<JDBC数据源连接池(3)---Tomcat集成DBCP>] 我们已经 了解了DBCP,C3P0,以及Tomcat内置的数据源连接池,那么,这些数据源连接池是如何实现的呢?为了究 ...

  6. JDBC数据源连接池(3)---Tomcat集成DBCP

    此文续<JDBC数据源连接池(2)---C3P0>. Apache Tomcat作为一款JavaWeb服务器,内置了DBCP数据源连接池.在使用中,只要进行相应配置即可. 首先,确保Web ...

  7. JDBC数据源连接池(2)---C3P0

    我们接着<JDBC数据源连接池(1)---DBCP>继续介绍数据源连接池. 首先,在Web项目的WebContent--->WEB-INF--->lib文件夹中添加C3P0的j ...

  8. DBCP,C3P0与Tomcat jdbc pool 连接池的比较

    hibernate开发组推荐使用c3p0; spring开发组推荐使用dbcp(dbcp连接池有weblogic连接池同样的问题,就是强行关闭连接或数据库重启后,无法reconnect,告诉连接被重置 ...

  9. JDBC数据源连接池的配置和使用实例

    个人学习参考所用,勿喷! 使用JDBC建立数据库连接的两种方式: 1.在代码中使用DriverManager获得数据库连接.这种方式效率低,并且其性能.可靠性和稳定性随着用户访问量得增加逐渐下降. 2 ...

  10. mysql,jdbc、连接池

    show processlist; select * from information_schema.processlist; Command: The type of command the thr ...

随机推荐

  1. ubuntu设置分辨率

    前言 装过ubuntu的虚拟机人应该都知道,刚刚装完系统时,分辨率小的令人发指,根本就不能愉快的使用,所以必须调整,但是有些分辨率ubuntu里面也没有,这就需要我们自己自定义. 自定义分辨率 1. ...

  2. vultr搭建ss

    我在Ubuntu1604上运行的sslocal,但是发现firefox无法链接ss代理,后来用的chromium才成功连接上, ---------------------------- 下面是正文 - ...

  3. open-falcon实现邮件报警

    1.请安装好Go的环境,参考上一篇open-falcon的安装博文 2.安装 mail-provider https://github.com/open-falcon/mail-provider 安装 ...

  4. Window应急响应(五):ARP病毒

    0x00 前言 ARP病毒并不是某一种病毒的名称,而是对利用arp协议的漏洞进行传播的一类病毒的总称,目前在局域网中较为常见.发作的时候会向全网发送伪造的ARP数据包,严重干扰全网的正常运行,其危害甚 ...

  5. linux telnet检测与某个端口是否开通

    转自:http://blog.51cto.com/meiling/1982402 一:telnet此法常被用来检测是个远端端口是否通畅. 测试域名: # telnet baidu.com 80 Try ...

  6. 卸载ie

    今天卸载ie11失败,最后使用下面这个命令实现了卸载,记录下 IE11卸载命令如下: FORFILES /P %WINDIR%\servicing\Packages /M Microsoft-Wind ...

  7. 四、Sql Server 基础培训《进度4-插入数据(实际操作)》

    知识点: 假设有订单表 CREATE TABLE Order ( ID int identity(1,1) not null primary key, --内码 BillNo varchar(100) ...

  8. 【Zookeeper系列】Zookeeper简单介绍(转)

    原文链接:https://www.cnblogs.com/sunddenly/p/4033574.html 一.分布式协调技术 在给大家介绍ZooKeeper之前先来给大家介绍一种技术——分布式协调技 ...

  9. CF 1131C Birthday

    C. Birthday time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...

  10. 线程的条件Condiition

    条件Condition相当于给锁造钥匙,但是这钥匙是一次性的.一个线程拿到钥匙进去,出来之后钥匙没有归还,而是没了. 如下代码: from threading import Thread, Condi ...