防止SQL注入
sql注入:利用sql语句的语法特点,应用层输入特殊格式,让原有的sql语句失效
创建表结构 并加入数据
create table login(lid int primary key auto_increment,lname varchar(20),lpwd varchar(20),lsex varchar(2),laddr varchar(50)
);
insert into login(lname,lpwd,lsex,laddr)
values('zhangsan','123456','男','西安北大街');
正常写法:
public static void main(String[] args) throws ClassNotFoundException, SQLException {Scanner input = new Scanner(System.in);// 1. 加载驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2. 获取连接Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myhomework03?serverTimezone=GMT","root", "123456");System.out.println("请输入账号");String uname = input.next();System.out.println("请输入密码");String upwd = input.next();// 3.sqlString sql = "select * from login where lname ='" + uname + "' and lpwd=' " + upwd + "'";Statement statement = conn.createStatement();// 不能防止sql注入ResultSet rs = statement.executeQuery(sql);// 4.执行sql语句if (rs.next()) {int lid = rs.getInt("lid");String lname = rs.getString("lname");String lpwd = rs.getString("lpwd");String lsex = rs.getString("lsex");String laddr = rs.getString("laddr");System.out.println(lid + lname + lpwd + lsex + laddr);} else {System.out.println("登录失败");}}
防止sql注入:
public static void main(String[] args) throws ClassNotFoundException, SQLException {Scanner input = new Scanner(System.in);// 1. 加载驱动Class.forName("com.mysql.cj.jdbc.Driver");// 2. 获取连接Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myhomework03?serverTimezone=GMT","root", "123456");System.out.println("请输入账号");String uname = input.next();System.out.println("请输入密码");String upwd = input.next();// // 3.sql
// String sql = "select * from login where lname ='" + uname + "' and lpwd=' " + upwd + "'";
// Statement statement = conn.createStatement();// 不能防止sql注入
// ResultSet rs = statement.executeQuery(sql);// 防止sql注入 -- 利用sql语句的语法特点,应用层输入特殊格式,让原有的sql语句失效// 1.sql语句要变 -- 参数位置要使用 ?占位String sql = "select * from login where lname =? and lpwd =?";// 2. 执行对象要变 -- 预处理sql语句PreparedStatement prepareStatement = conn.prepareStatement(sql);// 3.给sql语句传参prepareStatement.setObject(1, uname);prepareStatement.setObject(2, upwd);ResultSet rs = prepareStatement.executeQuery();// 4.执行sql语句if (rs.next()) {int lid = rs.getInt("lid");String lname = rs.getString("lname");String lpwd = rs.getString("lpwd");String lsex = rs.getString("lsex");String laddr = rs.getString("laddr");System.out.println(lid + lname + lpwd + lsex + laddr);} else {System.out.println("登录失败");}}
使用PreparedStatement的优点:
- 安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。
- 语法不同:PreparedStatement可以使用预编译的sql,而Statment只能使用静态的sql
- 效率不同:对于更改参数的同一SQL语句,PreparedStatement可以使用sql缓存区,效率比Statment高
数据库连接池
其实就是一个容器(集合),存放数据库连接的容器。
当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。
优点:
节约资源用户访问高效
实现:
-
标准接口:DataSource javax.sql包下的
方法:
获取连接:getConnection()
归还连接:Connection.close()。如果连接对象Connection是从连接池中获取的,那么调用Connection.close()方法,则不会再关闭连接了。而是归还连接。
- 一般我们不去实现它,有数据库厂商来实现
- C3P0:数据库连接池技术
- Druid:数据库连接池实现技术,由阿里巴巴提供的
C3P0数据库连接池技术
- *导入jar包 (两个) c3p0-0.9.5.2.jar mchange-commons-java-0.2.12.jar ,
**** 不要忘记导入数据库驱动jar包
- 定义配置文件
名称: c3p0.properties 或者 c3p0-config.xml文件名称不可以修改
路径:直接将文件放在src目录下即可,路径不可修改
<c3p0-config><!-- 使用默认的配置读取连接池对象 --><default-config><!-- 连接参数 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://127.0.0.1/db6?serverTimezone=GMT</property><property name="user">root</property><property name="password">12345678</property><!-- 连接池参数 --><!-- 初始化连接数 --><property name="initialPoolSize">5</property><!-- 最大连接数 --><property name="maxPoolSize">10</property><!-- 超时时间:当连接池耗尽时,客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --><property name="checkoutTimeout">3000</property></default-config><named-config name="otherc3p0"><!-- 连接参数 --><property name="driverClass">com.mysql.cj.jdbc.Driver</property><property name="jdbcUrl">jdbc:mysql://127.0.0.1/db5?serverTimezone=GMT</property><property name="user">root</property><property name="password">12345678</property><!-- 连接池参数 --><!-- 初始化连接数 --><property name="initialPoolSize">5</property><!-- 最大连接数 --><property name="maxPoolSize">8</property><!-- 超时时间:当连接池耗尽时,客户端调用getConnection()后等待获取新连接的时间,超时后将抛出 SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --><property name="checkoutTimeout">3000</property></named-config>
</c3p0-config>
- 创建核心对象 数据库连接池对象 ComboPooledDataSource
- 获取连接: getConnection
package c3p0_conn_pool;import java.sql.Connection;
import java.sql.SQLException;import com.mchange.v2.c3p0.ComboPooledDataSource;public class Test01 {// c3p0数据库连接池对象static ComboPooledDataSource datasource = null;public static void main(String[] args) throws SQLException {// 创建连接池对象datasource = new ComboPooledDataSource();// 基础参数配置datasource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/db6?charset=utf8mb4&useSSL=false&useTimezone=true&serverTimezone=GMT%2B8");datasource.setUser("root");datasource.setPassword("12345678");// 设置连接池的配置参数datasource.setInitialPoolSize(3);// 初始化连接对象
// datasource.setMinPoolSize(2);// 最小连接数量datasource.setMaxPoolSize(10);// 最大连接池数量datasource.setCheckoutTimeout(3000);// 等待时间(单位:毫秒)for (int i = 1; i <= 11; i++) {Connection connection = datasource.getConnection();System.out.println(connection);if (i == 5) {connection.close();// 将连接对象归还给连接池,进行复用}}}
}
package c3p0_conn_pool;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;public class Test02 {static DataSource dataSource = null;public static void main(String[] args) throws SQLException {// 1.创建连接池对象dataSource = new ComboPooledDataSource();
// for (int i = 1; i <= 11; i++) {// 2.获取连接对象
// Connection connection = dataSource.getConnection();
// System.out.println(connection);
// if (i == 5) {
// connection.close();// 将连接对象归还给连接池,进行复用
// }
// }// 2.获取连接对象Connection conn = dataSource.getConnection();System.out.println(conn);PreparedStatement pre = conn.prepareStatement("select * from emp");ResultSet resultSet = pre.executeQuery();while (resultSet.next()) {System.out.println(resultSet.getInt(1));}}
}
package c3p0_conn_pool;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;public class Test03 {static DataSource dataSource = null;public static void main(String[] args) throws SQLException {// 1.创建连接池对象dataSource = new ComboPooledDataSource("otherc3p0");// 2.获取连接对象Connection conn = dataSource.getConnection();System.out.println(conn);PreparedStatement pre = conn.prepareStatement("select * from emp");ResultSet resultSet = pre.executeQuery();while (resultSet.next()) {System.out.println(resultSet.getInt(1));}}
}
Druid:数据库连接池实现技术,由阿里巴巴提供的
- 导入jar包 druid-1.0.9.jar
- 定义配置文件
是properties形式的
可以叫任意名称,可以放在任意目录下
driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db6?serverTimezone=GMT
username=root
password=12345678
initialSize=5
maxActive=10
maxWait=3000
validationQuery=SELECT 1
testWhileIdle=true
testOnBorrow=false
testOnReturn=false
poolPreparedStatements=false
- 加载配置文件。Properties
- 获取数据库连接池对象:通过工厂来来获取 DruidDataSourceFactory
- 获取连接:getConnection
package druid_conn_pool;import java.io.IOException;
import java.sql.Connection;
import java.util.Properties;import javax.sql.DataSource;import com.alibaba.druid.pool.DruidDataSourceFactory;public class Test01 {public static void main(String[] args) throws Exception {//1.导入jar包//2.定义配置文件//3.加载配置文件Properties properties = new Properties();properties.load(Test01.class.getResourceAsStream("/druid.properties"));//4.获取连接池对象DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);//5.获取数据库连接ConnectionConnection connection = dataSource.getConnection();System.out.println(connection);}
}