javaWeb-day04-JDBC(二)

查询account 表中内容
package jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
/**
 * 查询jt_db库中account表中的所有记录
 */
public class test1 {
    public static void main(String[] args) throws Exception {
        //1.注册数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2.获取数据库连接
        Connection conn = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8",
                "root", "root");
        //3.获取传输器
        Statement stat = conn.createStatement();
        //4.基于传输器发送SQL语句到服务器执行,返回执行结果
        String sql = "select * from account";
        ResultSet rs = stat.executeQuery(sql);
        //5.处理结果(打印到控制台)
        while( rs.next() ) {
            int id = rs.getInt( "id" );
            String name = rs.getString( "name" );
            double money = rs.getDouble( "money" );
            System.out.println( id+","+name+","+money );
        }
        //6.释放资源
        rs.close();
        stat.close();
        conn.close();
    }
}
进行异常处理后的代码
package jdbc;
import java.io.Closeable;
import java.sql.*;
import java.util.Arrays;
/**
 * 查询jt_db库中account表中的所有记录
 */
public class TestJdbc02 {
    public static void main(String[] args) {
        //将变量的声明提升到main函数的最上面
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //1.注册数据库驱动
            Class.forName("com.mysql.jdbc.Driver");
            //2.获取数据库连接
            conn = DriverManager.getConnection(
                    "jdbc:mysql:///jt_db?characterEncoding=utf-8",
                    "root", "root");
            //3.获取传输器
            stat = conn.createStatement();
            //4.基于传输器发送SQL语句到服务器执行,返回执行结果
            String sql = "select * from account";
            rs = stat.executeQuery(sql);

            //5.处理结果(打印到控制台)
            while( rs.next() ) {
                int id = rs.getInt( "id" );
                String name = rs.getString( "name" );
                double money = rs.getDouble( "money" );
                System.out.println( id+","+name+","+money );
            }
        } catch (Exception e) {
            System.out.println( "查询失败!" );
            e.printStackTrace();
        } finally { //finally中的代码一定会执行!
            //6.释放资源
            if( rs != null ) { //反之,如果rs为null,直接跳过,不需要关闭!
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    rs = null;
                }
            }
            if( stat != null ) {
                try {
                    stat.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    stat = null;
                }
            }
            if( conn != null ) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                } finally {
                    conn = null;
                }
            }
        }
    }
}
增删改查
package jdbc;
import org.junit.Test;
import util.JdbcUtil;
import java.sql.*;
public class TestJdbc03 {
    /* 1、新增:往account表中添加一个名称为john、money为3500的记录 */
    @Test
    public void testAdd() {
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //注册驱动并获取链接
            Class.forName( "com.mysql.jdbc.Driver" );
            conn = DriverManager.getConnection(
                    "jdbc:mysql:///jt_db?characterEncoding=utf-8",
                    "root", "root" );
            //获取传输器,并执行sql,返回执行结果
            stat = conn.createStatement();
            String sql = "insert into account value(null, 'john', 3500)";
            int rows = stat.executeUpdate( sql );
            //处理结果
            System.out.println( "影响行数: "+rows );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JdbcUtil.close(conn, stat, rs);
        }
    }
    /* 2、修改:将account表中名称为john的记录,money修改为1500 */
    @Test
    public void testUpdate() {
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //注册驱动并获取连接
            conn = JdbcUtil.getConn();
            //获取传输器并执行sql语句,返回执行结果
            stat = conn.createStatement();
            String sql = "update account set money=1500 where name='john'";
            int rows = stat.executeUpdate( sql );

            System.out.println( "影响行数: "+rows );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JdbcUtil.close(conn, stat, rs);
        }
    }
    /* 3、删除:删除account表中名称为john的记录 */
    @Test
    public void testDelete() {
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //注册驱动并获取连接
            conn = JdbcUtil.getConn();
            //获取传输器并执行sql语句,返回执行结果
            stat = conn.createStatement();
            String sql = "delete from account where name='john'";
            int rows = stat.executeUpdate( sql );
            System.out.println( "影响行数: "+rows );
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(conn, stat, rs);
        }
    }
    /* 4、查询:查询account表中id为1的记录 */
    @Test
    public void testFindById() {
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtil.getConn();
            stat = conn.createStatement();
            String sql = "select * from account where id=1";
            rs = stat.executeQuery( sql );
            if( rs.next() ) {
                int id = rs.getInt("id");
                String name = rs.getString( "name" );
                double money = rs.getDouble( "money" );
                System.out.println( id+":"+name+":"+money );
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(conn, stat, rs);
        }
    }
}

为了提高代码复用性,封装 JdbcUtil 工具,包括 getcon()函数和close()函数

JdbcUtil 工具类
package util;
import java.sql.*;
public class JdbcUtil {
    /**
     * 注册驱动并获取连接对象(默认连接的库是jt_db,用户名密码都是root)
     * @return 连接对象
     */
    public static Connection getConn(){
        Connection conn = null;
        try {
            Class.forName( "com.mysql.jdbc.Driver" );
            conn = DriverManager.getConnection(
                    "jdbc:mysql:///jt_db?characterEncoding=utf-8",
                    "root", "root" );
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 注册驱动并获取连接对象
     * @param db 连接的数据库的名字
     * @param user 连接的数据库的用户名
     * @param pwd 连接的数据库的密码
     * @return 连接对象
     */
    public static Connection getConn( String db, String user, String pwd ){
        Connection conn = null;
        try {
            Class.forName( "com.mysql.jdbc.Driver" );
            conn = DriverManager.getConnection(
                    "jdbc:mysql:///"+db+"?characterEncoding=utf-8",
                    user, pwd );
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }
    /**
     * 释放JDBC程序中的资源
     * @param conn 连接对象
     * @param stat 传输器对象
     * @param rs 结果集对象
     */
    public static void close(Connection conn, Statement stat, ResultSet rs) {
        if( rs != null ) { //反之,如果rs为null,直接跳过,不需要关闭!
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                rs = null;
            }
        }
        if( stat != null ) {
            try {
                stat.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                stat = null;
            }
        }
        if( conn != null ) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                conn = null;
            }
        }
    }
}
模拟用户登录

(1)准备数据

use jt_db;
create table user(
    id int primary key auto_increment,
    username varchar(50),
    password varchar(50)
);
insert into user values(null,'张三','123');
insert into user values(null,'李四','234');

(2)创建LoginUser 类,提供 main 方法 和 login 方法

package ps;
import org.junit.Test;
import util.JdbcUtil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Scanner;
/**
 * 模拟用户登录案例
 */
public class LoginUser {
    public static void main(String[] args) {
        Scanner sc = new Scanner( System.in );
        //1.提示用户登录
        System.out.println( "请登录:" );
        //2.提示用户输入用户名并接收用户名
        System.out.println( "请输入用户名:" );
        String user = sc.nextLine();
        //3.提示用户输入密码并接收密码
        System.out.println( "请输入密码:" );
        String pwd = sc.nextLine();
        //4.调用login方法,将用户名和密码传入,进行登录
        login( user, pwd );
    }
    /**
     * 根据用户名和密码查询jt_db.user表中的数据
     * @param user 用户名
     * @param pwd 密码
     */
    private static void login(String user, String pwd) {
        Connection conn = null;
        Statement stat = null;
        ResultSet rs = null;
        try {
            //注册驱动并获取连接
            conn = JdbcUtil.getConn();
            //获取传输器,执行sql,返回执行结果
            stat = conn.createStatement();
            String sql = "select * from user where username='"+user
                    +"' and password='"+pwd+"'";
            System.out.println( sql );
            rs = stat.executeQuery( sql );
            //处理结果
            if( rs.next() ) { //true,表明有数据,则用户名密码正确,允许登录
                System.out.println( "恭喜您登录成功!" );
            }else { //false,没有数据,则用户名后密码不正确,登录失败
                System.out.println( "登录失败! 用户名或密码不正确! " );
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JdbcUtil.close(conn, stat, rs);
        }
    }
}

执行时,输入:
请登录:
请输入用户名:
张飞’#’
请输入密码:

select * from user where username=‘张飞’#’’ and password=’’
恭喜您登录成功了!

或输入:
请登录:
请输入用户名:
张飞’ or '1=1
请输入密码:

select * from user where username=‘张飞’ or ‘1=1’ and password=’’
恭喜您登录成功了!

SQL注入攻击

通过上面的案例,我们发现在执行时,不输入密码只输入用户名也可以登陆成功。这就是SQL注入攻击。
SQL注入攻击产生的原因: 由于后台执行的SQL语句是拼接而来的:

select * from user where username='"+user+"' and password='"+pwd+"'

其中的参数是用户提交过来的,如果用户在提交参数时,在参数中掺杂了一些SQL关键字(比如or)或者特殊符号(#、-- 、’ 等),就可能会导致SQL语句语义的变化,从而执行一些意外的操作(用户名或密码不正确也能登录成功)

防止SQL注入攻击

如何防止SQL注入攻击?
(1) 使用正则表达式对用户提交的参数进行校验。如果参数中有(# – ’ or等)这些符号就直接结束程序,通知用户输入的参数不合法
(2) 使用PreparedStatement对象来替代Statement对象。下面通过第二种方式解决SQL注入攻击:添加loginByPreparedSatement方法,在方法中,使用PreparedStatement来代替Statement作为传输器对象使用,代码示例:

package ps;
import org.junit.Test;
import util.JdbcUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.Scanner;
/**
 * 模拟用户登录案例
 */
public class LoginUser2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner( System.in );
        //1.提示用户登录
        System.out.println( "请登录:" );
        //2.提示用户输入用户名并接收用户名
        System.out.println( "请输入用户名:" );
        String user = sc.nextLine();
        //3.提示用户输入密码并接收密码
        System.out.println( "请输入密码:" );
        String pwd = sc.nextLine();
        //4.调用login方法,将用户名和密码传入,进行登录
        login( user, pwd );
    }
    /**
     * 根据用户名和密码查询jt_db.user表中的数据
     * @param user 用户名
     * @param pwd 密码
     */
    private static void login(String user, String pwd) {
        Connection conn = null;
        //Statement stat = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //注册驱动并获取连接
            conn = JdbcUtil.getConn();
            //获取传输器,执行sql,返回执行结果
            String sql = "select * from user where username=? and password=?";
            //将sql(骨架)传给服务器编译并确定下来(一旦编译之后,就不能再被改变)
            ps = conn.prepareStatement( sql );
            //传参数
            ps.setString( 1, user );
            ps.setString( 2, pwd );
            //执行sql语句
            rs = ps.executeQuery( );//不要再次传入sql语句,上面已经传过了
            //处理结果
            if( rs.next() ) { //true,表明有数据,则用户名密码正确,允许登录
                System.out.println( "恭喜您登录成功!" );
            }else { //false,没有数据,则用户名后密码不正确,登录失败
                System.out.println( "登录失败! 用户名或密码不正确! " );
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //释放资源
            JdbcUtil.close(conn, ps, rs);
        }
    }
    /** 使用PreparedStatement传输器查询所有用户 */
    @Test
    public void testFindAll() {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtil.getConn();
            String sql = "select * from user";
            ps = conn.prepareStatement( sql );
            rs = ps.executeQuery(); //不要再传SQL语句
            while( rs.next() ) {
                int id = rs.getInt( "id" );
                String username = rs.getString( "username" );
                String password = rs.getString( "password" );
                System.out.println( id+":"+username+":"+password );
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(conn, ps, rs);
        }
    }
}

再次执行程序,按照上面的操作登录。
此时,已经成功的防止了SQL注入攻击问题了。
PreparedStatement对象是如何防止SQL注入攻击的:使用PreparedStatement对象是先将SQL语句的骨架发送给服务器编译并确定下来,编译之后SQL语句的骨架和语义就不会再被改变了,再将SQL语句中的参数发送给服务器,即使参数中再包含SQL关键字或者特殊符号,也不会导致SQL语句的骨架或语义被改变,只会被当作普通的文本来处理!

数据库连接池

什么是连接池?
池:指内存中的一片空间(容器,比如数组、集合)连接池:就是将连接存放在容器中,供整个程序共享,可以实现连接的复用,减少连接创建和关闭的次数,从而提高程序执行的效率!
在这里插入图片描述
为什么要使用连接池?
1、传统方式操作数据库
在这里插入图片描述

Connection conn = DriverManager.getConnection( url, user, pwd ); 
//创建连接对象
conn.close(); //关闭连接, 销毁连接

在传统方式中,每次用户需要连接访问数据库时,都是创建一个连接对象,基于这个连接对象访问数据库,用完连接后,会将连接关闭(conn.close)
由于每次创建连接和关闭连接非常的耗时间而且耗资源,因此会导致程序执行的效率低下
2、使用连接池操作数据库
在这里插入图片描述
可以在程序一启动时,就创建一批连接放在一个连接池中(容器),当用户需要连接时,就从连接池中获取一个连接对象,用完连接后,不要关闭,而是将连接再还回连接池中,这样一来,用来用去都是池中的这一批连接,实现了连接的复用,减少了连接创建和关闭的次数,从而提高了程序执行的效率

如何使用C3P0连接池

使用C3P0连接池开发步骤:
1、导入开发包
2、创建数据库连接池(对象)

ComboPooledDataSource cpds = new ComboPooledDataSource();

3、设置连接数据库的基本信息
(1)方式一:(不推荐) 直接将参数通过 pool.setXxx方法设置给c3p0程序这种方式直接将参数写死在了程序中,后期一旦参数发生变化,就要修改程序,要重新编译项目、重新发布项目,非常麻烦。
(2)方式二:将连接参数提取到properties文件中(推荐)
文件必须放在src(源码根目录)目录下 !
文件名必须叫做 c3p0.properties !
在类目录下(开发时可以放在src或者类似的源码目录下),添加一个c3p0.properties文件,配置内容如下:

c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///jt_db?characterEncoding=utf-8
c3p0.user=root
c3p0.password=root

这种方式由于是c3p0到指定的位置下寻找指定名称的properties文件,所以文件的位置必须是放在src或其他源码根目录下,文件名必须是c3p0.properties
(3)方式三:(推荐)文件必须放在src(源码根目录)目录下 !
文件名必须叫做 c3p0-config.xml
在类目录下(开发时可以放在src或者类似的源码目录下),添加一个c3p0-config.xml文件,配置内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property
        name="jdbcUrl">jdbc:mysql:///jt_db?characterEncoding=utf-8</property>
        <property name="user">root</property>
        <property name="password">root</property>
    </default-config>
</c3p0-config>

这种方式由于是c3p0到指定的位置下寻找指定名称的xml文件,所以文件的位置必须是放在src或其他源码根目录下,文件名必须是c3p0-config.xml
4、从连接池中获取一个连接对象并进行使用

Connection conn = pool.getConnection();

5、用完连接后将连接还回连接池中

JdbcUtil.close(conn, ps, rs);
/* 如果是自己创建的连接对象,这个连接对象没有经过任何的改动,调用
* conn.close方法,是将连接对象关闭
* 如果是从连接池中获取的连接对象,该连接对象在返回时就已经被连接池
* 改造了,将连接对象的close方法改为了还连接到连接池中
*/
package c3p0;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.junit.Test;
import util.JdbcUtil;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
public class TestC3P0 {
    /* 使用c3p0查询account表中的所有数据 */
    @Test
    public void testFindAll(){
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        //获取一个连接池对象(获取存放连接的容器)
        ComboPooledDataSource pool = new ComboPooledDataSource();
        try {
            //这只连接数据库的基本信息(Driver/url/user/password)
            //c3p0程序会到类目录下寻找c3p0.properties文件或者c3p0-config.xml文件
            //从连接池中获取一个连接对象,进行使用
//            connection = JdbcUtil.getConnection();
            connection = pool.getConnection();
            statement = connection.createStatement();
            String sql = "select * from account";
            resultSet = statement.executeQuery(sql);
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String username = resultSet.getString("name");
                double money = resultSet.getDouble("money");
                System.out.println(id+":"+username+":"+money);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JdbcUtil.close(connection,statement,resultSet);
        }
    }
}

c3p0.properties

# key = value
c3p0.driverClass = com.mysql.jdbc.Driver
c3p0.jdbcUrl = jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8
c3p0.user = root
c3p0.password = root

c3p0-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
 <default-config>
  <property name="driverClass">com.mysql.jdbc.Driver</property>
  <property name="jdbcUrl">jdbc:mysql:///jt_db?characterEncoding=utf-8</property>
  <property name="user">root</property>
  <property name="password">root</property>
 </default-config>
</c3p0-config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像的目标属于哪个类别。 定位问题:确定目标在图像的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值