使用JDBC连接数据库

本文测试程序使用MySQL数据库,不同数据库的驱动和URL格式有所差异。

一、使用JDBC连接数据库的步骤
  • 加载数据库驱动
//动态加载mysql驱动
Class.forName("com.mysql.cj.jdbc.Driver");
  • 配置URL
String url = "jdbc:mysql://localhost:3306/study?user=root&password=@@@zxm&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false";
  • 获取数据库连接
//获取连接
Connection connection = DriverManager.getConnection(url);
  • 获取Statement,Statement对应一条SQL语句
connection.createStatement();//获取一般Statement
connection.prepareStatement(sql);//获取预编译Statement
二、使用一般方法查询数据
public void testSelect() {
    try {
        String sql = "select * from tb_test t where t.content like '%6%'";
        Statement statement = connection.createStatement();
        ResultSet result = statement.executeQuery(sql);
        while(result.next()) {
            //通过result迭代可以获取每一行数据
            System.out.println(result.getInt(1) + ", " + result.getString(2));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
三、使用预编译SQL语句查询数据

当同一句SQL需要反复执行很多次的时候,我们可以使用预编译的SQL来提升执行效率,即PreparedStatement。

  • 缓存PreparedStatement并重复使用的用法
//预编译的SQL语句对象
private PreparedStatement statement1;

//对SQL语句进行预编译,如果statement1不为null,则无需再次编译
private void loadStatment() throws SQLException{
    if (null != statement1) return;
    String sql = "select * from tb_test t where t.content like ?";
    statement1 = connection.prepareStatement(sql);
}

//使用预编译的SQL语句查询数据
public void testPreparedSelect(String parameter) {
    try {
        loadStatment();
        //对预编译的SQL语句中需要的参数赋值
        statement1.setString(1, "%" + parameter + "%");
        statement1.executeQuery();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
  • PreparedStatement用完即销毁的用法,这种用法每次调用查询函数时,都会重新创建一个PreparedStatement,与直接Statement没有区别,不能获得效率上的提升,但是赋值相比Statement更加方便了,也比缓存PreparedStatement的用法节省内存开销,并且因为SQL语句是预编译的,可以有效防止SQL注入式攻击
public void testPreparedSelect2(String parameter) {
    try {
        String sql = "select * from tb_test t where t.content like ?";
        PreparedStatement statement = connection.prepareStatement(sql);
        statement.setString(1, "%" + parameter + "%");
        statement.executeQuery();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}
四、几种用法的效率简单对比
  • 我们使用三种方式对同一个SQL语句查询100000次,记录各自花费时间
package com.baymax.study;

import java.util.Date;

import com.baymax.study.tester.JDBCTester;

public class Main 
{
    public static void main( String[] args )
    {
        //在执行查询时,进程所占用的内存会持续增大,三个函数均执行时,后面的函数会因为内存不足异常缓慢,暂时不清楚为什么会出现这种情况,感觉是内存泄漏
        //分别执行,各组所花费的时间为29.639s,13.312s,29.685s
        //可以看出使用Statement和不重复使用PreparedStatement效率大同小异,而重复使用PreparedStatement预编译SQL语句,效率提升显著
        JDBCTester jdbcTester = new JDBCTester();
        test1(jdbcTester);
        test2(jdbcTester);
        test3(jdbcTester);
    }

    private static void test1(JDBCTester jdbcTester) {
        long start = new Date().getTime();
        for (int i = 0; i < 100000; i++) {
            jdbcTester.testSelect();
        }
        long end = new Date().getTime();
        System.out.println((end-start)/1000.0);
    }

    private static void test2(JDBCTester jdbcTester) {
        long start = new Date().getTime();
        for (int i = 0; i < 100000; i++) {
            jdbcTester.testPreparedSelect("6");
        }
        long end = new Date().getTime();
        System.out.println((end-start)/1000.0);
    }

    private static void test3(JDBCTester jdbcTester) {
        long start = new Date().getTime();
        for (int i = 0; i < 100000; i++) {
            jdbcTester.testPreparedSelect2("6");
        }
        long end = new Date().getTime();
        System.out.println((end-start)/1000.0);
    }
}
  • JDBCTester完整代码
package com.baymax.study.tester;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;

public class JDBCTester {
    private Connection connection;
    public JDBCTester() {
        loadConnection();
    }
    private void loadConnection(){
        try {
            String url = "jdbc:mysql://localhost:3306/study?user=root&password=@@@zxm&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&useSSL=false";
            Class.forName("com.mysql.cj.jdbc.Driver");//动态加载mysql驱动
            connection = DriverManager.getConnection(url);//获取连接
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //使用Statement,不对SQL进行预编译
    public void testSelect() {
        try {
            String sql = "select * from tb_test t where t.content like '%6%'";
            Statement statement = connection.createStatement();
            statement.executeQuery(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    //将PreparedStatement对象缓存,避免重复初始化,这样使用在执行频率相当高时,可以获得极大的效率提升
    private PreparedStatement statement1;
    private void loadStatment() throws SQLException{
        if (null != statement1) return;
        String sql = "select * from tb_test t where t.content like ?";
        statement1 = connection.prepareStatement(sql);
    }
    public void testPreparedSelect(String parameter) {
        try {
            loadStatment();
            statement1.setString(1, "%" + parameter + "%");
            statement1.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /*这样使用PreparedStatement类似于使用Statement,每次调用函数都会进行初始化,所以并不会获得效率上的提升。
    优点:
    1、可以让你更方便地对参数进行赋值;
    2、每次用完就将PreparedStatement销毁,也可以节约内存,对于执行频率不高的SQL语句,是一种不错的选择;
    3、使用预编译SQL可以有效防止SQL注入式攻击;*/
    public void testPreparedSelect2(String parameter) {
        try {
            String sql = "select * from tb_test t where t.content like ?";
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.setString(1, "%" + parameter + "%");
            statement.executeQuery();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}
五、批量操作

在进行增删改操作时,可以使用PreparedStatement进行批量操作来提升效率。

private PreparedStatement statement2;
private void loadStatment2() throws SQLException {
    if (null != statement2) return;
    String sql = "insert into tb_test (id, content) values (?, ?)";
    statement2 = connection.prepareStatement(sql);
}
public int[] testBatchInsert(List<Map<String, Object>> parameters) {
    try {
        loadStatment2();
        for (Map<String, Object> parameter : parameters) {
            //循环添加批量任务
            statement2.setInt(1, (Integer) parameter.get("id"));
            statement2.setString(2, (String) parameter.get("content"));
            statement2.addBatch();
        }
        //批量执行,results为各条sql执行后影响行数的集合
        int[] results = statement2.executeBatch();
        connection.commit();
        return results;
    } catch (SQLException e) {
        e.printStackTrace();
    }
    return null;
}
六、调用存储过程
  • 调用无参存储过程
public void testCallProcedureWithoutParameter() throws SQLException {
    CallableStatement statement = connection.prepareCall("{call pro_test()}");
    statement.execute();
}
  • 调用有输入参数存储过程
public void testCallProcedureWithInParameter(int id) throws SQLException {
    CallableStatement statement = connection.prepareCall("{call pro_test(?)}");
    statement.setInt(1, id);//给入参赋值
    statement.execute();
}
  • 调用有入参出参存储过程
public String testCallProcedureWithInOutParameter(int id) throws SQLException {
    CallableStatement statement = connection.prepareCall("{call pro_test(?,?)}");
    statement.setInt(1, id);//给入参赋值
    statement.registerOutParameter(2, Types.CHAR);//注册输出参数类型
    statement.execute();
    return statement.getString(2);//根据索引获取输出参数值
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值