05、JDBC 教程 - 以面向对象的思想编写JDBC程序

JDBC基础

以面向对象的思想编写JDBC程序

其实本章也没什么技术性的知识点,只是使用面向对象的方式去举例添加一条数据

前面的几章都是我们写好的SQL语句直接执行的,但是现实中我们不可能指望用户去编写SQL,我们可能需要从控制台或者前端获取一个对象,一个实体类对象,我们需要程序能直接添加实体类,而不是我们去手写SQL

所以我们需要写一个灵活的SQL,可以根据传输进来的对象实例进行自匹配,生成完整的可执行的SQL语句,再调用执行方法就可以了

一、数据库的准备

执行以下SQL,生成数据库和数据表并注入数据

/*
MySQL - 5.6.12 : Database - test
*/

/*创建test数据库*/
CREATE DATABASE test;

/*使用test数据库*/
USE test;

/*创建user表*/
CREATE TABLE user (
  id int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  name varchar(10) COLLATE utf8_bin NOT NULL COMMENT '姓名',
  password varchar(150) COLLATE utf8_bin DEFAULT NULL COMMENT '密码',
  age int(10) NOT NULL COMMENT '年龄',
  remark varchar(50) COLLATE utf8_bin DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

/*添加数据到user表*/
insert  into user(id,name,password,age,remark) values (1,'樟道','admin',21,'这是一个活泼的男孩'),(2,'浅夏','admin',19,'这是一个乐观的女孩');

数据表的结构如下:
 
数据表的内容如下:
 

二、JAVA项目

项目结构

 

  • pom.xml:本项目采用maven管理依赖
  • database.properties:存放数据库连接信息
  • PropertiesUtils:读取properties文件的工具类
  • User:用户实体类
  • JDBCUtils:JDBC的工具类
  • JdbcObjectService:业务层接口
  • JdbcObjectServiceImpl:业务层接口实现类
  • TestJdbcObjectDemo:测试类,测试工具类的功能效果

1. pom.xml

首先注入第三方依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tqazy</groupId>
    <artifactId>jdbc-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <description>使用JDBC操作数据库</description>
    <properties>
        <java.version>1.8</java.version>
        <build.sourceEncoding>UTF-8</build.sourceEncoding>
        <mysql.version>5.1.26</mysql.version>
        <spring.version>5.2.0.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!-- Spring start -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!-- Spring end -->
        <!-- database start -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!-- database end -->
        <!-- 测试 start -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- 测试 end -->
    </dependencies>
</project>

2. database.properties(数据库连接信息文件)

一般连接数据库需要以下四个信息:驱动、url、用户名、密码

其中url在test后的一串?useUnicode=true&characterEncoding=UTF-8是设置编码格式为UTF-8

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8
username=root
password=admin123

3. PropertiesUtils(读取配置文件的工具类)

只需要调用readProperties()静态方法并传入相关参数,即可得到文件内容

参数1:文件的全路径名
参数2:需要读取的key值list集合
返回的结果:由key值和对应读取到的value值组成的map集合

package com.tqazy.utils;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * @author 散场前的温柔
 */
public class PropertiesUtils {

    /**
     * 传入properties文件地址和要读取的key值list集合,返回由key值和读取数据组成的map集合
     *
     * @param path
     * @param list
     * @return Map<key, value>
     */
    public static Map<String, String> readProperties(String path, List<String> list) {
        if (list == null || list.isEmpty() || path == null || path.isEmpty()) {
            return new HashMap<String, String>(0);
        }
        Map<String, String> map = new HashMap<String, String>(10);
        PropertiesUtils propertiesUtils = new PropertiesUtils();
        Properties properties = propertiesUtils.readProperties(path);
        if (properties == null) {
            return new HashMap<String, String>(0);
        }
        for (String str : list) {
            map.put(str, properties.getProperty(str));
        }
        return map;
    }

    /**
     * 根据地址读取Properties文件并生成实例
     *
     * @param path 文件地址
     * @return Properties
     * @throws IOException
     */
    private Properties readProperties(String path) {
        Properties properties = null;
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path);
            InputStreamReader reader = new InputStreamReader(inputStream);
            // 此处需要使用JDK1.6以上的版本
            properties = new Properties();
            properties.load(reader);
        } catch (NullPointerException e) {
            // 读取文件异常
            e.printStackTrace();
            System.err.println("读取Properties文件异常,请检查文件路径和文件名:" + path);
        } catch (IOException e) {
            // 字符流写入异常
            e.printStackTrace();
            System.err.println("字符流写入Properties实例异常");
        }
        return properties;
    }
}

4. User(用户)实体类

实体类保持和数据库表是对应的

package com.tqazy.entity;

/**
 * @author 散场前的温柔
 */
public class User {

    private Integer id;
    private String name;
    private String password;
    private Integer age;
    private String remark;
    
    public User() {}

    public User(String name, String password, Integer age, String remark) {
        this.name = name;
        this.password = password;
        this.age = age;
        this.remark = remark;
    }
    
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getRemark() {
        return remark;
    }

    public void setRemark(String remark) {
        this.remark = remark;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                ", remark='" + remark + '\'' +
                '}';
    }
}

5. JDBCUtils(JDBC工具类)

在执行update()方法和select()方法时自动获取数据库连接,但是update()方法可以最后自动关闭连接,查询无法关闭且需要外部解析结果。

这里的耦合度做的还不是很好,可以改进。

package com.tqazy.jdbc;

import com.tqazy.utils.PropertiesUtils;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author 散场前的温柔
 */
public class JDBCUtils {

    private static Connection con;
    private static Statement sm;
    private static ResultSet rs;

    private static Map<String, String>  map;

    /**
     * 获取数据库连接信息
     */
    private static void getProperties(String path){
        List<String> list = new ArrayList<String>();
        list.add("driver");
        list.add("url");
        list.add("username");
        list.add("password");
        map = PropertiesUtils.readProperties(path, list);
    }

    /**
     * 获取数据库连接
     */
    public static void getConnection(String path){
        try {
            if(map == null){
                getProperties(path);
            }
            Class.forName(map.get("driver"));
            con = DriverManager.getConnection(map.get("url"), map.get("username"), map.get("password"));
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行新增/修改/删除操作的方法
     * @param sql
     * @param path
     * @return
     */
    public static int update(String sql, String path){
        int num = 0;
        getConnection(path);
        // 如果创建连接失败,返回0行
        if(con == null){
            System.out.println("创建数据库连接失败");
            return 0;
        }
        try {
            // 通过connection的createStatement()方法获取statement链接
            sm = con.createStatement();
            // 通过statement的executeUpdate()方法执行SQL语句
            num =  sm.executeUpdate(sql);
        } catch (SQLException e) {
            // 从连接中获取Statement异常
            e.printStackTrace();
        } finally {
            // 关闭statement和connection连接
            close();
        }
        return num;
    }

    /**
     * 执行查询操作的方法
     * @param sql
     * @param path
     * @return
     */
    public static ResultSet select(String sql, String path){
        getConnection(path);
        // 如果创建连接失败,返回0行
        if(con == null){
            System.out.println("创建数据库连接失败");
            return null;
        }
        try {
            // 通过connection的createStatement()方法获取statement链接
            sm = con.createStatement();
            // 通过statement的executeQuery(sql)方法获取resultSet的实例
            rs = sm.executeQuery(sql);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return rs;
    }

    /**
     * 关闭数据库相关连接
     */
    public static void close(){
        if(rs != null){
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(sm != null){
            try {
                sm.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(con != null){
            try {
                con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

6. JdbcObjectService(接口)

本章,读写数据的方式和代码不变,主要是在服务层体现出面向对象的思想

本章只以新增方法为例,查询、修改、删除方法均适用。

但是本文的操作数据库方式仍旧不是常用方式,同样过于繁琐难用,本章目的主要是用来体会一下面向对象的概念是什么样的实现

package com.tqazy.service;

import com.tqazy.entity.User;

/**
 * @author 散场前的温柔
 */
public interface JdbcObjectService {
    /**
     * 添加用户
     * @param user
     * @return
     */
    boolean addUser(User user);
}

7. JdbcObjectServiceImpl(接口实现类)

下面来实现刚才那个接口

我们可以看到,针对于传输进来的对象,sql进行了组装,最后
形成完整的sql,再调用相应的操作方法完成操作数据库的目的。

此时我们就初步的实现了传入对象操作数据库的目的,虽然仍旧缺陷很多

package com.tqazy.service.impl;

import com.tqazy.entity.User;
import com.tqazy.jdbc.JDBCUtils;
import com.tqazy.service.JdbcObjectService;
import org.springframework.stereotype.Service;

/**
 * @author 散场前的温柔
 */
@Service
public class JdbcObjectServiceImpl implements JdbcObjectService {
    public boolean addUser(User user) {

        if (user == null) {
            return false;
        }
        String sql = "INSERT INTO user (name, password, age, remark) VALUES ('" + user.getName() + "', '" + user.getPassword() + "', " + user.getAge() + ", '" + user.getRemark() + "')";
        int num = JDBCUtils.update(sql, "database.properties");
        if(num > 0){
            return true;
        }
        return false;
    }
}

8. TestJdbcObjectDemo(测试类)

测试类,需要提供一个用户的实体类,我们就假设这个实体类的数据是从前端传回来的或者控制台输入的,那么我们就完成了向数据库"添加对象实例"的操作效果。

package com.tqazy.test;

import com.tqazy.entity.User;
import com.tqazy.service.JdbcObjectService;
import com.tqazy.service.impl.JdbcObjectServiceImpl;
import org.junit.Test;

public class TestJdbcObjectDemo {

    @Test
    public void addUser(){
        User user = new User("苏熙", "admin123", 19, "这是一个可爱的美少女");
        JdbcObjectService jdbcObjectService = new JdbcObjectServiceImpl();
        boolean flag = jdbcObjectService.addUser(user);
        System.out.println("添加结果:" + flag);
    }
}

结果就是成功的插入一条数据,控制台输出:添加结果:true
 

此时我们只需要关注的输入的对象数据即可,不用再去关注SQL的组成,达到面向对象的目的。

本章结束

回到目录

如果本文有错误或对本文有不理解的地方欢迎评论 _

如果本文有帮助到您,可以点一下右上角的赞哦,谢谢啦