一、预处理对象
1.SQL注入问题
SQL注入:用户输入的内容作为了SQL语句语法的一部分,改变了原有SQL真正的意义。
假设有登陆案例SQL语句如下:
SELECT * FROM 用户表 WHERE NAME = 用户输入的用户名 AND PASSWORD = 用户输的密码;
此时,当用户输入正确的账号密码后,查询到了信息则让用户登录。但是当用户输入的账号为XXX 密码为:**‘XXX’ OR ‘a’=‘a’**时,则真正执行的代码变为:
SELECT * FROM 用户表 WHERE NAME = ‘XXX’ AND PASSWORD =’ XXX’ OR ’a’=’a’;
此时,上述查询语句是永远可以查询出结果的。那么用户就直接登录成功了,显然我们不希望看到这样的结果,这便是SQL的注入问题。
为此,我们使用PreparedStatement来解决对应的问题。
2.API详解:预处理对象
PreparedStatement:预编译对象,是Statement对象的子类。
特点:
性能高
会把sql语句先编译
能过滤掉用户输入的关键字。
PreparedStatement预处理对象,处理的每条sql语句中所有的实际参数,都必须使用占位符 ? 替换。
String sql = "select * from user where username = ? and password = ?";
PreparedStatement使用,需要通过以下3步骤完成:
- PreparedStatement预处理对象代码:
#获得预处理对象,需要提供已经使用占位符处理后的SQL语句
PreparedStatement psmt = conn.prepareStatement(sql)
2.设置实际参数
void setXxx(int index,Xxx,xx)将指定参数设置指定类型的值
参数1:index实际参数序列号,从1开始。
参数2:xxx实际参数值,xxx表示具体的类型。
例如:
setString(2,"1234")把sql语句中第2个位置的占位符?替换为实际参数“1234”
3.执行SQL语句:
int executeUpdate();--执行insert update delete语句。
ResultSet executeQuery();--执行select语句。
boolean execute();--执行select返回true执行其他的语句返回false.
举例:
1.插入
@Test
public void demo01(){
//添加:向分类表中添加数据
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try{
//1获取连接
conn = JdbcUtils.getConnection();
//2处理sql语句
String sql = "insert into category(cname) values(?)";
//3获得预处理对象
psmt = conn.preparedStatement(sql);
//4设置实际参数
psmt.setString(1,"预处理");
//5执行
int r = psmt.executeUpdate();
System.out.println(r);
} catch (Exception e){
throw new RuntimeException(e);
}finally{
//6释放资源
JdbcUtils.closeResource(conn,psmt,rs);
}
}
2.更新
@Test
public void demo02(){
//修改
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "update category set cname = ? where cid = ?";
psmt = conn.preparedStatement(sql);
psmt.setString(1,"测试数据");
psmt.setInt(2,4);
int r = psmt.executeUpdate();
System.out.println(r);
}catch(Exception e){
throw new RuntimeException(e);
}finally{
JdbcUtils.closeResource(conn,psmt,rs);
}
}
3.通过id查询详情
@Test
public void demo05(){
//通过id查询
Connection conn = null;
PreparedStatement psmt = null;
ResultSet rs = null;
try{
conn = JdbcUtils.getConnection();
String sql = "select * from category where cid = ?"
psmt = conn.preparedStatement(sql);
psmt.setInt(1,2);
rs = psmt.executeQuery();
if(rs.next()){
System.out.println("查询到");
}else{
System.out.println("查询不到");
}
}catch(Exception e){
throw new RuntimeException(e);
}finally{
JdbcUtils.closeResource(conn,psmt,rs);
}
}
二、使用连接池重写工具类
1.连接池原理:
理解为存放多个连接的集合。
目的:解决建立数据库连接耗费资源和时间很多的问题,提高性能。
2.编写标准的数据源(规范)
Java为数据库连接池提供了公共的接口:**javax.sql.DataSource,**各个厂商需要让自己的连接池实现这个接口。这样应用程序可以方便的切换不同厂商的连接池!
常见的连接池:DBCP、C3P0。
3.C3P0连接池(这里只讲C3P0)
C3P0开源免费的连接池!目前使用它的开源项目有:Spring、Hibernate等。使用第三方工具需要导入jar包,c3p0使用时还需要添加配置文件 c3p0-config.xml
使用步骤:
1、添加jar包
2、编写配置文件:
c3p0-config.xml,放在src中(注:文件名一定不要写错)
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<default-config>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/DB
</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<property name="user">root</property>
<property name="password">root</property>
<property name="initialPoolSize">3</property>
<property name="maxPoolSize">6</property>
<property name="maxIdleTime">1000</property>
</default-config>
</c3p0-config>
3.编写工具类:
public class C3P0Utils{
//创建一个连接池对象
static DataSource ds = new ComboPooledDataSource();
//从池中获得一个连接
public static Connection getConnection() throws SQLException{
return ds.getConnection();
}
//释放资源
public static void closeAll(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try{
rs.close();
}catch(SQLException e){
throw new RuntimeException(e);
}
rs = null;
}
if(stmt!=null){
try{
stmt.close();
}catch(SQLException e){
throw new RuntimeException(e);
}
stmt= null;
}
if(conn!=null){
try{
conn.close();
}catch(SQLException e){
throw new RuntimeException(e);
}
conn= null;
}
}
}
三、使用DBUtils 执行增删改查的操作
1.案例分析
简化JDBC代码开发,本案例我们将采用apache commons组件一个成员:DBUtils。
DBUtils就是JDBC的简化开发工具包。需要使用技术:连接池(获得连接),SQL语句都没有少。
2.案例相关知识
2.1JavaBean组件
JavaBean就是一个类,在开发中常用于封装数据。具有如下特性:
- 需要实现接口:java.io.Serializable ,通常偷懒省略了。
- 提供私有字段:private 类型 字段名;
- 提供getter/setter方法:
- 提供无参构造
public class Category {
private String cid;
private String cname;
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
…toString….
}
3.DBUtils完成CRUD
3.1概述
DBUtils是java编程中的数据库操作实用工具,小巧简单实用。
DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。
Dbutils三个核心功能介绍
QueryRunner中提供对sql语句操作的API.
ResultSetHandler接口,用于定义select操作后,怎样封装结果集.
DbUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法
3.2QueryRunner核心类
QueryRunner(DataSource ds) ,提供数据源(连接池),DBUtils底层自动维护连接connection
update(String sql, Object… params) ,执行更新数据 insert update delete
query(String sql, ResultSetHandler rsh, Object… params) ,执行查询 select
3.3ResultSetHandler结果集处理类
红色为重点掌握,其他了解
3.4实现
开发步骤:
1、创建项目,并导入jar包
2、创建连接池
3、编写测试类
添加
@Test
public void testInsert() {
try {
//1 核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 sql
String sql = "insert into category(cid,cname) values(?,?)";
//3 参数
Object[] params = {"c006","家电"};
//4执行
queryRunner.update(sql, params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
更新
@Test
public void testUpdate() throws Exception{
try {
//1 核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 sql
String sql = "update category set cname=? where cid = ?";
//3 参数
Object[] params = {"家电","c006"};
//4执行
queryRunner.update(sql, params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
删除
@Test
public void testDelete() throws Exception{
try {
//1 核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 sql
String sql = "delete from category where cid = ?";
//3 参数
Object[] params = {"c006"};
//4执行
queryRunner.update(sql, params);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
通过id查询
@Test
public void testFindById() throws Exception{
try {
//1 核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2 sql
String sql = "select * from category where cid=?";
//3 参数
Object[] params = {"c003"};
//4执行
Category category = queryRunner.query(sql, new BeanHandler<Category>(Category.class), params);
System.out.println(category);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
查询所有
@Test
public void testFindAll() throws Exception{
try{
//1核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2sql
String sql = "select * from category";
//3参数
Object[] params = {};
//4执行
List<Category> allCategory = queryRunner.query(sql,new BeanListHandler<Category>(Category.class),params);
for(Category category : allCategory){
System.out.println(category);
}
}catch(Exception e){
throw new RuntimeException(e);
}
}
总记录数
@Test
public void testCount() throws Exception{
try{
//1核心类
QueryRunner queryRunner = new QueryRunner(C3P0Utils.getDataSource());
//2sql
String sql = "select count(*) from category";
//3参数
Object[] params = {};
//4执行
Long numLong = (Long)queryRunner.query(sql,new ScalarHandler(),params);
int num = numLong.inValue();
System.out.println(num);
}catch(Exception e){
throw new RuntimeException(e);
}
}