JDBC 学习笔记

这篇文章是我对李刚老师的《疯狂Java讲义》第三版第十三章:MySQL 数据库与JDBC编程的学习总结。适合有一定SQL基础的同学,如果你还不是很了解SQL,建议去: w3school 熟悉一下SQL的概念和基本语法。本文更专注于数据库在Java程序中的实践。最近刚学会用Github和Hexo来搭建自己的个人博客,有兴趣的朋友可以关注一下,一起探讨技术。

SQL语句基础

语句 内容
查询语句 select
DML(Data Manipulation Language) insert, update, delete
DDL(Data Definition Language) create, alter, drop, truncate
DCL(Data Control Language) grant, revoke

JDBC 常用类

接口/类 解释
Driver Manager 用于管理JDBC驱动
Connection 数据库连接对象
Statement 用于执行SQL语句的工具接口
PreparedStatement 预编译的Statement对象
CallableStatement 用于调用储存过程
ResultSet 结果集对象

JDBC 编程步骤

  1. 加载数据库驱动: Class.forName("com.mysql.jdbc.Driver");

  2. 通过DriverManager获取数据库连接,获得Connection对象:
    jdbc:mysql://hostname:port/databasename

  3. 通过Connection对象创建Statement对象

  4. 使用Statement对象执行SQL语句

  • execute() 可执行任何SQL语句
  • executeUpdate() 用于执行DML和DDL语句。在执行DML语句返回受影响行数,执行DDL语句返回0。
  • executeQuery() 只执行查询语句,返回ResultSet对象
  1. 操作结果集
  • 程序可通过 next(), previous(), first(), last(), beforeFirst(), beforeLast(), afterLast(), absolute()等方法移动记录指针
  • 通过getXXX(column index)获取记录指针指向行、列的值。
  1. 回收数据库资源:关闭ResultSetStatementConnection等资源。

1. 用Properties类来加载属性文件

1.1 属性文件格式

drv = com.mysql.jdbc.Driver
url = jdbc:mysql://hostname:port/databasename
usr = username
pwd = password 

例如下面的配置建立的连接会占用电脑的3306端口,生成一个people_list数据库的Connection对象,我们把这个配置文件命名为mysql.ini并将其放置在项目的根目录中:

drv = com.mysql.jdbc.Driver
url = jdbc:mydql://127.0.0.1:3306/people_list
usr = enzeM
pwd = 1234567

需要注意的是 mysql 在计算机中的默认端口是3306,除非更改mysql的默认端口值,否则把配置文件端口设为其他端口会出现mysql连接异常

1.2 在Java程序中加载属性文件

private String drv;
private String url;
private String usr;
private String pwd;

void initConnFileds(String fileName) throws Exception {
    Properties p = new Properties();
    p.load(new FileInputStream(fileName));
    drv = p.getProperties("drv");
    url = p.getProperties("url");
    usr = p.getProperties("usr");
    pwd = p.getProperties("pwd");
    //step1: load the database
    Class.forName("mysql.ini")  
}

2. 通过JDBC实现数据库的基本操作

2.1 用Statement和execute()写一个可以执行任何SQL语句的函数

使用情境:

  • 不清楚SQL语句类型的情况下可以使用。
  • 使用getString()方法可以取得除Blob之外的任意类型列的值。
void executeSQL(String query) throws Exception {
    //step2: get Connection object
    try(Connection conn = DriverManager.getConnection(url, usr, pwd); 
        Statement stmt = conn.createStatement()) {//step3: get Statement object
        //step4: get ResutSet object
        boolean hasResultSet = stmt.execute(query);
        if(hasResultSet) {
            try(ResultSet rs = stmt.getResutSet()) {
                //use metadata object to visit all possible info from tables
                ResultSetMetaData rsmd = rs.getMetaData();
                int colunmCount = rsmd.getColumnCount();

                //print result after execute the query
                while(rs.next()) {
                    for(int i=0; i

上面的代码使用execute()来执行SQL语句返回了一个boolean值,它表明SQL是否返回了ResultSet对象。然后程序用getResutSet() 获取Statement执行查询语句后的RsultSet。使用getUpdateCount()获取Statement DML语句所影响的记录行数。

2.2 用PreparedStatement执行SQL语句

使用情境:

  • 适用于经常需要反复执行的一条语句
  • 使用占位符?代替需要输入的参数
  • 预编译SQL语句,性能更好
  • 防止SQL注入攻击,安全性高

PreparedStatement对象储存了预编译SQL语句,因此可以高效的反复执行该语句。
若清楚表格的参数类型,我们可以使用
setXXX(int index, XXX value)的方法传入参若不清楚表格的参数类型,我们可以使用setObject()的方法传入参数。接下来,我们在数据库里建一个Employees,然后完成:1)加入新的employee record2)根据ID找出Employee在Table里记录的讯息

CREATE TABLE Employees (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    Name VARCHAR(255) NOT NULL,
    Occupation VARCHAR(255),
    Salary VARCHAR(255)
)
  • 加入新的 employee record:
void insertNewEmployee(String name, String occupation, int salary) throws Exception {
    try(Connection conn = DriverManager.getConnection(url, usr, pwd); 
        PreparedStatement pstmt = conn.preparedStatement("INSERT INTO Employee VALUES(null, ?, ?, ?)")) {
        //pstmt.setXXX(index, value)
        pstmt.setString(1, "Tom");
        pstmt.setString(2, "Java Enginner");
        pstmt.setInt(3, 20000);
        pstmt.executeUpdate();
    }
}

这里的index指的是占位符?的位置,跟数组不同的是,SQL中的index相关的起始位置为1而不是0,比如column也是从0开始的。上面的代码用PreparedStatementsetXXX()方法添加了新的employee record并且在最后使用executeUpdate()更新了Table, 下面的代码实现了根据ID找出Employee在数据库里面的讯息

  • 根据ID找出Employee在Table里记录的讯息:
void findEmployeeBy(int id) throws Exception {
    try(Connection conn = DriverManager.getConnection(url, usr, pwd);
            PreparedStatement pstmt = conn.preparedStatement("SELECT * FROM Employee WHERE ID=?")) {
        pstmt.setInt(1, id); //replace ? to id parameter
        ResultSet rs = pstmt.executeQuery(); //get result set
        //if we know number of column in the table 
        /*
           if(rs.next()) {
           for(int i=0; i<4; i++) {
           System.out.print(rs.getString(i+1)+"\t");
           }
           System.out.println();
           }*/
        //if we do not know abut the table, we use metadata
        ResultSetMetaData rsmd = rs.getMetaData();
        int columnCount = rsmd.getColumnCount();
        if(rs.next()) {
            for(int i=0; i

2.3 用CallableStatement调用储存过程(Procedure)

使用场景:

  • 需要调用数据库中定义的procedure来处理数据

例子:建立一个储存过程:

delimiter //
create procedure diff_salary(a int, b int, out diff int)

begin
set diff = abs(a - b)
end;

以上例子在数据库里定义了一个procedure diff_salary 来计算两个input的差值。我们要通过程序调用这个procedure,需要使用CallableStatement,以下是具体步骤:

  • 使用CallableStatement调用 procedure:
  1. Connection对象的prepareCall()方法生成CallableStatement对象
  2. CallableStatmentsetXXX()为procedure传入参数
  3. rigisterOutParameter()的方法来注册获取储存过程的值
  4. CallStatementexecute()方法来执行储存过程
  5. getXXX(int index)获取指定参数的值
void callDiffSalaryProc(int a, int b) throws Exception {
    try(Connection conn = DriverManager.getConnection(url, usr, pwd); 
            CallableStatment cstmt = conn.prepareCall("{call diff_salary(?, ?, ?)}")) { //注意这里使用的格式
        cstmt.setInt(1, a);
        cstmt.setInt(2, b);
        cstmt.registerOutParameter(3, TYPE.INTEGER);
        cstmt.execute();
        System.out.println("result is:"+cstmt.getInt(3));
    }
}

管理结果集(to be continue)

  • 文章还会继续更新,有不足的地方请指教,或者在我的博客留言。

你可能感兴趣的:(JDBC 学习笔记)