一、JDBC技术引言
1.什么是JDBC技术
JDBC,全称Java DataBase Conectivity,JDBC技术即Java数据库连接技术。
技术核心:应用Java程序,访问操作数据库,对用户屏蔽SQL的存在,属于底层代码。
2.JDBC的API
DriverManager:驱动管理类,方便程序员使用Driver和数据库建立连接。
Connection:连接接口,代表JDBC和数据库的连接。
PreParedStatement:代表发送SQL的工具。
ResultSet:结果集接口,代表查询SQL执行之后的结果。
3.JDBC访问数据库的核心思想。
4.JDBC的编程步骤。
a).导入数据库驱动jar包。 //数据库厂商提供
b).注册(加载)驱动 //告诉虚拟机使用的是哪一个驱动(什么数据库)
c).获得连接 //使用JDBC中的Connection接口,完成对Oracle数据库的连接
d).获得语句执行平台 //通过连接对象获取对SQL语句的执行者对象
e).执行SQL语句 //使用执行者对象,向数据库执行SQL语句,并获取执行结果
f).处理结果 //只有查询操作才需要对查询到的结果做处理
g).释放资源 //就是调用一堆close()
5.日期类型的处理
a).java.util.Date:平时推荐使用的时期类型,不能应用在jdbc操作中。
b).java.sql.Date:特点:代表时间,只能用JDBC操作中。
6.动态参数(数据绑定)
a).字符串拼接
String sql = "select * from test where name = '"+username+"' and password = '"+userpwd+"'";
特点:
1.可能会被SQL注入攻击
2.可以拼接表名、列名、sql关键字
应用场景:动态查询不同的表 根据用户选择进行升序或者降序排列。
b).占位符绑定数据(请查阅PreparedStatementAPI文档翻看setXxx()类型方法)
String sql = "update test set address = ?,birthday = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "符文之地");
java.util.Date date = new java.util.Date();
java.sql.Date date2 = new java.sql.Date(date.getTime());
preparedStatement.setDate(2, date2);
preparedStatement.setInt(3, 3);
preparedStatement.executeUpdate();
特点:
1.可以防止SQL注入攻击
2.不可以拼接表名、列名、sql关键字
7.主键自动增长
a).首先在数据库中创建sequence序列,假设定义名为test_seq
b).test_seq.nextval代替插入传递的主键参数
c). insert into test (id,name,address,birthday) values (test_seq,‘艾希’,‘弗雷尔卓德’,日期);
二、原生JDBC代码
create table test(
id number(10) primary key,
name varchar2(20) not null,
address varchar2(60),
birthday date
);
insert into test (id,name,address,birthday) values (1,'艾希','弗雷尔卓德',sysdate);
insert into test (id,name,address,birthday) values (2,'厄运小姐','比尔吉沃特',sysdate);
insert into test (id,name,address,birthday) values (3,'卡特琳娜','诺克萨斯',sysdate);
commit;
select * from test;
1.增加
@Test
public void insert(){
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
//加载驱动,告诉虚拟机要开始使用什么数据库驱动
Class.forName("oracle.jdbc.OracleDriver");
//获取连接,使用JDBC中的类DriverManager中的静态方法getConnection方法获取连接
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hr","hr");
//定义SQL语句,此句测试插入操作
Date date = new Date();
java.sql.Date date2 = new java.sql.Date(date.getTime());
String sql = "insert into test (id,name,address,birthday) values (4,'艾希','弗雷尔卓德',?)";
//conn调用preparedStatement方法创建一个PreparedStatement对象并返回,这个对象相当于一个存放和传递SQL语句的平台,传给数据库
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setDate(1, date2);
//此句一旦执行就表示用当前对象执行SQL语句,执行结束后在数据库中的操作(增删改)也结束
preparedStatement.executeUpdate();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//关闭资源
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
2.删除
@Test
public void delete(){
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hr","hr");
String sql = "delete from test where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setInt(1, 4);
preparedStatement.executeUpdate();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3.修改
@Test
public void update(){
Connection connection = null;
PreparedStatement preparedStatement = null;
try {
Class.forName("oracle.jdbc.OracleDriver");
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hr","hr");
String sql = "update test set address = ?,birthday = ? where id = ?";
preparedStatement = connection.prepareStatement(sql);
preparedStatement.setString(1, "符文之地");
java.util.Date date = new java.util.Date();
java.sql.Date date2 = new java.sql.Date(date.getTime());
preparedStatement.setDate(2, date2);
preparedStatement.setInt(3, 3);
preparedStatement.executeUpdate();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
4.查询
@Test
public void select(){
Connection connection = null;
PreparedStatement preparedStatement = null;
ResultSet resultSet = null;
try {
//加载驱动,告诉虚拟机要开始使用什么数据库驱动
Class.forName("oracle.jdbc.OracleDriver");
//获取连接,使用JDBC中的类DriverManager中的静态方法getConnection方法获取连接
connection = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe","hr","hr");
//定义SQL语句,此句测试插入操作
String sql = "select * from test";
//conn调用preparedStatement方法创建一个PreparedStatement对象并返回,这个对象相当于一个存放和传递SQL语句的平台,传给数据库
preparedStatement = connection.prepareStatement(sql);
//此句一旦执行就表示用当前对象执行SQL语句,执行结束后在数据库中的查询操作也结束
resultSet = preparedStatement.executeQuery();
//开始处理数据
while (resultSet.next()) {
int id = resultSet.getInt(1);
String name = resultSet.getString(2);
String address = resultSet.getString(3);
java.util.Date date = resultSet.getDate(4);
System.out.println(id+"\t"+name+"\t"+address+"\t"+date);
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
//关闭资源
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (preparedStatement != null) {
try {
preparedStatement.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
5.常见错误
a).为什么程序没有显示错误
原因:catch块中没有 e.printStackTrace();
b).java.lang.ClassNotFoundException产生原因:
1 类名字书写错误
2 没有导入相关的jar包(记得build up with)
c).java.sql.SQLException
与sql语句相关的错误
1.约束错误
2.表名、列名书写错误
d).IO异常: The Network Adapter could not establish the connection
1.oracle服务的监听器问题
2.oracle:jdbc:thin:@ip问题
e).SQL语句书写有误:
1.字符串是单引号
2.在Java定义时,字符串内末尾不加分号
3.SQL语句本身语法有问题
三、原生JDBC的缺点
1.数据库连接,使用时就创建,不使用立即释放,对数据库进行频繁连接开启和关闭,造成数据库资源浪费,影响
数据库性能。使用数据库连接池管理数据库连接。但是现在连接池多种多样,可能存在变化,有可能采用DBCP的连接池,也有可能采用容器本身的JNDI数据库连接池。
**设想:**我们可以通过DataSource进行隔离解耦,我们统一从DataSource里面获取数据库连接,DataSource具体由DBCP实现还是由容器的JNDI实现都可以,所以我们将DataSource的具体实现通过让用户配置来应对变化。
2.将sql语句硬编码到java代码中,如果sql
语句修改,需要重新编译java代码,不利于系统维护。而且在每个功能都会对数据表进行操作,很多时候就会遇到一个SQL重复的问题,几个功能的SQL语句其实都差不多,有些可能是SELECT后面那段不同、有些可能是WHERE语句不同。有时候表结构改了,那么我们就需要改多个地方,不利于维护。
**设想:**将sql语句配置在xml配置文件中,即使sql变化,不需要对java代码进行重新编译。当我们的代码程序出现重复代码时怎么办?将重复的代码抽离出来成为独立的一个类,然后在各个需要使用的地方进行引用。对于SQL重复的问题,我们也可以采用这种方式,通过将SQL片段模块化,将重复的SQL片段独立成一个SQL块,然后在各个SQL语句引用重复的SQL块,这样需要修改时只需要修改一处即可。
针对上述缺点,将引入Java的封装机制与DAO的设计思想对原生代码进行改进。