JDBC

Java DataBase Connectivity,java数据库连接,为了降低操作数据的难度,java提供jdbc,按照java
面向对象特点,对操作进行了很多封装。



 

JDBC提供了很多接口,然后不同数据库厂商去实现这个接口,到底底层如何去实现,不同的数据库不一样,不同的数据库厂商需要提供接口实现类(驱动类、驱动程序
Driver、驱动)

我们连接不同的数据库,我们只需要使用不同的驱动即可。

J:Java:提供访问数据库的规范(接口),

DBC:接口的实现,厂商去实现这个接口。

JDBC是一种用于执行SQL语句的java api.

版本号

1.1.1 Major. Minor. Build

Major:项目由架构、大规模的变化

Minor:有新功能的时候

Build:编译版本

JDBC开发

Java程序使用第三方提供工具框架,都需要导入jar包

可以通过以下网址搜索找到mysql的相关jar包

https://mvnrepository.com/ <https://mvnrepository.com/>

下载好jar包后,在于src同级的目录下,建立一个lib文件夹,添加jar包,并添加依赖



代码实现

通过一个简单的案例来实现JDBC的使用
import java.sql.*; public class Demo02 { public static void main(String[]
args) throws ClassNotFoundException, SQLException { //1注册驱动
Class.forName("com.mysql.jdbc.Driver"); //2建立连接 String url =
"jdbc:mysql://localhost:3306/mydb01"; String usernName = "xxx"; //登录数据库的账号
String password = "xxxx"; //登录数据库的密码 Connection conn =
DriverManager.getConnection(url, usernName, password); //3获取执行sQL语句的对象
Statement statement = conn.createStatement(); //4获取数据库返回的结果 String sql =
"delete from emp where empno = " +"7499"; String sqlUpdate = "update emp set
sal = "+10000+" where empno = " +"7369"; String sqlInsert = "INSERT INTO emp
VALUES(2018,\"boss\",\"king\",NULL,\"2018-8- 8\",15000,10000,10);"; //5处理数据集
int i = statement.executeUpdate(sql); int s =
statement.executeUpdate(sqlUpdate); int ins =
statement.executeUpdate(sqlInsert); System.out.println(i + "行受到影响----删除");
System.out.println(s + "行受到影响----更新"); System.out.println(ins + "行受到影响----插入");
//6关闭连接 statement.close(); conn.close(); } }
使用JDBC的顺序

(1)注册数据库驱动

(2)和数据库建立连接

(3)获取执行SQL语句的对象

(4)获取数据库返回的结果

(5)处理数据集(逻辑代码)

(6)释放资源,关闭连接

常用类

Connection

通过配置文件可以创建一个connect对象

Statement

通过connect对象获取操作数据库的Statement对象,

         通过它来实现对数据库增删改查操作。

         executeQuery():查,返回数据集

         executeUpdate():增删改,返回int的数据,影响的行数

ResultSet

数据集,可以理解就是一个集合。

取出数据:

                   通过下标:从1开始

                   通过字段名:SQL语句中select后面跟的字段,有可能和数据库一样,也可能不一样

JDBC的优化

平时开发和项目上线之后使用的数据库是不一样的,不是同一个

这也就是我们说的,开发环境不一样

开发环境不一样,使用的数据库也就不一样,那么上面的数据库中配置的三要素就要进行修改

而这种修改是人工操作的,人工操作就有存在了失误,而修改之后的.java文件,也要重新编译,这也可能出现错误

假设项目上线,需要以下四个步骤:

测试环境-->修改配置 -->重新编译-->生产环境

如果想要避免上述出现的失误的情况,就要绕开中间的两个步骤

解决的方法就是,配置文件,添加配置文件,将要修改的配置信息存放到配置文件中,每次读取信息从配置文件中读取

而配置文件的位置是固定的,也不会重新编译,这样就可以降低风险

java中用IO流也可以读取配置文件,通过一个专有的类Properties也可以读写配置文件

IO读取配置文件
import java.io.BufferedReader; import java.io.FileReader; import
java.io.IOException; import java.sql.*; import java.util.Properties; public
class IoReadProp { public static void main(String[] args) throws
ClassNotFoundException, SQLException, IOException { //1注册驱动
Class.forName("com.mysql.jdbc.Driver"); String[] para = read(); //2建立连接 String
url = para[0]; String usernName = para[1]; String password = para[2];
Connection conn = DriverManager.getConnection(url,usernName,password);
//3获取执行sQL语句的对象 Statement statement = conn.createStatement(); //4获取数据库返回的结果
String sql = "select * from emp"; ResultSet resultSet =
statement.executeQuery(sql); //5处理数据集 try { while (resultSet.next()){
//.getXXX方法中的参数 1,字段名 2.字段的下标 int empno = resultSet.getInt("empno"); String
ename = resultSet.getString("ename"); String job = resultSet.getString(3); Date
date = resultSet.getDate(5); System.out.println("empno:"+empno+",
ename:"+ename+", job:"+job+", date:"+date); } } catch (Exception e){
e.printStackTrace(); } finally { //6关闭连接 resultSet.close(); statement.close();
conn.close(); } } public static String [] read()throws IOException { FileReader
fr = new FileReader( "E:\\javalearning\\src\\jdbc\\jdbc.properties" ); //创建 写入
缓冲区 BufferedReader bufferedReader = new BufferedReader( fr ); String [] str =
new String[3]; for(int i =0 ;i < 3;i++){ str[i] =
bufferedReader.readLine().split("=")[1].replace(";","").trim(); }
bufferedReader.close(); fr.close(); return str; } }
Properties读取配置文件
import java.io.*; import java.sql.*; import java.util.Iterator; import
java.util.Properties; public class PropReadProp { public static void
main(String[] args) throws ClassNotFoundException, SQLException, IOException {
//1注册驱动 Class.forName("com.mysql.jdbc.Driver"); //用户数组存放数据库信息 String[] para =
new String[3]; //读取配置文件 int i = 0; Properties prop = new Properties();
FileInputStream fileInputStream = new
FileInputStream("E:\\javalearning\\src\\jdbc\\jdbc.properties"); InputStream in
= new BufferedInputStream(fileInputStream); prop.load(in); Iterator<String> it
= prop.stringPropertyNames().iterator(); while (it.hasNext()) { para[i] =
prop.getProperty(it.next()); i++; } in.close(); //2建立连接 String url = para[0];
String usernName = para[1]; String password = para[2]; Connection conn =
DriverManager.getConnection(url, usernName, password); //3获取执行sQL语句的对象
Statement statement = conn.createStatement(); //4获取数据库返回的结果 String sql =
"select * from emp"; ResultSet resultSet = statement.executeQuery(sql);
//5处理数据集 try { while (resultSet.next()) { //.getXXX方法中的参数 1,字段名 2.字段的下标 int
empno = resultSet.getInt("empno"); String ename = resultSet.getString("ename");
String job = resultSet.getString(3); Date date = resultSet.getDate(5);
System.out.println("empno:" + empno + ", ename:" + ename + ", job:" + job + ",
date:" + date); } } catch (Exception e) { e.printStackTrace(); } finally {
//6关闭连接 resultSet.close(); statement.close(); conn.close(); } } }
分层DAO

Data Access Object数据访问对象是一个面向对象的数据库接口

会建立一个包:dao,里面的类都是用来操作数据库的。

通常情况下,有几张表,就有几个DAO

分层Entity、bean、pojo

实体,也就是一个一个类,该类里面只有属性,和对应set.get方法

往往一个表一个实体,实体的属性和表的字段有没有关系,名字一般一样,类型相对应

使用逆向工程,通过表导出实体。

Utils 工具类

代替我们去操作一系列的连接关闭等操作

案例:

目录结构如下,



EmpDAO代码如下:
package jdbc.dao; import jdbc.entity.Emp; import jdbc.utils.JDBCUtils; import
java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException;
import java.sql.Statement; public class EmpDAO { /** * 根据员工id获取员工信息 */ public
Emp getEmpById(Integer id){ Connection connection =null; Statement statement =
null; ResultSet rs = null; Emp emp = null; try { connection =
JDBCUtils.getConnection(); statement = connection.createStatement(); rs =
statement.executeQuery("select * from emp where empno='"+id+"'"); while
(rs.next()){ emp = new Emp(); int empno = rs.getInt("empno");
emp.setEmpno(empno); String ename = rs.getString("ename"); emp.setEname(ename);
String job = rs.getString(3); emp.setJob(job); String hiredate =
rs.getString(5); emp.setHiredate(hiredate); } } catch (SQLException e) {
e.printStackTrace(); } finally { JDBCUtils.close(connection,statement,rs); }
return emp; } public Emp getEmpById(String id){ Connection connection =null;
Statement statement = null; ResultSet rs = null; Emp emp = null; try {
connection = JDBCUtils.getConnection(); statement =
connection.createStatement(); rs = statement.executeQuery("select * from emp
where empno="+id); while (rs.next()){ emp = new Emp(); int empno =
rs.getInt("empno"); emp.setEmpno(empno); String ename = rs.getString("ename");
emp.setEname(ename); String job = rs.getString(3); emp.setJob(job); String
hiredate = rs.getString(5); emp.setHiredate(hiredate); } } catch (SQLException
e) { e.printStackTrace(); } finally { JDBCUtils.close(connection,statement,rs);
} return emp; } }
entity中的Emp代码如下
package jdbc.entity; public class Emp { //emp表中的相关属性 private Integer empno;
private String ename; private String job; private String mgr; private String
hiredate ; private double sal; private double comm; private Integer deptno;
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 String
getMgr() { return mgr; } public void setMgr(String mgr) { this.mgr = mgr; }
public String getHiredate() { return hiredate; } public void setHiredate(String
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; } //默认输出方法 @Override public String toString() { return
"Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\''
+ ", mgr='" + mgr + '\'' + ", hiredate='" + hiredate + '\'' + ", sal=" + sal +
", comm=" + comm + ", deptno=" + deptno + '}'; } }
utils中的JDBCUtils代码如下
package jdbc.utils; import java.io.BufferedInputStream; import
java.io.FileInputStream; import java.io.IOException; import
java.io.InputStream; import java.sql.*; import java.util.Iterator; import
java.util.Properties; public class JDBCUtils { private static final String URL
; private static final String USERNAME ; private static final String PASSWORD ;
static{ String [] parp = null; try { parp = PropRead(); } catch (IOException e)
{ e.printStackTrace(); } URL = parp[0]; USERNAME = parp[1]; PASSWORD=parp[2];
try { Class.forName("com.mysql.jdbc.Driver"); } catch (ClassNotFoundException
e) { e.printStackTrace(); } } /** * 创建连接 */ public static Connection
getConnection() throws SQLException { Connection conn =
DriverManager.getConnection(URL, USERNAME, PASSWORD); return conn; } public
static void close(Connection co , Statement state, ResultSet rs){ if(rs !=
null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } }
if(state !=null){ try { state.close(); } catch (SQLException e) {
e.printStackTrace(); } } if(co !=null){ try { co.close(); } catch (SQLException
e) { e.printStackTrace(); } } } public static void close(Connection co ,
Statement state){ if(state !=null){ try { state.close(); } catch (SQLException
e) { e.printStackTrace(); } } if(co !=null){ try { co.close(); } catch
(SQLException e) { e.printStackTrace(); } } } /** * 读取配置文件 * @return * @throws
IOException */ public static String [] PropRead()throws IOException { String[]
para = new String[3]; int i = 0; Properties prop = new Properties();
FileInputStream fileInputStream = new
FileInputStream("E:\\javalearning\\src\\jdbc\\jdbc.properties"); InputStream in
= new BufferedInputStream(fileInputStream); prop.load(in); Iterator<String> it
= prop.stringPropertyNames().iterator(); while (it.hasNext()) { para[i] =
prop.getProperty(it.next()); i++; } in.close(); return para; } }
测试代码如下:
package jdbc; import jdbc.dao.EmpDAO; import jdbc.entity.Emp; import
java.util.Scanner; public class Main { public static void main(String[] args) {
EmpDAO empDAO = new EmpDAO(); System.out.println("请输入ID"); Scanner scanner =
new Scanner( System.in ); String value = scanner.nextLine(); Emp emp =
empDAO.getEmpById (value); Emp emp1 = empDAO.getEmpById (7900);
System.out.println(emp); System.out.println(emp1); } }
这样就简单实现了一个分层的使用JDBC的案例

SQL注入攻击

根据上述案例,我们可以输入一个员工的id来查找该员工

但是有一个问题,你如何去规定用户的输入,下面给大家看一个现象



我的数据库在中并没有123456789这个id的人,那么为什么还会有结果呢?

就是因为我们的sql语句是根据字符串拼接生成的,当你输入的数据中包含sql关键字时,会被当成sql语句去执行

注意:这是很危险的!

不友好的用户可以根据这个漏洞对你的数据库进行修改,甚至删除你的数据库!

解决方法:PreparedStatement类

PreparedStatement是statement的子类

解决原理:

SQL语句不在拼接,而是通过预处理,也就是说,用户输入的任何内容,都只能作为值,不解析特殊字符。

修改之后打代码如下:
public Emp getEmpById2(String id){ Connection connection =null;
PreparedStatement statement = null; ResultSet rs = null; Emp emp = null; try {
connection = JDBCUtils.getConnection(); String sql = "select * from emp where
empno=?"; statement = connection.prepareStatement(sql);
statement.setString(1,id); rs = statement.executeQuery(); while (rs.next()){
emp = new Emp(); int empno = rs.getInt("empno"); emp.setEmpno(empno); String
ename = rs.getString("ename"); emp.setEname(ename); String job =
rs.getString(3); emp.setJob(job); String hiredate = rs.getString(5);
emp.setHiredate(hiredate); } } catch (SQLException e) { e.printStackTrace(); }
finally { JDBCUtils.close(connection,statement,rs); } return emp; }
 再次测试:结果如图



总结:并不是意味着Statement不能用,或者不能SQL拼接

但是如果是前端穿过的来的值需要直接放到SQL语句中,就需要注意。

 

 

 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信