JDBC 使用PreparedStatement操作数据库 数据库 连接池 及 动态代理
1 preparedStatement 预编译对象
2 数据库的连接池
3 动态代理
模拟用户登录功能
需求:
我们在控制台输入用户名和密码,输入完用户名和密码后,获取输入的值,使用jdbc操作数据库,完成登录功能.
找到了:登录成功 找不到:用户名或密码错误
技术分析:
jdbc
创建用户表:
create table user (
id int primary key auto_increment,
name varchar(20),
password varchar(20)
);
insert into user values(null,"tom","tom"),(null,"rose","rose"),(null,"jerry","jerry");、
代码实现:
public class LoginDemo {
public static void main(String[] args) {
Connection c = null;
PreparedStatement pst = null;
try {
c = JDBCUtils.getConnection();
//pst = c.prepareStatement();
Scanner sc = new Scanner(System.in);
System.out.println("----Welcome My Space----");
System.out.println("Please input User name: ");
String user = sc.nextLine();
System.out.println("Please input User Password: ");
String ps = sc.nextLine();
//int psi = Integer.valueOf(ps);
String sql = "select * from rentmoney where name=? and password=? ";
pst = c.prepareStatement(sql);
pst.setString(1,user);
pst.setString(2,ps);
ResultSet rs = pst.executeQuery();
if(rs.next()){
System.out.println("Yeah");
}
else{
System.out.println("Fuck off");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtil.closeNew(null, pst, c);
}
}
}
Statement编译对象:拼接什么样的sql就执行什么样的sql语句
**问题:**使用Statement对象来操作sql语句会有缺陷:会造成数据的安全隐患
比如登录中的sql拼接:select * from user where username=‘jack’ #’ and password=‘123’;
相当于注释掉了密码的校验,这种安全隐患我们称为:Sql注入
Sql注入:将用户输入的内容作为了sql语句的一部分 改变了原有sql语句的意义
**解决:**就不能使用当前的Statement对象来操作SQL语句了,得使用另一个对象–preparedStatement对象
PreparedStatement: 预编译对象
**作用:**也是用来执行sql语句的
语句执行者:Statement编译对象 preparedStatement预编译对象
区别:
Statement编译对象是有什么样的sql就执行什么样的sql语句,每次执行任何一条sql语句都得先让数据库去编译 其后才执行 如果执行一万条同样的查询语句 数据库要编译一万次 效率低
preparedStatement预编译对象是先将sql传递给数据库做预编译 其后拿着预编译结果传递参数执行sql,执行一万条同样的查询语句 数据库只编译一次 根据不同的参数做不用的执行
预编译的好处:
1 sql语法格式只需要编译一次,效率高
2 能让数据库提前知晓要执行的sql语句格式,只负责给数据库传参即可
语法格式:
Statement编译对象: select * from 表 where 字段1=值1 and 字段2=值2;
preparedStatement:select * from 表 where 字段1=? and 字段2=?;
?:占位符 所有的实际参数都用占位符替换了 不在是直接设值了
通过外部方法来设置实际参数的值:set字段类型(占位符的序号,要设置的值);
占位符的序号是从1开始的
setString(1,‘jack’);
setString(2,‘abcd/1234’);
preparedStatement对象操作数据库的增删改查
使用步骤:
1.编写sql
String sql = "insert into user values(null,?,?...) ";
2.创建预编译对象–提前编译sql语句
PreparedStatement pst = conn.preparedStatement(sql);
3.设置具体的参数
pst.set字段类型(int a,值);
a: 第几个 ? (占位符) 默认从左向右第1个开始
4.执行sql即可
ResultSet rs = pst.executeQuery(); // 执行查询,返回 resultSet
int i = pst.executeUpdate(); // 执行 增 删 改 返回的是影响的行数
数据库连接池
概述
连接池:存放数据库连接的容器(集合)
连接池出现的目的
之前在使用jdbc操作数据库数据的时候,有一个步骤是获取连接(创建连接)
连接用完,还需要释放连接(销毁连接),这2个步骤太消耗资源了
创建连接=0.1
销毁连接=0.1
10000000*0.2=2000000
目标:想将获取连接和释放资源的这个时长缩短
用来优化jdbc的2个步骤的
1 优化的是jdbc的创建连接部分
2 优化的是jdbc的销毁连接部分
优化原理
在连接池一初始话的时候,就在容器中创建一定量的连接
当用户要连数据库的时候,就从容器中拿一个连接使用
使用完毕之后,不再是销毁,而是把使用后的连接还放回容器 供下一个用户去循环使用
ps:
在企业中使用的都是已经成熟并且性能很高的提供好的连接池:c3p0和druid(学习重点)
只要是直接研发连接池或者是别人研发连接池都需要先实现java提供的规则—DataSource接口
不论是哪个连接池都统一会有DataSource接口下的所有方法:
获取连接的方法(从连接池中获取): 连接池对象.getConnection()
释放连接的方法(将连接归还给连接池): close()
只要当前要释放的连接是从连接池中拿的,当调用这个方法的时候是归还
如果当前的要释放的连接不是从连接池中拿的,当调用这个方法的时候是销毁
c3p0连接池的使用
硬编码方式(必须要写代码实现的方式)
了解即可
配置文件方式(掌握)
硬编码方式开发步骤:
1 导包 c3p0-0.9.1.2.jar
2 创建连接池
3 告诉连接池要连接的数据库信息
4 (可选)连接池的参数配置
5 获取连接
配置文件方式(掌握)企业开发中我们配置文件会使用2种:.properties key=value .xml 层级关系
1 导包 c3p0-0.9.1.2.jar
2 在src下放一个配置文件
这个配置文件如果是xml的话,必须叫c3p0-config.xml 必须放在src下
这个配置文件如果是properties的话,必须叫c3p0.properties 必须放在src下
3 创建连接池获取连接
好处:只要连接池一创建 底层会自动去src下加载名字叫c3p0-config.xml或c3p0.properties文件
4 代码实现
1:创建c3p0的连接池: DataSource ds=new CombopooledDataSource()
使用配置文件默认的<default-config>
DataSource ds=new CombopooledDataSource("name名称") 使用配置文件中带名称的<named-config name="otherc3p0">
2:从连接池中获取连接: Connection con=ds.getConnection()
3:拿着连接去操作数据库: 略
4:归还连接给连接池: con.close()
druid连接池的使用
配置文件方式(掌握)
1 导入1个jar包
druid-1.0.9.jar
2 存放配置文件
没有要求,可以是任何名称任何位置的properties文件即可(建议放入src下面)
原因:因为不会自动帮你去加载配置文件,需要自己手动去加载配置文件
3 代码实现
1:创建properties对象加载配置文件
InputStream is=类名.class.getClassLoad.getResourceAsStream();
Properties properties= new Properties();
properties.load(is);
2: 创建druid的连接池
DataSource ds=DruidDataSourceFactory.createDataSource(properties对象)
3: 获取连接
Connection con=ds.getConnection()
4: 拿着连接去操作数据库: 略
5:归还连接给连接池: con.close()
自定义工具类(jdbcUtils)的增强
1 定义一个连接池(c3p0或druid)
2 提供获取连接的方法 (连接得是从连接池中拿的)
3 提供一个获取连接池的方法(直接返回连接池)—>jdbcTemplate工具类要用
4 提供释放资源的方法
动态代理
作用:用来增强一个对象的方法 (框架的底层用了很多的动态代理来增强方法业务)
代理的概念:
· 代理对象:增强对象
· 被代理对象:要被增强的对象
要使用jdk提供的动态代理增强一个对象的方法有条件:
· 必须得知道要被代理的对象是谁 被代理的对象必须得有接口
java:面向接口 先有接口后有类
使用jdk提供的动态代理:什么包都不用导 都提供好了
jdk提供工具API: newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 会返回一个指定接口下的代理类的代理对象