1,预编译
在使用Statement对象时,在执行sql语句时,可能会产生字符串的拼接的现象,也叫SQL注入.
所以我们使用PrepareStatement
使用PrepareStatement:
可以防止SQL注入
采取预编译的方式,先将sql语句交给数据库译好,等待执行就可以了
使用PrepareStatement在执行多个重复语句时,速度比Statement更快,效率更高.
Statement的写法
Statement statement = connection.createStatement();
现在我们使用PrepareStatement
PreparedStatement pps = connection.prepareStatement(
"insert into stu values (null,?,?); ");
// ? 代表一个占位符
// 第一个参数是?的位置
// 与valuse后面括号里面是否有null,是否有具体值无关
// 在sql语句中有几个问号,就需要向sql语句中传递几个参数
// 第几个问号,那么下面的方法中的第一个参数就填几
pps.setString(1,"传递参数值");
pps.setInt(2,"传递参数值");
// 也可以写成 pps.setObject(2,"传递参数值");
// 兼容性更强
// 最后执行语句
pps.executeUpdate();
// 执行语句可以使用三个方法,返回值不同
// execute,executeUpdate,executeQuery
批处理操作
就是通过预处理对象PrepareStatement,调用addBatch()这个方法,实现批处理操作.
在调用这个方法后,会将sql语句先存起来,等待执行.
通过代码简单说明批处理操作:
//在一个main方法里面,或者测试方法
public static void main(String[] args) throws SQLException {
// 在上一篇文章中(JDBC连接-JDBCBase),封装了一个JDBCUtil,我们这边直接调用这个类的方法,获得连接对象
Connection conn = JDBCUtil.getConnection();
// 根据连接对象,获得预处理对象
PreparedStatement ups = conn.prepareStatement("insert into stu values (null,?,?);");
pps.setString(1,"站站");
pps.setInt(2,25);
// 调用addBatch()方法
// 通过这个方法实现预处理操作
// 调用这个方法后,先将sql语句存起来,等待这行
pps.addBatch();
pps.setString(1,"站站1");
pps.setInt(2,28);
// 再添加一条等待执行的sql语句到批处理的缓存中
pps.addBatch();
// 再添加一条删除语句到批处理的缓存中
pps.addBatch("delete from stu where name = '站站';")
// 执行批处理中存着的sql语句
// 批处理中各个sql语句之间执行成功或者失败是无联系的
// 即使第一条语句出现错误
// 也不会影响第二条语句将数据插入到数据库中
// 执行sql语句
pps.executeBatch();
}
事务处理
开启事务,将连接对象的提交方式设置为手动提交.
事务就是一个处理过程,在整个过程中,如果在某一步骤中出现错误,在这之前所做的操作,都将无效,将回到最开始的状态,我们把这个称为事务回滚.整个过程要么完全执行,要么完全不执行.
举个例子:
你要给老妈汇100元,一次完整的汇款操作就是一个事务。
简单列举下汇款的主要流程:
1:从你帐号拿出100元,相应的数据库操作就是—》减去100元从你的帐号
2:银行将100元存入老妈的帐号,相应的数据库操作就是—-》修改老妈的帐号的余额
步骤1,2和一起算一次事务,它包括两次数据库的修改处理,因此,如果两则有一个出现异常(比如汇款时停电),则正常的银行系统不会将你的100元丢失,也不会将老妈帐户加100.
就是事务回滚.
如果没有事务管理,减去100和加上100是两个单独的操作,这时候如果 把你帐户减去100元后,突然停电, 不仅老妈收不到钱,你的100元也没了。很可怕吧!还好只是100!有了事务管理呢,数据库系统发现这次事务出现了中断,就不会把你的钱扣除。
简单的代码说明:
// 在一个main方法中
public static void main(string[] args) {
Connection conn = null;
try{
conn = JDBCUtil.getConnection();
// 设置提交方式为手动提交
// 开启事务
conn.setAutoCommit(false);
// 创建一个预处理对象
PreparedStatement pps = conn.prepaseStatement("update money set m = ? where name = ?;");
pps.setInt(1,900);
pps.setString(2,"曹云金");
ps.executeUpdate();
int a = 100/0;
pps.setInt(1,1100);
pps.setString(2,"郭德纲");
ps.executeUpdate();
conn.commit();
}catch (Exception e) {
// 回滚到事务开始之前
try{
conn.rollback();
system.out.println("回滚了");
}catch (SQLException e1){
e1.printStackTrace();
}
}
}
DbUtils
DbUtils是一个Apache提供的一个,开源的方便我们操作jdbc的jar包
QueryRunner类,是DbUtils的核心类
所有的操作数据库的方法都被封装在这个类中
更新,查询都是使用QueryRunner类
1) BeanHandler:查询返回单个对象
2) BeanListHandler:查询返回list集合,集合元素是指定的对象
3) ArrayHandler:查询返回结果记录的第一行,封装对象数组,即返回:Object[]
4) ArrayListHandler:把查询的每一行都封装成对象数组,再添加到list集合中
5) ScalarHandler:通常单行单列的时候使用
6) MapHandler:查询返回结果记录第一条,封装成map
7) MapListHandler:查询返回结果记录的每一行都封装成map,在添加到集合
简单的代码说明:
// 在一个测试类中
@Test
// 使用QueryRunner这个类
public void test1() throws SQLException {
// 获得连接对象
Connection conn = JDBCUtil.getConnection();
// 建立一个QueryRunner类的对象,用来执行sql语句
QueryRunner qr = new QueryRunner();
String sql = "select * from stu;";
// 执行sql语句
// 调用query方法 查询语句
qr.query(conn,sql);
// 将得到的数据放到指定类类型的集合中
// qr.query(conn,sql,new BeanListHandler<>(Stu.class));
// 遍历集合 增强for循环,快捷键 'iter' + tab键
// 调用update方法, 增,删,改 语句
// qr.update(con,sql);
conn.close();
}
接口回调:
// ResultSetHandler是接口
// BeanHandler,BeanListHandler等类都实现了ResultSetHandler接口
// 接口回调
@Test
public void test2() throws SQLException {
Connection conn = JdbcUtil.getConnection();
QueryRunner qr = new QueryRunner();
String sql = "select * from stu where id = 1";
qr.query(connection, sql, new ResultSetHandler<Stu>() {
@Override
public Stu handle(ResultSet resultSet) throws SQLException {
while (resultSet.next()) {
Stu stu = new Stu();
stu.setName(
resultSet.getString("name"));
return stu;
}
return null;
}
});
}
复习接口
接口是一种规范
实现了接口的类,将一定要复写这个接口的方法
那么实现了接口的类,就叫该接口的实现类
实例:指的就是对象
实例化对象:就可以理解为创建一个对象
多态:
一个对象可以有多种形态
父类的引用指向了子类的对象