JDBC学习,从入门到入土

95 阅读7分钟

 JDBC引入

JDBC概念:

JDBC是使用Java语言操作关系型数据库的一套API。全称:(Java DataBase Connectivity)Java数据库连接

JDBC的本质:

官方定义的一套操作所有关系型数据库的规则,即接口。

各个数据库厂商去实现这套接口,即提供实现类,这些实现类也叫做驱动, 厂商提供的是相应的数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的是驱动jar包中的实现类。

JDBC的好处:

各数据库厂商使用相同的接口,Java代码不需要针对不同的数据库分别开发。可随时替换底层数据库,访问数据库的Java代码基本不变。

JDBC的使用步骤

有七步,如代码所示:

package JDBC学习;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;

public class test1 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement sta = null;
        try {
            //1 注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");

            //2 获取连接
            String url = "jdbc:mysql://127.0.0.1:3306/limingmao";
            String username = "liergou";
            String password = "liergou070509";
            conn = DriverManager.getConnection(url, username, password);

            //3 定义SQL
            String sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";

            //4 获取执行sql的对象Statement
            sta = conn.createStatement();

            //5 执行sql
            int i = sta.executeUpdate(sql_1);//i为受影响的行数

            //6 处理结果
            System.out.println(i);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //7 释放资源
            try {
                sta.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

注:mysql5.0之后可以省略注册驱动一步。

JDBC API详解

DiverManager

DiverManager(驱动管理类)作用:

  1. 注册驱动
  2. 获取数据库连接

关于DiverManager中的静态方法static Connection getConnection(String url,String user,String password)

参数:

  1. url:连接路径

  1. user:用户名
  2. password:密码

Connection

Connection(数据库连接对象)作用:

  1. 获取执行SQL的对象
  2. 管理事务

获取执行SQL的对象

  • 普通执行SQL对象

Statement createStatement()

  • 预编译SQL的执行SQL对象:防止SQL注入

PreparedStatement preparedStatement(sql)

  • 执行存储变量的对象

CallableStatement prepareCall(sql)

 事务管理

 可以利用JDBC的三个方法来管理事务:

package JDBC学习;

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

public class test2 {
    public static void main(String[] args) {
        Connection conn = null;
        Statement sta = null;
        try {
            //1 注册驱动
            //Class.forName("com.mysql.cj.jdbc.Driver");

            //2 获取连接
            String url = "jdbc:mysql://127.0.0.1:3306/limingmao";
            String username = "liergou";
            String password = "liergou070509";
            conn = DriverManager.getConnection(url, username, password);

            //3 定义SQL
            String sql_1 = "UPDATE emp1 SET salary = 20000 WHERE `name` = 'Tom'";
            String sql_2 = "UPDATE emp1 SET salary = 20000 WHERE `name` = '丘丘人'";

            //4 获取执行sql的对象Statement
            sta = conn.createStatement();

            //开启事务
            conn.setAutoCommit(false);

            //5 执行sql
            int i = sta.executeUpdate(sql_1);//i为受影响的行数
            int j = sta.executeUpdate(sql_2);//i为受影响的行数
            //6 处理结果
            System.out.println(i);
            System.out.println(j);

            //提交事务
            conn.commit();

        } /*catch (ClassNotFoundException e) {
            e.printStackTrace();
        } */catch (SQLException e) {
            //回滚事务
            try {
                conn.rollback();
            } catch (SQLException ex) {
                e.printStackTrace();
            }
            e.printStackTrace();
        } finally {
            //7 释放资源
            try {
                sta.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

先设置MySQL不自动提交事务,在try中末尾处加上提交事务的操作。如果出现异常,说明此异常操作的事务不应该提交,要回滚事务。将回滚事务的操作放在catch中,随着和对异常的处理操作一起进行回滚操作。

Statement

Statement作用:

执行SQL语句。

执行SQL语句

int executeUpdate(sql):执行DML、DDL语句

返回值:①DML语句影响的行数 ②DDL语句执行后,执行成功也可能返回0

ResultSet executeQuery(sql):执行DQL语句

返回值:ResultSet结果集对象

ResultSet

Result(结果集对象)作用:

封装了DQL查询语句的结果

ResultSet executeQuery(sql):执行DQL语句

返回值:ResultSet结果集对象

获取查询结果

boolean next():①将指针从当前位置移动到下一行 ②判断当前行是否为有效行

返回值:true,有效行,当前行有数据;false,无效行,当前行没有数据。

xxx getXxx(参数):获取数据

xxx:数据类型。如int getInt()、String getString(参数)

参数:int,列的编号,从1开始。String:列的名称。

使用

使用时通常会用上while循环

while(…….next()){

……

…….getXxx(参数);

}

例:查询员工表emp1中的数据并打印。

@Test
void test3() {
    Connection conn = null;
    Statement sta = null;
    ResultSet rs = null;
    try {
        //获取连接(注册驱动已省略)
        String url = "jdbc:mysql:///limingmao";
        String username = "liergou";
        String password = "liergou070509";
        conn = DriverManager.getConnection(url,username,password);
        //定义SQL语句
        String sql_1 = "select * from emp1";
        //获取statement对象
        sta = conn.createStatement();
        //执行sql
        rs = sta.executeQuery(sql_1);
        //处理结果,遍历查询的所有结果
        while(rs.next())
        {
            int id = rs.getInt("id");
            String name = rs.getString(2);
            Date date = rs.getDate(3);
            double salary = rs.getDouble("salary");

            System.out.print(id + "\t");
            System.out.print(name + "\t");
            System.out.print(date + "\t");
            System.out.print(salary + "\t");
            System.out.println();
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        //释放资源
        try {
            rs.close();
            sta.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

还可以使用其查询数据做Java代码的处理,例:将员工的sal添加到一个Arraylist中。

@Test
void test4() {
    Connection conn = null;
    Statement sta = null;
    ResultSet rs = null;
    try {
        //获取连接(注册驱动已省略)
        String url = "jdbc:mysql:///limingmao";
        String username = "liergou";
        String password = "liergou070509";
        conn = DriverManager.getConnection(url,username,password);
        //定义SQL语句
        String sql_1 = "select salary from emp1";
        //获取statement对象
        sta = conn.createStatement();
        //执行sql
        rs = sta.executeQuery(sql_1);
        //处理结果,遍历查询的所有结果
        ArrayList<Double> sal = new ArrayList<>();
        while(rs.next())
        {
            double salary = rs.getDouble("salary");
            sal.add(salary);
        }
        Iterator ii = sal.iterator();
        while (ii.hasNext())
        {
            System.out.println(ii.next());
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        //释放资源
        try {
            rs.close();
            sta.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

例:将员工的信息添加到一个Arraylist中。

@Test
void test5() {
    Connection conn = null;
    Statement sta = null;
    ResultSet rs = null;
    try {
        //获取连接(注册驱动已省略)
        String url = "jdbc:mysql:///limingmao";
        String username = "liergou";
        String password = "liergou070509";
        conn = DriverManager.getConnection(url,username,password);
        //定义SQL语句
        String sql_1 = "select * from emp1";
        //获取statement对象
        sta = conn.createStatement();
        //执行sql
        rs = sta.executeQuery(sql_1);
        //处理结果,遍历查询的所有结果
        ArrayList<Employee> employees = new ArrayList<>();
        while(rs.next())
        {
            int id = rs.getInt(1);
            String name = rs.getString("name");
            Date date = rs.getDate(3);
            double salary = rs.getDouble("salary");
            employees.add(new Employee(id,name,date,salary));
        }
        Iterator ii = employees.iterator();
        while (ii.hasNext())
        {
            System.out.println(ii.next());
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        //释放资源
        try {
            rs.close();
            sta.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

PreparedStatement

PreparedStatement作用:

预编译SQL语句并执行:预防SQL注入问题

SQL注入

即利用SQL语句的语法,在填入时,强制查询结果为true。

操作

①获取PrepareStatement对象

//SQL语句中的参数值,使用?占位符替代
String sql = "SELECCT * FROM user WHERE username = ? AND password = ?";

//通过Connection对象获取,并传入相应的SQL语句。
PreparedStatement psta = conn.prepareStatement(sql);

②设置参数值

PreparedStatement对象:setXxx(参数1,参数2):给?赋值

Xxx指的是数据类型,参数1是?的顺序编号,从一开始。参数2是?的具体的值。

③执行SQL

使用:executeUpdate()/executeQuery():不需要再传入SQL语句。

例:

@Test
void test7()
{
    Connection conn = null;
    PreparedStatement psta = null;
    ResultSet rs = null;
    try {
        //获取连接
        String url = "jdbc:mysql:///limingmao";
        String username = "liergou";
        String password = "liergou070509";
        conn = DriverManager.getConnection(url,username,password);

        //接收用户输入的用户名和密码
        String uname = "张三";
        String pwd = "1234";
        //定义SQL
        String sql = "SELECT * FROM tb_user WHERE username = ? AND password = ?";
        //获取psta对象
        psta = conn.prepareStatement(sql);
        //设置?的值
        psta.setString(1,uname);
        psta.setString(2,pwd);
        //执行SQL语句
        rs = psta.executeQuery();
        //判断是否成功
        if(rs.next()) {
            System.out.println("登录成功");
        }else {
            System.out.println("登录失败");
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        try {
            //释放资源
            rs.close();
            psta.close();
            conn.close();

        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

PreparedStatement原理

  1. 在获取PreparedStatement对象时,将SQL语句发送给MySQL服务器进行检查、编译
  2. 执行时就不用再进行这些步骤了,速度更快
  3. 如果SQL模板一样,则只需要进行一次检查、编译

PreparedStatement好处:

  1. 预编译SQL,性能更高
  2. 防止SQL注入:将敏感字符进行转义

开启预编译功能:

userServerPrepStmts=true:将此参数键值对放到url的参数键值对处。

数据库连接池

简介

数据库连接池是个容器,负责分配、管理数据库连接(Connection)

它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏

好处:

  • 资源重用
  • 提升系统响应速度
  • 避免数据库连接遗漏

数据库连接池实现

标准接口:DataSource

官方提供的数据库连接池标准接口,由第三方组织实现此接口。

功能:获取连接

Connection getConnection()

常见的数据库连接池:

  • DBCP
  • C3P0
  • Druid

Druid(德鲁伊)

Druid连接池是阿里巴巴开源的数据库连接池项目

功能强大,性能优秀,是Java语言最好的数据库连接池之一

使用步骤以及代码实现如下:

public class test_druid {
    public static void main(String[] args){
        try {
            //加载配置文件
            Properties prop = new Properties();
            prop.load(new FileInputStream("D:\李明茂\Java学习\JDBC\src\druid.properties"));
            //获取连接池对象
            DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
            //获取数据库连接Connection
            Connection conn = dataSource.getConnection();
            System.out.println(conn);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}