JDBC

JDBC 全称:( Java DataBase Connectivity ) Java 数据库连接

1.概述

  • 官方(sun公司)定义的一套操作所有关系型数据库的规则,即接口
  • 各个数据库厂商去实现这套接口,提供数据库驱动jar包
  • 我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类

优点

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

以后编写操作数据库的代码只需要面向JDBC(接口),操作哪儿个关系型数据库就需要导入该数据库的驱动包,如需要操作MySQL数据库,就需要再项目中导入MySQL数据库的驱动包。

2. JDBC快速入门

  1. 创建工程,导入驱动jar包

  1. 注册驱动

    Class.forName("com.mysql.jdbc.Driver");
    
  2. 获取连接

    Connection conn = DriverManager.getConnection(url, username, password);
    
  3. 定义SQL语句

    String sql =  “update…” ;
    
  4. 获取执行SQL对象

    Statement stmt = conn.createStatement();
    
  5. 执行SQL

    stmt.executeUpdate(sql); 
    
  6. 处理返回结果

    System.out.println(result);
    
  7. 释放资源

    stmt.close();
    conn.close();
    

完整示例

public static void main(String[] args) {
        try {
            //1.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            try {
                String url = "jdbc:mysql://127.0.0.1:3306/db6";
                // 如果连接本机mysql并且端口是3306的话,可以用/代替
//              String url = "jdbc:mysql:///db6";
                String name = "root";
                String password = "1234";
                //2.获取连接
                Connection conn = DriverManager.getConnection(url,name,password);
                //3.定义SQL语句
                String sql = "update account set money = 3000 where id = 1";
                //4.获取执行SQL对象
                Statement stmt = conn.createStatement();
                //5.执行SQL
                int result = stmt.executeUpdate(sql);
                //6.处理返回结果
                System.out.println(result);
                //7.释放资源
                stmt.close();
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

3.JDBC API详解

3.1 DriverManager

DriverManager(驱动管理类)作用:

  • 注册驱动

    Class.forName("com.mysql.jdbc.Driver");
    

    通过阅读源码发现,jdbc注册驱动是通过Java 反射,加载预定义Driver类的静态代码块。创建对象。

    == 提示:==

    • MySQL 5之后的驱动包,可以省略注册驱动的步骤
    • 自动加载jar包中META-INF/services/java.sql.Driver文件中的驱动类
  • 获取数据库连接

    Connection conn = DriverManager.getConnection(url,name,password);
    

    参数说明:

    • url : 连接路径

      语法:jdbc:mysql://ip地址(域名):端口号/数据库名称?参数键值对1&参数键值对2…

      示例:jdbc:mysql://127.0.0.1:3306/db1

      ==细节:==

      • 如果连接的是本机mysql服务器,并且mysql服务默认端口是3306,则url可以简写为:jdbc:mysql:///数据库名称?参数键值对

      • 配置 useSSL=false 参数,禁用安全连接方式,解决警告提示

    • user :用户名

    • poassword :密码

3.2 Connection

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

  • 获取执行 SQL 的对象
  • 管理事务

3.2.1 获取执行对象

  • 普通执行SQL对象

    Statement createStatement()
    

    入门案例中就是通过该方法获取的执行对象。

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

    PreparedStatement  prepareStatement(sql)
    

    通过这种方式获取的 PreparedStatement SQL语句执行对象它可以防止SQL注入。

3.2.2 事务管理

Connection几口中定义了3个对应的方法:

  • 开启事务

    void setAutoCommit(boolean autoCommit);//autoCommit = true 启用自动提交模式; false 禁用它 抛出:SQLException – 如果发生数据库访问错误。
    
  • 提交事务

    void commit();
    
  • 回滚事务

    void rollback();//撤消在当前事务中所做的所有更改并释放此 Connection 对象当前持有的所有数据库锁
    

完整示例

public static void main(String[] args) throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql:///db6?useSSL=false";
        String name = "root";
        String pass = "1234";
        Connection conn = DriverManager.getConnection(url, name, pass);
        String sql1 = "update account set money = 3000 where id = 1";
        String sql2 = "update account set money = 3000 where id = 2";
        Statement stmt = conn.createStatement();
        try {
            //开启事务
            conn.setAutoCommit(false);
            int result1 = stmt.executeUpdate(sql1);
            System.out.println(result1);
            int i = 3 / 0;//制造异常
            int result2 = stmt.executeUpdate(sql2);
            System.out.println(result2);
            //提交事务
            conn.commit();
        } catch (Exception e) {
            // 回滚事务
            conn.rollback();
            e.printStackTrace();
        } finally {
            stmt.close();
            conn.close();
        }
    }

3.3 Statement

Statement对象的作用就是用来执行SQL语句。而针对不同类型的SQL语句使用的方法也不一样。

  • 执行DDL、DML语句

    int executeUpdate(String sql);//返回:int (DML) 语句的行计数或 0 用于不返回任何内容的 SQL 语句 抛出:SQLException
    
  • 执行DQL语句

    ResultSet executeQuery(String sql);//返回 ResultSet 对象列的数量、类型和属性由 ResultSet.getMetaData 方法返回的
    

示例代码

//演示Jdbc Statement executeUpdate
    @Test
    public void testJDBCDML() throws Exception {
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql:///db6?useSSL=false";
        String user = "root";
        String pass = "1234";
        Connection conn = DriverManager.getConnection(url, user, pass);
        String sql = "update account set money = 3000 where id = 1";
        Statement stmt = conn.createStatement();
        int result = stmt.executeUpdate(sql);
        System.out.println(result);
        stmt.close();
        conn.close();
    }

    //演示Jdbc Statement executeQuery
    @Test
    public void testJDBCDQL() throws  Exception{
        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql:///db6?useSSL=false";
        String user = "root";
        String pass = "1234";
        Connection conn = DriverManager.getConnection(url, user, pass);
        String sql = "select * from account";
        Statement stmt = conn.createStatement();
        ResultSet resultSet = stmt.executeQuery(sql);
        while (resultSet.next()){
//            System.out.println(resultSet);
//          	int id = rs.getInt(1);//使用index也可以
            int id = resultSet.getInt("id");
            String name = resultSet.getString("name");
            double money = resultSet.getDouble("money");

            System.out.println(id);
            System.out.println(name);
            System.out.println(money);

            System.out.println("--------------");
        }
        stmt.close();
        conn.close();
    }

3.4 ResultSet

ResultSet(结果集对象)作用:

  • ==封装了SQL查询语句的结果。==

而执行了DQL语句后就会返回该对象,对应执行DQL语句的方法如下:

ResultSet  executeQuery(sql):执行DQL 语句,返回 ResultSet 对象

那么我们就需要从 ResultSet 对象中获取我们想要的数据。ResultSet 对象提供了操作查询结果数据的方法,如下:

boolean next()

  • 将光标从当前位置向前移动一行
  • 判断当前行是否为有效行

方法返回值说明:

  • true : 有效行,当前行有数据
  • false : 无效行,当前行没有数据

xxx getXxx(参数):获取数据

  • xxx : 数据类型;如: int getInt(参数) ;String getString(参数)
  • 参数
    • int类型的参数:列的编号,从1开始
    • String类型的参数: 列的名称

3.5 PreparedStatement

Statement对象会存在SQL注入问题,PreparedStatement的出现预编译SQL语句并执行:预防SQL注入问题

  • 获取 PreparedStatement 对象

    // SQL语句中的参数值,使用?占位符替代
    String sql = "select * from user where username = ? and password = ?";
    // 通过Connection对象获取,并传入对应的sql语句
    PreparedStatement pstmt = conn.prepareStatement(sql);
    
  • 设置参数值

    上面的sql语句中参数使用 ? 进行占位,在之前之前肯定要设置这些 ? 的值。

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

    • Xxx:数据类型 ; 如 setInt (参数1,参数2)

    • 参数:

      • 参数1: ?的位置编号,从1 开始

      • 参数2: ?的值

  • 执行SQL语句

    executeUpdate(); 执行DDL语句和DML语句

    executeQuery(); 执行DQL语句

    ==注意:==

    • 调用这两个方法时不需要传递SQL语句,因为获取SQL语句执行对象时已经对SQL语句进行预编译了。

示例代码

  • SQL语句

    -- 创建用户表
    	CREATE TABLE tb_user ( 
    	id INT PRIMARY KEY auto_increment,
    	username VARCHAR ( 20 ),
    	password VARCHAR( 20 )
    	);
    -- 添加数据
    	INSERT INTO tb_user ( username, password )
    	VALUES
    		( 'zhangsan', '123' ),
    		( 'lisi', '456' );
    		-- 查询数据
    		SELECT
    			* 
    		FROM
    		tb_user;
    
  • Java代码

    public static void main(String[] args) throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
            String url = "jdbc:mysql:///db6?useSSL=false";
            String user = "root";
            String pass = "1234";
            Connection conn = DriverManager.getConnection(url, user, pass);
            String sql = "select * from tb_user where username = ? and password = ?";
            // 获取PreparedStatement对象
            PreparedStatement pstmt = conn.prepareStatement(sql);
            //设置?里面的值
            pstmt.setString(1,"zhangsan");
            pstmt.setString(2,"123");
            ResultSet rs = pstmt.executeQuery();
            // 判断登录是否成功
            if(rs.next()){
                System.out.println("登录成功~");
            }else{
                System.out.println("登录失败~");
            }
            //释放资源
            rs.close();
            pstmt.close();
            conn.close();
        }
    

4. 数据库连接池

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

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

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

  • 好处

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

之前我们代码中使用连接是没有使用都创建一个Connection对象,使用完毕就会将其销毁。这样重复创建销毁的过程是特别耗费计算机的性能的及消耗时间的。

而数据库使用了数据库连接池后,就能达到Connection对象的复用,如下图

连接池是在一开始就创建好了一些连接(Connection)对象存储起来。用户需要连接数据库时,不需要自己创建连接,而只需要从连接池中获取一个连接进行使用,使用完毕后再将连接对象归还给连接池;这样就可以起到资源重用,也节省了频繁创建连接销毁连接所花费的时间,从而提升了系统响应的速度。

4.1 数据库连接池实现

  • JDBC提供标准接口:interface DataSource

    官方(SUN) 提供的数据库连接池标准接口,由第三方组织实现此接口。该接口提供了获取连接的功能:

    Connection getConnection()
    

    那么以后就不需要通过 DriverManager 对象获取 Connection 对象,而是通过连接池(DataSource)获取 Connection 对象。

  • 常见的数据库连接池

    • DBCP
    • C3P0
    • Druid

    我们现在使用更多的是Druid,它的性能比其他两个会好一些。

  • Druid(德鲁伊)

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

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

4.2 Driud使用

  • 导入jar包 druid-1.1.12.jar
  • 定义配置文件
  • 加载配置文件
  • 获取数据库连接池对象
  • 获取连接

定义配置文件

driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql:///db6?useSSL=false&useServerPrepStmts=true
username=root
password=1234
# 初始化连接数量
initialSize=5
# 最大连接数
maxActive=10
# 最大等待时间
maxWait=3000

简单使用

public static void main(String[] args) throws Exception {
        //1.导入jar包
        //2.定义配置文件
//        druid.properties
        //3. 加载配置文件
        Properties prop = new Properties();
        InputStream is = DruidDemo.class.getClassLoader().getResourceAsStream("druid.properties");
        prop.load(is);
        //4. 获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);

        //5. 获取数据库连接 Connection
        Connection connection = dataSource.getConnection();
        System.out.println(connection); //获取到了连接后就可以继续做其他操作了
    }

5. JDBC练习

完成商品品牌数据的增删改查操作

  • 查询:查询所有数据
  • 添加:添加品牌
  • 修改:根据id修改
  • 删除:根据id删除

数据库表 tb_brand

		
		-- 删除tb_brand表
drop table if exists tb_brand;
-- 创建tb_brand表
create table tb_brand (
    -- id 主键
    id int primary key auto_increment,
    -- 品牌名称
    brand_name varchar(20),
    -- 企业名称
    company_name varchar(20),
    -- 排序字段
    ordered int,
    -- 描述信息
    description varchar(100),
    -- 状态:0:禁用  1:启用
    status int
);
-- 添加数据
insert into tb_brand (brand_name, company_name, ordered, description, status)
values ('三只松鼠', '三只松鼠股份有限公司', 5, '好吃不上火', 0),
       ('华为', '华为技术有限公司', 100, '华为致力于把数字世界带入每个人、每个家庭、每个组织,构建万物互联的智能世界', 1),
       ('小米', '小米科技有限公司', 50, 'are you ok', 1);
			 
 SELECT * FROM tb_brand;

Java代码实现

  • 公共部分代码,链接池对象

    private static Connection connection;
        //使用链接池对象管理jdbc链接
        static {
            try {
                Properties prop = new Properties();
                InputStream is = JdbcTestCRUD.class.getClassLoader().getResourceAsStream("druid.properties");
                prop.load(is);
                //获取连接池对象
                DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
                connection = dataSource.getConnection();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

5.1 增

@Test
    public void addData() throws Exception {
        // 模拟接收页面提交的参数
        String brandName = "香飘飘";
        String companyName = "香飘飘";
        int ordered = 1;
        String description = "绕地球一圈";
        int status = 1;
        String sql = "insert into tb_brand (brand_name, company_name, ordered, description, status) values(?,?,?,?,?) ";
        PreparedStatement ps = connection.prepareStatement(sql);
        //4. 设置参数
        ps.setString(1, brandName);
        ps.setString(2, companyName);
        ps.setInt(3, ordered);
        ps.setString(4, description);
        ps.setInt(5, status);
        int result = ps.executeUpdate();
        //6. 处理结果
        System.out.println(result > 0);
        ps.close();
        connection.close();
    }

5.2 删

/**
     * 删除
     * 1. SQL:
     * delete from tb_brand where id = ?
     * 2. 参数:需要,id
     * 3. 结果:boolean
     */
    @Test
    public void deleteData() throws Exception {
        int id = 4;
        String sql = "delete from tb_brand where id = ?";
        PreparedStatement ps = connection.prepareStatement(sql);
        ps.setInt(1, id);
        int result = ps.executeUpdate();
        if (result > 0) {
            System.out.println("删除成功");
        } else {
            System.out.println("删除失败");
        }
        ps.close();
        connection.close();
    }

5.3 改

/**
     * 修改
     * 1. SQL:
     update tb_brand
     set brand_name  = ?,
     company_name= ?,
     ordered     = ?,
     description = ?,
     status      = ?
     where id = ?
     * 2. 参数:需要,所有数据
     * 3. 结果:boolean
     */
    @Test
    public void editData() throws Exception{
        // 模拟接收页面提交的参数
        String brandName = "香飘飘";
        String companyName = "香飘飘";
        int ordered = 1000;
        String description = "绕地球三圈";
        int status = 1;
        int id = 4;

        String sql = " update tb_brand\n" +
                "         set brand_name  = ?,\n" +
                "         company_name= ?,\n" +
                "         ordered     = ?,\n" +
                "         description = ?,\n" +
                "         status      = ?\n" +
                "     where id = ?";
        PreparedStatement ps = connection.prepareStatement(sql);
        ps.setString(1,brandName);
        ps.setString(2,companyName);
        ps.setInt(3,ordered);
        ps.setString(4,description);
        ps.setInt(5,status);
        ps.setInt(6,id);

        int result = ps.executeUpdate();
        if (result > 0) {
            System.out.println("修改成功");
        } else {
            System.out.println("修改失败");
        }
        ps.close();
        connection.close();
    }

5.4 查

@Test
    public void selectAll() throws SQLException {
        String sql = "select * from tb_brand";
        PreparedStatement ps = connection.prepareStatement(sql);
        ResultSet rs = ps.executeQuery();
        Brand brand = null;
        List<Brand> brands = new ArrayList<>();
        while (rs.next()) {
            int id = rs.getInt("id");
            String brandName = rs.getString("brand_name");
            String companyName = rs.getString("company_name");
            int ordered = rs.getInt("ordered");
            String description = rs.getString("description");
            int status = rs.getInt("status");
            //封装Brand对象
            brand = new Brand();
            brand.setId(id);
            brand.setBrandName(brandName);
            brand.setCompanyName(companyName);
            brand.setOrdered(ordered);
            brand.setDescription(description);
            brand.setStatus(status);
            //装载集合
            brands.add(brand);
        }
        //输出结果
        System.out.println(brands);
        rs.close();
        ps.close();
        connection.close();
    }
Loading...