Web基础-JavaWeb:MySQL+JDBC+DBCP入门

说是Web基础,其实JDBC并不是专在Web开发中用的
只是因为我现在的主要语言已经从Java转Python了,只有Web开发中会用到JDBC
所以就把这篇扔到Web基础里了

什么是JDBC

全称:Java DataBase Connectivity,顾名思义即Java数据库连接
它是由SUN公司制定的一个与访问数据库有关的API规范,该规范规定了JDBC的使用者(Java、Applet、Servlet等不同类型的程序)如何以统一标准使用JDBC驱动程序与数据库交互。

如何连接MySQL

首先需要一个jar包
MySQL 8.0以下版本
MySQL 8.0 及以上版本

然后把jar包导入到工程中
Eclipse导入外部jar包

一个简单示例

import java.sql.*;
//第一步:导入所需要的包

public class MyJDBC {
    static final String JDBC_DRIVER="com.mysql.jdbc.Driver";
    //JDBC驱动名,不用改
    static final String DB_URL="jdbc:mysql://localhost:3306/YourDatabaseName;
    //数据库url
    static final String USER="username";
    static final String PSWD="pswd";
    //你的数据库用户名及密码
    
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
        Class.forName(JDBC_DRIVER);
        //第二步:注册JDBC驱动程序
        
        Connection conn=DriverManager.getConnection(DB_URL,USER,PSWD);
        //第三步:建立与数据库的连接
        //使用DriverManager的getConnection方法创建一个Connection对象conn
        
        Statement stmt1=conn.createStatement();
        Statement stmt2=conn.createStatement();
        //第四步:创建Statement对象用于执行SQL语句
        
        /*使用createStatement方法可以创建基本的Statement对象
        *此外还可以使用prepareStatent(String sql)创建预编译Statement对象
        *使用prepareCall(String sql)创建CallableStatement对象
        */
        
        //一个Connection对象可以创建多个Statement对象
        
        ResultSet rs1=stmt1.executeQuery("SELECT * FROM emailuserpass");
        ResultSet rs2=stmt2.executeQuery("SELECT password FROM emailuserpass");
        // 第五步:执行SQL语句,使用executeQuery方法时返回一个ResultSet(结果集)对象
        
        /*所有的Statement对象都有三个方法执行SQL语句
         * 1.execute:可以执行任何SQL语句,但比较麻烦
         * 2.executeUpdate:主要用于执行DML和DDL (INSERT DELETE UPDATE)
         * 3.executeQuery:只能查询(SELECT),执行后返回一个ResultSet对象
         * */
        
        while(rs1.next()) {            
            System.out.println("stmt1:"+rs1.getString("emailAddress")+rs1.getString("userName"));        
        }      
        while(rs2.next()) {            
            //第六步:操作结果集(如果有)
            //使用next()方法判断是否有下一条记录,初始时指针位于所有记录之前
            System.out.println("stmt2:"+rs2.getString("password"));
            //使用getType("ColumnName")方法获取本结果集某条记录的某列名对应的值
        }
        
        
        if(rs1!=null) {
            rs1.close();
        }
        if(stmt1!=null) {
            stmt1.close();
        }
        if(rs2!=null) {
            rs2.close();
        }
        if(stmt2!=null) {
            stmt2.close();
        }
        if(conn!=null) {
            conn.close();
        }
        //第七步:关闭资源
    }
}

一些说明

  1. 因为是一个简单示例,所以我写的主方法没有对异常进行处理,直接使用了throws,实际开发中不要这样!
  2. SQL语言分类(DQL、DML、DDL、DCL)
  3. 最好使用预编译SQL语句,防止SQL注入

预编译语句的使用

package jdbc_test;

import java.sql.*;
// 第一步:导入包
public class PreparedStatement {
    static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
    //JDBC驱动名,不用改
    static final String DB_URL = "";
    //数据库url
    static final String USER = "";
    static final String PSWD = "";
    //你的数据库用户名及密码
    public static void main(String[] args) {
        try {
            Class.forName(JDBC_DRIVER);
            // 第二步:注册驱动
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        String PreparedSQL = "SELECT * FROM emailuserpass WHERE userName = ?"; 
        // 注意:问号就表示SQL语句中的参数,如果是String型不需再加引号!
        String UpdateSQL = "UPDATE emailuserpass SET password = ? WHERE userName = ?";
        // 一条UPDATE语句
        
        Connection conn = null;
        java.sql.PreparedStatement ps = null;
        java.sql.PreparedStatement us = null;
        ResultSet rs = null;
        
        String parameter = "abc";
        String NewPassword = "123";
        int EffectedRows = 0;
        // 查询用户名为parameter的整条记录,然后将其密码改为123
        try {
            conn = DriverManager.getConnection(DB_URL, USER, PSWD);
            //第三步:获得连接
            
            ps = conn.prepareStatement(PreparedSQL);
            us = conn.prepareStatement(UpdateSQL);
            //第四步:创建预编译statement对象
            
            ps.setString(1, parameter);
            us.setString(1, NewPassword);
            us.setString(2, parameter);
            //第五步:将预编译statement对象ps的问号处的值替换为不同参数
            
            rs = ps.executeQuery();
            //第六步:接收返回的结果集对象
            EffectedRows = us.executeUpdate();
            if (rs.next()) {
                System.out.println(parameter + "处的记录: " + rs.getString("emailAddress") + rs.getString("password"));
                //第七步:对结果集进行数据提取
            }
            else {
                System.out.println("username" + parameter + "not found");
            }
            if (EffectedRows != 0) {
                System.out.println(parameter + "密码已更新为" + NewPassword);
            }
            else {
                System.out.println("can not update password");
            }
        } catch (SQLException se) {
            se.printStackTrace();
        }
        finally {
            if (rs!=null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (us != null) {
                try {
                    us.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}

程序执行前用户名为abc的一条记录:
在这里插入图片描述程序运行结果:
在这里插入图片描述
程序运行后查看数据库:
在这里插入图片描述UPDATE操作执行成功

数据库连接池DBCP (DataBase Connection Pool)

JDBC的缺点
上述使用JDBC驱动程序访问数据库虽然简单易用,但存在许多问题

  1. 每次Web请求都要建立数据库连接,费时费力,对大网站来说是致命缺陷
  2. 每个数据库连接使用完都要断开,否则可能导致数据库系统内存泄露
  3. 不能控制被创建的连接数,容易遭受攻击

DBCP的基本思想

  1. 为数据库连接建立一个缓冲池,在系统初始化时预先创建并向其中放入一定数量的连接,这些连接不能被随意关闭
  2. 当需要建立数据库连接时,只需在缓冲池中取出一个,使用完毕后放回缓冲池,这样就节省了创建和关闭连接的时间

连接池的三部分 (建立、管理、关闭)

建立:系统初始化时根据相应的配置文件建立连接并放入池中

管理:

客户端请求数据库连接
if (连接池有空闲连接){
	将一个空闲连接分配给客户端
	此连接标记为正在使用
}
else if (连接数 < 最大连接数maxConn){
	创建一个新连接分配给客户端
	此连接标记为正在使用
	连接数 += 1
}
else{
	for(int i = 0, i < maxWaitTime;i++){
		if (有占用的连接被释放){
			将被释放的连接分配给正在等待的客户端
			break
		}
		else{
			等待
		}
		if (i == maxWaitTime-1){
			throw Exceptioin:无空闲连接
		}
	}
}
客户端使用连接
客户端释放连接
if (该连接引用次数 >= 规定值){
	删除该连接
	if (当前池内连接数 < 最小连接数minConn){
		将连接池充满
	}
}
else{
	此连接标记为可再分配
}

关闭:应用程序退出时关闭连接池,把向数据库申请的连接对象归还,即关闭所有数据库连接

DBCP配置
可以在tomcat下配置全局的,不过不建议,最好一工程一配
第一步:
根据自己的Java版本下载所需的jar包
commons-dbcp
commons-logging
commons-pool
然后放到 工程名/WebContent/WEB-INF/lib/

第二步:
工程名/WebContent/META-INF/ 下新建context.xml

一定要注意不要写成content.xml…

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xml>
<Context>
    <Resource 
    name="jdbc/myDataSource" 
    auth="Container"
    type="javax.sql.DataSource" 
    factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 
    maxActive="100" 
    maxIdle="30" 
    maxWait="10000" 
    username="" 
    password="" 
    driverClassName="com.mysql.jdbc.Driver" 
    url="jdbc:mysql://localhost:3306/..." 
    />
</Context>

参数解析

name:JNDI资源名称,此处表示数据源名称
auth:连接池管理权属性,一般为容器Container
type:对象类型,此处声明为数据库连接池类型
factory:
maxActive:最大活动连接数,为0表示无限制
maxIdle:最大空闲连接数,为0表示无限制
maxWwait:最大等待时长,单位为ms
url:数据库路径
username:连接到数据库url的用户名
password:连接到数据库url的密码
driverClassName:数据库驱动名

第三步:
写一个用于创建、管理、关闭DBCP的类ConnectionPool.java

package dbcp;

import java.sql.*;
import javax.sql.DataSource; 
import javax.naming.InitialContext; 
import javax.naming.NamingException; 

public class ConnectionPool { 
    private static ConnectionPool pool = null; 
    private static DataSource dataSource = null; 
    private ConnectionPool() { 
        try { 
            InitialContext ic = new InitialContext(); 
            dataSource = (DataSource) ic.lookup ( "java:/comp/env/jdbc/myDataSource");

        } catch (NamingException e) { 
            System.out.println(e); 
        } 
    } 
    
    public static synchronized ConnectionPool getinstance() { 
        if (pool == null) { 
            pool = new ConnectionPool(); 
        } 
        return pool; 
    }
    
    public Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e){
            System.out.println (e);
            return null;
        }
    }
    
    public void freeConnection(Connection c) {
        try {
            c.close();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
}

第四步:
使用DBCP,以DBCPTest.jsp为例

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import = "javax.sql.DataSource" %>
<%@ page import = "javax.naming.*" %>
<%@ page import = "java.sql.*" %>

<%@ page import = "dbcp.ConnectionPool" %>
<!-- 导入写数据库连接池的类-->

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>数据库连接池测试</title>
</head>
<body>
    <%
    ConnectionPool pool = ConnectionPool.getinstance();
    // 获得所有的客户端共用的一个连接池
    Connection conn = pool.getConnection();
    // 获得一个连接
    // 下面和使用JDBC基本类似
    ResultSet rs = null;
    java.sql.PreparedStatement ps = null;
       
    ps = conn.prepareStatement("SELECT * FROM emailuserpass WHERE userName = ?");
    
    ps.setString(1,"abc");
    rs = ps.executeQuery();
    if (rs.next()){
        out.println(rs.getString("emailAddress"));
    }
    else {
        out.println("Null");
    }
    
    pool.freeConnection(conn);
    // 直接释放连接即可
    %>
</body>
</html>

保存,Run on server,访问此jsp测试一下,成功
在这里插入图片描述

DBCP使用总结:

发布了61 篇原创文章 · 获赞 11 · 访问量 4879

猜你喜欢

转载自blog.csdn.net/weixin_43249758/article/details/102906981