Java JDBC 3

Statement

用于执行静态SQL并返回结果对象。
默认情况下,每个Statement对象只能有一个ResultSet对象同时打开。如果打开ResultSet则会隐式关闭当前ResultSet对象。

  1. 属性
// ResultSet能返回的最大行数,超过则丢弃
// 0表示无限制
int getMaxRows();
void setMaxRows(int max);

// ResultSet行被处理的方向
// 可为
//     ResultSet.FETCH_FORWARD(默认,1000)
//     ResultSet.FETCH_REVERSE(1001)
//     ResultSet.FETCH_UNKNOWN(1002)
int getFetchDirection();
void setFetchDirection(int direction);

// 一次查询返回的行数
// 0表示无限制,默认为0
int getFetchSize();
void setFetchSize(int rows);

// ResultSet类型
// 可为
//     ResultSet.TYPE_FORWARD_ONLY(1003)
//     ResultSet.TYPE_SCROLL_INSENSITIVE(1004)
//     ResultSet.TYPE_SCROLL_SENSITIVE(1005)
int getResultSetType();

// ResultSet并发类型
// 可为
//     ResultSet.CONCUR_READ_ONLY(1007)
//     ResultSet.CONCUR_UPDATABLE(1008)
int getResultSetConcurrency();

// ResultSet保持类型
// 可为
//     ResultSet.HOLD_CURSORS_OVER_COMMIT(1)
//     ResultSet.CLOSE_CURSORS_AT_COMMIT(2)
int getResultSetHoldability();

// 超时秒数
// 0表示无限制,默认为0
int getQueryTimeout();
void setQueryTimeout(int seconds);

// 当所有ResultSet关闭时是否自动关闭Statement
boolean isCloseOnCompletion();
void closeOnCompletion();
  1. 查询
ResultSet executeQuery(String sql);

例:

// executeQuery
ResultSet resultSet = statement.executeQuery("select *, id as userId from user");
while (resultSet.next()) {
    // 列标
    long userId = resultSet.getLong("userId");
    String userName = resultSet.getString("userName");
    System.out.println(userId + " " + userName);
}
resultSet.close();
  1. 更新
// 返回影响行数
int executeUpdate(String sql);
  1. 多结果
// 执行给定SQL,可能返回多个结果(一般是调用存储过程)
// 先使用getResultSet()或getUpdateCount()获取第一个结果(已移动到第一个结果)
// 然后再使用getMoreResults()判断下一个结果类型
// 返回:
//     true:第一个结果是ResultSet
//     false:第一个结果是更新数,或没有更多结果
boolean execute(String sql);

// 移动到下一个结果
// 返回:
//     true:下个结果是ResultSet
//     false:下个结果是更新数,或没有更多结果
boolean getMoreResults();

// 移动到下一个结果,并处理当前ResultSet
// current:
//     Statement.CLOSE_CURRENT_RESULT(1)
//     Statement.KEEP_CURRENT_RESULT(2)
//     Statement.CLOSE_ALL_RESULTS(3)
boolean getMoreResults(int current);

// 返回更新数
//      -1:当前结果是ResultSet,或没有更多结果
int getUpdateCount();

// 返回ResultSet
//      null:当前结果是更新数,或没有更多结果
ResultSet getResultSet();

例:

// 存储过程
// mysql> delimiter $$ // 临时将结束符由;改为$$
// mysql> create procedure getTwoUsers()
//     -> begin
//     -> select * from user where id = 1;
//     -> select * from user where id = 2;
//     -> update user set status = 3 where id = 3;
//     -> end$$
// mysql> delimiter ;
// mysql> call getTwoUsers();

// 多结果
String sql = "call getTwoUsers()";
// 已经移动到下一个结果
boolean isResultSet = statement.execute(sql);

int resultIndex = 0;
while (true) {
    if (isResultSet) {
        System.out.println("结果" + (++resultIndex) + ":");
        ResultSet resultSet = statement.getResultSet();
        while (resultSet.next()) {
            long id = resultSet.getLong("id");
            String userName = resultSet.getString("userName");
            System.out.println(id + " " + userName);
        }
        resultSet.close();

    } else {
        int updateCount = statement.getUpdateCount();
        if (updateCount == -1) {
            // 结果遍历结束:getMoreResults()==false && getUpdateCount()==-1
            break;
        } else {
            System.out.println("结果" + (++resultIndex) + ":");
            System.out.println("更新数:" + updateCount);
        }
    }
    System.out.println();

    isResultSet = statement.getMoreResults();
}
  1. 批量更新
void addBatch(String sql);
void clearBatch();

// 批量执行SQL,返回更新数数组
// 更新数 >=0,表示影响行数
// 更新数 = Statement.SUCCESS_NO_INFO(-2),表示影响行数未知
// 如果其中一个SQL出错,抛出BatchUpdateException
int[] executeBatch();
  • BatchUpdateException
// 批量更新时各SQL的更新数结果
// 更新数 = Statement.EXECUTE_FAILED(-3),表示执行失败
int[] getUpdateCounts();

例:

String[] sqlList = new String[]{
    "update user set status = 1 where id = 1",
    "update user set status = 2 where id = a",
    "update user set status = 3 where id = 3"
};

Consumer<int[]> updateCountsConsumer = new Consumer<int[]>() {
    @Override
    public void accept(int[] updateCounts) {
        for (int i = 0; i < sqlList.length; i++) {
            String sql = sqlList[i];
            int updateCount = updateCounts[i];

            if (updateCount == Statement.SUCCESS_NO_INFO) {
                System.out.println(sql + ":未知");
            } else if (updateCount == Statement.EXECUTE_FAILED) {
                System.out.println(sql + ":失败");
            } else {
                System.out.println(sql + ":" + updateCount);
            }
        }
    }
};

try {
    for (String sql : sqlList) {
        statement.addBatch(sql);
    }

    int[] updateCounts = statement.executeBatch();
    updateCountsConsumer.accept(updateCounts);

} catch (BatchUpdateException bue) {
    updateCountsConsumer.accept(bue.getUpdateCounts());
    bue.printStackTrace();

} catch (SQLException e) {
    e.printStackTrace();
}
  1. 生成键
// 执行SQL,并指定是否返回自动生成的键
// autoGeneratedKeys:
//     Statement.RETURN_GENERATED_KEYS(1)
//     Statement.NO_GENERATED_KEYS(2)
int executeUpdate(String sql, int autoGeneratedKeys);

// columnIndexes指定返回的自动生成键
int executeUpdate(String sql, int columnIndexes[]);

// columnNames指定返回的自动生成键
int executeUpdate(String sql, String columnNames[]);

// 返回:
//     true,第一个结果是ResultSet
boolean execute(String sql, int autoGeneratedKeys);
boolean execute(String sql, int columnIndexes[]);
boolean execute(String sql, String columnNames[]);

ResultSet getGeneratedKeys();

例:

String sql = "INSERT INTO user(userName, nickName, status, createTime, updateTime)VALUES" +
        "('lmztest@163.com', '测试', 0, unix_timestamp()*1000, unix_timestamp()*1000)";
int updateCount = statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
System.out.println("更新:" + updateCount);

ResultSet resultSet = statement.getGeneratedKeys();
while (resultSet.next()) {
    // 列名为GENERATED_KEY
    long id = resultSet.getLong(1);
    System.out.println("键:" + id);
}
resultSet.close();
  1. 关闭
void close();

PreparedStatement

预编译SQL语句,可以动态设置参数,多次执行。继承Statement。

  1. 参数,参数序号1起
// 设置null
// sqlType:java.sql.Types
void setNull(int parameterIndex, int sqlType);
void setBoolean(int parameterIndex, boolean x);
void setInt(int parameterIndex, int x);
void setObject(int parameterIndex, Object x);
void setObject(int parameterIndex, Object x, int targetSqlType);
...

// 清除参数
void clearParameters();

// 查询参数信息
ParameterMetaData getParameterMetaData();
  1. 查询
ResultSet executeQuery();

例:

String sql = "select * from user where userName = ?";

PreparedStatement preparedStatement = connection.prepareStatement(sql);

preparedStatement.setString(1, "li_maozhi@163.com");

ResultSet resultSet = preparedStatement.executeQuery();
while (resultSet.next()) {
    // 列标
    long userId = resultSet.getLong("id");
    String userName = resultSet.getString("userName");
    String nickName = resultSet.getString("nickName");
    System.out.println(userId + " " + userName + " " + nickName);
}
resultSet.close();

preparedStatement.close();
  1. 更新
int executeUpdate();
  1. 多结果(同Statement)
// 执行任何类型SQL
boolean execute();
  1. 批量更新
void addBatch();

ParameterMetaData

对于某些驱动,需要在PreparedStatement执行后才能获取参数信息。

// 参数数量
int getParameterCount();

// 参数类型,参数序号1起
int getParameterType(int param);

// 参数类型名称
String getParameterTypeName(int param);

// 参数类型对应的Java类名
String getParameterClassName(int param);

// 参数模式
// 返回:
//     ParameterMetaData.parameterModeIn
//     ParameterMetaData.parameterModeOut
//     ParameterMetaData.parameterModeInOut
//     ParameterMetaData.parameterModeUnknown
int getParameterMode(int param);

CallableStatement

用于执行SQL存储过程。继承PreparedStatement。
IN参数值使用set方法设置,OUT参数registerOut方法注册。参数序号1起。
ResultSet按Statement方式获取。

  1. 设置IN参数
void setString(String parameterName, String x);
void setBoolean(String parameterName, boolean x);
...
  1. 注册OUT参数
// sqlType: java.sql.Types
void registerOutParameter(int parameterIndex, int sqlType);
void registerOutParameter(int parameterIndex, int sqlType, int scale);

void registerOutParameter(String parameterName, int sqlType);
void registerOutParameter(String parameterName, int sqlType, int scale);
void registerOutParameter (String parameterName, int sqlType, String typeName);
  1. 获取OUT结果
String getString(int parameterIndex);
boolean getBoolean(int parameterIndex);
...
  1. 例子
  • 存储过程
// 改结束符,为$$
mysql> delimiter $$

// 创建存储过程
mysql> create procedure getUser(INOUT p_u varchar(128), IN p_s tinyint(4), OUT p_i bigint(20))
begin
// 赋值给OUT变量p_i,p_u
SELECT id, nickName INTO p_i, p_u
FROM user
WHERE userName = p_u AND status = p_s;
end$$
  • 调用存储过程
// 赋值系统变量
mysql> set p_userName='li_maozhi@163.com'$$

// 调用存储过程,将OUT变量赋值给系统变量
mysql> call getUser(@p_userName, 0, @p_id)$$

// 查询系统变量
mysql> select @p_userName$$

// 查询系统变量
mysql> select @p_id$$
  • Java Code
// 存储过程getUser(INOUT, IN, OUT)
String sql = "call getUser(?, ?, ?)";

CallableStatement callableStatement = connection.prepareCall(sql);

// 设置IN参数p_u
callableStatement.setString(1, "li_maozhi@163.com");

// 设置IN参数p_s
callableStatement.setInt(2, 0);

// 注册OUT参数p_u
callableStatement.registerOutParameter(1, Types.VARCHAR);

// 注册OUT参数p_i
callableStatement.registerOutParameter(3, Types.BIGINT);

// 执行
callableStatement.execute();

// 获取OUT结果p_u
String nickName = callableStatement.getString(1);

// 获取OUT结果p_i
long userId = callableStatement.getLong(3);

System.out.println("userId = " + userId + ", nickName = " + nickName);

callableStatement.close();
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容

  • 本节介绍Statement接口及其子类PreparedStatement和CallableStatement。 它...
    zlb阅读 1,157评论 0 0
  • JDBC基础知识 一、采用JDBC访问数据库的基本步骤: A.载入JDBC驱动程序 B.定义连接URL ...
    java日记阅读 3,844评论 0 20
  • 本人的环境为Myeclipse10、MySQL5.7.15 本文包括:简介JDBC编程步骤打通数据库程序详解—Dr...
    廖少少阅读 3,942评论 7 39
  • 器 生活中有不同的“器”,器能盛纳万物,美的形制与好的内容相得益彰;器能助人成事,有利器方成匠心之作;有一种“器”...
    JohnVeeCaptain阅读 341评论 2 1
  • 幼儿时期是大量学习动作技能的最佳时期。这个时期幼儿身体柔软,容易学习,再加上她们喜欢模仿,喜欢不厌其烦的重...
    蔡蔡_678a阅读 76评论 0 0