02.SSM框架集~再谈JDBC?

02.SSM框架集~再谈JDBC?

本文是上一篇文章的后续,详情点击该链接~

jar包

提取码:1asg

JDBC:

       JDBC(Java DataBase Connectivity, Java数据库连接) ,是一种用于执行SQL语句的Java API,为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。有了JDBC,程序员只需用JDBC API写一个程序,就可访问所有数据库。

       SUN公司是规范制定者,制定了规范JDBC(连接数据库规范)

       DriverManager类

              作用:管理各种不同的JDBC驱动

       Connection接口

       Statement接口和PreparedStatement接口

       ResultSet接口

       数据库厂商微软、甲骨文等分别提供实现JDBC接口的驱动jar包 程序员学习JDBC规范来应用这些jar包里的类。

JDBC访问数据库的步骤:

       加载一个Driver驱动

       创建数据库连接(Connection)

       创建SQL命令发送器Statement

       通过Statement发送SQL命令并得到结果

       处理结果(select语句)

       关闭数据库资源ResultSet Statement Connection

加载Driver驱动

       使用反射加载驱动,其实就是获得一个类的字节码,在获得类的字节码的过程中,一定会加载类进入内存,一旦进入内存会执行代码中的静态代码块,一执行代码块,就会自动的向DriverManager中注册一个驱动

 static {
          try {
              DriverManager.registerDriver(new Driver());
          } catch (SQLException var1) {
              throw new RuntimeException("Can't register driver!");
          }
     }

        mysql8 之前的数据库驱动名 com.mysql.jdbc.Driver

        mysql8 开始的数据库驱动 com.mysql.cj.jdbc.Driver

通过DriverManager获得链接

        url                             同一资源定位符

       协议                            jdbc:mysql:

        ip地址                       127.0.0.1/localhost

        url                             同一资源定位符

        端口号                      3306

        具体的资源路径       mydb

        mysql8之前:             jdbc:mysql://127.0.0.1:3306/mydb

        mysql8开始:             jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai

       useSSL=false            不使用SSL加密机制

       &useUnicode=true     使用unicode字符集

       &characterEncoding=utf8       使用utf8作为通信字符集

       &serverTimezone=Asia/Shanghai       确定时区为 Asia/Shanghai

       其中的mydb指的是数据库名,可以根据需求修改

使用JDBC完成添加操作

public static void insert(){

        Connection connection = null;
        Statement statement = null;
        try {
            //1:加载一个Driver驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //2:创建数据库连接(Connection)
            String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
            String uid = "root";    //账号
            String pwd = "root";    //密码

            connection = DriverManager.getConnection(url,uid,pwd);
            //创建SQL命令发送器
            statement = connection.createStatement();
            // 向数据库发送语句 数据库执行完毕后 返回参数
            int n = statement.executeUpdate("insert into student values('689845','黄贵根','656972','信息工程学院',666)");

            if(n > 0){
                System.out.println("数据添加成功!");
            }else{
                System.out.println("数据添加失败!");
            }

        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }finally{
            //关闭处理
            if(connection != null){
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }

            if(statement != null){
                try {
                    statement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

       从上述代码中不难发现,仅仅只是实现添加这么一个操作,就需要如此多的代码,细想,如果要写多个增删改的操作,难道每次都要写这么多行的代码嘛?

       所以一般到了这个时候,我们就需要一个工具类,来简化。

编写DBUtil工具类

public class DBUtil {
    
    //数据库的连接的静态方法
    public static Connection getConnection(){
        String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        String uid = "root";    //账号
        String pwd = "root";    //密码
        Connection connection = null;
        Statement statement = null;
        //1:加载一个Driver驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection(url,uid,pwd);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    //关闭处理
    public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
        //关闭处理
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

这个时候我们只需要直接调用,就可以省略很多的代码

public static void insert(){
        Connection connection = null;
        Statement statement = null;
        try {
            connection = DBUtil.getConnection();
            //创建SQL命令发送器
            statement = connection.createStatement();
            // 向数据库发送语句 数据库执行完毕后 返回参数
            int n = statement.executeUpdate("insert into student values('689845','黄贵根','656972','信息工程学院',666)");

            if(n > 0){
                System.out.println("数据添加成功!");
            }else{
                System.out.println("数据添加失败!");
            }

        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            DBUtil.CloseAll(connection,statement,null);
        }
    }

       这样子添加看似好像没问题,而且也已经很简化了,可是再想想,假如我要换一个表,或者说我不想添加操作了,我要修改或者删除。怎么办?重复写不麻烦嘛?所以这个时候,我们就需要扩展一下DBUtil工具类了

扩展DBUtil

public static int executeUpdate(String sql,Object [] params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int n = 0;//添加失败
        try {
            //2.建立和数据库的连接
            conn = getConnection();
            //3.创建一个SQL命令发送器

            pstmt = conn.prepareStatement(sql);
            //4.准备好SQL语句,通过SQL命令发送器发送给数据库,并得到结果
            for (int i = 0; i <params.length ; i++) {
                pstmt.setObject(i+1, params[i]);
            }
            n = pstmt.executeUpdate();
            //System.out.println(n);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6.关闭资源
            CloseAll(conn,pstmt,null);
        }
        return n;
    }

       这个时候我们再添加数据,实际上只需要三行代码就可以实现了,即使是换了个数据库表或者其他操作,也无需重复写代码

public static void InsertPlus(){
        //三行代码即可完成
        String sql = "insert into student value(?,?,?,?,?)";
        Object []objects = {"689845","黄贵根","656972","信息工程学院",666.0};
        int n = DBUtil.executeUpdate(sql,objects);

        if(n > 0){
            System.out.println("数据添加成功!");
        }else{
            System.out.println("数据添加失败!");
        }
    }

删除行不行呢?试试呗~

		String sql = "delete from student where realname = ?";
        Object []objects = {"黄贵根"};
        int n = DBUtil.executeUpdate(sql,objects);

JDBC常见异常

       Exception in thread "main"java.lang.ClassNotFoundException: com.mysql.jdbc2.Driver

       原因:没有添加jar包或者com.mysql.jdbc2.Driver路径错误

       Exception in thread "main" java.sql.SQLException: No suitable driver found for jbdc:mysql://127.0.0.1:3306/stumgr

       url错误

       Exception in thread "main" java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)

       原因:用户名或者密码错误

       Exception in thread "main" com.mysql.jdbc.exceptions .jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry '90' for key 'PRIMARY'

       原因:主键冲突

使用JDBC完成查询操作

需求:查询所有信息工程学院的学生
创建学生实体类(get set就不写在文章里面了,自行添加。):
public class Student {
    private String son;			//学号
    private String realname;	//姓名
    private String password;	//密码
    private String classname;	//院系
    private Double score;		//总成绩
    }
查询操作
    public static List<Student> FindAll(){
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        //创建List集合来接收数据
        List<Student> list = new ArrayList<>();
        try {
            preparedStatement = connection.prepareStatement("select * from student where classname = ?");
            //1表示第一个占位符,也就是?。 而不是数据库里面的第几个字段
            preparedStatement.setString(1,"信息工程学院");
            //接收结果
            resultSet = preparedStatement.executeQuery();
            while(resultSet.next()){
                //后面对应的是数据库里面的字段名
                String son = resultSet.getString("son");
                String realname = resultSet.getString("realname");
                String password = resultSet.getString("password");
                String classname = resultSet.getString("classname");
                Double score = resultSet.getDouble("score");
                //存到实体类
                Student student = new Student(son,realname,password,classname,score);
                //存到集合
                list.add(student);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return list;
    }

测试

public static void main(String[] args) {
        //测试
        List<Student> list = FindAll();
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

       这个时候我们发现,每个数据库里面的字段,都要定义一个相应的变量来接收,这么做很不方便。怎么办呢?那我们就来扩展一下DBUtil工具类吧。

扩展DBUtil工具类

public static <T> List<T> baseQuery(T t, String sql, Object ... args){
        // 获取list集合中要装的对象的字节码
        Class aClass = t.getClass();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        List<T> list = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.prepareStatement(sql);
            // 设置参数的过程
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            set = statement.executeQuery();
            // 获取全部的字段
            Field[] fs = aClass.getDeclaredFields();
            // 先设置属性可以访问
            for(Field f:fs){
                f.setAccessible(true);
            }
            list=new ArrayList<>();
            while(set.next()){
                // 创建对象
                T  element = (T)aClass.newInstance();
                // 从结果集的一条数据中取出每个字段的信息,放入element对象上去
                // 遍历fs 通过属性名 去结果集中获取数据
                for(Field f:fs){
                    String name = f.getName();
                    Object value=null;
                    // 判断实体类属性的数据类型,选择对应的get方法
                    if(f.getType()==int.class){
                        value = set.getInt(name);
                    }else if(f.getType()==double.class){
                        value = set.getDouble(name);
                    }else if(f.getType()==boolean.class){
                        value = set.getBoolean(name);
                    }else{
                        value= set.getObject(name);
                    }
                    f.set(element,value);
                }
                list.add(element);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseAll(connection,statement,set);
        }
        return list;
    }

       有了这个工具类之后,我们几乎只需要一行代码,就可以兼容多种查询的操作方法

测试:

public static void FindAllPlus(){
        //查询所有信息工程学院的学生
        String sql = "select * from student where classname = ?";
        //这个时候几乎一行代码就可以完成操作
        List<Student> list = DBUtil.baseQuery(new Student(),sql,"信息工程学院");

        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }

       怎么样?是不是简化好多了~

最终代码

DBUtil工具类

public class DBUtil {

    //数据库的连接的静态方法
    public static Connection getConnection(){
        String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai";
        String uid = "root";    //账号
        String pwd = "root";    //密码
        Connection connection = null;
        Statement statement = null;
        //1:加载一个Driver驱动
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
            connection = DriverManager.getConnection(url,uid,pwd);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
    //关闭处理
    public static void CloseAll(Connection connection, Statement statement, ResultSet resultSet){
        //关闭处理
        if(connection != null){
            try {
                connection.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        if(statement != null){
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if(resultSet != null){
            try {
                resultSet.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static int executeUpdate(String sql,Object [] params) {
        Connection conn = null;
        PreparedStatement pstmt = null;
        int n = 0;//添加失败
        try {
            //2.建立和数据库的连接
            conn = getConnection();
            //3.创建一个SQL命令发送器

            pstmt = conn.prepareStatement(sql);
            //4.准备好SQL语句,通过SQL命令发送器发送给数据库,并得到结果
            for (int i = 0; i <params.length ; i++) {
                pstmt.setObject(i+1, params[i]);
            }
            n = pstmt.executeUpdate();
            //System.out.println(n);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //6.关闭资源
            CloseAll(conn,pstmt,null);
        }
        return n;
    }

    public static <T> List<T> baseQuery(T t, String sql, Object ... args){
        // 获取list集合中要装的对象的字节码
        Class aClass = t.getClass();
        Connection connection = null;
        PreparedStatement statement = null;
        ResultSet set = null;
        List<T> list = null;
        try {
            connection = DBUtil.getConnection();
            statement = connection.prepareStatement(sql);
            // 设置参数的过程
            for (int i = 0; i < args.length; i++) {
                statement.setObject(i + 1, args[i]);
            }
            set = statement.executeQuery();
            // 获取全部的字段
            Field[] fs = aClass.getDeclaredFields();
            // 先设置属性可以访问
            for(Field f:fs){
                f.setAccessible(true);
            }
            list=new ArrayList<>();
            while(set.next()){
                // 创建对象
                T  element = (T)aClass.newInstance();
                // 从结果集的一条数据中取出每个字段的信息,放入element对象上去
                // 遍历fs 通过属性名 去结果集中获取数据
                for(Field f:fs){
                    String name = f.getName();
                    Object value=null;
                    // 判断实体类属性的数据类型,选择对应的get方法
                    if(f.getType()==int.class){
                        value = set.getInt(name);
                    }else if(f.getType()==double.class){
                        value = set.getDouble(name);
                    }else if(f.getType()==boolean.class){
                        value = set.getBoolean(name);
                    }else{
                        value= set.getObject(name);
                    }
                    f.set(element,value);
                }
                list.add(element);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            CloseAll(connection,statement,set);
        }
        return list;
    }
}

使用工具类完成操作

    public static List<Student> FindAllPlus(){
        //查询所有信息工程学院的学生
        String sql = "select * from student where classname = ?";
        //这个时候几乎一行代码就可以完成操作
        List<Student> list = DBUtil.baseQuery(new Student(),sql,"信息工程学院");
        return list;
    }

    public static void InsertPlus(){
        //三行代码即可完成
        String sql = "insert into student value(?,?,?,?,?)";
        Object []objects = {"689845","黄贵根","656972","信息工程学院",666.0};
        int n = DBUtil.executeUpdate(sql,objects);
    }

       然而即使如此,我们未来将还会有更优质的解决方案可以使用,这就等我们接下来学Mybatis之后就知道了。下期再见~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章