JDBC实现对数据库的CURD

        最近在学习JDBC的基础部分,刚好只把基础的增删改查写完了,拿来和大家一起分享,有问题的地方多多指教,同时也相当于对这一段时间的总结吧(菜鸟一枚)。

为了提高我们代码的复用性,我们将一些信息写在配置文件中,如果我们以后需要查询不同的数据库时,只需要对配置文件中url进行修改即可。

        因为我们在使用JDBC连接数据库的时候,获取连接的方式基本上都是一样的,所以我们也将其封装为一个类,并且所有的使用的对象,我们在对数据库进行增删改查以后,都要关闭资源,所以我们也将关闭资源的方法,写在这个类下边。

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

public class JDBCutil {
    /*
    获取链接,工具类都是静态方法 :连接数据库
     */
    public static Connection getConnection() throws Exception{
        /*创建io流对象,读取配置文件中的信息 */
        InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("JDBC.properties");
        Properties pro = new Properties();
        pro.load(is);
        
        String user = pro.getProperty("user");
        String url = pro.getProperty("url");
        String password = pro.getProperty("password");
        String driverClass = pro.getProperty("driverClass");
        // 创建驱动
        Class.forName(driverClass);

        Connection conn = DriverManager.getConnection(url, user, password);
        return conn;
    }
    // 关闭资源
    public static void closeResource(Connection conn, PreparedStatement pre) {
        try {
            if (conn != null) conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (pre != null) pre.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void closeResource(Connection conn, PreparedStatement pre, ResultSet res) {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (pre != null) {
                pre.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            if (res != null) {
                res.close();
            }

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

DriverManager类:

        用于实现数据库的连接,即实现创建驱动和创建数据库的连接对象。 

        解释一下这里为什么写两个关闭资源的方法,因为对数据库的增删改查其实可以分为两类,一类是增删改,一类是查,二者的区别在于查的这个过程,我们会产生一个数据集,就相当于我们在mysql中写查询语句的时候一样,会出现一张表,所以我们在Java中要对查询到的结果进行处理,而前者呢,只是对数据库表内信息的修改,修改成功以后,我们是看不到的,只能通过查询语句来验证。所以写了两个关闭资源的方法来针对两种类别的修改。

        那么接下来就让我正式开始写增删改查的代码了,呜呼!!

/* 先来看一个基础版本的添加数据*/ 

 public static void insert() {
        Connection con = null;
        PreparedStatement pre = null;
        try {
            con = JDBCutil.getConnection();
            // 预编译sql语句,返回prepareStatement实例对象
            String sql = "INSERT INTO student (s_no,class_no,s_name,s_sex,s_birthday) values (?,?,?,?,?)"; // ? 代表占位符
            pre = con.prepareStatement(sql);
            // 填充占位符
            pre.setString(1, "12000");
            pre.setString(2, "13007");
            pre.setString(3, "张三");
            pre.setString(4, "男");
            //日期类的数据类型要解析
            SimpleDateFormat simp = new SimpleDateFormat("yyyy-MM-dd");
            Date date = simp.parse("1999-12-12");
            pre.setDate(5, new java.sql.Date(date.getTime()));
            // 执行sql语句
            pre.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutil.closeResource(con,pre);
        }
    }

Connection接口:从DriverManager对象中获取对象,用于表示与数据库的连接对象

preparedStatement 对象PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句, 它的setXXX()方法,主要是用来设置我们占位符所在位置的内容,其中第一个形参表示下标,记住: 从1开始,第二个参数是占位符所在位置的内容,记住要一一对应。从Connection对象中获取。

其实有很多可以改进的地方,当然我们后面会有。

下一个是修改语句:

       

/*也是一个基础版本的修改*/ 

    // 修改student表的一条记录
    public static void update() {
        // 1,获取数据库的连接
        Connection connection = null;
        PreparedStatement prep = null;
        try {
            connection = JDBCutil.getConnection();
            // 2,预编译数据库语句,返回preparedStatement实例
            String sql = "update student set s_name = ? where s_no = ? ";
            prep = connection.prepareStatement(sql);
            // 3,填充占位符
            prep.setString(1, "李四");
            prep.setString(2, "12000");
            // 4,执行
            prep.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        // 5,关闭资源
        JDBCutil.closeResource(connection, prep);
        }
   }

其实学的差不多了,感觉基本套路都是一样的。

下一个看看删除:

     

 // 删除数据
    public static void delete() {
        Connection con = null;
        PreparedStatement pre = null;
        try {
            con = JDBCutil.getConnection();
            // 预编译sql语句,
            String sql = " delete from student where s_name = ? and s_no = ? ";
            // 填充占位符
            PreparedStatement prep = con.prepareStatement(sql);
            prep.setObject(1, "李四");
            prep.setObject(2, 12000);
            prep.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutil.closeResource(con, pre);
        }
    }

        接下来看看一个基础版本的查询方法,后面我会多给出几种查询以及对前面的增删改代码的修改,让他们更加使用于不同的场景。         

 // 查询数据
    public static void search() {
        Connection conn = null ;
        PreparedStatement pre = null;
        try {
            conn = JDBCutil.getConnection();
            String sql = "select * from student";
            PreparedStatement prep = conn.prepareStatement(sql);
            ResultSet result = prep.executeQuery();
            while (result.next()) {
                String s_no = result.getString("s_no");
                String class_no = result.getString("class_no");
                String  s_name = result.getString("s_name");
                String s_sex = result.getString("s_sex");
                String s_birthday = result.getString("s_birthday");
                System.out.println("s_no  " + s_no + "  class_no  " + class_no + "   s_name  " + s_name + "  s_sex  " + s_sex + "  s_birthday " + s_birthday);

            }
        } catch (Exception e ) {
            e.printStackTrace();
        } finally {
            JDBCutil.closeResource(conn,pre);
        }
    }

 ResultSet接口:

        用于表示查询以后的结果集,当prepareStatement对象调用查询操作的时候会返回该接口的对象。

        然后我们在对结果集进行解析的时候,使用ResultSet对象的getXXX()方法,获取对应数据库表中的字段名,并且进行一个输出,就会得到我们想要查询的结果。


  接下来我会给大家提供一个删除或者修改或者增加语句的改进方式

/*给大家来个删除操作的改进吧,其他的两种基本上一致,希望大家自己琢磨*/

import java.sql.Connection;
import java.sql.PreparedStatement;

public class update {
    public static void main(String[] args) {
        String sql = "delete from student where s_name = ? ";
        update p = new update();
        p.updataDatabase(sql,"xiao");

    }
    public  void updataDatabase(String sql, Object ...args) {
        Connection conn = null;
        PreparedStatement pre = null;
        try {
            conn = JDBCutil.getConnection();
            pre = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                pre.setObject(i + 1, args[i]);
            }
            pre.execute();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutil.closeResource(conn,pre);
        }
    }
}

提示: Object ... args :我们可以看成一个数组,传参的时候,传入几个,args.length就是几

               setObject() : 填充占位符,记住下标从1开始,并且由于我们不知道sql语句中的占位符有几个,所以选择使用循环进行填充。为什么使用setObject呢??因为我们也无法知道占位符所在的数据的数据类型啊!!!

其他的增加语句和修改语句都是这样的进行操作


接下来就是最难处理的查询了:

        首先看看对一条结果集的处理方式:

 这是咱们的学生表:

 

提示一下,我们设计的数据库中肯定不止一张表,我们在进行查询操作的时候尽量将每张表都封装进一个类中。

我封装的学生类:

import java.util.Date;

public class studentTest {
    private String sNo;
    private String sName;
    private String classNo;
    private Date sBirthday;

    public studentTest() {
    }

    public studentTest(String sNo, String sName, String classNo, Date sBirthday) {
        this.sNo = sNo;
        this.sName = sName;
        this.classNo = classNo;
        this.sBirthday = sBirthday;
    }

    public String getsNo() {
        return sNo;
    }

    public void setsNo(String sNo) {
        this.sNo = sNo;
    }

    public String getsName() {
        return sName;
    }

    public void setsName(String sName) {
        this.sName = sName;
    }

    public String getClassNo() {
        return classNo;
    }

    public void setClassNo(String classNo) {
        this.classNo = classNo;
    }

    public Date getsBirthday() {
        return sBirthday;
    }

    public void setsBirthday(Date sBirthday) {
        this.sBirthday = sBirthday;
    }

    @Override
    public String toString() {
        return "studentTest{" +
                "sNo='" + sNo + '\'' +
                ", sName='" + sName + '\'' +
                ", classNo='" + classNo + '\'' +
                ", sBirthday='" + sBirthday + '\'' +
                '}';
    }
}

        我们对王蕾的信息进行查询:

        

public void studentTest() {
        Connection conn = null;
        PreparedStatement pre = null;
        ResultSet resultSet = null;
        try {
            conn = JDBCutil.getConnection();
            String sql = "select s_no sNo,s_name sName,class_no classNo,s_birthday sBirthday from student where s_name = ?";
            pre = conn.prepareStatement(sql);
            pre.setString(1, "王蕾");
            resultSet = pre.executeQuery();
    //ResultSetMetaData 有关 ResultSet 中列的名称和类型的信息。
            ResultSetMetaData meta = resultSet.getMetaData();
            // 获取列数
            int columnCount = meta.getColumnCount();
            if (resultSet.next()) {
                studentTest s = new studentTest();
                for (int i = 0; i < columnCount; i++) {
                    // 获取列值
                    Object columValue = resultSet.getObject(i + 1);
         // 获取列名,这里因为我封装的类中的属性和数据库中对不上,所以使用别名,获取的也是别名
                    String columnLabelnName = meta.getColumnLabel(i + 1);
      // getDeclaredFiled() 能获取类本身的属性成员(私有,公共,保护),这里返回一个Field类对象,通过对象进行操作
                   Field declaredField = s.getClass().getDeclaredField(columnLabelnName);
                    // 取消java语言访问检查,能够提高反射的速度
                    declaredField.setAccessible(true);
                    //通过反射给指定的字段赋值
                    declaredField.set(s, columValue);
                }
                System.out.println(s);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCutil.closeResource(conn, pre, resultSet);
        }
    }
}

 这里可能注释有点多,我慢慢来解释,

 ResultSetMetaData 有关 ResultSet 中列的名称和类型的信息,我们可以通过此对象来找到数据表中列名信息。

提示:数据库中一般命名都是s_name 这种有下划线的,而java中命名一般都是驼峰命名法,所以我们在写jdbc代码的时候,sql语句进行使用别名,避免通过反射找不到与之对应的类的属性。

接下来给大家介绍一种针对不同的表的通用查询方式:

  /*
    针对不同的表的通用查询操作
     */

    public <T> T testDifTable(Class<T> clazz, String sql, Object... args) throws Exception {

        Connection conn = JDBCutil.getConnection();
        PreparedStatement pre = conn.prepareStatement(sql);
        for (int i = 0; i < args.length; i++) {
            pre.setObject(i + 1, args[i]);
        }
        ResultSet resultSet = pre.executeQuery();
        ResultSetMetaData metaData = pre.getMetaData();
        int columnCount = metaData.getColumnCount();
        if (resultSet.next()) {
            T t = clazz.newInstance();
            for (int i = 0; i < columnCount; i++) {
                Object clomnValue = resultSet.getObject(i + 1);
                String columnName = metaData.getColumnName(i + 1);
                Field declaredField = t.getClass().getDeclaredField(columnName);
                declaredField.setAccessible(true);
                declaredField.set(t, clomnValue);
            }
            JDBCutil.closeResource(conn, pre, resultSet);
            return t;
        }
        return null;
    }


/*再给大家几个测试用例:*/
   @Test
    public void test() throws Exception {
//        String sql = "select s_no from student where s_name = ?";
//        student clazz = new student();
//        student s = testDifTable(clazz.getClass(), sql, "王蕾");
//        System.out.println(s);

        String sql1 = "select s_no,s_name from student where s_name = ?";
        student s1 = testDifTable(new student().getClass(), sql1, "王蕾");
        System.out.println(s1);
    }

        clazz.newInstence: 用于创建此Clazz对象表示的类的新实例,它是一种非静态的方法,只能通过类对象访问。

其实大多数的代码我们自己动手写一遍以后,大概的思路基本上就清晰了,我们可以先不着急往后学,停下来,做做总结,加油

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值