JDBC

ODBC(Open Database Connectivity)是一组对数据库访问的标准API。ODBC的最大优点是能以统一的方式处理所有的数据库。

▪ JDBC(Java Database Connectivity)是基于JAVA语言访问数据库的一种技术。
▪ JDBC(Java Data Base Connectivity,java数据库连接)是一种用于执行SQL语句的Java API
▪ JDBC的设计思想:由sun公司提供的访问数据库的接口,由数据库厂商提供对这些接口的实现,程序员编程时都是针对接口进行编程的。
▪ JDBC可以做些什么?
 – 连接到数据库
 – 在Java app中执行SQL命令
 – 处理结果

一、jdbc职责
1、java: 客户端 :接收数据、拼接sql 、发送sql、分析结果、返回结果browser
2、db: 服务器 :接收sql, 分析处理,返回结果给java

二、jdbc操作
D:\oracle\product\11.2.0\dbhome_1\jdbc\libojdbc6.jar,或者D:\oracle\product\11.2.0\dbhome_1\oui\jlib中的classes12.jar加入到idea中:
在这里插入图片描述
在Driver中可以发现有对应的实现方式:
在这里插入图片描述
这就意味着此时我们已经能够找到对应的实现方式了。当我们把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
public static void main(String[] args) throws Exception {
//1. 加载驱动
Class.forName("oracle.jdbc.driver.OracleDriver");
//2. 建立连接
Connection connection = DriverManager.getConnection("jdbc:oracle:thin:@192.168.12.1:1521:orcl",
"scott", "tiger");
//3. 测试是否成功
System.out.println(connection);
//4. 定义sql语句
String sql = "select * from emp";
//5. 准备静态处理块对象,将sql语句放置到静态处理块中,理解为sql语句放置对象
Statement statement = connection.createStatement();
//6. 执行sql语句,返回值对象是结果集合
ResultSet resultSet = statement.executeQuery(sql);
//7. 循环处理
while (resultSet.next()) {
int anInt = resultSet.getInt(1);
System.out.println(anInt);
String ename = resultSet.getString("ename");
System.out.println(ename);
System.out.println("---------------");
}
// 8. 关闭连接
statement.close();
connection.close();
}

解释

  1. 加载驱动

    Java SPI机制
    SPI(Service Provider Interface)是一种动态替换发现的机制, 比如有个接口,想运行时动态的给它添加实现,你只需要添加一个实现。我们经常遇到的就是java.sql.Driver接口,其他不同厂商可以针对同一接口做出不同的实现,比如oracle和mysql都有不同的实现提供给用户,而Java的SPI机制可以为某个接口寻找服务实现
    spi接口定义在调用方。
    在这里插入图片描述
    接口对应的抽象SPI接口;实现方实现SPI接口;调用方依赖SPI接口
    当服务的提供者提供了接口的实现后,需要在指定目录创建以服务接口命名的文件【配置文件】,当程序需要这个服务的时候,就可以通过查找这个jar包的配置文件,里面有接口的具体实现类名,通过这个类名进行加载实例化,就可以使用该服务了。
    JDK中查找服务实现的工具类是:java.util.ServiceLoader

    当执行了当前代码后,会返回一个Class对象,在此对象的创建过程中,会调用具体类(OracleDriver)的静态代码块,里面会将当前对象注册进DriverManager

  2. 建立连接
    “jdbc:oracle:thin:@localhost:1521:orcl”
    thin:不同的数据库连接方式
    orcl:对应数据库实例(名字)

    数据库DriverManager就用到了SPI机制。DriverManager是jdbc里管理和注册不同数据库driver的工具类。针对一个数据库,可能会存在着不同的数据库驱动实现。我们在使用特定的驱动实现时,DriverManager是怎么获得某确定驱动类的?就是通过第一步把driver静态注册到driverManager中。

    第一步中已经将driver对象注册到了driverManager中,所以此时可以直接通过drivermanager来获取数据库的连接了
    需要输入连接数据库的参数:

    • url: 数据库的地址
    • username:用户名
    • password:密码
  3. 定义sql语句
    只要填写正常sql语句即可

  4. 准备静态处理块对象,将sql语句放置到静态处理块中,理解为sql语句放置对象
    在执行sql语句的过程中,需要一个对象来存放sql语句,将对象进行执行的时候,调用的是数据库的服务,数据库会从当前对象中拿到对应的sql语句进行执行。

  5. 执行sql语句,返回值对象是结果集合
    将结果放到resultset中,是返回结果的一个集合,需要经过循环迭代才能获取得到其中的每一条记录.
    statement在执行的时候可以选择三种方式:
    1.execute:任何sql语句都可以执行
    2.executeQuery:只能执行查询语句
    3.executeUpdate:只能执行DML语句 增删改查

  6. 循环处理
    使用while循环,有两种获取具体值的方式:
    1.通过下标索引编号来获取 从1开始
    2.通过列名来获取
    推荐使用列名,列名一般不会发生修改。

查找数据
1、存在sql注入问题

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
@Override
public Emp getEmpByEname(String ename) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
Emp emp = null;
try {
connection = DButil.getConnection();
statement = connection.createStatement();
String sql = "select * from emp where ename = "+ ename;
System.out.println(sql);
// 返回结果
resultSet = statement.executeQuery(sql);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
while (resultSet.next()) {
emp = new Emp(resultSet.getInt("empno"),resultSet.getString("ename"),
resultSet.getString("job"),resultSet.getInt("mgr"),
sdf.format(resultSet.getDate("hiredate")), resultSet.getDouble("sal"),
resultSet.getDouble("comm"),resultSet.getInt("deptno"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DButil.closeConnection(connection,statement,resultSet);
}
return emp;
}
public static void main(String [] args) {
EmpDao empDao = new EmpDaoImpl();
Emp emp1 = empDao.getEmpByEname("'SMITH' or 1 = 1");
System.out.println(emp1);//会打印出emp表中最后一条记录
Emp emp2 = empDao.getEmpByEname("'SMITH'");
System.out.println(emp2);//会打印出emp表对应的记录
}

2、防止sql注入问题

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
@Override
public Emp getEmpByEname(String ename) {
Connection connection = null;
PreparedStatement pstmt = null; // 预处理块
ResultSet resultSet = null;
Emp emp = null;
try {
connection = DButil.getConnection();
String sql = "select * from emp where ename = ?";
pstmt = connection.prepareStatement(sql);
pstmt.setString(1,ename);
System.out.println(sql);
// 返回结果
resultSet = pstmt.executeQuery();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
while (resultSet.next()) {
emp = new Emp(resultSet.getInt("empno"),resultSet.getString("ename"),
resultSet.getString("job"),resultSet.getInt("mgr"),
sdf.format(resultSet.getDate("hiredate")), resultSet.getDouble("sal"),
resultSet.getDouble("comm"),resultSet.getInt("deptno"));
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DButil.closeConnection(connection,pstmt,resultSet);
}
return emp;
}
public static void main(String [] args) {
EmpDao empDao = new EmpDaoImpl();
Emp emp1 = empDao.getEmpByEname("'SMITH' or 1 = 1");
System.out.println(emp1);//null
Emp emp2 = empDao.getEmpByEname("SMITH");
System.out.println(emp2);//会打印出emp表对应的记录
}

批量提交

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
/**
* 批量提交 时间比单条插入快
* 中间省略了打开关闭连接过程
*/
public static void insertBatch() {
Connection connection = DButil.getConnection();
String sql = "insert into emp(empno,ename) values(?,?)";
PreparedStatement pstmt = null;
// 准备预处理块对象
try {
pstmt = connection.prepareStatement(sql);
for (int i = 0; i < 100; i++) {
pstmt.setInt(1,i);
pstmt.setString(2,"msb"+i);
// 向批处理中添加sql语句
pstmt.addBatch();
}
int[] ints = pstmt.executeBatch();
for (int anInt : ints) {
System.out.println(anInt);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
DButil.closeConnection(connection,pstmt);
}
}