JDBC详解

JDBC简介

JDBC(Java DataBase Connectivity),是Java和数据库连接的桥梁,是一个规范而不是实现,能够执行sql语句。它由一组用Java语言编写的类和接口组成。

各个不同类型的数据库都有相应的实现。本文中的代码都是针对MySql数据库实现的。

JDBC流程简介

  • 创建一个简单的Java项目,通过build path导入连接数据库的jar包 
  • 初始化驱动类Driver
Class.forName("com.mysql.jdbc.Driver");

          Class.forName的作用是加载和初始化类Driver,返回的是一个类对象。

  • 通过DriverManager创建与数据库之间的一个连接
conn= DriverManager.getConnection("jdbc:mysql:///jdbc_demo01?characterEncoding=UTF-8", "root","Cpic1234");

   第一个参数是连接数据库的地址,第二个参数是用户名,第三个参数是密码。

  • 通过连接创建Statement或者PreparedStatement
Statement s=conn.createStatement();

  它们的作用都是执行sql语句。这里创建的是Statement,平时很少用到Statement,基本上用的都是PrepareStatement,至于为什么后面会讲到。

  • 写sql语句,用execute方法执行
String sql="insert into student values(1,"+"'九儿'"+"'男')";
s.execute(sql);

  这里可以看出,Statement执行的sql语句是多段字符串拼接而成的,代码看着很费劲。

  • 释放资源
s.close();
conn.close();

  这里要注意,释放资源的顺序是从里到外。

以上是使用JDBC整体的一个流程,下面对增删改查,资源释放,Statement和PreparedStatement之间的区别做一个详细介绍。

JDBC编程详解

  • 插入
//增加学员
    public static void add() {
         String sql="insert into student values(?,?,?)";
         Connection conn=null;
         PreparedStatement ps=null;
         conn=Dbutil.getConnection();
         try {
             ps=conn.prepareStatement(sql);
             ps.setInt(1, 2);
             ps.setString(2, "牛皮");
             ps.setString(3, "男");
             ps.executeUpdate();
             ps.close();
             conn.close();
         } catch (SQLException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
    }
  • 修改
//修改学员信息
    public static void update() {
        String sql="update student set sname=? where sid=?";
        Connection conn=null;
        PreparedStatement ps=null;
        conn=Dbutil.getConnection();
        try {
            ps=conn.prepareStatement(sql);
            ps.setString(1, "学渣");
            ps.setInt(2, 2);
            ps.executeUpdate();
            ps.close();
            conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
  • 删除
//删除学员
    public static void delete() {
        String sql="delete from student";
        Connection conn=null;
        PreparedStatement ps=null;
        conn=Dbutil.getConnection();
        try {
            ps=conn.prepareStatement(sql);
            //ps.setInt(1, 1);
            ps.executeUpdate();
            ps.close();
            conn.close();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

以上是增删改操作,通过代码可以发现,出了sql语句有区别,其他都一样。上面代码有个缺点,释放资源的代码重复出现。我们可以优化下代码,方法是写一个工具类Dbutil。具体代码如下

public class Dbutil {
    /**
     * 取得数据库的连接
     * @return 数据库的一个链接
     */
    public static Connection getConnection() {
        Connection conn=null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn= DriverManager.getConnection("jdbc:mysql:///jdbc_demo01?characterEncoding=UTF-8", "root","Cpic1234");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }
    /**
     * 释放资源
     * @param rs 
     * @param ps
     * @param conn
     */
    public static void closeAll(ResultSet rs,PreparedStatement ps,Connection conn) {
        try {
            rs.close();
            ps.close();
            conn.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

这样可以通过Dbutil.getConnection()方法获取一个Connection对象,事务执行完毕,再调用Dbutil.closeAll()将资源释放。

  • 查询
//查询
    public static List<Student> find(){
        List<Student>list=new ArrayList<Student>();
         String sql="select * from  student ";
         Connection conn=null;
         PreparedStatement ps=null;
         conn=Dbutil.getConnection();
         try {
             ps=conn.prepareStatement(sql);
             ResultSet rs=ps.executeQuery();
        if(rs!=null){   
while(rs.next()) {   Student stu=new Student();   stu.setSid(rs.getInt("sid"));   stu.setSname(rs.getString("sname"));   stu.setSex(rs.getString("sex").toCharArray()[0]);   list.add(stu);   }
} Dbutil.closeAll(rs, ps, conn); }
catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return list; }

调用executeQuery()返回的是结果集ResultSet。必须先检查值为Null的情况,否则后面可能会有报空指针异常的情况。

首先用while(rs.next())遍历结果集,循环体内用rs.getInt("sid")获取一条学生记录的sid,rs.getString("sname"),rs.getString("sex")获取一条学生记录的sname和sex。

然后我们就可以把这些值复制给一个具体的对象new Student();

当然,也可以用getInt(1)通过下标的方式取值,但不建议这么做,因为如果数据库表结构发生改变就会报错。

Statement和PreparedStatement的区别

  1. 都可以执行sql。Statement需要拼接sql语句,如果是复杂的sql语句,很容易写错,看代码也费劲。PreparedStatement根据sql创建,sql语句使用占位符,语句结构已经事先定义好。
  2. Statement没执行一次sql,都要重新编译一次;PreparedStatement使用预编译机制,大大提高了运行效率。
  3. Statement有sql注入的风险;PreparedStatement因为已经定义好了sql的语句结构,大大降低了sql注入的风险。

 

posted on 2020-05-23 00:33  只挣朝夕  阅读(452)  评论(0)    收藏  举报