简介
导入/移除 jar包
JDBC使用
对数据增删改查
实体类封装结果集
JDBC介绍 JDBC概述 JDBC(Java DataBase Connectivity, Java数据库连接) ,是一种用于执行SQL语句的Java API,为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成
有了JDBC,程序员只需用JDBC API写一个程序,就可访问所有数据库
Sun公司、数据库厂商、程序员三方关系
SUN公司是规范制定者,制定了规范JDBC(连接数据库规范)
DriverManager类 作用:管理各种不同的JDBC驱动
Connection接口 作用:Java程序和mysql建立的连接
Statement接口和PreparedStatement接口 作用:承载SQL给数据库
ResultSet接口 作用:返回SQL运算的结果给Java程序
数据库厂商微软、甲骨文等分别提供实现JDBC接口的驱动jar包
程序员学习JDBC规范来应用这些jar包里的类。
JDBD历史版本及特征
JDBC 1.0
JDBC 1.0 随JDK1.1一起发布,JDBC操作相关的接口和类位于java.sql包中
JDBC 2.0
JDBC 2.0 API被划分为两部分:核心API和扩展API,有两个包,分别是java.sql包和javax.sql包
1 2 3 4 5 6 7 8 9 10 11 12 13 在支持新功能方面:包括结果集可以向后滚动,批量的更新数据。另外,还提供了UNICODE字符集的字符流操作。 在支持SQL的数据类型方面:新增加的BLOB, CLOB,和数组接口能够是应用程序操作大块的数据类型 JDBC1.0是原来是用DriverManager类来产生一个对数据源的连接。JDBC2.0用一种替代的方法,使用DataSource的实现,代码变的更小巧精致,也更容易控制。 如果DataSource对象实现与一个支持连接池的中间层的服务器一起工作,DataSource对象就会自动的返回连接池中的连接,这个连接也是可以重复利用的。 在一个事务中涉及到了多个数据库服务器。获得一个用来支持分布式事务的连接与获得连接池中的连接是很相似的。同样,不同之处在于DataSource的实现上的不同,而不是在应用程序中获得连接的方式上有什么不同。 RowSet接口扩展了ResultSet接口。这样RowSet对象就有了ResultSet对象所有的功能。不可以滚动的ResultSet变成了可以滚动的RowSet。
JDBC访问数据库编码步骤
加载一个Driver驱动
创建数据库连接(Connection)
创建SQL命令发送器Statement
通过Statement发送SQL命令并得到结果
处理结果(select语句)
关闭数据库资源ResultSet Statement Connection
模块/项目 导入依赖jar包 创建项目
创建Java项目和模块
结构图
导入jar包 mysql-connector-java-8.0.11.jar
将jar文件放入项目的lib目录中
给当前项目添加依赖(告诉当前项目/模块可以依赖jar文件中的代码)
移除jar包
移除依赖
移除jar包
JDBC使用
数据库名:mydb
字符集:utf8mb4
表:4张表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 package com.excepenxi.test1;import java.sql.Connection;import java.sql.Driver;import java.sql.DriverManager;import java.sql.Statement;public class TestJDBC { public static void main (String[] args) throws Exception { Driver driver = new com .mysql.cj.jdbc.Driver(); DriverManager.registerDriver(driver); String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai" ; String user="root" ; String password="root" ; Connection connection = DriverManager.getConnection(url, user,password ); Statement statement = connection.createStatement(); String sql="insert into dept values(50,'教学部','北京');" ; int rows = statement.executeUpdate(sql); System.out.println("影响数据行数为:" +rows); statement.close(); connection.close(); } }
JDBC常见异常分析
错误1:没有添加jar包或者com.mysql.jdbc2.Driver路径错误
Exception in thread "main" java.lang.ClassNotFoundException: com.mysql.jdbc2.Driver
解决:导入依赖jar包
错误2:URL错误
Exception in thread "main" java.sql.SQLException:No suitable driver found for jbdc:mysql://127.0.0.1:3306/stumgr
解决:检查协议、IP、端口号、库名
错误3:用户名或者密码错误
Exception in thread "main" java.sql.SQLException:Access denied for user 'root'@'localhost' (using password: YES)
解决:更正用户名和密码
错误4:主键冲突
Exception in thread "main" com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Duplicate entry '90' for key 'PRIMARY'
解决:已经存在90,更新为其他数值或者 default/null 默认自增(前提主键设置自增)
错误5:mysql安全加密机制
Exception in thread "main" java.sql.SQLException:Public Key Retrieval is not allowed
如果用户使用 sha256_password 认证,密码在传输过程中必须使用 TLS 协议保护,但是如果 RSA 公钥不可用,可以使用服务器提供的公钥;可以在连接中通过 ServerRSAPublicKeyFile 指定服务器的 RSA 公钥,或者AllowPublicKeyRetrieval=True参数以允许客户端从服务器获取公钥;但是需要注意的是 AllowPublicKeyRetrieval=True可能会导致恶意的代理通过中间人攻击(MITM)获取到明文密码,所以默认是关闭的,必须显式开启 在jdbc连接添加上参数allowPublicKeyRetrieval=true即可,注意参数间用&
解决:添加参数 allowPublicKeyRetrieval=true(参数最好不加,容易被攻击)
驱动的加载 加载数据库驱动时,我们可以通过自己创建一个实例的方式,然后去注册驱动
在查看Driver的源代码时我们发现,该类内部有一个静态代码块,在代码块中就是在实例化一个驱动并在驱动中心注册.静态代码块会在类进入内存时执行,也就是说,我们只要让该类字节码进入内存,就会自动完成注册,不需要我们手动去 new com.mysql.cj.jdbc.Driver()
,在代码中直接使用反射,通过Class.forName(“com.mysql.jdbc.Driver”),加载该类进入内存即可
1 2 3 4 Driver driver = new com .mysql.cj.jdbc.Driver();DriverManager.registerDriver(driver); Class.forName("com.mysql.cj.jdbc.Driver" );
查看jar包发现jar包中已经默认配置了驱动类的加载
jar–META-INF–services–java.sql.Driver–com.mysql.jdbc.Driver,在加载jar包时,会自动读取该内容并加载驱动,所以我们不去编写Class.forName(“com.mysql.jdbc.Driver”),程序也是可以自动完成加载驱动的;稳妥起见,建议加上,以免出现mysql版本不一致,以及jar包不一致导致无法加载驱动
添加异常捕获处理
优化代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 package com.excepenxi.test1;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;public class TestJDBC2 { private static String driver = "com.mysql.cj.jdbc.Driver" ; private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true" ; private static String user="root" ; private static String password="root" ; public static void main (String[] args) { Connection connection=null ; Statement statement=null ; try { Class.forName(driver); connection =DriverManager.getConnection(url, user,password); statement = connection.createStatement(); String sql="insert into dept values(DEFAULT,'助教部门','北京');" ; int rows = statement.executeUpdate(sql); System.out.println("影响数据行数为:" +rows); }catch (Exception e){ e.printStackTrace(); }finally { if (null != statement){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != connection){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
对数据库进行增删改查 增加、删除和修改操作 如果出现报错,可能是有外键约束,删除或者修改外键
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 package com.excepenxi.test1;import java.sql.Connection;import java.sql.DriverManager;import java.sql.SQLException;import java.sql.Statement;public class TestJDBC3 { private static String driver = "com.mysql.cj.jdbc.Driver" ; private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true" ; private static String user="root" ; private static String password="root" ; public static void main (String[] args) { testUpdate(); } public static void testUpdate () { Connection connection=null ; Statement statement=null ; try { Class.forName(driver); connection =DriverManager.getConnection(url, user,password); statement = connection.createStatement(); String sql="update dept set dname='总部',loc='上海' where deptno=50;" ; int rows = statement.executeUpdate(sql); System.out.println("影响数据行数为:" +rows); }catch (Exception e){ e.printStackTrace(); }finally { if (null != statement){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != connection){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
查询操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 package com.excepenxi.test1;import java.sql.*;public class TestJDBC4 { private static String driver = "com.mysql.cj.jdbc.Driver" ; private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true" ; private static String user="root" ; private static String password="root" ; public static void main (String[] args) { testQuery(); } public static void testQuery () { Connection connection=null ; Statement statement=null ; ResultSet resultSet=null ; try { Class.forName(driver); connection = DriverManager.getConnection(url, user,password); statement = connection.createStatement(); String sql="select * from emp;" ; resultSet = statement.executeQuery(sql); while (resultSet.next()){ int empno = resultSet.getInt("empno" ); String ename = resultSet.getString("ename" ); String job = resultSet.getString("job" ); int mgr = resultSet.getInt("mgr" ); Date hiredate = resultSet.getDate("hiredate" ); double sal = resultSet.getDouble("sal" ); double comm = resultSet.getDouble("comm" ); int deptno = resultSet.getInt("deptno" ); System.out.println("" +empno+" " +ename+" " +job+" " +mgr+" " +hiredate+" " +sal+" " +comm+" " +deptno); } }catch (Exception e){ e.printStackTrace(); }finally { if (null != resultSet){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != statement){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != connection){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } } }
ResultSet里的数据一行一行排列,每行有多个字段,且有一个记录指针,指针所指的数据行叫做当前数据行,我们只能来操作当前的数据行。我们如果想要取得某一条记录,就要使用ResultSet的next()方法 ,如果我们想要得到ResultSet里的所有记录,就应该使用while循环。
ResultSet对象自动维护指向当前数据行的游标。每调用一次next()方法,游标向下移动一行。
初始状态下记录指针指向第一条记录的前面,通过next()方法指向第一条记录。循环完毕后指向最后一条记录的后面。
作为一种好的编程风格,应在不需要Statement对象和Connection对象时显式地关闭它们。关闭Statement对象和Connection对象的语法形式为:用户不必关闭ResultSet。当它的 Statement 关闭、重新执行或用于从多结果序列中获取下一个结果时,该ResultSet将被自动关闭。
方法名
说明
boolean next()
将光标从当前位置向下移动一行
boolean previous()
游标从当前位置向上移动一行
void close()
关闭ResultSet 对象
int getInt(int colIndex)
以int形式获取结果集当前行指定列号值
int getInt(String colLabel)
以int形式获取结果集当前行指定列名值
float getFloat(int colIndex)
以float形式获取结果集当前行指定列号值
Float getFloat(String colLabel)
以float形式获取结果集当前行指定列名值
String getString(int colIndex)
以String 形式获取结果集当前行指定列号值
StringgetString(String colLabel)
以String形式获取结果集当前行指定列名值
实体类封装结果集
为什么将结果封装成对象或者对象集合?
Java是面向对象的编程语言,java中所有的数据处理都是基于面向对象的编码风格实现的,让数据以符合java风格的形式存在,便于对数据的后续处理
ResultSet 集合虽然可以存放数据,但是它是JDBC中查询数据的一种手段,是一种数据的临时存储方案,使用完毕是要进行释放和关闭
如何将结果集中的数据在java中进行存储和传递?
准备和数据库表格相对应的一个实体类,用于封装结果集中的每一条数据,数据库表格中的每一个字段就是实体类的一个属性,实体类的一个对象就可以用于存储数据库表中的一条记录。
准备实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 package com.excepenxi.entity;import java.io.Serializable;import java.util.Date;public class Emp implements Serializable { private Integer empno; private String ename; private String job; private Integer mgr; private Date hiredate; private Double sal; private Double comm; private Integer deptno; @Override public String toString () { return "Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr=" + mgr + ", hiredate=" + hiredate + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}' ; } public Emp (Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double comm, Integer deptno) { this .empno = empno; this .ename = ename; this .job = job; this .mgr = mgr; this .hiredate = hiredate; this .sal = sal; this .comm = comm; this .deptno = deptno; } public Emp () { } public Integer getEmpno () { return empno; } public void setEmpno (Integer empno) { this .empno = empno; } public String getEname () { return ename; } public void setEname (String ename) { this .ename = ename; } public String getJob () { return job; } public void setJob (String job) { this .job = job; } public Integer getMgr () { return mgr; } public void setMgr (Integer mgr) { this .mgr = mgr; } public Date getHiredate () { return hiredate; } public void setHiredate (Date hiredate) { this .hiredate = hiredate; } public Double getSal () { return sal; } public void setSal (Double sal) { this .sal = sal; } public Double getComm () { return comm; } public void setComm (Double comm) { this .comm = comm; } public Integer getDeptno () { return deptno; } public void setDeptno (Integer deptno) { this .deptno = deptno; } }
实体类封装结果集 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 package com.excepenxi.test1;import com.excepenxi.entity.Emp;import java.sql.*;import java.util.ArrayList;import java.util.List;public class TestJDBC5 { private static String driver = "com.mysql.cj.jdbc.Driver" ; private static String url="jdbc:mysql://127.0.0.1:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true" ; private static String user="root" ; private static String password="root" ; public static void main (String[] args) { List<Emp> emps = testQuery(); for (Emp emp : emps) { System.out.println(emp); } } public static List<Emp> testQuery () { Connection connection=null ; Statement statement=null ; ResultSet resultSet=null ; List<Emp> list =null ; try { Class.forName(driver); connection = DriverManager.getConnection(url, user,password); statement = connection.createStatement(); String sql="select * from emp;" ; resultSet = statement.executeQuery(sql); list=new ArrayList <>(); while (resultSet.next()){ int empno = resultSet.getInt("empno" ); String ename = resultSet.getString("ename" ); String job = resultSet.getString("job" ); int mgr = resultSet.getInt("mgr" ); Date hiredate = resultSet.getDate("hiredate" ); double sal = resultSet.getDouble("sal" ); double comm = resultSet.getDouble("comm" ); int deptno = resultSet.getInt("deptno" ); Emp emp = new Emp (empno, ename, job, mgr, hiredate, sal, comm, deptno); list.add(emp); } }catch (Exception e){ e.printStackTrace(); }finally { if (null != resultSet){ try { resultSet.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != statement){ try { statement.close(); } catch (SQLException e) { e.printStackTrace(); } } if (null != connection){ try { connection.close(); } catch (SQLException e) { e.printStackTrace(); } } } return list; } }