• JDBC02 利用JDBC连接数据库【使用数据库连接池】


    目录

      1/2/3  Statement 和 Preparedstatement 的区别

      4 读取properties配置文件

      5 数据库连接池

      6 利用数据库连接池连接数据库

    1 使用Statement执行含有动态信息的SQL语句时有几个不足:

      1.1 由于需要将动态数据拼接到SQL语句中,这导致程序复杂度高,容易出错
      1.2 拼接的数据若含有SQL语法内容就会导致拼接后的SQL语法含义改变而出现SQL注入攻击
      1.3 当大批量执行语义相同,但是含有动态数据的SQL时效率很差

    2 使用Statement执行SQL语句不好的原因

      2.1 当执行一条SQL语句发送到数据库时,数据库先将该SQL解析并生成一个执行计划(这个过程会消耗资源和性能),如果多次执行一样的SQL语句,数据库会重用执行计划,但是若多次执行语义相同但是含有动态数据的SQL时,数据库会生成不同的执行计划,严重影响数据库的开销
      2.2 例如

        执行 SELECT * FROM userifo_fury 生成一个执行计划再次执行SELECT * FROM userifo_fury会重用上面的执行计划(因为这是静态的SQL语句 

        但是,执行INSERT INTO userifo VALUES(1, 'JACK','122314','141234@QQ.COM','FURY',15600) ) 生成一个执行计划,再执行执行INSERT INTO userifo VALUES(2, 'rose','122314','141234@QQ.COM','FURY',15600)由于内容不同,会再次生成另外一个执行计划,若执行1000次上述情况的INSERT,数据库会产生1000个执行计划,这样就严重影响了数据库的效率
        因此,Statement只适合执行静态的SQL语句,不适合执行动态的SQL语句

        

    3 利用PreparedStatement代替Statement

      编写简单

      没有SQL注入问题

      批量执行语义相同的SQL语句会重用执行计划

     1 package cn.xiangxu.entity;
     2 
     3 import java.io.Serializable;
     4 
     5 public class User implements Serializable {
     6 
     7     private static final long serialVersionUID = -5109978284633713580L;
     8     
     9     private Integer id;
    10     private String name;
    11     private String pwd;
    12     public User() {
    13         super();
    14         // TODO Auto-generated constructor stub
    15     }
    16     public User(Integer id, String name, String pwd) {
    17         super();
    18         this.id = id;
    19         this.name = name;
    20         this.pwd = pwd;
    21     }
    22     @Override
    23     public int hashCode() {
    24         final int prime = 31;
    25         int result = 1;
    26         result = prime * result + ((id == null) ? 0 : id.hashCode());
    27         return result;
    28     }
    29     @Override
    30     public boolean equals(Object obj) {
    31         if (this == obj)
    32             return true;
    33         if (obj == null)
    34             return false;
    35         if (getClass() != obj.getClass())
    36             return false;
    37         User other = (User) obj;
    38         if (id == null) {
    39             if (other.id != null)
    40                 return false;
    41         } else if (!id.equals(other.id))
    42             return false;
    43         return true;
    44     }
    45     public Integer getId() {
    46         return id;
    47     }
    48     public void setId(Integer id) {
    49         this.id = id;
    50     }
    51     public String getName() {
    52         return name;
    53     }
    54     public void setName(String name) {
    55         this.name = name;
    56     }
    57     public String getPwd() {
    58         return pwd;
    59     }
    60     public void setPwd(String pwd) {
    61         this.pwd = pwd;
    62     }
    63     @Override
    64     public String toString() {
    65         return "User [id=" + id + ", name=" + name + ", pwd=" + pwd + "]";
    66     }
    67     
    68     
    69 
    70 }
    user表对应的实体类
     1 package testJDBC;
     2 
     3 import java.sql.Connection;
     4 import java.sql.DriverManager;
     5 import java.sql.PreparedStatement;
     6 import java.sql.ResultSet;
     7 import java.sql.SQLException;
     8 import java.util.ArrayList;
     9 import java.util.List;
    10 
    11 import org.junit.Test;
    12 
    13 import cn.xiangxu.entity.User;
    14 
    15 public class TestCase {
    16     @Test
    17     public void test01() {
    18         Connection conn = null;
    19         PreparedStatement ps = null;
    20         ResultSet rs = null;
    21         try {
    22             Class.forName("com.mysql.jdbc.Driver"); // 加载数据库驱动
    23             
    24             conn = DriverManager.getConnection( // 初始化连接对象
    25                     "jdbc:mysql://localhost:3306/test", "root", "182838");
    26             
    27             
    28             String sql = "SELECT * FROM user WHERE pwd = ? "; // 拼接SQL语句,位置参数用?代替
    29             
    30             ps = conn.prepareStatement(sql); // 初始化预编译执行对象
    31             
    32             ps.setString(1, "182838"); // 设置SQL语句中的位置位置参数(注意:是从1开始数不是从0开始数)
    33             
    34             rs = ps.executeQuery(); // 执行SQL语句
    35             
    36             List<User> users = new ArrayList<User>(); // 创建一个集合来存放记录对象
    37             while(rs.next()) { // 遍历结果集
    38 //                System.out.println("====================");
    39 //                System.out.println(rs.getInt("id"));
    40 //                System.out.println(rs.getString("name"));
    41 //                System.out.println(rs.getString("pwd"));
    42                 User user = new User();
    43                 user.setId(rs.getInt("id"));
    44                 user.setName(rs.getString("name"));
    45                 user.setPwd(rs.getString("pwd"));
    46                 users.add(user); // 向集合中添加元素
    47             }
    48             
    49             System.out.println(users); // 打印输出集合
    50             for(User user : users) {
    51                 System.out.println(user);
    52             }
    53             
    54             // 释放资源
    55             rs.close();
    56             ps.close(); 
    57             conn.close();
    58             
    59         } catch (Exception e) {
    60             // TODO Auto-generated catch block
    61             e.printStackTrace();
    62         } finally {
    63             if(rs != null) {
    64                 try {
    65                     rs.close();
    66                 } catch (SQLException e) {
    67                     // TODO Auto-generated catch block
    68                     e.printStackTrace();
    69                 }
    70             }
    71             if(ps != null) {
    72                 try {
    73                     ps.close();
    74                 } catch (SQLException e) {
    75                     // TODO Auto-generated catch block
    76                     e.printStackTrace();
    77                 }
    78             }
    79             if(conn != null) {
    80                 try {
    81                     conn.close();
    82                 } catch (SQLException e) {
    83                     // TODO Auto-generated catch block
    84                     e.printStackTrace();
    85                 }
    86             }
    87         }
    88         
    89     }
    90     
    91 }
    使用预编译Statement的实例

    4 利用Properties对象读取properties配置文件中的信息

      4.1 Properties继承了Hashtable类,Properties对象也是使用键值对的方式来保存数据,但是Properties对象的键和值都是字符串类型

        class Properties extends Hashtable<Object,Object>

      4.2 Properties 类中的主要方法

        4.2.1 public synchronized void load(InputStream inStream) throws IOException

          将properties属性文件的文件输入流加载到Properties对象

         

        4.2.2 public void store(OutputStream out, String comments) throws IOException

           将Properties对象中的属性列表保存到输出流文件中

          

          注意:第二个参数表示注释信息(注意:properties文件中不能用中文),在注释信息后面会自动添加一个时间信息

          注意:新创建的文件在项目的根目录下面(问题:为什么在eclipse中没有,但是到文件夹中却能找到???)

        4.2.3 public String getProperty(String key)

          获取属性值,参数是属性的键

         4.2.4 public synchronized Object setProperty(String key, String value)

          修改属性值,参数1是属性的键,参数2是属性的新值

      4.3 案例

        要求:读取properties配置文件总的属性值,将读取到的属性值进行修改后保存到另外一个properties配置文件中

     1 package cn.xiangxu.entity;
     2 
     3 import java.io.FileInputStream;
     4 import java.io.FileOutputStream;
     5 import java.io.InputStream;
     6 import java.util.Iterator;
     7 import java.util.Properties;
     8 
     9 public class Test {
    10     public static void main(String[] args) {
    11         try {
    12             Properties prop = new Properties(); // 创建Properties对象
    13             
    14 //            prop.load(new FileInputStream("config.properties")); // 使用这种方式时,配置文件必须放在项目的根目录下
    15             InputStream  is = Test.class.getClassLoader().getResourceAsStream("config/config.properties"); // 读取属性文件
    16             
    17             prop.load(is); // 加载属性列表
    18             
    19             Iterator<String> it=prop.stringPropertyNames().iterator(); // 将配置文件中的所有key放到一个可迭代对象中
    20             while(it.hasNext()){ // 利用迭代器模式进行迭代
    21                 String key=it.next(); // 读取下一个迭代对象的下一个元素
    22                 System.out.println(key+":"+prop.getProperty(key)); // 根据key值获取value值(获取属性信息)
    23             }
    24             
    25             is.close(); // 关闭输入流,释放资源
    26             
    27             FileOutputStream oFile = new FileOutputStream("b.properties", true);//创建一个输出流文件,true表示追加打开
    28             prop.setProperty("maxactive", "33"); // 修改属性信息
    29             prop.store(oFile, "zhe shi yi ge xin de shu xing pei zhi wen jian."); // 将Properties对象中的内容放到刚刚创建的文件中去
    30             oFile.close(); // 关闭输出流,释放资源
    31             
    32         } catch (Exception e) {
    33             // TODO Auto-generated catch block
    34             e.printStackTrace();
    35         } 
    36     }
    37 }
    读取属性配置文件信息

        等待读取的properties配置文件的位置如下图所示

          

    5 数据库连接池

      5.1 什么是数据库连接池

        程序启动时就创建足够多的数据库连接,并将这些连接组成一个连接池,由程序自动地对池中的连接进行申请、使用、释放

      5.2 数据库连接池的运行机制

        》程序初始化时创建连接池

        》需要操作数据库时向数据库连接池申请一个可用的数据库连接

        》使用完毕后就将数据库连接还给数据库连接池(注意:不是关闭连接,而是交给连接池)

        》整个程序退出时,断开所有连接,释放资源(即:管理数据库连接池的那个线程被杀死后才关闭所有的连接)

         

      5.3 数据库连接池的编程步骤

        5.3.1 导包

          

        5.3.2 声明ThreadLocal、BasicDataSource成员变量(注意:这两个成员变量是静态的)

          

        5.3.3 在静态代码块中实例化那两个成员变量,并通过Properties对象读取配置文件信息,利用这些配置文件信息给BasicDataSource对象进行初始化处理

      

        5.3.4 编写创建连接静态方法

          利用BasicDataSource对象实例化一个连接对象

          将这个连接对象放到ThreadLocal对象中

          

        5.3.5 编写释放连接静态方法

          从ThreadLocal对象中获取连接对象

          清空ThreadLocal对象

          判断连接对象是否释放

          

    6 利用数据库连接池操作数据库

      项目结构图

        

    1 # zhe shi zhu shi , yi ban bu yong zhong wen 
    2 # deng hao liang bian mei you kong ge, mo wei mei you fen hao
    3 # hou mian bu neng you kong ge
    4 driverClassName=com.mysql.jdbc.Driver
    5 url=jdbc:mysql://localhost:3306/test
    6 username=root
    7 password=182838
    8 maxActive=100
    9 maxWait=3000
    properties配置文件
     1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     2   <modelVersion>4.0.0</modelVersion>
     3   <groupId>cn.xiangxu</groupId>
     4   <artifactId>testJDBC</artifactId>
     5   <version>0.0.1-SNAPSHOT</version>
     6   <dependencies>
     7       <dependency>
     8           <groupId>mysql</groupId>
     9           <artifactId>mysql-connector-java</artifactId>
    10           <version>5.1.37</version>
    11       </dependency>
    12       <dependency>
    13           <groupId>junit</groupId>
    14           <artifactId>junit</artifactId>
    15           <version>4.12</version>
    16       </dependency>
    17       <dependency>
    18           <groupId>commons-dbcp</groupId>
    19           <artifactId>commons-dbcp</artifactId>
    20           <version>1.4</version>
    21       </dependency>
    22   </dependencies>
    23 </project>
    maven依赖文件
     1 package cn.xiangxu.tools;
     2 
     3 import java.io.IOException;
     4 import java.io.InputStream;
     5 import java.sql.Connection;
     6 import java.sql.SQLException;
     7 import java.util.Properties;
     8 
     9 import org.apache.commons.dbcp.BasicDataSource;
    10 
    11 public class DBUtil {
    12     /*
    13      * ThreadLocal用于线程跨方法共享数据使用
    14      * ThreadLocal内部有一个Map,  key为需要共享数据的线程本身,value就是其需要共享的数据
    15      */
    16     private static ThreadLocal<Connection> tl; // 声明一个类似于仓库的东西
    17     private static BasicDataSource dataSource; // 声明一个数据库连接池对象
    18     
    19     // 静态代码块,在类加载的时候执行,而且只执行一次
    20     static {
    21         tl = new ThreadLocal<Connection>(); // 实例化仓库对象
    22         dataSource = new BasicDataSource(); // 实例数据库连接池对象
    23 
    24         Properties prop = new Properties(); // 创建一个Properties对象用(该对象可以用来加载配置文件中的属性列表)
    25         InputStream is = DBUtil.class.getClassLoader().getResourceAsStream("config/mysql.properties"); // 读取配置文件信息
    26         try {
    27             prop.load(is); // 加载配置文件中的属性列表
    28             
    29             String driverClassName = prop.getProperty("driverClassName"); // 获取属性信息
    30             String url = prop.getProperty("url");
    31             String username = prop.getProperty("username");
    32             String password = prop.getProperty("password");
    33             Integer maxActive = Integer.parseInt(prop.getProperty("maxActive"));
    34             Integer maxWait = Integer.parseInt(prop.getProperty("maxWait"));
    35             
    36             dataSource.setDriverClassName(driverClassName); // 初始化数据库连接池(即:配置数据库连接池的先关参数)
    37             dataSource.setUrl(url);
    38             dataSource.setUsername(username);
    39             dataSource.setPassword(password);
    40             dataSource.setMaxActive(maxActive);
    41             dataSource.setMaxWait(maxWait);
    42             
    43             is.close(); // 关闭输入流,释放资源
    44         } catch (IOException e) {
    45             // TODO Auto-generated catch block
    46             e.printStackTrace();
    47         } 
    48         
    49     }
    50     
    51     /**
    52      * 创建连接对象(注意:静态方法可以直接通过类名来调用)
    53      * @return 连接对象
    54      * @throws Exception
    55      */
    56     public static Connection getConnection() throws Exception { 
    57         try {
    58             Connection conn = dataSource.getConnection(); // 创建连接对象(利用数据库连接池进行创建)
    59             tl.set(conn); // 将连接对象放到仓库中
    60             return conn; 
    61         } catch (Exception e) {
    62             // TODO Auto-generated catch block
    63             e.printStackTrace();
    64             throw e;
    65         }
    66     }
    67     
    68     /**
    69      * 关闭连接对象(注意:静态方法可以通过类名直接调用)
    70      * @throws Exception
    71      */
    72     public static void closeConnection() throws Exception {
    73         Connection conn = tl.get(); // 从仓库中取出连接对象
    74         tl.remove(); // 清空仓库
    75         if(conn != null) { // 判断连接对象是否释放资源
    76             try {
    77                 conn.close();
    78             } catch (Exception e) {
    79                 // TODO Auto-generated catch block
    80                 e.printStackTrace();
    81                 throw e;
    82             }
    83         }
    84     }
    85 
    86 }
    数据库连接池类
     1 package testJDBC;
     2 
     3 import java.sql.Connection;
     4 import java.sql.PreparedStatement;
     5 import java.sql.ResultSet;
     6 
     7 import org.junit.Test;
     8 
     9 import cn.xiangxu.tools.DBUtil;
    10 
    11 public class TestDBUtil {
    12     @Test
    13     public void test01() {
    14         try {
    15             Connection conn = DBUtil.getConnection(); // 创建连接对象
    16             String sql = "SELECT * FROM user "; // 拼接SQL语句
    17             PreparedStatement ps = conn.prepareStatement(sql); // 创建执行对象
    18             ResultSet rs = ps.executeQuery(sql); // 执行SQL语句
    19             while(rs.next()) { // 遍历结果集
    20                 System.out.println(rs.getString("name"));
    21             }
    22         } catch (Exception e) {
    23             e.printStackTrace();
    24         } finally {  // 关闭连接,释放资源
    25             try {
    26                 DBUtil.closeConnection();
    27             } catch (Exception e) {
    28                 e.printStackTrace();
    29             }
    30         }
    31     }
    32 }
    数据库连接池的应用

      

  • 相关阅读:
    ios数据处理 简单文件处理
    ios硬件开发 照相机图像选取器(UIImagePickerController)的用法
    ios UI设计与开发 卷动视图
    ios数据处理 使用SQLite保存学生信息
    ios数据处理 Application preferfences
    ios数据处理 SQLite基本知识
    GDI+ 为了阴影和透明,使用双层窗口遇到的一些问题
    MFC CToolTipCtrl 总是显示
    遍历删除文件夹及文件
    WebService远程调试
  • 原文地址:https://www.cnblogs.com/NeverCtrl-C/p/7132006.html
Copyright © 2020-2023  润新知