一颗简单的JDBC栗子

前言:安装好数据库之后,我们编写的java程序是不能直接使用数据库的,而JDBC(Java Database Connectivity,即java数据库连接)是java语言里用来规范客户端程序访问数据库的API,有了它,我们就可以向各种关系型数据库发送SQL语句,从而实现对数据库的增删改查等操作。

准备工作:

1.数据库:这里以MySQL为例,创建一个Person表,四个字段分别为:自增主键id、姓名name、性别gender、年龄age

 1 DROP TABLE IF EXISTS `person`;
 2 CREATE TABLE `person` (
 3   `id` int(11) NOT NULL AUTO_INCREMENT,
 4   `name` varchar(11) DEFAULT NULL,
 5   `gender` varchar(11) DEFAULT NULL,
 6   `age` int(11) DEFAULT NULL,
 7   PRIMARY KEY (`id`)
 8 ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
 9 
10 INSERT INTO `person` VALUES ('1', '小明', '', '18');
11 INSERT INTO `person` VALUES ('2', '小芳', '', '19');
12 INSERT INTO `person` VALUES ('3', '小刚', '', '20');
13 INSERT INTO `person` VALUES ('4', '小丽', '', '21');

 

2.数据库驱动程序jar包:这里使用的是mysql-connector-java-5.1.42-bin.jar

3.在eclipse中导入驱动包:右键项目点击Builder Path----Configure Builder Path----Add External JARs----找到jar包位置选择打开----Ok,可以开始搞事情了!

图示如下:

先完整演示一段简单的JDBC操作过程。

 

 1 package com.jdbc.demo;
 2 
 3 import java.sql.Connection;
 4 import java.sql.DriverManager;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 
 9 //一段完整的jdbc操作过程,后面会详细介绍,为了代码视图简洁,异常均抛出。
10 public class Demo {
11     
12     public static void main(String[] args) throws ClassNotFoundException, SQLException {
13         //第1步,注册加载驱动类
14         Class.forName("com.mysql.jdbc.Driver");
15         //第2步,获取数据库连接,方法中3个参数依次为:
16         //url:就是你要连接的数据库的地址,不同的数据库格式会有差异
17         //user:就是数据库的用户名,例如MySQL的root
18         //password:数据库连接密码
19         String url = "jdbc:mysql://127.0.0.1/hb?characterEncoding=utf-8";
20         String user = "root";
21         String password = "123123";
22         Connection conn = DriverManager.getConnection(url, user, password);
23         //第3步,构造语句集对象,为了简要直观,这里使用Statement,不过实际开发建议用PreparedStatement
24         String sql = "select * from person";
25         Statement stmt = conn.createStatement();
26         //第4步,提交SQL语句,这是是查询,所以调用executeQuery方法,会返回一个集合,我们可以遍历输出其中信息;
27         //如果是增删改,不同于数据库中的3种SQL语句,这里都是调用executeUpdate方法,返回的是int值
28         ResultSet rs = stmt.executeQuery(sql);
29         //第5步(可选),处理结果,在这里我们输出Person表中所有人名
30         while(rs.next()) {
31             String name = rs.getString("name");
32             System.out.println(name);
33         }
34         //第6步,关闭相关对象,这里为ResultSet,Statement,Connection
35         //注意!关闭顺序和声明顺序相反!依次如下
36         rs.close();
37         stmt.close();
38         conn.close();
39         
40     }
41 
42 }

程序运行结果如下:

 相关API介绍

java.sql.Connection:

  与数据库的连接,注意导包不要导错,因为导入MySQL驱动后,在com.mysql.jdbc下也有个Connection,如果导成这个会出错;

  连接由JDBC管理层的DriverManager类调用getConnection方法获得,方法中后两个参数比较简单,一个用户名一个密码,第一个参数url格式则与各数据库有关

    MySQL: jdbc:mysql://<host><:port>/<database_name>,默认端口3306,如果服务器使用默认端口则port可以省略,可以在URL中添加额外的连接属性jdbc:mysql://<host>:<port>/<database_name>?property1=value1&property2=value2;

    ORACLE:jdbc:oracle:thin:@<host><:port>:<database_name>

java,sql.Statement 和java.sql.PreparedStatement

  语句对象,用于提交SQL语句;

  Statement通常用于执行静态SQL语句,statement.excute(sql)即可提交;

  PreparedStatement可以执行动态SQL语句,允许参数化查询,而且性能更好,还可以有效避免SQL注入式攻击,后面示例都使用PreparedStatement

  

 

java.sql.ResultSet:

  指定SQL语句(通常为查询)执行返回的原始结果集,在实际开发我们通常对结果进行再封装,以方便调用

实体类Person

 

 1 package com.jdbc.entity;
 2 //实体类Person,属性与数据库中字段对应
 3 public class Person {
 4     private Integer id;
 5     private String name;
 6     private String gender;
 7     private Integer age;
 8     public Integer getId() {
 9         return id;
10     }
11     public void setId(Integer id) {
12         this.id = id;
13     }
14     public String getName() {
15         return name;
16     }
17     public void setName(String name) {
18         this.name = name;
19     }
20     public String getGender() {
21         return gender;
22     }
23     public void setGender(String gender) {
24         this.gender = gender;
25     }
26     public Integer getAge() {
27         return age;
28     }
29     public void setAge(Integer age) {
30         this.age = age;
31     }
32     @Override
33     public String toString() {
34         return "Person [id=" + id + ", name=" + name + ", gender=" + gender
35                 + ", age=" + age + "]";
36     }
37     
38 }

 

JdbcUtil工具类供加载驱动类、获取连接、关闭对象

package com.jdbc.demo;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class JdbcUtil {
    private static String driver = "com.mysql.jdbc.Driver";
    private static String url = "jdbc:mysql://127.0.0.1/hb?characterEncoding=utf-8";
    private static String username = "root";
    private static String password = "hjh123";
    //静态代码块中注册加载驱动类
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    //封装获取连接方法
    public static Connection getConnection() {
        try {
            return DriverManager.getConnection(url, username, password);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //封装关闭对象方法
    public static void close(ResultSet rs, Statement statement, Connection conn) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    
}

 

简易封装一个DAO类实现对Person表的增删改查

 

  1 package com.jdbc.demo;
  2 
  3 import java.sql.Connection;
  4 import java.sql.PreparedStatement;
  5 import java.sql.ResultSet;
  6 import java.sql.SQLException;
  7 import java.util.ArrayList;
  8 import java.util.List;
  9 
 10 import com.jdbc.entity.Person;
 11 
 12 
 13 //封装Person表的增删改查方法
 14 public class PersonDaoImpl {
 15     //这里的问号?是占位符,用于给将要传递的参数占位置,实现了动态SQL语句的执行
 16     //添加一条记录的SQL语句,第一个参数由于数据表中是主键自增,这里可以用null
 17     private static final String SQL_ADD = "insert into person values(null,?,?,?)";
 18     //删除,指定id的记录
 19     private static final String SQL_DEL = "delete from person where id = ?";
 20     //修改,指定id的记录
 21     private static final String SQL_UPD = "update person set name = ?,gender = ?,age = ? where id = ?";
 22     //查询,指定id记录
 23     private static final String SQL_ID = "select * from person where id = ?";
 24     //查询,所有记录
 25     private static final String SQL_ALL = "select * from person";
 26     
 27     //添加一条记录
 28     public boolean add(Person p) {
 29         Connection conn = JdbcUtil.getConnection();
 30         PreparedStatement ps = null;
 31         try {
 32             ps = conn.prepareStatement(SQL_ADD);
 33             //把我们传入的person对象的属性值分作为占位符的值传入,数组各值顺序对应占位符字段顺序
 34             Object[] params = {p.getName(),p.getGender(),p.getAge()};
 35             int len = params.length;
 36             for(int i = 0;i < len;i++) {
 37                 //!!!这里比较特殊,很多下标都是从0开始,例如数组,
 38                 //!!!但是这个setObject方法第一个索引参数是从1开始
 39                 ps.setObject(i+1, params[i]);
 40             }
 41             //这里的整型返回值line意指更新的记录数,或者说是数据库中受影响的记录行数
 42             //之前的Statement.excute方法要传入SQL语句字符串参数,
 43             //但是用了PreparedStatement就不用传参数了,因为在前面我们已经预定义处理了
 44             int line = ps.executeUpdate();
 45             if (line > 0) {
 46                 System.out.println("添加成功,受影响记录数为"+line);
 47                 return true;//结束,但是后面finally区代码会执行
 48             }
 49         } catch (SQLException e) {
 50             e.printStackTrace();
 51         } finally {
 52             //关闭相关对象
 53             JdbcUtil.close(null, ps, conn);
 54         }
 55         System.out.println("添加失败");
 56         return false;
 57     }
 58     //删除一条记录
 59     public boolean delete(int id) {
 60         Connection conn = JdbcUtil.getConnection();
 61         PreparedStatement ps = null;
 62         try {
 63             ps = conn.prepareStatement(SQL_DEL);
 64             ps.setInt(1, id);
 65             //这里的整型返回值line意指更新的记录数,或者说是数据库中受影响的记录行数
 66             int line = ps.executeUpdate();
 67             if (line > 0) {
 68                 System.out.println("删除成功,受影响记录数为"+line);
 69                 return true;//结束,但是后面finally区代码会执行
 70             }
 71         } catch (SQLException e) {
 72             e.printStackTrace();
 73         } finally {
 74             //关闭相关对象
 75             JdbcUtil.close(null, ps, conn);
 76         }
 77         System.out.println("删除失败");
 78         return false;
 79     }
 80     //修改一条记录
 81     public boolean update(Person p) {
 82         Connection conn = JdbcUtil.getConnection();
 83         PreparedStatement ps = null;
 84         try {
 85             ps = conn.prepareStatement(SQL_UPD);
 86             //把我们传入的person对象的属性值分作为占位符的值传入
 87             Object[] params = {p.getName(),p.getGender(),p.getAge(),p.getId()};
 88             int len = params.length;
 89             for(int i = 0;i < len;i++) {
 90                 //!!!这里比较特殊,很多下标都是从0开始,例如数组,
 91                 //!!!但是这个setObject方法第一个索引参数是从1开始
 92                 ps.setObject(i+1, params[i]);
 93             }
 94             //这里的整型返回值line意指更新的记录数,或者说是数据库中受影响的记录行数
 95             int line = ps.executeUpdate();
 96             if (line > 0) {
 97                 System.out.println("修改成功,受影响记录数为"+line);
 98                 return true;//结束,但是后面finally区代码会执行
 99             }
100         } catch (SQLException e) {
101             e.printStackTrace();
102         } finally {
103             //关闭相关对象
104             JdbcUtil.close(null, ps, conn);
105         }
106         System.out.println("修改失败");
107         return false;
108     }
109     //获取一条记录,这里返回的不再是布尔值,而是一个对应数据表中一条记录的Person对象
110     public Person findById(int id) {
111         Connection conn = JdbcUtil.getConnection();
112         PreparedStatement ps = null;
113         ResultSet rs = null;
114         try {
115             ps = conn.prepareStatement(SQL_ID);
116             ps.setInt(1, id);
117             //返回结果集,这里是查询指定id,所以结果集中应该最多只有一条记录
118             rs = ps.executeQuery();
119             if(rs.next()) {
120                 Person p = new Person();
121                 p.setId(id);
122                 //这里的Result的getObject方法,参数为数据表中字段名,可以获取对应字段值
123                 p.setName(rs.getString("name"));
124                 p.setGender(rs.getString("gender"));
125                 p.setAge(rs.getInt("age"));
126                 return p;//返回p对象,结束
127             }
128         } catch (SQLException e) {
129             e.printStackTrace();
130         } finally {
131             //关闭相关对象
132             JdbcUtil.close(rs, ps, conn);
133         }
134         return null;
135     }
136     //获取所有记录,返回结果集不便操作,故封装到一个List中作为方法返回值
137         public List<Person> findAll() {
138             Connection conn = JdbcUtil.getConnection();
139             PreparedStatement ps = null;
140             ResultSet rs = null;
141             List<Person> list = new ArrayList<>();
142             try {
143                 ps = conn.prepareStatement(SQL_ALL);
144                 //返回结果集
145                 rs = ps.executeQuery();
146                 while(rs.next()) {
147                     //创建一个Person对象
148                     Person p = new Person();
149                     //这里的Result的getObject方法,参数为数据表中字段名,可以获取对应字段值
150                     p.setId(rs.getInt("id"));
151                     p.setName(rs.getString("name"));
152                     p.setGender(rs.getString("gender"));
153                     p.setAge(rs.getInt("age"));
154                     list.add(p);//添加至集合
155                 }
156                 return list;
157             } catch (SQLException e) {
158                 e.printStackTrace();
159             } finally {
160                 //关闭相关对象
161                 JdbcUtil.close(rs, ps, conn);
162             }
163             return null;
164         }
165 }

 小结

JDBC操作数据库步骤概述如下:

1.注册加载驱动类

2.获取连接

3.创建语句对象

4.执行SQL语句(excute)

5(可选).处理结果

6.关闭相关对象(注意顺序:依次为ResultSet、Statement/PreparedStatement、Connction)

扩展

上述过程能基本完整实现对一个数据表的操作,但是只能针对固定的单个数据表,利用泛型、反射等技术,可对dao层代码进行抽取和封装,添加SQL语句实现联表查询,使得程序更具有通用性和灵活性,对任意的数据表都适用。在实际开发过程中,有框架已经封装了JDBC,如hibernate和mybatis,可以通过底层的JDBC操作进一步学习。

posted @ 2017-07-15 16:35  窗外天空晴朗  阅读(589)  评论(3编辑  收藏  举报