jdbc简介以及jdbc的使用

1、jdbc简介

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-r82FsXnQ-1607073697935)(C:\Users\刘元汉\Desktop\java\javaweb\jdbc操作.assets\image-20201126211709934.png)]

发展历史:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hpnUCeq4-1607073697939)(C:\Users\刘元汉\Desktop\java\javaweb\jdbc操作.assets\image-20201126211746299.png)]

2、如何使用jdbc

可分为5步

//1.    加载数据库驱动 (可以省略的.  在JavaEE的web项目中,jar包不可以省略.)
//      mysql 6以下驱动:com.mysql.jdbc.Driver
//      mysql 6及以上驱动:com.mysql.cj.jdbc.Driver
Class.forName("com.mysql.jdbc.Driver");
//2.    通过驱动管理器, 获取JDBC的连接对象
//      连接地址格式:
//           主协议:子协议://ip地址:端口号/数据库名称
//           mysql:     jdbc:mysql://localhost:3306/jdbc
//           oracle:    jdbc:oracle:thin:@ip地址:1521/ORCL
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8", "root", "123");
//3.    通过连接对象,创建SQL执行对象 (SQL执行环境)
Statement state = conn.createStatement();
//4.    通过SQL执行对象 执行SQL
state.execute("create table person(id int,nickname varchar(32))");
//5.    释放连接
state.close();
conn.close();

jdbc常用的类型与方法

1. DriverManager  :  驱动管理器
2. Connection :  数据库连接对象
//前两个就是连接的
3. Statement  :  SQL执行对象
	常用方法:
		- excute(执行所有sql都可以用)
		返回值:Boolean
		- excuteUpdate(用于执行DML与DDL语句)
		返回值:int(表示对数据库影响的行数)
		- excuteQuery(用于执行DQL语句)
		返回值:ResultSet(set集合)
4、ResultSet  :  结果集对象 (指的是一个select语句的查询结果)
	常用方法:
		1、控制游标移动的常用方法(注意是行的移动):
			  - boolean next() ****
             作用: 控制游标向下一行移动.
              -下面4个作为了解(都返回的布尔):
             privious() 控制游标向上一行移动
             absolute(int 行号)  控制游标向指定行移动
             beforeFirst()控制游标移动到第一行
             afterLast() 控制游标移动到最后一行
        2、获取游标指向行的字段值的常用方法:
        	 - XXX getXXX(String 列名) ***
        	 根据字段名, 得到此字段的值
        	 -  XXX getXXX(int 字段的索引) *
             根据字段的索引, 得到字段的值 , 索引从1开始

工厂方法设计模式

( 静态工厂方法模式 )

图:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J1d3Ar9L-1607073697940)(C:\Users\刘元汉\Desktop\java\javaweb\基础笔记.assets\image-20201125164541860.png)]

3、SQL注入问题 (重)

问题描述

进行用户登录时, 输入不存在的帐号 和 如下的密码:
 1' or '1'='1
结果显示登录成功.
因为用户输入的密码, 与我们的查询语句拼接后, 使得我们的查询语句产生了歧义:
原查询语句:
 select * from xzk_user where username='' and password='密码'
拼接后:
 select * from xzk_user where username='hahahaheiheihei' and password='1' or
'1'='1'

如何解决

我们可以将SQL语句与参数分离,将参数作为SQL的特殊部分进行预处理.

即通过PreparedStatement 预编译的SQL执行环境解决问题

内部实现原理:
 1. 将未拼接参数的SQL语句, 作为SQL指令, 先传递给数据库 进行编译.
 2. 再将参数传递给数据库, 此时传递的参数不会再作为指令执行, 只会被当作文本存在.
操作流程与Statement基本一致:
 1. 如何得到一个PreparedStatement 对象
     PreparedStatement state = conn.prepareStatement("预编译的SQL语句");
 2. 预编译的SQL语句如何编写
     需要填充参数的位置, 使用?代替即可! 例如:
     select id from xzk_user where username=? and password=?
 3. 参数如何填充
     state.setXXX(int index,XXX value);
       setXXX中XXX指的是数据类型,
       参数1:  index  :  SQL语句中?的索引值 ,1开始
       参数2:  value  :  填充的参数值.
 4. 如何执行填充完毕参数的SQL
     -  boolean execute();
     -  int executeUpdate();
     -  ResultSet executeQuery();

4、事务

概述: 对数据进行操作的多条sql语句放在一起形成的一个完整的逻辑单元叫做事务

特性: 事务是一个整体. 要么一起成功, 要么一起失败.

事务在mysql中, 是默认自动提交的 .

如何操作事务

1、通过命令行

-  开启事务:  start transaction;
-  回滚   :  rollback;  --此次事务中所有的sql操作, 放弃.
-  提交   :  commit; --此次事务中所有的sql操作, 作为一个整体, 提交.

2、通过java

JDBC事务通过连接对象开启, 回滚 ,提交. 只针对当前连接对象生效.
-  开启事务:  conn.setAutoCommit(false);
-  回滚事务:  conn.rollback();
-  提交事务:  conn.commit();

关于事务的面试题

1. 请描述事务的四大特征 :
   <1>.  原子性:  事务是一个整体 , 不可分割 , 要么同时成功, 要么同时失败.
   <2>.  持久性:  当事务提交或回滚后, 数据库会持久化的保存数据.
   <3>.  隔离性:  多个事务之间, 隔离开, 相互独立.
   <4>.  一致性:  事务操作的前后 , 数据总量不变 (例如: 转账时: 孟亮给帅兵转账是
一个事务, 转账完毕后. 两人余额的和不变.)

2. 请描述什么是脏读, 幻读, 不可重复读 ?
   -  脏读: 读取到了一个事务 未提交的数据.
   -  不可重复读: 一个事务中, 两次连续的读取 ,结果不一致(中间被其它事务更改了). 
   -  幻读: 一个事务A在执行DML语句时, 另一个事务B也在执行DML语句 , B修改了A修改过的
数据, 导致A在查询时就像发生了幻觉一样(A更改的内容A看不到了.)
3. 请描述事务的隔离级别
//三种级别锁: 页级,表级,行级(共享锁,排它锁).
   1. 读未提交  :  read uncommitted; (可能产生:脏读, 不可重复读, 幻读)
   2. 读已提交  :  read committed; (可能产生: 不可重复度, 幻读)
   3. 可重复读  :  repeatable read;(mysql默认值) (可能产生: 幻读)
   4. 串行化 :  serializable;
   -  查看数据库当前的隔离级别:  select @@tx_isolation; (了解)
   -  数据库设置隔离级别: set global transaction isolation level 级别字符串;
(了解)

总结:实际上可以理解为(假设有a,b事务):

1、脏读就是a没提交表的数据就自动变化影响了b,

2、不可重复读就是a提交了数据表的的数据就自动变化影响了b

3、幻读就是a提交了数据,表虽然自动变化了,但是我重复读不会发现问题,但是一旦b对表进行了操作,此时数据就会出现问题

5、批处理

概念:

将多条语句, 放到一起批量处理 .

批处理的原理: 将多条SQL语句, 转换为一个SQL指令. 显著的提高大量SQL语句执行时的数据库性能.

使用流程

//Statement对象使用流程:
 1. 得到Statement对象
   Statement state = conn.createStatement();
 2. 将一条SQL语句, 加入到批处理中.
   state.addBatch(String sql);
 3. 执行批处理
   state.executeBatch();
 4. 清空批处理
 state.clearBatch();
   
//PreparedStatement对象使用流程:
 1. 得到PreparedStatement对象
   PreparedStatement state = conn.prepareStatement("预编译的SQL");
2. 填充预编译的参数
state.setXXX(1,填充参数);
 3. 将一条填充完毕参数的SQL, 加入到批处理中.
   state.addBatch();
 4. 执行批处理
   state.executeBatch();
 5. 清空批处理
 state.clearBatch();

6、连接池(DataSource)概念(重!)

概念

连接池用于缓存连接!
当我们需要使用连接时, 可以不用再创建连接 ! 可以直接从连接池中获取连接.
当连接池中存在空闲连接时, 会将空闲连接给到程序使用.
当连接池中不存在空闲连接时, 且连接池未满时 , 则创建连接提供给程序使用 ,并在程序使用完毕后,缓存连接.
当连接池中不存在空闲连接时, 且连接池已满时 , 则排队等候空闲连接的出现.

注意:
使用连接池中的连接对象操作数据库时, 操作完毕依然需要释放连接(调用close()).
连接池中的连接在设计时, 使用了动态代理设计模式+装饰者设计模式 . 我们调用它的close方法,
代理没有关闭这个连接, 而是将连接重新放入了池中.

Properties 作为配置文件

这个是后面连接池的使用需要这个文件

Properties类 是Java中的Map集合的实现类.
.properties文件 用于通过文件描述一组键值对!
.properties文件 ,可以快速的转换为Properties类的对象.
文件中内容的格式:
 文件内容都是字符串 , 键与值之间通过等号连接 , 多个键值对之间换行分割.
 例如:
 url=xxx
 user=xxx
 password=xxx
     
如何将文件 转换为 集合:
 步骤:
   1. 创建Properties对象
       Properties ppt = new Properties();
   2. 创建一个字节输入流 , 指向.properties文件
       InputStream is = new FileInputStream("文件地址");
   3. 将字节输入流, 传递给properties对象, 进行加载.
       ppt.load(is)

配置例子

#获取连接数据库的地址
url=jdbc:mysql://localhost:3306/自己的数据库名?useUnicode=true&characterEncoding=utf-8
username=自己的
password=自己的
#获取驱动类
driverClassName=com.mysql.jdbc.Driver
#最大初始化数
initialSize=5
#最大连接数
maxActive=10
#最小连接数
minIdle=5
#最大等待时间(比如数据库正在被访问,访问3s访问不到就不访问了)
maxWait=3000

DBCP连接池

1、使用步骤

1. 引入相关的jar文件
   -  druid-1.0.9.jar
2. 将配置文件引入
3. 将配置文件, 转换为Properties对象
   Properties ppt = new Properties();
   ppt.load(配置文件的输入流);
4. 通过连接池的工厂类(DruidDataSourceFactory)的创建连接池的方法(createDataSource())
   DataSource ds = DruidDataSourceFactory.createDataSource(ppt);
5. 从连接池中 获取连接对象
   Connection conn = ds.getConnection();

2、DBCPUtil工具类(简化获取连接的方式)

注意:需要自己创建,下面只有类的方法和属性

private static DataSource ds = null;

/**
 * 通过静态代码块创建一次连接池就行
 * 先加载Properties,然后通过德鲁伊工厂创造连接池
 */
static{
    Properties ppt = new Properties();
    try {
        ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
        ds = DruidDataSourceFactory.createDataSource(ppt);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

}
/**
  * 用于从DBCP连接池中 获取一个连接
  * @return DBCP连接池中的一个连接对象.
  */
public static Connection getConnection(){
    try {
        return ds.getConnection();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    return null;
}

/**
 * 释放资源不止一个,要全部释放
 * 有顺序,最后获取的最先关闭
 * @param conn 要释放的连接资源
 * @param state 要释放的执行环境资源
 * @param result 要释放的结果集资源
 */
public static void close(Connection conn, ResultSet rs, Statement state){
    try {
        rs.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        state.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        conn.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
}

德鲁伊(Druid)连接池

1、使用步骤(跟上面的差不多,除了创建连接池的工厂类和要导入的jar包不一样)

1. 引入相关的jar文件
   -  druid-1.0.9.jar
2. 将配置文件引入
3. 将配置文件, 转换为Properties对象
   Properties ppt = new Properties();
   ppt.load(配置文件的输入流);
4. 通过连接池的工厂类(DruidDataSourceFactory)的创建连接池的方法(createDataSource())
   DataSource ds = DruidDataSourceFactory.createDataSource(ppt);
5. 从连接池中 获取连接对象
   Connection conn = ds.getConnection();

2、DruidUtil工具类(简化获取连接的方式)(和上面的创建一样)

注意:需要自己创建,下面只有类的方法和属性

private static DataSource ds = null;

/**
 * 通过静态代码块创建一次连接池就行
 * 先加载Properties,然后通过德鲁伊工厂创造连接池
 */
static{
    Properties ppt = new Properties();
    try {
        ppt.load(DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties"));
        ds = DruidDataSourceFactory.createDataSource(ppt);
    } catch (IOException e) {
        e.printStackTrace();
    } catch (Exception e) {
        e.printStackTrace();
    }

}
//创建连接
public static Connection getConnection(){
    try {
        return ds.getConnection();
    } catch (SQLException throwables) {
        throwables.printStackTrace();
    }
    return null;
}

/**
 * 释放资源不止一个,要全部释放
 * 有顺序,最后获取的最先关闭
 * @param conn
 */
public static void close(Connection conn, ResultSet rs, Statement state){
    try {
        rs.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        state.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        conn.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
}
public static void close(Connection conn, ResultSet rs, Statement state){
    try {
        rs.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        state.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
    try {
        conn.close();
    } catch (Exception throwables) {
        throwables.printStackTrace();
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值