数据库之使用JDBC访问数据库

本篇文章主要介绍使用JDBC连接数据库,少量内容是笔者在学习《数据库系统概念》时摘抄的,当作笔记。

一个应用程序通常包括很多部分,查询或更细数据只是其中之一,而其他部分则需要使用通用设计语言实现。对于集成应用来说,必须用某种方法把SQL与通用程序语言结合起来。

我们可以使用动态SQL从通用编程语言中访问SQL。即通过函数或方法来连接数据库服务器并与之交互,利用动态SQL可以在运行时以字符串形式构建SQL查询,提交查询,然后把结果存入程序变量中,每次一个元组。动态SQL的SQL组件允许程序在运行时构建和提交SQL查询。

而把SQL与通用程序语言相结合的最大挑战是:这些语言处理数据的方式互不兼容。在SQL中,数据的主要类型是关系。SQL语句在关系上进行操作,并返回关系作为结果。程序设计语言通常一次操作一个变量,这些变量大致相当于关系中一个元组的一个属性的值。因此,为了在同一应用中整合这两类语言,必须提供一种转换机制,使得程序语言可以处理查询的返回结果。

JDBC标准定义了Java程序连接数据库服务器的应用程序接口(Application Program Interface,API),JDBC原来是Java数据库连接(Java Database Connectivity)的缩写,但现在已经不用了。

在学习使用JDBC接口连接数据库之前必要的一步是了解要用到的API。

DriverManager

DriverManager是用于管理一组JDBC驱动的基础服务。其内部维护了一个已注册驱动列表,在获取数据库连接时,DriverManager会尝试从初始化时加载的驱动或者手动加载的驱动中查找合适的驱动程序。

//向DriverManager注册给定驱动程序
public static synchronized void registerDriver(java.sql.Driver driver);
//从DriverManager的驱动列表中删除指定的驱动程序
public static synchronized void deregisterDriver(Driver driver);
//尝试获取数据库连接
public static Connection getConnection(String url,java.util.Properties info);
//尝试获取数据库连接
public static Connection getConnection(String url,String user, String password);
//尝试获取数据库连接
public static Connection getConnection(String url);
//从已注册的驱动中通过url获取驱动程序
public static Driver getDriver(String url);
//获取调用者可以获取的驱动的枚举
public static java.util.Enumeration<Driver> getDrivers();
//获取日志writer
public static java.io.PrintWriter getLogWriter();
//将一条消息打印到JDBC日志流中
public static void println(String message);
//设置驱动程序连接数据库时等待的最长时间,单位是秒
public static void setLoginTimeout(int seconds);
//设置DriverManager和所有驱动程序使用的日志PrintWriter对象
public static void setLogWriter(java.io.PrintWriter out);

我们最常使用的是使用getConnection()方法获取数据库连接,参数中的url格式如下:

jdbc:mysql(以mysql数据库举例)://host:port/数据库名?参数名1=参数值1&参数名2=参数值2;
例如:
jdbc:mysql://localhost:3306/country?useUnicode=true&characterEncoding=gbk;

在调用getConnection()方法时,其方法内部会遍历所有的已注册的驱动使用传递的url尝试去连接数据库,直到连接成功并返回Connection实例。可以看出真正连接数据库的是驱动类Driver,而每个数据库厂商都提供了一套自己内部实现,我们只需要使用JDBC就可以了。

Connection

Connection对象代表对特定数据库的连接,可以执行SQL语句并返回结果。

//立刻释放此Connection对象的数据库和JDBC资源
void close();
//创建一个Statement对象
Statement createStatement();
//提交事务,并释放此Connection对象保存的所有数据库锁
void commit();
//检查当前连接是否关闭
boolean isClosed();
//创建一个PreparedStatement对象,用于将参数化的SQL语句发送到数据库
PreparedStatement prepareStatement(String sql);
//撤销在当前事务中做的所有更改,并释放该Connection持有的数据库锁
void rollback();
//创建一个CallableStatement对象,用于调用数据库存储过程
CallableStatement prepareCall(String sql);

Statement

一个Statement对象表示原始语句,而Statement对象又分为三种,分别为Statement、PreparedStatement和CalleableStatement,他们主要区别如下:

  1. Statement:用于执行简单的不带参数的SQL语句,每次执行SQL语句数据库都要编译该SQL语句,单次查询返回结果的情形效率高;
  2. PreparesStatement:继承自Statement,但支持可变参数和预编译SQL语句,可防止SQL注入问题;
  3. CallableStatement:继承自PreparedStatement,支持调用存储过程和输入输出参数。

我们依次来看一下Statement和PreparedStatement的主要API。

Statement:

//释放该Statement对象的数据库和JDBC资源
void close();
//执行给定的SQL语句
boolean execute(String sql);
//将一批命令提交到数据库执行,返回一个更新计数的数组
int[] executeBatch();
//指定给定的SQL语句,并返回ResultSet对象
ResultSet executeQuery(String sql);
//指定给定的SQL语句,可能是INSERT、UPDATE或DELETE语句
int executeUpdate(String sql);
//获取生成此Statement对象的Connection对象
Connection getConnection();

PreparedStatement:

//清除当前参数值
void clearParameters();
//执行此PreparedStatement对象中的SQL语句,可以是任何类型的SQL
boolean execute();
//执行此PreparedStatement对象中的查询语句,并返回ResultSet对象
ResultSet executeQuery();
//执行此PreparedStatement对象中的DML语句,如INSERT、UPDATE或DELETE语句,或不返回内容的DDL语句
int executeUpdate();
//将指定的参数设置为给定的int值,类似的还有double,long,object等等
void setInt(int parameterIndex, int x);

ResultSet

表示数据库的结果集,包含所有符合SQL的记录。ResultSet提供了一套可以访问到全部结果集记录的方法。

//将光标移到此ResultSet对象中指定的行号
boolean absolute( int row );
//释放此ResultSet的数据库和JDBC资源
void close();
//从此ResultSet对象和底层数据库中删除当前行
void deleteRow();
//获取当前行行号
int getRow();
//获取生成此ResultSet对象的Statement对象
Statement getStatement();
//将光标从当前位置向前移动一行
boolean next();
//将光标移到此ResultSet对象的上一行
boolean previous();
//获取当前行指定属性的值
String getString(String columnLabel);

连接数据库

public class Test5 {
    public static void main(String[] args){

        String url = "jdbc:mysql://127.0.0.1:3306/country?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8";
        String user = "root";
        String password = "root";

        //获取数据库连接,即Connection对象
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            conn = DriverManager.getConnection(url,user,password);
            //创建Statement对象,此处使用PreparedStatement
            ps = conn.prepareStatement("SELECT * FROM cityWHERE province_id = ?");
            ps.setInt(1,130000);
            //执行此Statement对象中的SQL语句并返回ResultSet对象
            rs = ps.executeQuery();
            System.out.println("河北省包括以下城市:");
            while (rs.next()) {
                System.out.println("城市id为:"+rs.getInt("city_id")+" 城市名称为:"+rs.getString("city_name"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            close(conn,ps,rs);
        }
    }

    //释放资源
    private static void close(Connection conn,PreparedStatement ps,ResultSet rs){
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (ps != null) {
            try {
                ps.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

在以上代码中我没有用Class.forName()方法显示加载MySQL驱动,因为JDBC4之后会自行加载驱动,但需要我们把MySQL驱动添加到当前项目依赖jar包中。另外,释放资源的顺序应该是与声明相反的。

输出结果如下:

河北省包括以下城市:
城市id为:130101 城市名称为:石家庄市
城市id为:130201 城市名称为:唐山市
城市id为:130301 城市名称为:秦皇岛市
城市id为:130401 城市名称为:邯郸市
城市id为:130501 城市名称为:邢台市
城市id为:130601 城市名称为:保定市
城市id为:130701 城市名称为:张家口市
城市id为:130801 城市名称为:承德市
城市id为:130901 城市名称为:我的家乡
城市id为:131001 城市名称为:廊坊市
城市id为:131101 城市名称为:衡水市

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值