JDBC连接数据库实现数据库的增删查改详细分析及代码实现


一、连接数据库


1.Java代码

import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

/**
 * Java连接数据库 JDBC:
 * 一、创建连接 Connection 对象
 * 二、创建执行的语句 Statement 对象
 * 三、执行 SQL 语句
 *
 * 一、创建连接
 * 1.最耿直,直接创建对象。由于获取驱动的实例化对象时使用了第三方的包 mysql.jdbc.Driver()
 *   Driver driver = new com.mysql.jdbc.Driver();
 *
 * 2.法一不利于代码的移植和扩展性,所以在此基础之上,利用反射的方法创建 Driver 对象
     * 获取类对象 getClassname()
     * 获取构造器,创建对象 getDeclaredConstructor().newInstance()
     * 获取指定的方法 getMethod(方法名,参数列表),如 getMethod("setPrice", int.class)
     * 使用类的方法进行初始化 invoke(创建的对象, 14)
 *
 *   Class clazz = Class.forName("com.mysql.jdbc.Driver");
 *   Driver driver = (Driver)clazz.getDeclaredConstructor().newInstance();
 *
 * 3.直接使用驱动不方便,引入驱动管理的实现类,进一步简化。并且在 mysql的Driver实现类中已经
 *   声明了注册驱动
 *   Class.forName("com.mysql.jdbc.Driver");
 *   Connection conn = DriverManager.getConnection(url, user, password);
 *
 * 4.直接写死了用户名、密码等信息,不安全、不方便,引入配置文件
 *   连接mysql,jdbc:mysql:协议,localhost:ip地址,3306:默认mysql的端口号,test:连接的数据库名称
 *         String string = "jdbc:mysql://localhost:3306/test";
 *         Properties info = new Properties();
 *         // 将用户名和密码封装在Properties中
 *         info.setProperty("user", "tom");
 *         info.setProperty("password", "123");
 *    配置文件让用户能够脱离程序本身去修改相关的变量设置。
 *        1、从目标路径 myjdbc.properites 中获取输入流对象
 *        2、使用 Properties类的 load()方法从字节输入流中获取数据
 *        3.使用 Properties类的 getProperty(String key)方法,根据参数key获取value
 *
 *
 * 大白话讲解反射机制
 *      https://www.cnblogs.com/chanshuyi/p/head_first_of_reflection.html
 *
 *  介绍配置文件
 *      https://www.cnblogs.com/gongchenglion/p/properties.html
 *
 * @Auther:sommer1111
 * @date 2020/10/10 17:36
 */
public class _01_ConnectionMySQL {
    public static void main(String[] args) throws Exception{
        //1.从目标路径myjdbc.properites中获取输入流对象
        InputStream in = _01_ConnectionMySQL.class.getClassLoader().getResourceAsStream("myjdbc.properties");

        //2.使用Properties类的load()方法从字节输入流中获取数据
        Properties pro = new Properties();
        pro.load(in);
        String driverClass = pro.getProperty("driverClass");
        String url = pro.getProperty("url");
        String name = pro.getProperty("user");
        String password = pro.getProperty("password");

        //3.加载驱动
        Class.forName(driverClass);

        //4.获取连接
        Connection connect = DriverManager.getConnection(url,name,password);
        System.out.println(connect);
    }
}

2.配置文件myjdbc.properties

#设置配置信息
url=jdbc:mysql://localhost:3306/myemployees
user=tom
password=123
driverClass=com.mysql.jdbc.Driver


二、创建执行语句,Statement语句


将代码专门抽象成一个工具类


import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * @Auther:sommer1111
 * @date 2020/10/13 16:25
 */
public class statementUtil {
    //获取连接
    public static Connection getConnect() throws Exception {
        InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("myjdbc.properties");
        Properties ps = new Properties();
        ps.load(in);

        String driverClass = ps.getProperty("driverClass");
        String url = ps.getProperty("url");
        String user = ps.getProperty("user");
        String password = ps.getProperty("password");

        Class.forName(driverClass);
        return DriverManager.getConnection(url, user, password);
    }

    //关闭资源
    public static void closeConnetion(Connection con,PreparedStatement sta){
            try {
                if(con != null){
                    con.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }

            try {
                if(sta != null){
                    sta.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
    }

    //增加一个关闭资源
    public static void closeConnetion(Connection con, PreparedStatement sta, ResultSet rs){
        try {
            if(con != null){
                con.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        try {
            if(sta != null){
                sta.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        try {
            if(rs != null){
                rs.close();
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }


    //设置statment
    public static void update(String sql,Object ...args) {
        Connection connection = null;
        PreparedStatement statement = null;
        try {
            //1.预编译
            connection = getConnect();
            statement = connection.prepareStatement(sql);
            //2.填充占位符
            for(int i = 0;i<args.length;i++){
                statement.setObject(i+1,args[i]);
            }
            //3.执行
            statement.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            closeConnetion(connection,statement);
        }
    }
}


三、执行SQL语句


1.实现数据库的操作:增删改,此时并没有返回值


import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Properties;

/**
 * 实现创建数据库语句的操作(增删改,没有返回)
 *
 * 1.获取数据库连接
 *             InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("myjdbc.properties");
 *             Properties ps = new Properties();
 *             ps.load(in);
 *             String driverClass = ps.getProperty("driverClass");
 *             String url = ps.getProperty("url");
 *             String user = ps.getProperty("user");
 *             String password = ps.getProperty("password");
 *             Class.forName(driverClass);
 *             connection = DriverManager.getConnection(url, user, password);
 *
 * 2.预编译sql语句,返回PreparedStatement的实例
 *             String sql = new String("UPDATE locations SET street_address = ? WHERE location_id = ?;");
 *             statement = connection.prepareStatement(sql);
 *
 * 3.填充占位符
 *             statement.setObject(1,"wuhan");
 *             statement.setObject(2,"2200");
 * 4.执行
 *             statement.execute();
 * 5.资源的关闭(都需要用 try catch)
 *             statement.close();
 *             connection.close()
 *
 * 优化:
 * 1.将数据库的连接、预编译、关闭资源都封装成方法 statementUtil,简化代码
 *
 * @Auther:sommer1111
 * @date 2020/10/13 15:38
 */
public class _02_Statement {
    public static void main(String[] args) {

        String sql = "UPDATE locations SET street_address = ? WHERE location_id = ?;";
        Object[] arg = {"jiangxi","2300"};
        statementUtil.update(sql,arg);

//        Connection connection = null;
//        PreparedStatement statement = null;
//        try {
//            //1.获取数据库连接
//            InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream("myjdbc.properties");
//            Properties ps = new Properties();
//            ps.load(in);
//            String driverClass = ps.getProperty("driverClass");
//            String url = ps.getProperty("url");
//            String user = ps.getProperty("user");
//            String password = ps.getProperty("password");
//            Class.forName(driverClass);
//            connection = DriverManager.getConnection(url, user, password);
//
//
//            //2.预编译sql语句,返回PreparedStatement的实例
//            String sql = new String("UPDATE locations SET street_address = ? WHERE location_id = ?;");
//            statement = connection.prepareStatement(sql);
//            //3.填充占位符
//            statement.setObject(1,"wuhan");
//            statement.setObject(2,"2200");
//
//            //4.执行
//            statement.execute();
//        } catch (Exception e) {
//            e.printStackTrace();
//        }finally {
//            //5.资源的关闭
//            if(statement != null){
//                try {
//                    statement.close();
//                } catch (SQLException throwables) {
//                    throwables.printStackTrace();
//                }
//            }
//            if(connection != null){
//                try {
//                    connection.close();
//                } catch (SQLException throwables) {
//                    throwables.printStackTrace();
//                }
//            }
//        }
    }
}

2.实现数据库的操作:

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.Collection;

/**
 * JDBC 实现数据库的查询
 * 一、分析:
 * 1. 使用 PreparedStatement实现查询操作,查询操作的区别在于会有一个数据返回
 * 2. 返回的数据用一个类封装 ResultSet,这个表中只有数据,但是如果我们还需要获取表头信息
 * 3. 用 getMetaData 获取关于 ResultSet 对象中列的类型和属性信息的对象 ResultSetMetaData
 * 4. ResultSet 资源也需要释放
 *
 * 二、实现:
 * 1.获取连接
 * 2.执行sql语句,得打结果返回 ResultSet,ResultSet rs = ps.executeQuery();
 * 3.要想显示结果,将数据读取出来封装在一个 Collection 对象中 key-value 键值对
 *   |--读取出表头信息:
 *      (1)获取元数据集,ResultSetMetaData rsmd = rs.getMetaData();
 *      (2)获取结果集中的列数,迭代读取元数据集的表头:
 *          int columnCount = rsmd.getColumnCount();
 *          String columnName = rsmd.getColumnName(i + 1);
 *      (3)获取列值,此时列值属性失去,都变成了 Object
 * 			Object columValue = rs.getObject(i + 1);
 * 		(4)利用反射恢复列值在 Collection 对象的属性,并添加到集合中:
 * 	        Field field = Customer.class.getDeclaredField(columnLabel);
 * 			field.setAccessible(true);使在用反射时能访问私有变量
 * 			field.set(cust, columValue);
 * 4.关闭资源
 *
 * 三、笔记
 *  1.查询需要调用PreparedStatement 的 executeQuery() 方法,查询结果是一个ResultSet 对象
 *    ResultSet通过指针迭代取数据,常用方法有:
 *      next(),用于迭代的指针,指向下一个值。
 *      getObject(),获取列值。
 *
 *  2.ResultSetMetaData对象的常用方法
 *    getColumnName(int column):获取指定列的名称
 *    getColumnLabel(int column):获取指定列的别名(MySQL中的别名,推荐使用)
 *    getColumnCount():返回当前 ResultSet 对象中的列数。
 *    getColumnTypeName(int column):检索指定列的数据库特定的类型名称。
 *
 * @Auther:sommer1111
 * @date 2020/10/14 15:35
 */


public class _03_StatementQuery {
    public static void main(String[] args) {
        String sql = "SELECT employee_id,last_name,email,salary FROM employees WHERE employee_id>?;";
        Collection<Employees> employees = queryForEmployees(sql, 128);
        for(Employees employee:employees){
            System.out.println(employee);
        }

    }

    //基本实现
    public static Collection<Employees> queryForEmployees(String sql, Object...args) {
        statementUtil util = null;
        Connection connect = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        Collection<Employees> list = new ArrayList<>();

        try {
            util = new statementUtil();
            connect = util.getConnect();
            ps = connect.prepareStatement(sql);

            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }

            //得到数据集
            rs = ps.executeQuery();
            //获取元数据
            ResultSetMetaData rsmd = rs.getMetaData();
            //开始读取值

            while(rs.next()){//一行的数据为一个next
                Employees em = new Employees();
                int columnCount = rsmd.getColumnCount();
                for (int i = 0; i < columnCount; i++) {
                    //获取数据
                    Object value = rs.getObject(i+1);
                    //获取列名,最好使用别名来获取
                    String columnName = rsmd.getColumnLabel(i + 1);
                    //恢复属性
                    Field field = Employees.class.getDeclaredField(columnName);
                    field.setAccessible(true);
                    field.set(em,value);
                }
                list.add(em);
            }
            return list;

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            util.closeConnetion(connect,ps,rs);
        }
        return null;
    }

    //优化增强扩展性,将具体的类换成泛型
    public static <T>T queryForEmployees(Class<T> clazz,String sql, Object...args) throws Exception {
        //修改创建类的语句
        T t = clazz.getDeclaredConstructor().newInstance();
        //修改反射设值的语句,其余不变
        //field.set(t,value);
        return null;
    }
}

3.用到的Employees类

/**
 * @Auther:sommer1111
 * @date 2020/10/14 16:28
 */
class Employees {
    private int employee_id;
    private String last_name;
    private String email;
    private double salary;

    public Employees() {
    }

    public Employees(int employee_id, String last_name, String email, int salary) {
        this.employee_id = employee_id;
        this.last_name = last_name;
        this.email = email;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Employees{" +
                "employee_id=" + employee_id +
                ", last_name='" + last_name + '\'' +
                ", email='" + email + '\'' +
                ", salary=" + salary +
                '}';
    }

    public int getEmployee_id() {
        return employee_id;
    }

    public void setEmployee_id(int employee_id) {
        this.employee_id = employee_id;
    }

    public String getLast_name() {
        return last_name;
    }

    public void setLast_name(String last_name) {
        this.last_name = last_name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值