day03

JDBC

结果集元数据

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

原理:

day03_第1张图片
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语句的处理,批处理更为有效
day03_第2张图片
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();
day03_第3张图片
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

你可能感兴趣的:(day03)