目录
2 使用Statement执行SQL语句不好的原因
发送到数据库时,数据库先将该SQL解析并生成一个执行计划(这个过程会消耗资源和性能),如果多次执行一样的SQL语句,数据库会重用执行计划,但是若多次执行语义相同但是含有动态数据的SQL时,数据库会生成不同的执行计划,严重影响数据库的开销
  2.2 例如" >  2.1 当执行一条SQL语句发送到数据库时,数据库先将该SQL解析并生成一个执行计划(这个过程会消耗资源和性能),如果多次执行一样的SQL语句,数据库会重用执行计划,但是若多次执行语义相同但是含有动态数据的SQL时,数据库会生成不同的执行计划,严重影响数据库的开销
  2.2 例如
3 利用PreparedStatement代替Statement
  没有SQL注入问题" >  没有SQL注入问题
  批量执行语义相同的SQL语句会重用执行计划" >  批量执行语义相同的SQL语句会重用执行计划
利用Properties对象读取properties配置文件中的信息" >4 利用Properties对象读取properties配置文件中的信息
  4.1 Properties继承了Hashtable类,Properties对象也是使用键值对的方式来保存数据,但是Properties对象的键和值都是字符串类型
  4.2 Properties 类中的主要方法
load(InputStream inStream) throws IOException" >    4.2.1 public synchronized void load(InputStream inStream) throws IOException
     4.2.4 public synchronized Object setProperty(String key, String value)
  4.3 案例
5 数据库连接池
  5.1 什么是数据库连接池
  5.2 数据库连接池的运行机制
  5.3 数据库连接池的编程步骤
    5.3.1 导包
声明ThreadLocal、BasicDataSource成员变量(注意:这两个成员变量是静态的)" >    5.3.2 声明ThreadLocal、BasicDataSource成员变量(注意:这两个成员变量是静态的)
实例化那两个成员变量,并通过Properties对象读取配置文件信息,利用这些配置文件信息给BasicDataSource对象进行初始化处理" >    5.3.3 在静态代码块中实例化那两个成员变量,并通过Properties对象读取配置文件信息,利用这些配置文件信息给BasicDataSource对象进行初始化处理
    5.3.4 编写创建连接静态方法
    5.3.5 编写释放连接静态方法
6 利用数据库连接池操作数据库
首页 Java java教程 JDBC连接数据库实例讲解

JDBC连接数据库实例讲解

Jul 21, 2017 pm 03:36 PM
jdbc 数据库

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 stub15     }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     @Override23     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     @Override30     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     @Override64     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     @Test17     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 block61             e.printStackTrace();62         } finally {63             if(rs != null) {64                 try {65                     rs.close();66                 } catch (SQLException e) {67                     // TODO Auto-generated catch block68                     e.printStackTrace();69                 }70             }71             if(ps != null) {72                 try {73                     ps.close();74                 } catch (SQLException e) {75                     // TODO Auto-generated catch block76                     e.printStackTrace();77                 }78             }79             if(conn != null) {80                 try {81                     conn.close();82                 } catch (SQLException e) {83                     // TODO Auto-generated catch block84                     e.printStackTrace();85                 }86             }87         }88         89     }90     91 }
登录后复制
使用预编译Statement的实例

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

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

    class Properties extends Hashtable

  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 block34             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 hao3 # hou mian bu neng you kong ge4 driverClassName=com.mysql.jdbc.Driver5 url=jdbc:mysql://localhost:3306/test6 username=root7 password=1828388 maxActive=1009 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 "> 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 block46             e.printStackTrace();47         } 
48         49     }50     51     
/**52      
* 创建连接对象(注意:静态方法可以直接通过类名来调用)53      * @return 连接对象54      * @throws Exception55      */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 block63             
e.printStackTrace();64             throw e;65         }66     }67     68     /**69      * 关闭连接对象(注意:静态方法可以通过类名直接调用)70      * @throws Exception71      */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 block80                 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     
 @Test13     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 }
登录后复制
数据库连接池的应用

以上是JDBC连接数据库实例讲解的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

Go语言如何实现数据库的增删改查操作? Go语言如何实现数据库的增删改查操作? Mar 27, 2024 pm 09:39 PM

Go语言是一种高效、简洁且易于学习的编程语言,因其在并发编程和网络编程方面的优势而备受开发者青睐。在实际开发中,数据库操作是不可或缺的一部分,本文将介绍如何使用Go语言实现数据库的增删改查操作。在Go语言中,我们通常使用第三方库来操作数据库,比如常用的sql包、gorm等。这里以sql包为例介绍如何实现数据库的增删改查操作。假设我们使用的是MySQL数据库。

iOS 18 新增'已恢复”相册功能 可找回丢失或损坏的照片 iOS 18 新增'已恢复”相册功能 可找回丢失或损坏的照片 Jul 18, 2024 am 05:48 AM

苹果公司最新发布的iOS18、iPadOS18以及macOSSequoia系统为Photos应用增添了一项重要功能,旨在帮助用户轻松恢复因各种原因丢失或损坏的照片和视频。这项新功能在Photos应用的"工具"部分引入了一个名为"已恢复"的相册,当用户设备中存在未纳入其照片库的图片或视频时,该相册将自动显示。"已恢复"相册的出现为因数据库损坏、相机应用未正确保存至照片库或第三方应用管理照片库时照片和视频丢失提供了解决方案。用户只需简单几步

Hibernate 如何实现多态映射? Hibernate 如何实现多态映射? Apr 17, 2024 pm 12:09 PM

Hibernate多态映射可映射继承类到数据库,提供以下映射类型:joined-subclass:为子类创建单独表,包含父类所有列。table-per-class:为子类创建单独表,仅包含子类特有列。union-subclass:类似joined-subclass,但父类表联合所有子类列。

在PHP中使用MySQLi建立数据库连接的详尽教程 在PHP中使用MySQLi建立数据库连接的详尽教程 Jun 04, 2024 pm 01:42 PM

如何在PHP中使用MySQLi建立数据库连接:包含MySQLi扩展(require_once)创建连接函数(functionconnect_to_db)调用连接函数($conn=connect_to_db())执行查询($result=$conn->query())关闭连接($conn->close())

深入解析HTML如何读取数据库 深入解析HTML如何读取数据库 Apr 09, 2024 pm 12:36 PM

HTML无法直接读取数据库,但可以通过JavaScript和AJAX实现。其步骤包括建立数据库连接、发送查询、处理响应和更新页面。本文提供了利用JavaScript、AJAX和PHP来从MySQL数据库读取数据的实战示例,展示了如何在HTML页面中动态显示查询结果。该示例使用XMLHttpRequest建立数据库连接,发送查询并处理响应,从而将数据填充到页面元素中,实现了HTML读取数据库的功能。

如何在PHP中处理数据库连接错误 如何在PHP中处理数据库连接错误 Jun 05, 2024 pm 02:16 PM

PHP中处理数据库连接报错,可以使用以下步骤:使用mysqli_connect_errno()获取错误代码。使用mysqli_connect_error()获取错误消息。通过捕获并记录这些错误信息,可以轻松识别并解决数据库连接问题,确保应用程序的顺畅运行。

如何用 Golang 连接远程数据库? 如何用 Golang 连接远程数据库? Jun 01, 2024 pm 08:31 PM

通过Go标准库database/sql包,可以连接到MySQL、PostgreSQL或SQLite等远程数据库:创建包含数据库连接信息的连接字符串。使用sql.Open()函数打开数据库连接。执行SQL查询和插入操作等数据库操作。使用defer关闭数据库连接以释放资源。

如何在 Golang 中使用数据库回调函数? 如何在 Golang 中使用数据库回调函数? Jun 03, 2024 pm 02:20 PM

在Golang中使用数据库回调函数可以实现:在指定数据库操作完成后执行自定义代码。通过单独的函数添加自定义行为,无需编写额外代码。回调函数可用于插入、更新、删除和查询操作。必须使用sql.Exec、sql.QueryRow或sql.Query函数才能使用回调函数。

See all articles