java Jdbc 编程之编写Jdbc工具类,事务和批处理

目录

编写Jdbc工具类

由于每个Jdbc程序都需要连接数据库和关闭资源,因此可以将它们封装中一个工具类方便调用

代码

package com.thinknet.jdbc;

import java.io.FileReader;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

public class JdbcUtils {
    private static String user;
    private static String password;
    private static String driver;
    private static String url;
    static {
        try {
            //读取配置文件建立连接
            Properties properties = new Properties();
            properties.load(new FileReader("src/mysql.properties"));
            user = properties.getProperty("user");
            password=properties.getProperty("password");
            driver=properties.getProperty("driver");
            url=properties.getProperty("url");
            Class.forName(driver);

        } catch (IOException | ClassNotFoundException e) {
            //最好将编译异常转成运行时异常,调用者可以选择捕获异常进行处理,也可默认处理
            throw  new  RuntimeException(e);
        }


    }
    public static Connection getConnection(){
        //返回连接
        try {
            return DriverManager.getConnection(url,user,password);
        } catch (SQLException e) {
            //转换成运行时异常
            throw new RuntimeException(e);
        }
    }
    public static void close(ResultSet resultSet, Statement statement ,Connection connection){
        //如果不为null就关闭连接
        try {
            if(resultSet!=null){
                resultSet.close();
            }
            if(statement!=null){
                statement.close();
            }
            if(connection!=null){
                connection.close();
            }
        } catch (SQLException e) {
            //转成运行时异常
            throw new RuntimeException(e);
        }
    }

}

应用:

用Jdbc工具类连接数据库,查询,更新数据库

package com.thinknet.jdbc;

import java.sql.*;

/**
 * 使用Jdbc工具类
 */
public class JdbcUtilsUse {
    public static void main(String[] args) {
        //更新数据库
       // update();
        //查询数据库
        select();
    }
    public static void update(){
        String sql="update actor set `name`=? where `id`=?";
        //获取连接
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        try {
             connection = JdbcUtils.getConnection();//调用工具类获取连接
             preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"king");
            preparedStatement.setInt(2,1);
            preparedStatement.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(null,preparedStatement,connection);//调用工具类关闭资源
        }


    }
    public static void select(){
        String sql="select `id`,`name`,`sex`,`borndate`,`phone` from `actor`";
        
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        ResultSet resultSet=null;
        try {
            connection=JdbcUtils.getConnection();//调用工具类获取连接
            preparedStatement = connection.prepareStatement(sql);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()){
                int id = resultSet.getInt("id");
                String name = resultSet.getString("name");
                String sex = resultSet.getString("sex");
                Date borndate = resultSet.getDate("borndate");
                String phone = resultSet.getString("phone");
                System.out.println("\t"+id+"\t"+name+"\t"+sex+"\t"+borndate+"\t"+phone+"\t");
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(resultSet,preparedStatement,connection);//调用工具类关闭资源
        }
    }
}

事务处理

基本介绍:

  1. 在jdbc程序中当一个Connection对象创建时,默认情况下是自动提交事务:每次执行一条sql语句,如果执行成功,就会向mysql数据库自动提交 而不能回滚.
  2. Jdbc程序为了让多条sql语句作为一个整体执行,需要使用事务.
  3. 调用Connection对象的setAutoCommit(false)可以取消自动提交事务.
  4. 在所有SQL语句成功执行后调用Connection对象的commit()方法提交事务.
  5. 在某个sql语句执行失败或出现异常时,调用rollback()方法回滚事务

案例:

 public static void transferAccounts()  {
        String sql1 ="update `account` set balance = balance-1000 where id= ?";
        String sql2="update `account` set balance=balance+1000 where id=?";
        double money=1000;
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        try {
            connection=JdbcUtils.getConnection();
            connection.setAutoCommit(false); //开启了事务
            preparedStatement=connection.prepareStatement(sql1);
            preparedStatement.setInt(1,1);
            preparedStatement.executeUpdate();
            preparedStatement=connection.prepareStatement(sql2);

            preparedStatement.setInt(1,2);
            preparedStatement.executeUpdate();
            connection.commit(); //当所有任务执行完后提交事务
        } catch (SQLException e) {
            try {
                connection.rollback(); //如果在执行sql语句的过程中出现了异常,回滚事务
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            JdbcUtils.close(null,preparedStatement,connection); //关闭资源
        }
    }

上面的代码模拟了转账操作,转账的过程应该视为一个整体,一个人的账户金额少了多少,令一个人就应该多多少,不能一个人的账户金额少了,另一个人的账户金额却不增加,这就要求出账的sql语句和进账的SQL语句应该同时成功,或同时失败,不能一个成功,一个失败.所以要用到事务,只有都成功了,才真正改变数据库,否则就回滚事务

批处理

基本介绍:

  1. 当需要成批插入或更新记录时,可使用java的批量更新机制,该机制允许多条语句一次提交给数据库批量处理,通常情况下,比单独提交更有效率
  2. Jdbc批处理包含下面方法:
    addBatch():添加需要批处理的SQL语句或参数
    executeBatch(): 执行批量处理语句
    clearBatch(): 情况批处理包的语句
  3. Jdbc连接mysql时,向要用批处理,要在url加上参数?rewriteBatchedStatements=true
  4. 批处理往往和PreparedStatement一起搭配使用,可以既减少编译次数,又减少运行次数,效率大大提高

案例:

不进行批处理:

 public static void noBatch()  {
        String sql="insert into admin2 values(?,?)";
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        //获取连接
        try {
            connection = JdbcUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            long state=System.currentTimeMillis();
            for (int i=1;i<=5000;i++){
                preparedStatement.setString(1,"jack"+i);
                preparedStatement.setString(2,"666");
                preparedStatement.executeUpdate();
            }
            long end=System.currentTimeMillis();
            System.out.println("耗时: " + (end-state)+ " ms");//耗时: 3340 ms
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(null,preparedStatement,connection);
        }

    }

输出:

耗时: 3340 ms

批处理:

public static void Batch() {
        //注意:要在url上加参数?rewriteBatchedStatements=true
        String sql="insert into admin2 values(?,?)";
        Connection connection=null;
        PreparedStatement preparedStatement=null;
        //获取连接
        try {
            connection = JdbcUtils.getConnection();
            preparedStatement = connection.prepareStatement(sql);
            long state=System.currentTimeMillis();
            for (int i=1;i<=5000;i++){
                preparedStatement.setString(1,"jack"+i);
                preparedStatement.setString(2,"666");
                //添加需要批处理的SQL语句或参数
                //1. 第一次进入后创建ArrayList() ->elementData->Object[]
                //2. 接着将预处理后的SQL语句放入Object[]中
                //3. 如果满了,就按1.5倍扩容
                //4. 到达指定的数就executeBatch
                //5. 批处理会大大减少发送sql语句的网络开销,减少编译次数,效率提高
               /*源码:
                public void addBatch() throws SQLException {
                    synchronized(this.checkClosed().getConnectionMutex()) {
                        if (this.batchedArgs == null) {
                            this.batchedArgs = new ArrayList();
                        }

                        for(int i = 0; i < this.parameterValues.length; ++i) {
                            this.checkAllParametersSet(this.parameterValues[i], this.parameterStreams[i], i);
                        }

                        this.batchedArgs.add(new com.mysql.jdbc.PreparedStatement.BatchParams(this.parameterValues, this.parameterStreams, this.isStream, this.streamLengths, this.isNull));
                    }
                }
                */
                preparedStatement.addBatch();
                if(i%1000==0){ //没以前条处理一次
                    //执行批量处理语句
                    preparedStatement.executeBatch();
                    //清空批处理包的语句
                    preparedStatement.clearBatch();

                }
                else if (5000-i<1000){ //处理不足sql语句1000条的情况
                    //执行批量处理语句
                    preparedStatement.executeBatch();
                    //清空批处理包的语句
                    preparedStatement.clearBatch();
                }
            }
            long end=System.currentTimeMillis();
            System.out.println("耗时: " + (end-state)+ " ms");//耗时: 924 ms
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JdbcUtils.close(null,preparedStatement,connection);
        }

    }

输出:

耗时: 924 ms

上面的代码是向表中插入5000条数据,不进行批处理和批处理的情况下的时间消耗,可以开到批处理比不进行批处理要快一些.

全部评论

相关推荐

10-11 17:30
湖南大学 C++
我已成为0offer的糕手:羡慕
点赞 评论 收藏
分享
不愿透露姓名的神秘牛友
10-05 10:13
已编辑
HHHHaos:让这些老登来现在秋招一下,简历都过不去
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务