文章目录
1. 结果集ResultSet
1.1 结果集ResultSet的滚动特性
何为滚动?
如果结果集的光标,既可以向上移动,又可以向下移动就称之为可滚动的结果集;如果只能向下移动则称为不可滚动的结果集!
按照jdbc标准默认的结果集,不可滚动!但mysql并没有遵循jdbc的标准,mysql的默认结果集就是滚动的!
移动结果集ResultSet游标位置的方法:
按照jdbc标准,非滚动结果集只能调用next方法,滚动结果集可以调用所有方法,但mysql并没有遵循这一标准,mysql的默认结果集对以下所有的方法都支持。
- (绝对移动)
- void beforeFirst():把光标放到第一行的前面,这也是光标默认的位置;
- void afterLast():把光标放到最后一行的后面;
- boolean first():把光标放到第一行的位置上,返回值表示调控光标是否成功;
- boolean last():把光标放到最后一行的位置上;
- boolean absolute(int row):绝对位移,把光标移动到指定的行上;
- (相对移动)
- boolean previous():把光标向上挪一行;注意:必须先向下移,才能向上 移。
- boolean next():把光标向下挪一行;
- boolean relative(int row):相对位移,当row为正数时,表示向下移动row行,为负数时表示向上移动row行;
判断结果集位置的方法:
按照jdbc标准,不管是不是滚动结果都可以使用以下方法!
- boolean isBeforeFirst():当前光标位置是否在第一行前面;
- boolean isAfterLast():当前光标位置是否在最后一行的后面;
- boolean isFirst():当前光标位置是否在第一行上;
- boolean isLast():当前光标位置是否在最后一行上;
- int getRow():返回当前光标所在行。
1.2 结果集ResultSet的敏感和可更新特性
结果集的特性有:
- 是否可滚动
- 是否敏感
- 是否可更新
何为敏感?
数据库的更新会带动结果集的更新!
何为不敏感?–数据库厂商实现了
数据库的更新不会带动结果集的更新!
何为可更新?
结果集的变化会反向修改数据库中的记录
何为不可更新?
结果集的变化不会修改数据库中的记录
结果集的特性是什么时候确定的?(按照jdbc说的)
结果集是通过statement得到的
结果集特性是当使用Connection的createStatement方法时,就已经确定了Statement生成的结果集是什么特性!
补充: ResultSet的特性是他的爷爷确定的,而不是爸爸确定的!
ResultSet的爸爸—>Statement.executeQuery(sql)
ResultSet的爷爷—>Connection.createStatement()/createStatement(int,int)得到Statement
如何配置参数确定结果集的特性
默认方法con.createSttement():生成的结果集:不滚动、不敏感、不可更新!
如果想设置结果集的特性,可以调用该方法进行设置,con.createStatement(int,int):
Statement createStatement(int resultSetType, int resultSetConcurrency)
Publci interface rst{
Public static final int TYPE_FORWARD_ONLY=10;
}
Ret.TYPE_FORWARD_ONLY
1.3 ResulstSet给我们提供了一些静态参数!
第一个参数resultSetType:决定是否可滚动、是否敏感
- ResultSet.TYPE_FORWARD_ONLY:不滚动结果集;
- ResultSet.TYPE_SCROLL_INSENSITIVE:滚动结果集,但结果集数据不会再跟随数据库而变化;
- ResultSet.TYPE_SCROLL_SENSITIVE:滚动结果集,但结果集数据会再跟随数据库而变化;(但没数据库厂商去实现)
第二个参数:决定结果集是否可更新 - CONCUR_READ_ONLY:结果集是只读的,不能通过修改结果集而反向影响数据库;
- CONCUR_UPDATABLE:结果集是可更新的,对结果集的更新可以反向影响数据库。
2. 元数据
什么是元数据(metadata)?
数据本身的数据
Html里面有这样的一个元标签,元标签设置了html页面的编码
获取结果集元数据
有些数据我们可以通过结果集直接获得,而有些数据就要通过元数据来获得!
如何得到结果集元数据对象?
通过调用结果集的getMetaData()方法可以元数据对象,元数据对象的类型为ResultSetMetaData
通过元数据对象获得结果集的列数及列的名称
ResultSetMetaData
- 获取结果集列数:int getColumnCount()
- 获取指定列的列名:String getColumnName(int colIndex)
例子:假如我们只有一个结果集对象,但不知道结果集中有多少条记录及列的个数和名称,现在让我们把结果集遍历出来!
public static void main(String[] args) throws Exception {
//加载驱动
Class.forName("com.mysql.jdbc.Driver");
//获得连接
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/vip03test01",
"root", "123456");
//通过元数据来遍历表
Statement stmt = con.createStatement();
//执行查询
ResultSet rst = stmt.executeQuery("select * from stu");
//得到结果集的元数据
ResultSetMetaData metaData = rst.getMetaData();
//列数
int colCnt = metaData.getColumnCount();
//把表的字段名称打出来
for(int i=1;i<=colCnt;i++){
String columnName = metaData.getColumnName(i);
System.out.print(columnName+"\t");
}
System.out.println();
while(rst.next()){ //控制行,控制游标的移动
for(int i=1;i<=colCnt;i++){//控制列
Object col = rst.getObject(i);
System.out.print(col+"\t");
}
System.out.println();
}
}
3. 预编译PreparedStatement对象
3.1 PreparedStatement是什么?
PreparedStatement叫预编译声明!可以使用PreparedStatement来替换Statement。
PreparedStatement和Statement的关系
PreparedStatement是Statement接口的子接口。
PreparedStatement的优势:
- 防SQL攻击;
防止SQL攻击的手段有哪些?
1.1 使用PreparedStatement。(推荐使用)
1.2 过滤用户输入的数据中是否包含非法字符;(不允许出现单引号)
1.3 分步交验!先使用用户名来查询用户,如果查找到了,再比较密码; - 提高代码的可读性、可维护性;
- 提高效率! – (预编译声明,他会把sql语句编译成一个sql模板,存到数据库中去。这个sql模板类似于一个函数的东西。)
3.2 PreparedStatement的用法:
- 通过调用Connection的PreparedStatement prepareStatement(String sql)方法得到PreparedStatement对象pstmt;模板 sql语句中的参数用?代替
- 调用pstmt的setXxx()系列方法sql模板中的?赋值!
- 调用pstmt的executeUpdate()或executeQuery(),但它的方法都没有参数。
public static void main(String[] args) throws Exception{
//获得连接
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/vip03test01?useServerPrepStmts=true&cachePrepStmts=true", "root", "123456");
System.out.println(con);//com.mysql.jdbc.JDBC4Connection@446cdf90
String sql = "select * from user where username=? and password = ?";//用?代替参数值 sql模板
//执行查询操作
//PrepareStatement(避免sql攻击)
PreparedStatement pstmt = con.prepareStatement(sql);//prepareStatement执行的sql语句跟Statement执行的sql语句是不一样的
//设置参数,通过pstmt
pstmt.setString(1,"huangchenglong");
pstmt.setString(2,"1234");
//执行pstmt
ResultSet resultSet = pstmt.executeQuery();
}
3.3 预处理PreparedStatement的原理
首先说普通的Statemen的执行过程:
1、 把sql语句发送给数据库服务器
2、 数据库服务器对发送过来的sql语句进行语法校验
3、 对sql语句进行编译
4、 执行sql语句
如果多次发送sql语句,每一次都会执行上面的4步流程!
再来说PreparedStatement的执行流程:
1、 把sql语句(模板)发送给数据库服务器
2、 对sql语句(模板)进行语法校验
3、 对sql语句(模板)进行编译。(编译之后的东西就像函数)(数据库会把该“函数”保存,供以后反复使用)
4、 把pstmt中设置的参数传递给第三步编译之后的sql语句,并执行。(就像调用函数)
如果再次调用该预编译执行,则不会重复以上1/2/3步,只会执行第四步!
1.4 配置mysql的预编译功能
因为mysql4.0之后,预编译的功能默认是关闭的,所以我们需要手动打开mysql的预编译功能才能使用!否则,mysql就不能真正实现预编译的功能!
如何打开mysql的预编译功能呢?其实也很简单!
只需要在jdbc的url后添加两个参数即可!
useServerPrepStmts=true
cachePrepStmts=true
Connection con = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/mydb1? useServerPrepStmts=true& cachePrepStmts=true",
"root", "1234");
4. JDBC的批处理(batch)
什么是批处理()
所谓的批处理就是一批一批的处理,而不是一个一个的处理!这里的批指的就是集合。
之前的sql语句是一条一条的发送,而如果是批处理就可以一次性发送一批sql语句给数据库服务器执行。
批处理只针对更新(增、删、改)语句,批处理没有查询什么事儿!
代码演示(关键代码:stmt.addBatch(sql))
注意事项
开启批处理:在url后面添加参数:rewriteBatchedStatements=true
public void method() throws Exception{
Connection connection = JdbcUtils03.getConnection();
String sql = "insert into student values(?,?)";
PreparedStatement pstmt = connection.prepareStatement(sql);
for(int i=3;i<103;i++){
pstmt.setInt(1,i); //id
pstmt.setString(2,"aa"+i); //name
pstmt.addBatch();//添加批
}
pstmt.executeBatch();//执行批处理
}