jdbc之批处理

来源:互联网 发布:盐城大数据产业园官网 编辑:程序博客网 时间:2024/06/08 03:36

批操作可以一次性向数据库端发送若干SQL语句,从而减少与数据库服务端的网络通信,提高执行效率。
当大批量执行SQL语句时,影响效率的三个因素:
1:事务,事务越多速度越慢(事务最好一次提交);
2:网络调用,网络调用越多速度越慢(这里可以使用缓存解决);
3:Statement,PreparedStatement的选用,因为执行计划越多效率越慢。

关于第三点,做过测试,选用PrepareStatement效率明显比Statement高,因为用它只生成一次执行计划,后面传参使用同一个计划。就好像java程序中定义方法,动态信息被定义为参数,多次调用方法传入不同参数即可,但是方法不用每次都重新定义。

关于第一点,可以不让事务自动提交(默认事务是自动提交的,比如prepareStatement.executeUpdate()执行后事务就是自动提交了的,关于事务的问题也讲过,这样在出现异常事务却提交了,没有保证一致性,有时候会存在很大问题),最后事务一次提交。
关于第三点,使用缓存解决,添加一个批操作,将很多sql语句缓存在本地,最后语句一次性发送给数据库服务端,这样做可以有效的减少网络调用次数,提高与数据库服务端的通讯效率。

需求:向数据库中userinfo表插入10000条数据
自动提交事务,不添加缓存测试:

public class JDBCBatch {    public static void main(String[] args) {        Connection connection = null;        Statement statement = null;        try {            connection = DBUtil.getConnection();            statement = connection.createStatement();            long start =new Date().getTime();            System.out.println("开始前:"+start);            for (int i = 0; i < 10000; i++) {                String sql="INSERT INTO userinfo "                        + "VALUES "                        + "(seq_userinfo_id.NEXTVAL,'test"+i+"','123456',"                        + "5000,'test"+i+"@tedu.cn')";                //立刻将SQL发送至数据库服务端                statement.executeUpdate(sql);            }            System.out.println("结束用时:"+(new Date().getTime()-start));        } catch (Exception e) {        }finally {            DBUtil.closeConnection();        }    }}
输出:开始前:1502871180710结束用时:10757

使用以上给出的解决方案:

public class JDBCDemo2 {    public static void main(String[] args) {        Connection connection = null;        PreparedStatement pStatement;        try {            connection = DBUtil.getConnection();            connection.setAutoCommit(false);            String sql="INSERT INTO userinfo "                    + "VALUES "                    + "(seq_userinfo_id.NEXTVAL,?,'123456',5000"                    + ",?)";            pStatement = connection.prepareStatement(sql);            long time = new Date().getTime();            for (int i = 0; i < 10000; i++) {                pStatement.setString(1, "aa"+i);                pStatement.setString(2, "scu@qq.com"+i);                pStatement.addBatch();            }            pStatement.executeBatch();            System.out.println("用时:"+(new Date().getTime() - time));            //清空本地缓存            pStatement.clearBatch();            connection.commit();        } catch (Exception e) {            try {                connection.rollback();            } catch (SQLException e1) {                e1.printStackTrace();            }            e.printStackTrace();        }finally {            DBUtil.closeConnection();        }    }}
输出:用时:103

结果:
一个用时10757ms一个用时103ms,效率得到了极大的提高。
注:虽然说应该用控制变量法,但是为了方便就一起测了,自己可以分别测试。三种方案都能提供效率。

Api:connection.setAutoCommit(false):事务自动提交关闭connection.commit():提交事务connection.rollback():回滚事务pStatement.addBatch():添加批操作(相对于缓存至本地)pStatement.executeBatch():执行批操作pStatement.clearBatch():清空本地缓存

DBUtil是个自己封装的工具类,能获取和关闭连接

public class DBUtil {    private static String driver;    private static String url;    private static String username;    private static String password;    private static String maxactive;    private static String maxwait;    //数据库连接池    private static BasicDataSource dateSource;    private static ThreadLocal<Connection> tl;    static{        try {            tl = new ThreadLocal<>();            //加载配置文件            Properties properties = new Properties();            properties.load(new FileInputStream(new File("D:\\测试\\jdbc\\src\\config.properties")));            //读取配置文件,初始化成员变量            driver = properties.getProperty("driver");            url = properties.getProperty("url");            username = properties.getProperty("username");            password = properties.getProperty("password");            maxactive = properties.getProperty("maxactive");            maxwait = properties.getProperty("maxwait");            //测试初始化是否成功            System.out.println(driver);            System.out.println(url);            System.out.println(username);            System.out.println(password);            System.out.println(maxactive);            System.out.println(maxwait);            dateSource = new BasicDataSource();            dateSource.setDriverClassName(driver);            dateSource.setUrl(url);            dateSource.setUsername(username);            dateSource.setPassword(password);            dateSource.setMaxActive(new Integer(maxactive));            dateSource.setMaxWait(new Integer(maxwait));        } catch (Exception e) {            //静态方法块里面是不能抛出异常的            e.printStackTrace();        }    }    /*     * 从连接池获取数据库连接     */    public static Connection getConnection() throws Exception{        Connection connection = dateSource.getConnection();        tl.set(connection);        return connection;    }    public static void closeConnection(){        Connection conn=tl.get();        if(conn!=null){            try {                //这个时候用的是连接池的close,其他方法是oracle的,                //连接池只是起了代理的做用                conn.close();                tl.remove();            } catch (SQLException e) {                e.printStackTrace();            }        }    }    /*     * 关闭连接     */    public static void closeConnection(Connection connection,Statement statement,ResultSet resultSet){        if(resultSet != null){            try {                resultSet.close();            } catch (SQLException e) {                e.printStackTrace();            }        }        if(statement != null){            try {                statement.close();            } catch (SQLException e) {                e.printStackTrace();            }        }        if (connection != null) {            try {                connection.close();            } catch (SQLException e) {                e.printStackTrace();            }        }    }}
原创粉丝点击