day03

JDBC

结果集元数据

ResultSetMetaData用于描述查询结果的相关信息,其中包含列名称,列数量,类数据类型等.

原理:

1.png

使用案例:

public static void main(String[] args) {
    Connection conn = null;
    try {
        conn = DBUtils.getConnection();
        String sql = "select * from robin_user";
        Statement st = conn.createStatement();
        ResultSet rs = st.executeQuery(sql);
        
        //结果集元数据
        ResultSetMetaData meta = rs.getMetaData();
        int n = meta.getColumnCount();
        
        for (int i = 1; i <=n ; i++) {
            // i = 1 ... n
            String name = meta.getColumnName(i);
            System.out.println(name);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        DBUtils.close(conn);
    }
}

作业:

/**
 * 打印一个SQL查询结果的全部列名
 * @param sql
 */
public static void print(String sql) {
    //...
}

JDBC 实务控制

数据库提供了实务控制功能,支持ACID特性.

JDBC提供了API,方便的调用数据库的实务功能,其方法有:

相关API:

  • Connection.getAutoCommit():获得当前事务的提交方式,默认为true
  • Connection.setAutoCommit():设置事务的的提交属性,参数是
    • true:自动提交;
    • false:不自动提交;
  • Connection.commit():提交事务
  • Connection.rollback():回滚事务

API调用模板:

Connection conn = null;
try {
    conn = DBUtils.getConnection();
    //取消自动提交,后续手动提交
    conn.setAutoCommit(false);
    //SQL... update
    //SQL... update
    // 余额不足 抛出异常 throw e;
    //SQL... update
    conn.commit();
} catch (Exception e) {
    e.printStackTrace();
    DBUtils.rollback(conn);
} finally {
    DBUtils.close(conn);
}

提示:事务API经典的用法是采用如下模板,其中DBUtils.rollback()方法封装了回滚方法,其声明如下:

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

事务测试案例数据:

create table account(
    id int(6),
    name varchar(100),
    balance float(8,2)
);

insert into account (id,name,balance) values (1,'范老师',500);

insert into account (id,name,balance) values (2,'刘老师',1500); 

insert into account (id,name,balance) values (3,'河仙姑',2000);

update account set balance=balance-1000 where id=2;
update account set balance=balance+1000 where id=1;

commit;

rollback;

案例:

public class Demo03 {
    public static void main(String[] args) {
        pay(3,4,200);
        System.out.println("ok");
    }

    public static void pay(int from,int to,double money) {
        String sql1 = "update account set balance=balance+? where id=?";
        String sql2 = "select balance from account where id=?";
        Connection conn = null;
        try {
            conn = DBUtils.getConnection();
            conn.setAutoCommit(false);
            PreparedStatement ps = conn.prepareStatement(sql1);

            //减钱
            ps.setDouble(1, -money);
            ps.setInt(2, from);
            int n = ps.executeUpdate();
            if(n!=1) {
                throw new Exception("扣错了");
            }

            //增加
            ps.setDouble(1, money);
            ps.setInt(2, to);
            n = ps.executeUpdate();
            if(n!=1) {
                throw new Exception("加错了");
            }
            ps.close();

            //检查
            ps = conn.prepareStatement(sql2);
            ps.setInt(1, from);
            ResultSet rs = ps.executeQuery();
            while(rs.next()) {
                double bal = rs.getDouble(1);
                if(bal<0) {
                    throw new Exception("透支");
                }
            }
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            DBUtils.rollback(conn);
        } finally {
            DBUtils.close(conn);
        }
    }
}

批量更新

批量更新的优势

  • 批处理:发送到数据库作为一个单元执行的一组更新语句
  • 批处理降低了应用程序与数据库之间的网络调用
  • 相比单个SQL语句的处理,批处理更为有效
2.png

用法:

  • addBatch(String sql)

    • Statement类的方法,可以将多条sql语句添加Statement对象的SQL语句列表中
  • addBatch()

    • PreparedStatement类的方法,可以将多条预编译的sql语句添加到PreparedStatement对象的SQL语句列表中
  • executeBatch()

    • 把Statemennt对象或PreparedStatemenn对象语句列表中的所有SQL语句发送给数据库进行处理
  • clearBatch()

    • 清空当前SQL语句列表

批量执行DDL

public class Demo04 {
    public static void main(String[] args) {
        String sql1 = "create table log_01(id int(8),msg varchar(100))";
        String sql2 = "create table log_02(id int(8),msg varchar(100))";
        String sql3 = "create table log_03(id int(8),msg varchar(100))";

        // 执行一批SQL
        Connection conn = null;
        try {
            conn = DBUtils.getConnection();
            Statement st = conn.createStatement();

            // sql1 添加到Statement的缓存中
            st.addBatch(sql1);
            st.addBatch(sql2);
            st.addBatch(sql3);

            // 执行一批SQL
            int[] ary = st.executeBatch();
            System.out.println(Arrays.toString(ary));
            System.out.println("OK");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(conn);
        }
    }
}

批量插入数据

public class Demo05 {
    public static void main(String[] args) {
        String sql = "insert into robin_user (id,name,pwd) values (?,?,?)";
        Connection conn = null;
        try {
            conn = DBUtils.getConnection();
            PreparedStatement ps = conn.prepareStatement(sql);
            for (int i = 0; i < 100; i++) {
                //替换参数
                ps.setInt(1, i);
                ps.setString(2, "name"+i);
                ps.setString(3, "123");
                //将参数添加到ps缓冲区
                ps.addBatch();
            }
            //批量执行
            int[] ary = ps.executeBatch();
            System.out.println(Arrays.toString(ary));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtils.close(conn);
        }
    }
}

防止OutOfMemory

  • 如果Preparedstatement对象中的缓存列表包含过多的待处理数据,可能会产生OutOfMerry错误

返回自动主键

JDBC API 提供了返回插入数据期间生成的ID的API,

API方法:

  1. PrepareStatement ps = con.prepareStatement(sql,列名列表);
  2. rs = stmt.getGeneratement();
3.png

create table r_post(
id int(8) auto_increment primary key ,
content varchar(100),
k_id int(8)
);

create table r_keywords(
id int(8) auto_increment primary key,
word varchar(8)
);

需要执行的SQL:

insert into r_keywords (id,word) values (null,?);
insert into r_post (id,content,k_id) values (null,?,?)

案例:

public class Demo06 {
    public static void main(String[] args) {
        Connection conn = null;
        try {
            conn = DBUtils.getConnection();
            conn.setAutoCommit(false);
            String sql = "insert into r_keywords (id,word) values (null,?)";
            String[] cols = {"id"};
            //自动生成序号的列名
            PreparedStatement ps = conn.prepareStatement(sql,cols);
            ps.setString(1, "雾霾");
            int n = ps.executeUpdate();
            if(n!=1) {
                throw new Exception("话题添加失败");
            }
            //获取自动生成的ID
            ResultSet rs = ps.getGeneratedKeys();
            int id = -1;
            while(rs.next()) {
                id = rs.getInt(1);
            }
            rs.close();
            ps.close();

            sql = "insert into r_post (id,content,k_id) values (null,?,?)";
            ps=conn.prepareStatement(sql);
            ps.setString(1, "今天天气不错,晚上有雾霾");
            ps.setInt(2, id);
            n = ps.executeUpdate();
            if(n!=1) {
                throw new Exception("天气太糟");
            }
            conn.commit();
            System.out.println("OK");
        } catch (Exception e) {
            e.printStackTrace();
            DBUtils.rollback(conn);
        } finally {
            DBUtils.close(conn);
        }
    }
}

作业

  1. 设计一个方法打印一个SQL查询结果的全部列名
  2. 利用JDBC事物保护一个汇款业务的完整性
  3. 批量建立10个表,再批量的向每个插入100条数据
  4. 向部门表插入一个数据并且返回自动生成的ID
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,743评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,296评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,285评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,485评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,581评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,821评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,960评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,719评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,186评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,516评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,650评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,329评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,936评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,757评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,991评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,370评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,527评论 2 349

推荐阅读更多精彩内容

  • 非本人总结的笔记,抄点笔记复习复习。感谢传智博客及黑马程序猿记笔记啊记笔记 Hibernate的查询操作 Hibe...
    键盘瞎阅读 465评论 0 1
  • 经验:1.sqlite表中的类型限定并不起作用,底层所有的数据都是String,为了节约手机内存 2.4.0版本以...
    123yuan123阅读 343评论 0 1
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • JDBC概述 在Java中,数据库存取技术可分为如下几类:JDBC直接访问数据库、JDO技术、第三方O/R工具,如...
    usopp阅读 3,533评论 3 75
  • 能够波澜不惊地看着以前那个非常非常喜欢的人,大抵都经历过彻底的失望。 橙子以前是一个很爱撒娇的女孩...
    怀绮阅读 250评论 0 0