javaweb基础----JDBC、servlet(二)

一、连接数据库

在昨天的基础上,现在我想来实现前后端以及数据库的连接。

CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/135388510?spm=1001.2101.3001.4503在cn2包下创建2个类,一个登录界面login,还有一个实现登录过程的loginServlet。

login:

public class login {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入用户名");
        String username = sc.nextLine();
        System.out.println("请输入密码");
        String password = sc.nextLine();
        boolean flag = loginServlet.selectByUsAndPa(username, password);
        if (flag) {
            System.out.println("登录成功");
        } else {
            System.out.println("用户名或密码错误");
        }
    }
}

这个登录界面很简单,Scanner接收用户名密码,通过loginServlet中的静态方法selectByUsAndPa判断是否登录成功。

loginServlet:

public class loginServlet {
        public static boolean  selectByUsAndPa(String username,String password) {
            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection
                        ("jdbc:mysql:///mydb_21?user=root&password=********");
                stat = conn.createStatement();
                rs = stat.executeQuery("SELECT * FROM user2 WHERE username='"
                        + username + "' AND PASSWORD='" + password + "'");
                if (rs.next()) return true;
                else return false;
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException();
            } finally {
                if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    } finally {
                        conn = null;
                    }
                    if (stat != null) {
                        try {
                            stat.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        } finally {
                            stat = null;
                        }
                        if (rs != null) {
                            try {
                                rs.close();
                            } catch (SQLException e) {
                                e.printStackTrace();
                            } finally {
                                rs = null;
                            }
                        }
                    }

                }
            }
        }
}

先建立一个新的数据库user2:

CREATE TABLE user2 (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50),
PASSWORD VARCHAR(50)
);

整体格式与昨天所讲的基础别无二至,在查询的时候SQL语句用的是    SELECT * FROM user2 WHERE username = 'zs' AND PASSWORD = '123';

rs = stat.executeQuery("SELECT * FROM user2 WHERE username='"
        + username + "' AND PASSWORD='" + password + "'");

注意书写格式。

                if (rs.next()) return true;
                else return false;

 这段语句有个坑要注意!判断是否查询到,不能写rs != null    因为rs本质上是个地址,不管查没查到地址都不会是空而是个具体的地址值,所以不管输入什么最终都会得到查询成功的结果。因此这里要用游标,如果有数据就说明查到了该位置是要查询的结果。

       

二、连接池

在写代码的时候我意识到一个问题,我多次重复了一段相同的操作-----创建连接,关闭连接:

            Connection conn = null;
            Statement stat = null;
            ResultSet rs = null;

            conn.close();
            stat.close();
            rs.close();

频繁地这样操作,开关连接,会造成内存的不足。

类似List的扩容操作,如果容量一满就开辟一个新的空间,这样会造成系统资源的浪费,我们可以初始时开辟一定大小的空间,每次要扩容时再开辟一定大小,避免频繁扩容。

这里也是一样,为了避免频繁开关连接,初始时建立一个连接池,给其中分配一定数量的连接,当连接池中连接都用完再扩充连接池,避免多次扩充造成浪费。

首先建立内存池,存放链接。用List集合存放,并初始化5个链接放入连接池。

public class MyPool implements DataSource {
    //存放链接
    private static List<Connection> list = new ArrayList<>();
    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            //初始化5个连接
            for (int i = 0; i < 5; i++) {
                Properties info = new Properties();
                info.setProperty("user","root");
                info.setProperty("password","1194006164qwer");
                Connection conn = DriverManager.getConnection("jdbc:mysql:///",info);
                list.add(conn);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

因为MyPool类继承的是DataSource这个父类,因此需要在MyPool中实现父类的所有方法。

DataSource 是自 JDK 1.4 提供的一个标准接口,用于获取访问物理数据库的 Connection 对象。

 但是并不是DataSource中所有的继承方法都需要实现,实现需要的几个就可以了:

主要实现这2个方法:getConnection() , returnConncetion

    public Connection getConnection() throws SQLException {
        if(list.size() <= 0){
            for (int i = 0; i < 3; i++) {
                Connection conn = DriverManager.getConnection
                        ("jdbc:mysql:///mydb_21?user=root&password=********");
                list.add(conn);
            }
        }
        return list.remove(0);
    }

    public void returnConnection(Connection conn) {
        if(conn != null) list.add(conn);
    }

当连接池中没有链接时,也就是list.size() <= 0 ,往连接池中放入3个链接。

如果连接池中有链接,直接return返回,使外部拿到这个链接,注意返回类型,是Connection类型。要用remove方法,而不能用get方法。因为get(0)是一直返回第0个链接,而remove(0)会返回后将该位置的链接删除,后一个链接移动到该位置,如此便可return所有链接。

连接池的创建和获取链接、归还链接写完后,我们写个测试类来测试一下连接池的功能:

public class test01 {
    public static MyPool myPool = new MyPool();
    public void test01(){
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = myPool.getConnection();
            ps.executeQuery("select* from user2 where id < ?");
            ps.setString(1,"3");
            rs = ps.executeQuery();
            while (rs.next()){
                String name = rs.getString("username");
                System.out.println(name);
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            myPool.returnConnection(conn);
        }
    }
}

1、创建MyPool对象,执行getConnection方法获取连接池中的链接。

2、用SQL查询语句将查询结果放入rs对象中,通过游标得到打印出来。

这里用的是PreparedStatement类型的对象,有别于Statement:

Statement每次执行sql语句,数据库都要执行sql语句的编译,最好用于仅执行一次查询并返回结果的情形,效率高于PreparedStatement。但存在sql注入风险

PreparedStatement是预编译执行的。在执行可变参数的一条SQL时,PreparedStatement要比Statement的效率高,因为DBMS预编译一条SQL当然会比多次编译一条SQL的效率高。安全性更好,有效防止SQL注入的问题。对于多次重复执行的语句,使用PreparedStatement效率会更高一点。执行SQL语句是可以带参数的,并支持批量执行SQL。
总的来说,Statement是适合一条语句查询,存在SQL注入风险;PreparedStatement适合可变参数的SQL语句和多次重复执行的SQL语句,能有效防止SQL注入问题。

在实际项目中我们不需要自己实现连接池,可以采用现成的连接池 (如cp30连接池)。

import com.mchange.v2.c3p0.ComboPooledDataSource;

import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class Test02 {
    //c3p0连接池
    private static ComboPooledDataSource source=new ComboPooledDataSource();

    public static void main(String[] args) {
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;

        try {
            conn=source.getConnection();
            ps=conn.prepareStatement("select * from user2 where id<?");
            ps.setInt(1,3);
            rs=ps.executeQuery();
            while (rs.next()){
                String username = rs.getString("username");
                System.out.println(username);
            }
        } catch (Exception throwables) {
            throwables.printStackTrace();
        }finally {
            if(conn!=null){
                source.close();
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/308128.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CST—EMC(电磁兼容)仿真及分析工具

背景概述 随着汽车电子的发展特别是新能源互联网汽车的兴起&#xff0c;整车的EMC环境越来越恶劣&#xff0c;传统的EMC设计面临着设计阶段盲目性强、调试测试阶段工作量大、整改阶段重复性高等诸多挑战&#xff0c;需要通过EMC仿真来解决上述问题。EMC仿真贯穿产品开发全周期&…

40-特殊运算符delete,new,.getDate,.setDate,运算符优先级

1.delete删除. 数组 // 可以删除数组元素&#xff0c;可以删除对象键值对// 删除数组的值&#xff0c;数组长度保持不变// 删掉的值变成emptyvar arr [1,2,3,4,5];delete arr[0];console.log(arr); 对象 var obj {"a":"aa","b":"bb&quo…

Xcalibur软件Qual Brower程序的使用

找到Qual Brower&#xff1a;在System>Program里 打开采集的数据文件*.RAW&#xff0c;软件界面主窗口能查看色谱图和质谱图&#xff1a; 1、图形的放大和拷贝、色谱中查看峰的质谱信息&#xff1a; 点亮如图图像右上角的按钮&#xff0c;可以激活该图形并进行操作&#x…

AI Agent落地先行者实在智能:2023人工智能领军者、百强、TOP30揭榜

实在智能连登三榜&#xff01; 【2023年十佳人工智能行业领军人物】 【2023年度人工智能领域创新企业】 【2023年度最具投资价值企业】 喜大普奔&#xff01;近期&#xff0c;国内科技行业颇具含金量的三张榜单接连发布&#xff0c;实在智能皆榜上有名&#xff0c;“2023「…

WPF真入门教程26--项目案例--欧姆龙PLC通讯工具

1、案例介绍 前面已经完成了25篇的文章介绍&#xff0c;概括起来就是从0开始&#xff0c;一步步熟悉了wpf的概念&#xff0c;UI布局控件&#xff0c;资源样式文件的使用&#xff0c;MVVM模式介绍&#xff0c;命令Command等内容&#xff0c;这节来完成一个实际的项目开发&#…

C++类和对象(万字超详细讲解!!!)

文章目录 前言1.面向过程和面向对象区别2.类的基本概念2.1 类的引入2.2 类的定义2.3 类成员变量的命名规则2.4 类的访问限定符2.5 类的封装2.6 类的作用域2.7 类的实例化 3.类对象模型3.1 如何计算类对象的大小3.2 对齐规则 4.this指针4.1 this指针的引出4.2 this指针的特性4.3…

Python - 深夜数据结构与算法之 Two-Ended BFS

目录 一.引言 二.双向 BFS 简介 1.双向遍历示例 2.搜索模版回顾 三.经典算法实战 1.Word-Ladder [127] 2.Min-Gen-Mutation [433] 四.总结 一.引言 DFS、BFS 是常见的初级搜索方式&#xff0c;为了提高搜索效率&#xff0c;衍生了剪枝、双向 BFS 以及 A* 即启发式搜索…

动手学深度学习-卷积神经网络

卷积神经网络 在前面的章节中&#xff0c;我们遇到过图像数据。这种数据的每个样本都由一个二维像素网格组成&#xff0c;每个像素可能是一个或者多个数值&#xff0c;取决于是黑白还是彩色图像。到目前为止&#xff0c;我们处理这类结构丰富的数据方式还不够有效。我们仅仅通…

【web缓存】nginx和CDN应用

目录 一、代理的工作机制 二、代理服务器的概念 三、代理服务器的作用 四、常用的代理服务器 五、nginx缓存代理部署 步骤一&#xff1a;首先脚本完成三台nginx的部署 步骤二&#xff1a;在两个后端原始服务器上分别创建测试页面 步骤三&#xff1a;完成nginx缓存服务器…

RedisTemplate详解

一、SpringDataRedis简单介绍及引入 SpringData是Spring中数据操作的模块&#xff0c;包括对各种数据库的集成&#xff0c;其中对Redis的集成模块就叫SpringDataRedis 官网地址&#xff1a;https://spring.io/projects/spring-data-redis 1.1 特点&#xff1a; 提供了对不同…

观成科技-加密C2框架EvilOSX流量分析

工具简介 EvilOSX是一款开源的&#xff0c;由python编写专门为macOS系统设计的C2工具&#xff0c;该工具可以利用自身释放的木马来实现一系列集成功能&#xff0c;如键盘记录、文件捕获、浏览器历史记录爬取、截屏等。EvilOSX主要使用HTTP协议进行通信&#xff0c;通信内容为特…

公司新来的同事给出了if-else优化的8种方案

我们日常开发的项目中&#xff0c;如果代码中存在大量的if-else语句&#xff0c;阅读起来非常的折磨&#xff08;直接劝退&#xff09;&#xff0c;维护起来也很难&#xff0c;也特别容易出问题。比如说以下&#xff1a; 接下来&#xff0c;本文介绍我们常使用的8种方法去优化…

xinput1_4.dll缺失了怎么办?快速修复xinput1_4.dll文件的方法指南

在快速发展的数字时代&#xff0c;电子设备尤其是电脑成为了我们生活工作中必不可少的工具。然而&#xff0c;在使用过程中&#xff0c;我们可能会遇到各式各样的技术问题&#xff0c;其中一个常见问题是系统提示缺少 xinput1_4.dll文件。这个错误通常会在你尝试运行一个游戏或…

EF Core 在实际开发中,如何分层?

前言&#xff1a;什么是分层&#xff1f; 分层就是将 EF Core 放在单独的项目中&#xff0c;其它项目如 Asp.net core webapi 项目引用它这样的好处是解耦和项目职责的清晰划分&#xff0c;并且可以重用 EF Core 项目但是也会数据库迁移变得复杂起来 Step by step 步骤 创建一…

linux 安装 reids并使用Windows测试结果

要安装两个软件 Windows端安装下面的软件连接虚拟机中的redis Another Redis DeskTop Manager 安装和使用_another redis desktop怎么连接-CSDN博客 redis安装 查找可用版本 选择安装最多点赞的一个 安装完成后创建redis容器 docker run -t --name redis -p 6379:6379 -d r…

这6个设计小白学习网站,海量免费学习教程!

划到最后“阅读原文”——领取工具包&#xff08;超过1000工具&#xff0c;免费素材网站分享和行业报告&#xff09; Hi&#xff0c;我是胡猛夫~&#xff0c;专注于分享各类价值网站、高效工具&#xff01; ​更多资源&#xff0c;更多内容&#xff0c;欢迎交流&#xff01;公…

3d模型显示不出来?3d不显示全模型---模大狮模型网

如果3D模型在显示时不完整或者无法显示&#xff0c;可能有几个原因导致&#xff1a; 缩放问题&#xff1a;检查一下模型的缩放是否正确。有时候模型的缩放比例可能非常大或非常小&#xff0c;导致模型无法正确显示。尝试调整模型的缩放值&#xff0c;使其适合场景。 材质问题&…

主食冻干哪款好?十大放心主食冻干名单推荐

作为养猫的人&#xff0c;我们都知道每天最担心的事情就是如何为心爱的猫咪选择一款高品质的猫粮。我们都希望为猫咪提供最好的营养&#xff0c;让它们健康快乐地成长。然而&#xff0c;近期的一些事件&#xff0c;如百利猫粮生虫和VE主食冻干掰开有虫&#xff0c;让我们不得不…

Django的数据库模型的CharField字段的max_length参数与中文字符数的关系探索(参数max_length的单位是字符个数还是字节数?)

01-清理干净之前的数据库迁移信息 02-根据setting.py中的信息删除掉之前建立的数据库 03-删除之后重新创建数据库 04-models.py中创建数据库模型 from django.db import modelsclass User(models.Model):username models.CharField(max_length4)email models.EmailField(uni…