导读
1.PreparedStatement
2.封装优化
3.ORM思想
PreparedStatement
–是Statement的子接口
特点:可以设定参数,把带参数的SQL语句先传过去,再设置对应参数的值传过去执行
较Statement来看,PreparedStatement的变化主要在第三,第四步骤
第三步,创建PreparedStatement,传入带参数的SQL语句
对于变化的数值,可以参数化,用?做占位符占位
String sql = "INSERT INTO t_user (id,username,password,sex,"
+ "id_number,tel,addr) "
+ "VALUES(t_user_id_seq.NEXTVAL,?,?,?,?,?,?)";
PreoareStatement pstmt=conn.prepareStatement(sql);
第四步,执行SQL语句
1)先设置占位符的值,发过去值执行SQL语句
每一个问号对应一个索引,从1开始,语句按照从左到右的顺序
pstmt.setXXX(索引,对应的值);
2)执行,注意不要再次传入SQL语句了
int rows = pstmt.executeUpdate();
PreparedStatement vs Statement
直观看:
利用PreparedStatement不需要拼接,不需要关心单引号的问题
先传带参数的SQL语句
在传参数执行
利用Statement利用拼接,注意文本型要加单引号拼接
把完整的拼接后的语句传过去执行
效率看:
如果添加1个学生,Statement相对快一点(后者只传一次)
如果添加100个学生,
对于Statement,循环第四步,发送100次语句过去,都不相同
对于一个语法,发送过去需要先编译处理,再执行,编译100次
对于Preparedstatement,循环第四步,发送100次参数值过去,语句是一样的
对于带参数的语句,先预编译,只要预编译1次,执行100次,相对效率高一点
从安全角度来看:
需求:登录时,通过用户名和密码查找一个用户
Statement:
"SELECT id,username,password,sex FROM t_user WHERE username="+username+" and password='"+password+"'";
PreparedStatement:
"SELECT id,username,password,sex FROM t_user WHERE username=? and password=?";
假如:用户名:aa
密码:111
结果一致
假如:用户名:aa
密码:"111' OR '1'='1"
Statement中枪,可以查到所有的用户信息
PreparedSatement直接报错,不允许设置
PreparedStatement更安全
PreparedStatement可以替代Statement,我们推荐使用PreparedSatement
封装优化
1.封装第一,二步
自创类ConnectionFactory实现
package com.hala.jdbc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Connection工厂类
* 利用这个类获取连接的数据库对象
* @author air
*
*/
public class ConnectionFactory {
private static final String DRIVER="oracle.jdbc.driver.OracleDriver";
public static Connection getConnection(){
//这里把声明放在try{}里边的话成为局部变量,会报错
Connection conn=null;
try {
Class.forName(DRIVER);
conn=DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:XE",
"easybuy",
"easybuy");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
}
替换
Connection conn=ConnectionFactory.getConnection();
注意:这里有两种优化思想
(1)将常量抽出为private static final 属性,便于使用改动
(2)将这些常量存在一个配置文件中,在ConnectionFactory所在的包下创建一个properties文件
properties:属性文件(不能带引号,否则引号也作为有效的一部分)
键值对
key=value
key=value
key=value
Java中:Properties类,集合类,存储键值对
这个类对象可以从properties文件中加载数据,把所有的键值对
加载到内存对象中
jdbcinfo.properties
driver=oracle.jdbc.driver.OracleDriver
url=jdbc:oracle:thin:@localhost:1521:XE
username=easybuy
userpassword=easybuy
怎样获取文件中的键值对来使用呢?
->更改后的 ConnectionFactory.java
package com.hala.jdbc;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;
/**
* Connection工厂类
* 利用这个类获取连接的数据库对象
* @author air
*
*/
public class ConnectionFactory {
//用来存储从文件中获得的值
private static String DRIVER;
private static String URL;
private static String USERNAME;
private static String USERPASSWORD;
//利用静态代码块实现,在类加载时执行,只会执行一次
static{
//1.创建一个Properties对象
Properties prop=new Properties();
try {
//2.加载properties文件的数据,这种写法只能对同包下的文件获取一个字节流
//加载后prop里边就有了文件里边的键值对
prop.load(ConnectionFactory.class.
getResourceAsStream("jdbcinfo.properties"));
//3.通过键获取对应的值,注意大小写
DRIVER=prop.getProperty("driver");
URL=prop.getProperty("url");
USERNAME=prop.getProperty("username");
USERPASSWORD=prop.getProperty("userpassword");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static Connection getConnection(){
//这里把声明放在try{}里边的话成为局部变量,会报错
Connection conn=null;
try {
Class.forName(DRIVER);
conn=DriverManager.getConnection(URL,USERNAME,USERPASSWORD);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
}
2.释放资源:自创一个类实现
package com.hala.jdbc;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
/**
* 释放资源
* @author air
*
*/
public class DBUtils {
//这里PreparedStatement是Statement的子接口,所以这里用Statement即可
public static void close(ResultSet rs,Statement stmt,Connection conn){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(stmt!=null){
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if(conn!=null){
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
替换
DBUtils.close(rs,stmt,conn);
ORM思想
Object/Relational Mapping
java对象<---->数据库映射
对象模型 关系模型
实体类(pojo) 表
属性 列(字段)
OID 主键
对象 记录
实体类之间的关联关系 外键
一对一
映射到Java中:
Person Passport
id id
name ...
Passport Person
Person中含有Passport属性,Passport属性也含有Person属性
一对多
Order (订单) OrderDetail(订单明细)
List<OrderDetail> Order
Order中含有List<OrderDetail> 属性,OrderDetail含有Order 属性
多对多
Teacher Student
List<Student> List<Teacher>
ORM思想其实本质就是将两个类相互关联起来
实例:
定义一个方法,
查询一个订单,及其对应的明细并返回
要求,返回订单对象,里面包含对应的明细集合对象
分步操作:
1.定义一个OrderJDBC类,
定义 Order getOrder(long id){}
2.定义一个OrderDetailJDBC类,
定义 List<OrderDetail> getDetails(long orderId){}
3.定义一个方法,
查询一个订单,及其对应的明细并返回
要求,返回订单对象,里面包含对应的明细集合对象