SQL注入:通过输入一些特殊的参数值,在拼接SQL时,导致SQL语句的结构发生变化,绕过了SQL的条件
解决方案:使用预编译对象preparedStatement代替Statement
预编译对象:PreparedStatement
是Statement
的子接口,是另外一种SQL执行平台,用来执行SQL语句的
//1.注册驱动
//2.获取连接
?
//3.创建SQL执行平台:预编译对象PreparedStatement
//3.1 改造SQL:SQL语句里的参数要使用?代替
//3.2 使用connection的方法,预编译SQL,得到预编译对象
//3.3 设置SQL参数值
//4 执行SQL语句
?
//5.处理结果
//6.释放资源
减少编译次数,提高效率
解决SQL注入漏洞
提高程序可读性(SQL语句的可读性)
连接池:存储了一堆连接对象的容器。当我们要使用Connection时,不需要创建,而是从连接池中取出一个使用;当使用完成之后,要把Connection对象归还到连接池里。
好处:
效率高
连接池里的连接可以循环使用
少量连接,就可以支持大量的数据库操作
只要少量连接,避免了数据库可用连接被占用完
只要少量连接,避免了创建的Connection过多造成的内存溢出
继承重写父类方法
动态代理:调用代理对象,让代理对象调用目标对象;代理对象里进行增强(依赖于反射技术)
装饰者模式:包装类
之前使用过的:new BufferedReader(new FileReader())
:BufferedReader,对FileReader对象进行了功能增强
原理:见图
示例:有一个接口Man,有实现类普通人CommonMan,要进行功能增强,创建包装类:IronMan
public interface Man {
void eat();
void fight();
}
public class CommonMan implements Man {
public class IronMan implements Man {
private Man commanMan;
?
public IronMan(Man commanMan) {
this.commanMan = commanMan;
}
?
public class WrapperTest {
?
public static void main(String[] args) {
//先有一个被包装的目标对象
Man man = new CommonMan();
?
//不增强,直接调用目标对象
man.eat();
man.fight();
?
System.out.println("-------------------------");
?
//创建一个包装类对象,进行功能增强
Man ironMan = new IronMan(man);
ironMan.eat();
ironMan.fight();
}
}
在实际开发中,不需要自己写连接池。市面上有一些成熟的连接池工具,功能更强大
所有的连接池,都实现了JDBC规范的一个接口:javax.sql.DataSource
。所有连接池使用的基本步骤:
创建连接池对象:连接池的类名不同
从连接池中获取连接:getConnection()
使用连接操作数据库
操作完成归还到连接池:close()
常见的连接池有:
dbcp:Apache提供的开源、免费的连接池工具
c3p0:是一个开源的、免费的连接池工具,使用的很多,方便,功能比dbcp要强
druid:Alibaba的开源的、免费的、高效的连接池工具。
导入jar包
提供配置文件
编写代码,使用连接池
名称必须是:c3p0-config.xml
位置必须在:src下(类加载路径下)
配置示例
<c3p0-config>
<default-config>
<!--前边四项是必须配置的-->
<!--驱动类名-->
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!--数据库url地址-->
<property name="jdbcUrl">jdbc:mysql:///heima62</property>
<!--数据库登录名-->
<property name="user">root</property>
<!--数据库密码-->
<property name="password">root</property>
?
<!--以下非必须配置项-->
<!--最大等待时间-->
<property name="checkoutTimeout">30000</property>
<!--初始化容量-->
<property name="initialPoolSize">10</property>
<!--连接的最大空闲时间-->
<property name="maxIdleTime">30</property>
<!--连接池最大容量-->
<property name="maxPoolSize">100</property>
<!--连接池最小容量-->
<property name="minPoolSize">10</property>
</default-config>
?
<!-- This app is massive! -->
<named-config name="heima">
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql:///heima</property>
<property name="user">root</property>
<property name="password">root</property>
</named-config>
</c3p0-config>
public class DemoC3p0 {
?
/**
* 无参构造,加载的是配置文件中的默认配置:default-config
*/
导入jar包:
提供配置文件
编写代码,使用连接池
文件名:xxx.properties
文件位置:建议放在src下(类加载路径下)
示例
#数据库的url地址
url=jdbc:mysql:///heima62
#数据库的用户名
username=root
#数据库密码
password=root
#数据库的驱动类名
driverClassName=com.mysql.jdbc.Driver
#连接池初始化容量
initialSize=30
#连接池最大容量
maxActive=50
#连接池最小容量
minIdle=10
public class DemoDruid {
/**
* 读取配置文件,使用druid连接池
*/
连接池对象,一个项目中只要一个就可以了,通常设置成某个类的静态变量
对JdbcUtils进行改造
原本的JdbcUtils:
静态代码块里:读取配置文件,得到配置信息
提供getConnection方法:使用配置信息,创建连接
提供close方法:释放资源
改造之后的JdbcUtils:
提供一个静态变量:连接池对象
提供getConnection方法:从连接池里获取连接
提供close方法:释放资源
掌握预编译对象的使用
改造SQL语句:把参数写成占位符?
编译SQL,得到预编译对象:PreparedStatement pstmt = connection.prepareStatement(sql)
设置SQL的参数值:pstmt.setXXX(参数序号, 参数值)
执行SQL语句:pstmt.executeQuery()
;pstmt.executeUpdate()
预编译对象的好处:
解决了SQL注入漏洞
性能高:同一语句,只要编译一次,可以执行多次
提高可读性:SQL语句易读
理解装饰者模式:进行方法的功能增强
理解连接池的原理:
理解连接池的好处:
效率高
连接循环使用:
少量连接,可以支持大量的数据库操作;不用创建大量的Connection对象,避免内存溢出
创建的连接少了,避免数据库所有可用连接,都被占用,导致没有连接可用
掌握c3p0/druid连接池的使用
导入jar包
提供配置文件
无论什么连接池,都有一些必须的配置项:
数据库连接地址
数据库的用户名
数据库的密码
数据库的驱动类名(建议提供)
c3p0的配置文件:c3p0-config.xml,放在src下(类加载路径下)
druid的配置文件:xxx.properties,建议放在src下
编写代码,使用连接池
创建一个连接池对象
c3p0连接池对象的创建:new ComboPooledDataSource()
druid连接池对象的创建:DruidDataSourceFactory.createDataSource(properties对象)
从连接池中获取一个连接:getConnection()
使用连接操作数据库
归还到连接池:connection.close()
原文:https://www.cnblogs.com/penghuake/p/10886284.html