对数据库操作中的JDBC进阶使用

  • 一、批处理(以插入为例)
  • (一)原理方法
  • (二)应用实例
  • 二、ResultSet接口的用法
  • (一)新定义了若干个常数用于指定游标移动的方向
  • (二)ResultSet 接口提供了一整套的定位方法。
  • (三)ResultSet 接口添加了对行操作的支持
  • (1)原理方法
  • (2)插入操作
  • (3)更新操作
  • (4)删除操作
  • 三、对于上面代码例用到的数据库工具类方法
  • 四、过程中碰到的一些问题
  • (一)对于已经设置了默认自增长的字段在插入时如何使其默认插入?


一、批处理(以插入为例)

(一)原理方法

public void addBatch(String sql); //将SQL 语句添加到SQL 语句块中。
public void clearBatch(); //将SQL 语句块中的所有SQL 语句全部删除。
public int[] executeBatch(); //将SQL 语句块发送到数据库服务器去并执行,它返回的结果是一个整型数组。

//在Statement 接口实现数据库批操作的方法是:
	//(1) 创建Statement 接口的实例对象
	//(2) 调用addBatch( )方法往SQL 语句块中添加若干个SQL 语句
	//(3) 使用executeBatch( )方法完成数据库批操作

(二)应用实例

//演示批处理插入
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement prep = null;
        ResultSet rs = null;
        //中间就是我们的方位体
        try {
        	//通过工具类方法获得数据库连接
            conn = DBConnection.getInstance().getConnection();
            //创建sql语句对象
            String sql = "insert into tb_user values (?,?,?,?);";
            prep = conn.prepareStatement(sql);
            prep.setString(1,null); //该字段为自增长,赋为null即可
            prep.setString(2,"张小小");
            prep.setString(3,"aaa");
            prep.setInt(4,18);
            prep.addBatch();
            prep.setString(1,null);
            prep.setString(2,"网右");
            prep.setString(3,"bbb");
            prep.setInt(4,18);
            prep.addBatch();
            prep.setString(1,null);
            prep.setString(2,"网左");
            prep.setString(3,"ccc");
            prep.setInt(4,18);
            prep.addBatch();
            //4 执行sql语句对象
            int [] ints = prep.executeBatch();
            //5 处理结果集,通常的处理是遍历
            for (int anInt : ints) {
                System.out.println(anInt);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            DBConnection.getInstance().closeConnection(conn,prep,rs);
        }
    }

二、ResultSet接口的用法

(一)新定义了若干个常数用于指定游标移动的方向

FETCH_FORWORD: 指定处理记录集中行的顺序是由前到后,即从第一行开始处理一直到最后一行。

FETCH_REVERSE: 指定处理记录集中行的顺序是由后到前,即从最后一行开始处理一直到第一行。

FETCH_UNKNOWN: 不指定处理记录集中行的顺序,而由JDBC 驱动程序和数据库系统决定。

TYPE_FORWARD_ONLY: 指定数据库游标的移动方向是向前,不允许向后移动,即只能使用ResultSet 接口的next()方法而不能使用previous()方法,否则会产生错误。

TYPE_SCROLL_INSENSITIVE: 指定数据库游标可以在记录集中前后移动,并且当前数据库用户获取的记录集对其他用户的操作不敏感。

TYPE_SCROLL_SENSITIVE: 指定数据库游标可以在记录集中前后移动并且当前数据库用户获取的记录集对其他用户的操作敏感。

CONCUR_READ_ONLY: 该常数的作用是指定当前记录集的协作方式(concurrency mode)为只读。一旦使用了这个常数,那么用户就不可以更新记录集中的数据。

CONCUR_UPDATABLE: 该常数的作用是指定当前记录集的协作方式(concurrency mode)为可以更新。一旦使用了这个常数,那么用户就可以使用updateXXX()等方法更新记录集中的数据。

(二)ResultSet 接口提供了一整套的定位方法。

public boolean absolute(int row); 该方法的作用是将记录集中的某一行设定为当前行,亦即将数据库游标移动到指定的行。参数row 指定了目标行的行号,这是绝对的行号,由记录集的第一行开始计算。

public boolean relative(int rows); 该方法的作用也是将记录集中的某一行设定为当前行,但是它的参数rows 表示目标行相对于当前行的行号。

public boolean first(); 该方法的作用是将当前行定位到数据库记录集的第一行。

public boolean last(); 该方法的作用刚好和first()方法相反,是将当前行定位到数据库记录集的最后一行。

public boolean isFirst(); 该方法的作用是检查当前行是否记录集的第一行。如果是,返回true ,否则返回false。

public boolean isLast(); 该方法的作用是检查当前行是否记录集的最后一行。如果是,返回true, 否则返回false。

public void afterLast(); 该方法的作用是将数据库游标移到记录集的最后,位于记录集最后一行的后面。如果该记录集不包含任何的行该方法不产生作用。

public void beforeFirst(); 该方法的作用是将数据库游标移到记录集的最前面,位于记录集第一行的前面。如果记录集不包含任何的行,该方法不产生作用。

public boolean isAfterLast(); 该方法检查数据库游标是否处于记录集的最后面。如果是,返回true, 否则返回false。

public boolean isBeforeFirst( ); 该方法检查数据库游标是否处于记录集的最前面。如果是,返回true, 否则返回false。

public boolean next( ); 该方法的作用是将数据库游标向前移动一位,使得下一行成为当前行。当刚刚打开记录集对象时,数据库游标的位置在记录集的最前面。

public boolean previous( ); 该方法的作用是将数据库游标向后移动一位,使得上一行成为当前行。

示例

//结果集指针的移动示例
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement prep = null;
        ResultSet rs = null;
        try {
            conn = DBConnection.getInstance().getConnection();
            //创建sql语句对象
            String sql = "select * from tb_user;";
            prep = conn.prepareStatement(sql);
            rs = prep.executeQuery();
            System.out.println(rs.isBeforeFirst()); //检查数据库游标是否处于记录集的最前面
            System.out.println(rs.isFirst()); //检查当前行是否记录集的第一行
            rs.absolute(3);  //将数据库游标移动到指定的行
            rs.getString("userName");
            rs.relative(-2);  //将记录集中相当于当前游标位置的某一行设定为当前行
            rs.getString("userName");
            rs.last(); //将当前行定位到数据库记录集的最后一行
            System.out.println(rs.getRow()); //获取当前行号
            rs.beforeFirst(); //将数据库游标移到记录集的第一行的前面
            while (rs.next())
                System.out.println(rs.isAfterLast()); //检查数据库游标是否处于记录集的最后面
        } catch (
                SQLException e) {
            e.printStackTrace();
        }finally {
            DBConnection.getInstance().closeConnection(conn,prep,rs);
        }
    }

(三)ResultSet 接口添加了对行操作的支持

(1)原理方法

public boolean rowDeleted( ); 如果当前记录集的某行被删除了,调用该方法返回true,否则返回false 。

public boolean rowInserted( ); 如果当前记录集中插入了一个新行,该方法将返回true,否则返回false。

public boolean rowUpdated( ); 如果当前记录集的当前行的数据被更新,该方法返回true, 否则返回false。

public void insertRow( ); 该方法将执行插入一个新行到当前记录集的操作。

public void updateRow( ); 该方法将执行更新当前记录集当前行的数据。

public void deleteRow( ); 该方法将执行删除当前记录集的操作。 

public void updateString(int columnIndex, String x); 该方法更新当前记录集的当前行某列的值,该列的数据类型是String, 该方法的参数columnIndex 指定所要更新的列的列索引,第一列的列索引是1 ,以此类推。

public void updateString(String columnName, String x); 该方法同上,其第一个参数是columnName 代表需要更新的列的列名而不是columnIndex。

(2)插入操作

向数据库当前记录集插入新行的操作流程如下:
1) 调用moveToInsertRow( )方法
2) 调用updateXXX( )方法指定插入行各列的值
3) 调用insertRow( )方法往数据库中插入新的行

例子:

//通过更新结果集来完成数据库的持久化操作
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement prep = null;
        ResultSet rs = null;
        try {
            conn = DBConnection.getInstance().getConnection();
            //创建sql语句对象
            String sql = "select * from tb_user;";
            /* ① TYPE_SCROLL_INSENSITIVE: 指定数据库游标可以在记录集中前后移动,并且当前数据库用户获取的记录集对其他用户的操作不敏感;② CONCUR_UPDATABLE: 该常数的作用是指定当前记录集的协作方式(concurrency mode)为可以更新。一旦使用了这个常数,那么用户就可以使用updateXXX()等方法更新记录集中的数据。 */
            prep = conn.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_UPDATABLE);
            rs = prep.executeQuery();

            //新增操作
            rs.moveToInsertRow();
            rs.updateString(1,null);
            rs.updateString(2,"网下");
            rs.updateString(3,"98123");
            rs.updateInt(4,18);

            rs.insertRow();
        } catch (
                SQLException e) {
            e.printStackTrace();
        }finally {
            DBConnection.getInstance().closeConnection(conn,prep,rs);
        }
    }

(3)更新操作

更新数据库中某个记录的值(某行的值)的方法是
1、定位到需要修改的行
2、使用相应的updateXXX( )方法设定某行某列的新值,也可以使用cancelRowUpdates( )方法进行回滚
3、使用updateRow( )方法完成UPDATE 的操作
例:

rs.first( );
	rs.updateString("name","Steven");  
	rs.updateRow( );

(4)删除操作

删除记录集中某行(亦即删除某个记录)的方法
1、定位到需要修改的行(使用absolute() relative()等方法)
2、使用deleteRow()方法
例:

rs.first( );
 rs.deleteRow( );

三、对于上面代码例用到的数据库工具类方法

需要用到自己编写的数据库工具类
好处是使代码更简洁,便于维护;功能是获取数据库连接、关闭数据库操作中的相关接口

package cn.edu.lingnan.util;

import java.sql.*;

//功能,处理数据库连接,作成单例模式
public class DBConnection {
    private String dirver = "com.mysql.jdbc.Driver";
    private String url = "jdbc:mysql://localhost:3306/数据库名?characterEncoding=UTF8&useUnicode=true&useSSL=false";
    private String user = "账户";
    private String password = "密码";
    private static DBConnection dbConnection = null;
    private Connection conn = null;

    //私有的构造方法,保证对象的唯一性
    private DBConnection(){
        try {
            //1 注册驱动程序
            Class.forName("com.mysql.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.out.println("[Debug] mysql的jar驱动下载失败... ...");
            e.printStackTrace();
        }
    }

    //静态工厂方法
    public static DBConnection getInstance(){
        if(dbConnection == null)
            dbConnection = new DBConnection();
        return dbConnection;
    }

    //获取数据库连接
    public Connection getConnection(){
        try {
            //2 获取数据库连接,如果是mysql8.0的还要加SSL和ZONE的设置
            conn = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public void closeConnection(Connection conn, Statement stat, ResultSet rs){
        try {
            if(rs != null) {
                rs.close();
            }
            if (stat != null) {
                stat.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void closeConnection(Connection conn, PreparedStatement prep, ResultSet rs){
        try {
            if(rs != null) {
                rs.close();
            }
            if (prep != null) {
                prep.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public void closeConnection(Connection conn, PreparedStatement prep){
        try {
            if (prep != null) {
                prep.close();
            }
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

四、过程中碰到的一些问题

(一)对于已经设置了默认自增长的字段在插入时如何使其默认插入?

无论字段的类型为何种,整型还是字符串型或其他,都可以像下面那样赋为null。

prep.setString(1,null); //该字段为自增长,赋为null即可

 rs.updateString(1,null); //使用了结果集接口的插入更新方法