首页 > 代码库 > 一颗简单的JDBC栗子
一颗简单的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 }
简易封装一个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操作进一步学习。
一颗简单的JDBC栗子