Druid数据库连接池的介绍及使用、Statement对象和PreparedStatement对象的区别

Druid数据库连接池的介绍及使用、Statement对象和PreparedStatement对象的区别

面试题:

Statement对象和PreparedStatement对象的区别:

1)执行sql效率区别
Statement对象:执行sql,每一次将sql都需要发送一次,相对于PreparedStatement对象效率低,不用它的原因
数据库的性能优化—>减少服务器的交互次数(和数据库的交互次数减少)
PreparedStatement对象:预编译对象: 执行的参数化的sql,直接先发送给数据库,数据库会进行校验(参数类型,以及参数的字段是哪一列),并且保存在预编译对象中,可以不断的重新赋值;执行sql效率高!
2)是否存在sql注入的区别
Statement对象:执行的sql语句,都是静态化sql,sql存在字符串拼接,就会导致可能出现sql注入,非常不安全!
举例:
select * from user where username = ‘“+变量名+”’ and password ‘“+值…+”’ ;

​ PreparedStatement预编译对象:每次是在自己内存中直接赋值对应的值,sql语句永远是占位符号?
​ select * from user where username = ? and password = ? ;
​ 不会造成sql注入问题,非常安全的!

Druid数据库连接池的介绍及使用

可以分配,释放,管理数据库连接对象,当前某个连接对象释放之后,会归还到连接池中,大大提高了JDBC操作数据库性能!
	弊端:维护成本高; (维护它druid的版本以及监控它的连接数量)
	好处:可以设置参数,将数据库连接池进行调优;
	
    每一个线程都会使用自己的连接对象!
    前某个连接对象释放之后,会归还到连接池中,等待下一次利用(大大提高了连接对象的使用率)

在连接池中:会初始化一些连接数量(提供了很多参数)
    initialSize:初始化数量
    maxActive:最大激活数量
    maxWait:最大等多等待时间(毫秒值)
    maxidle:最大空闲数量
    minidel:最小空闲数量
    ...
    ...
druid.properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/homework11
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
DruidJdbcUtils封装类
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @Author 豆三岁
 * @Date 2022-05-19 19:08
 * 改进优化:
 * 1)从DataSource获取连接对象getConnection(),DataSource替代了DriverManager (连接池获取连接对象)
 * 2)读取的连接池的配置文件
 * 3)提供静态代码块----加载当前类的时候,直接读取连接池的配置文件,
 * 		获取的连接池对象---DruidDataSourceFactroy工厂类获取数据源对象
 **/
public class DruidJdbcUtils {
    //成员变量位置:提供ThreadLocal:模拟线程,每一个线程使用自己的Connection
    private static ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
    //声明一个DataSource类型的变量
    private static DataSource dataSource;

    //无参构造私有化:目的外界不能new对象了
    private DruidJdbcUtils(){}

    //静态代码块
    static {
        try {
            //创建属性集合列表
            Properties properties = new Properties();
            //直接读取连接池的配置文件
            InputStream inputStream = DruidJdbcUtils.class.getClassLoader().getResourceAsStream("druid.properties");
            //将字节输入流的内容加载属性列表中
            properties.load(inputStream);
            //DruidDataSourceFactroy工厂类获取数据源对象
            dataSource = DruidDataSourceFactory.createDataSource(properties);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //封装一个功能:获取数据源
    public static DataSource getDataSource(){
        return  dataSource;
    }

    //封装一个功能:获取数据库的连接对象
    public static Connection getConnection(){
        //1)首先要从当前线程中获取连接对象
        try {
            Connection connection = threadLocal.get();
            //2)判断conn是空的
            if(connection==null){
                //当前线程中没有开始绑定连接对象
                //3)从数据源连接池获取连接对象
                connection = dataSource.getConnection() ;
                //4)将当前连接对象绑定给自己的线程中
                threadLocal.set(connection);
            }
            return connection ;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //封装释放资源
    public static void close(PreparedStatement preparedStatement, Connection connection){
        close(null,preparedStatement,connection);
    }
    public static void close(ResultSet resultSet, PreparedStatement preparedStatement, Connection connection){
        if(resultSet!=null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(preparedStatement!=null){
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(connection!=null){
            try {
                connection.close();
                //需要将自己线程中的连接对象解绑
                threadLocal.remove();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


    //测试连接是否成功
    public static void main(String[] args) {
        // DataSource dataSource = DruidJdbcUtils.getDataSource();
        //  System.out.println(dataSource);
        //获取连接对象
        Connection connection = DruidJdbcUtils.getConnection();
        System.out.println(connection);
    }
}

单元测试的介绍

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gPmKUiP4-1653231696745)(…/…/…/AppData/Roaming/Typora/typora-user-images/image-20220521170145941.png)]

使用PrepareStatement预编译对象执行sql语句(DML/DQL)

//添加员工数据
Connection connnection = JdbcUtils.getConnnection();
//sql---参数化的sql语句
//sql语句中的值不是写死的,是在执行sql执行之前,可以多次赋值
String sql = "insert into emploee(name,age,gender,address,salary) values(?,?,?,?,?)" ;
//通过连接对象获取预编译对象PreparedStatement
//Connection---->PreparedStatement prepareStatement(String sql) throws SQLException
//将参数化的sql发送给数据库,并且存储到PreparedStatement对象中
PreparedStatement ps = connnection.prepareStatement(sql);
//PreparedStatement预编译对象中,需要给 ?  (占位符号)进行赋值
//通用方法:void setXxx(int parameterIndex, Xxx x)  :给占位符号赋值,
//参数1:第几个占位符号(从1开始)
//参数2:实际参数
ps.setString(1,"亓桑") ;
ps.setInt(2,20);
ps.setString(3,"男");
ps.setString(4,"西安市") ;
ps.setDouble(5,10000.00) ;

//PreparedStatement预编译对象 :执行sql
//通用方法:int executeUpdate()  :DML语句
//ResultSet executeQuery()  :DQL语句
int count = ps.executeUpdate();
System.out.println("影响了"+count+"行");

//释放资源
JdbcUtils.close(ps,connnection);


//查询员工数据
Connection connnection = JdbcUtils.getConnnection();
//sql---参数化的sql语句
//sql语句中的值不是写死的,是在执行sql执行之前,可以多次赋值
String sql = "select * from emploee where id = ?" ;
//通过连接对象获取预编译对象PreparedStatement
//Connection---->PreparedStatement prepareStatement(String sql) throws SQLException
//将参数化的sql发送给数据库,并且存储到PreparedStatement对象中
PreparedStatement ps = connnection.prepareStatement(sql);

//给参数赋值
ps.setInt(1,7) ;

//执行查询
//ResultSet executeQuery()  :DQL语句
ResultSet rs = ps.executeQuery();
while (rs.next()){
    int id = rs.getInt("id");
    String name = rs.getString("name");
    int age = rs.getInt("age");
    String gender = rs.getString("gender");
    String address = rs.getString("address");
    double salary = rs.getDouble("salary");
    System.out.println(id+"\t"+name+"\t"+age+"\t"+gender+"\t"+address+"\t"+salary);
}

//释放资源
JdbcUtils.close(ps,connnection);

使用Statement/PreparedStatement分别完成模拟登录功能

Statement模拟登录

import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Scanner;

/**
 * @author Kuke
 * @date 2022/5/19 14:44
 * 使用Statement完成,模拟用户登录的操作
 * 一张user表
 * 				id    username  password
 * 				1		rose    123
 * 				2       jacky   123456
 *
 * 分析:
 *  1)有一个张表user表,里面有两条数据
 *  2)定义一个功能:登录功能  返回值类型 boolean
 *  3)键盘录入模拟用户的数据,用户名和密码
 *
 *  使用上面Statement能够完成模拟用户登录操作,但是可能会存在问题
 *  “SQL注入”----就是因为在操做sql语句的时候,存在字符串拼接造成的
 *  select * from user where username = 'qisang' and password = 'nihao' or '1'='1'
 *
 *  Statement另一方面,执行sql语句的效率比较低 ,实际开发中不会使用Statement对象来操作数据库
 *  后面mybatis框架底层封装对象:PreparedStatement预编译对象!
 *
 */
public class Statement_LoginTest {
    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 = isLogin(username,password) ;
        if(flag){
            System.out.println("恭喜您,登录成功!! ");
        }else{
            System.out.println("登录失败!");
        }
    }

    /**
     * 登录的功能
     * @param username 用户名
     * @param password 密码
     * @return 返回值true,登录成功;否则失败
     */
    public static boolean isLogin(String username,String password){
        Connection conn = null ;
        Statement stmt = null ;
        ResultSet rs = null ;
        try {
            //获取数据库的链接对象
            conn = JdbcUtils.getConnnection() ;
            //准备好sql
            String sql = "select * from user where username = '"+username+"' and password = '"+password+"'" ;
            System.out.println(sql) ;
            //获取Statement对象
            stmt = conn.createStatement();

            //执行查询sS
            rs = stmt.executeQuery(sql);

            return  rs.next() ;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //释放资源
            JdbcUtils.close(rs,stmt,conn);
        }
        return  false ;
    }
}

PreparedStatement模拟登录

package com.qf.statement_and_preparedstatement_04;

import com.qf.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Scanner;

/**
 * @author Kuke
 * @date 2022/5/19 15:40
 * 使用PreparedStatement完成,模拟用户登录的操作
 */
public class PerparedStatement_LoginTest {

    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  = login(username,password) ;
        if(flag){
            System.out.println("恭喜您,登录成功!!");
        }else{
            System.out.println("对不起,登录失败!");
        }
    }

    /**
     * 登录功能
     * @param username 登录的用户名
     * @param password 登录密码
     * @return  返回登录是否成功,true,成功;false,失败!
     */
    public static boolean login(String username, String password) {

        try {
            //获取数据库的连接对象
            Connection conn = JdbcUtils.getConnnection();
            //准备sql----参数化的sql
            String sql = "select * from user where username = ? and password = ?" ;
            //获取预编译对象,并且发送sql到数据库
            PreparedStatement ps = conn.prepareStatement(sql) ;
            System.out.println(sql) ;
            //给参数赋值
            ps.setString(1,username) ;
            ps.setString(2,password);

            //执行查询
            ResultSet rs = ps.executeQuery();
            return rs.next() ;
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return  false ;
    }
}

conn.prepareStatement(sql) ;
System.out.println(sql) ;
//给参数赋值
ps.setString(1,username) ;
ps.setString(2,password);

        //执行查询
        ResultSet rs = ps.executeQuery();
        return rs.next() ;
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return  false ;
}

}


你可能感兴趣的:(Java基础,MySQL,JAVA学习,数据库,sql,mysql)