一、什么是jdbc?
java database Connectivity 建立java与数据库之间的连接
针对一套接口进行开发
java.sql.Connection 获取数据库连接
java.sql.Statement 获取Statement对象,可以执行sql语句
java.sql.ResultSet 特殊的集合,用来暂时存放数据库的记录
接口的好处?
定义一个标准 ,多实现
厂商可以定义自己的实现
二、jdbc的编程相关:
建立表 - - > java 对应一个实体类
1、对于增删改的编程步骤
写一些方法,进行数据增删改查
1、加载数据库驱动
2、获取数据库连接
3、创建Statement对象
4、执行sql
5、关闭连接
2、开发流程:
创建一个 Dynamic Web Project
添加oracle自己对jdbc的实现 — 添加 oracle10g.jar
第二步:选中ok
找到jar包的所在目录,添加完成点击ok
然后在项目的java Resources下的src下创建包:
com.xingxue.entity 存放的每个实体类对应数据库一张表
com.xingxue.test 存放测试代码
3、示例代码:
// 1、加载驱动
/*
* 参数 包名.类名 类加载:初始化静态变量,初始化静态代码块
* 包含了加载驱动的逻辑
* */
Class.forName(“oracle.jdbc.OracleDriver”);
// 2、获取数据库连接 DriverManager 工具类
/* 参数1: 数据库服务器的地址
* 参数2:数据库用户名
* 参数3:数据库密码
*
* 数据库服务器的地址:jdbc:oracle:thin:@ip地址:1521:xe
* 1521:oracle默认的监听端口
* ip地址 ipconfig —> localhost
* orcl 企业版
* xe 快捷版
* */
String url = “jdbc:oracle:thin:@localhost:1521:xe”;
String user = “hr”;
String password = “hr”;
Connection conn = DriverManager.getConnection(url, user, password);
// 3、创建Statement对象
Statement stmt = conn.createStatement();
// 测试新增
//String sql = "insert into w_student values (w_student_seq.nextval,'张三',18)";
// 给名字拼接一个_
//String sql = "select concat(name,'c') from w_student";
// 测试修改
String sql = "update w_student set name = '赵四' where id = 1 ";
// 测试删除
String sql = "delete from w_student where id = 1";
// 查询
String sql = "select * from w_student";
// 4、执行sql insert、update、delete调用executeUpdate(sql)
// select 调用的是 executeQuery()
// int x = stmt.executeUpdate(sql);// 返回值代表影响的记录数
// int x = stmt.executeUpdate(sql);
// System.out.println(“影响的记录数:x = “+x);
ResultSet rs = stmt.executeQuery(sql);
// 遍历
/* .next() 调用时指针移动,返回值为boolean类型,true代表有下一条记录,false代表没有
* .getXXX(参数) XXX 表示列的数据类型
* 参数类型为int类型时,代表列的下标,从1开始,递增1
* 参数类型为String类型时,参数值为列名,列名必须与数据库中表的列名一致
* */
while(rs.next()){
// rs.getInt(1)
// rs.getString(2)
// rs.getInt(“age”)
System.out.print(rs.getInt(1)+” “+rs.getString(2)+” “+rs.getInt(“age”));
}
// 5、关闭连接 原则: 先打开的后关闭
stmt.close();
conn.close();
对于查询,示例代码:
// 查询所有记录的方法 返回多个对象 用list存对象
public List findAll() throws Exception{
// Class.forName(“oracle.jdbc.OracleDriver”);
// Connection conn = DriverManager.getConnection(“jdbc:oracle:thin:@localhost:1521:xe”, “hr”, “hr”);
Connection conn = JdbcUtil.getConnection();
Statement stmt = conn.createStatement();
String sql = “select * from w_student”;
ResultSet rs = stmt.executeQuery(sql);
// 定义一个集合存放student对象
List list = new ArrayList<>();
while(rs.next()){
// 从resultset集合中取值
int id = rs.getInt("id");
String name = rs.getString("name");
int age = rs.getInt("age");
// 给对象赋值
Student s = new Student();
s.setId(id);
s.setName(name);
s.setAge(age);
// 把对象添加到集合中
list.add(s);
}
// 关闭资源
rs.close();
stmt.close();
conn.close();
return list;
}
4、查询时对于ResultSet集合的遍历:
5、对于查询,jdbc的编程步骤如下:
1、注册驱动
2、获取连接
3、创建statement对象
4、执行sql
ResultSet rs = stmt.executeQuery(sql);
5、遍历结果集ResultSet【比增删改多的步骤】
rs.next() 移动指针,返回值为boolean类型,true表示有下一条记录,false表示没有
rs.getXXX(参数) 表示获取一条记录中的列名对应的值
参数类型为int 类型表示列的下标,从1开始
参数类型为String 类型,表示列名,与数据库表中的列名一致
使用while循环遍历
6、关闭资源
原则:先打开的后关闭
注意:对于增删改查,我们都有一些重复的逻辑,比如,加载驱动,获取数据库连接
还有关闭资源。所以可以写一个工具类把这些重复的逻辑抽取出来
详情见:JdbcUtil.java
7、代码的改进
8、PreparedStatement对象
preparedStatement 是Statement对象的子接口。
使用PreparedStatement对象后代码的书写步骤:
1》加载数据库驱动
2》获取数据库连接 conn
3》创建PreparedStatement对象 时的步骤:
3.1 预先写好增删改查的sql语句,
比如,String sql = “insert into w_user values (w_student_seq.nextval,?,?)”;
3.2创建PreparedStatement对象,
比如,pstmt = conn.prepareStatement(sql);//预编译
3.3 给sql语句中的占位符赋值
调用 pstmt.setXXX(参数1,参数2);方法
XXX表示数据类型,包括基本类型和引用类型(pstmt.setInt()、pstmt.setString())
参数1是占位符(问号)在sql语句中的下标,从1开始,每次加1
参数2是给占位符赋值,该值来自于方法的参数中
4》执行sql
如果是增删改:调用方法pstmt.executeUpdate();方法,方法无参数
如果是查询:调用方法pstmt.executeQuery(); 方法,方法无参数
5》关闭资源
9、Statement和PreparedStatement
preparedStatement继承自Statement,是Statement的子接口
Statement和preparedStatement的区别
preparedStatement的好处:
1》不用拼接sql字符串,让代码变的更简洁
2》让代码更安全,不会存在sql注入问题
【备注】sql注入:如果用拼接字符串的方法来生成sql,就会存在注入攻击漏洞。
10、性能提升
10.1连接池
连接池的好处:
连接池:预先创建好一批数据库连接 —> 节省了创建连接的时间
使用连接池后,每次连接对象使用完毕,不是真正关闭,而是将连接
还回了连接池 —> 这样达到了连接的重用
比较著名的连接池实现:c3p0
使用c3p0连接池的步骤:
1、添加c3p0相关jar包
mchange-commons-java-0.2.11.jar
c3p0-oracle-thin-extras-0.9.5.2.jar
c3p0-0.9.5.2.jar
ojdbc-5.0.jar —> 新版本的jdbc的驱动包,为了支持数据源
2、创建一个ComboPooledDataSource连接池对象
3、设置连接参数
4、调用连接池对象的getConnection方法获取连接
示例代码见:jdbc003 项目中的 com.xingxue.test包下的 Testc3p0.java
数据源中的代理模式:
连接池创建了代理连接对象,代理连接对象覆盖原始连接对象的close方法的实现
(池连后的close()方法不是真正关闭数据库连接,而是将连接还回连接池)
直连:直接从数据库服务器获取连接
池连:从连接池中获取连接
10.2 批处理
批量向数据库执行一些增删改操作
pstmt.addBatch(); 把多条sql同时加入批处理包中
pstmt.executeBatch();执行批处理sql,把所有sql以及对应的占位符的值发送给数据库服 务器
11、jdbc中的事务
jdbc中的事务默认是提交的。(通过数据库连接对象的方法来控制)
想要自己控制事务,
conn.setAutoCommit(false);// false 代表设置事务手动提交
conn.commit(); // 提交事务 —- 事务完成,try块后提交事务
conn.rollback(); // 回滚 —- 出现异常,在catch块中回滚事务
四、jdbc中的优化
1、对于每个表增删改查的代码,都有重复的操作
例如,加载驱动、获取连接、关闭资源
所以可以把重复的逻辑代码抽取出来,写成一个工具类
详细示例代码:
public class JdbcUtil {
// 直连加载驱动
/*static{
try {
Class.forName(“oracle.jdbc.OracleDriver”);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}*/
// 定义一个数据源
private static DataSource dataSource;
// 通过数据源加载驱动
static{
try {
// ComboPooledDataSource对象的 创建会预先创建号3个连接对象
ComboPooledDataSource ds = new ComboPooledDataSource();
ds.setDriverClass(“oracle.jdbc.OracleDriver”);
ds.setJdbcUrl(“jdbc:oracle:thin:@192.168.1.192:1521:xe”);
ds.setUser(“hr”);
ds.setPassword(“hr”);
dataSource = ds;
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取数据库连接 —- 直连 —> 池连
public static Connection getConnection(){
// Connection conn = null;
Connection conn2 = null;
try {
// 直连:直接从数据获取连接
//conn=DriverManager.getConnection(“jdbc:oracle:thin:@localhost:1521:xe”, “hr”, “hr”);
// System.out.println(“直连:数据库连接对象的实际类型:”+conn.getClass());
// 池连:从数据源获取连接
conn2 = dataSource.getConnection();
System.out.println(“池连:数据库连接对象的实际类型:”+conn2.getClass());
// 此处体现了代理模式
} catch (SQLException e) {
e.printStackTrace();
}
return conn2;
}
// 使用Statement时关闭资源 ResultSet Statement Connection
// 使用PrepareStatement对象关闭资源时,ResultSet PreparedStatement Connection
// public static void close( ResultSet rs, Statement stmt, Connection conn){
public static void close( ResultSet rs, PreparedStatement pstmt, Connection conn){
try {
if(rs != null){
rs.close();
}
if(pstmt != null){
pstmt.close();
}
if(conn != null){
conn.close();// 直连时,调用close()方法是关闭数据连接
// 池连时,调用close()方法并不是真正的关闭连接,而是把连接还回连接池
}
} catch (Exception e) {
e.printStackTrace();// 打印异常堆栈信息
}
}
}
五、三层开发
javaweb应用开发分为三层:
1、表现层:用来向用户展示一些新的
网页html css javascript、jsp、
2、业务逻辑层: service
根据一些需求来定义你的业务。每一个业务有需要dao中不同的方法组合完成
例如:
注册功能
// 判断用户名是否存在
1、如果存在 给提示,不能注册
2、如果用户不存在 可以注册
2.1用户名的合法性(用户名是否为空)
2.1.1 不合法 无法注册
2.1.2 用户名合法,检测密码与确认密码
2.1.2.1 合法 注册
2.1.2.2 不合法 提示 密码不一致
// 下单的业务
加购物车 —- 商品 库存-1
订单项 —- 订单项 数量-1
真正下单 — 清空购物车
至少涉及到3张表
商品表 订单项表 订单表 —- 3个dao层代码组合,才可以完成完成一个业务
3、数据访问层:dao Data Access Object(数据访问对象)
每一个数据访问层对应数据库一张表的增删改查方法
UserDao
4、entity 实体类 、javabean、domain 领域对象、
POJO(Plain Ordinary Java Object) — 普通的java对象
这4个名词都是在说我们的实体类
每个实体类对应数据库一张表 真正传递数据
dao sercei 同一个连接
dao不关闭数据库连接 conn
ThreadLocal 当前线程对象
main 主线程
ThreadLocal t = new ThreadLocal();
t .set(对象) ; 把对象存入当前线程
t .get(); 从当前线程获取该对象
t .remove(); 从当前线程移除该对象
工厂模式:
jdbc005
工厂模式:统一生产程序中需要使用的类
代码的修改:
eitity — 对应数据库表的实体类
dao — 接口 : 定义标准
dao.imp — 实现 :
耦合度:类与类之间的依赖关系
弱耦合:将低类与类之间的依赖关系
service — 接口 加载dao
sercice.imp — service 的实现
servlet — 控制器 调用service
html 用来显示响应的内容
*.properties 键值对
在类里面改 – 重新编译一次
设计模式: — 思想
单例模式 懒汉式饿汉式手写出来
克隆模式 – java中创建对象的方式
代理模式 –
程序运行中使用的对象不再是原始的对象 【该对象可能是院士对象的子类】
直连:直接从数据库服务器获取连接
conn.getClass(); TConnection
池连:从连接池获取
conn.getClass(); NewProxyConnection 是 TConnection的子类
conn.close(); // 不是真正关闭连接,而是还回连接池
close()自定子类的实现
工厂模式 – 统一生成对象
接口:多实现 定义一个规则
作用:接口中的代码重用