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注入问题,非常安全的!
可以分配,释放,管理数据库连接对象,当前某个连接对象释放之后,会归还到连接池中,大大提高了JDBC操作数据库性能!
弊端:维护成本高; (维护它druid的版本以及监控它的连接数量)
好处:可以设置参数,将数据库连接池进行调优;
每一个线程都会使用自己的连接对象!
前某个连接对象释放之后,会归还到连接池中,等待下一次利用(大大提高了连接对象的使用率)
在连接池中:会初始化一些连接数量(提供了很多参数)
initialSize:初始化数量
maxActive:最大激活数量
maxWait:最大等多等待时间(毫秒值)
maxidle:最大空闲数量
minidel:最小空闲数量
...
...
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/homework11
username=root
password=root
initialSize=5
maxActive=10
maxWait=3000
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)]
//添加员工数据
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);
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 ;
}
}
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 ;
}
}