JDBC

一、什么是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()自定子类的实现

工厂模式 – 统一生成对象

接口:多实现 定义一个规则
作用:接口中的代码重用

你可能感兴趣的:(java基础)