JDBC详解

■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■↓↓↓↓↓↓↓↓↓ JDBC ↓↓↓↓↓↓↓↓↓↓↓■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

JDBC;
    为什么要有?
    当如果Java程序要连接数据库的时候,
    那么要通过写对应的数据库驱动,
    那样的话数据库更新可能这些驱动要重写,
    从而造成大量的人力资源浪费。
   
   
    是什么?
       java database connection java程序连接数据库技术(规范)
       是由SUN公司开发的一套接口、规范,类似于Servlet规范那样,
       JDBC这套规范是由数据库厂商实现的。
       
       
    作用;
       1.可以通过Java程序管理数据库(发送SQL语句)
       2.可以减少人力资源,
       因为这个规范是由数据库厂商自己实现了,从而数据库升级的时候,
       只是需要下载数据库厂商在官网提供的对应的驱动即可,而不必重写驱动。
       
       
    特点;
       1.一样也是发送数据库对应的数据库语言的语句
       2.真正连接到数据库的是数据库驱动程序
       3.在无特殊情况操作数据库的接口的时候,基本都是通过一些接口来操作的。
       
   
    位于;
       1.Java_API ---> java.sql.*
       2.Java_API ---> javax.sql.*
       
---------------------------------------↓↓↓↓↓↓↓↓↓ JDBC 与 数据库的关系 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

JDBC与数据库的关系;
   数据库是存储数据的,而JDBC是SUN公司开发的一套标准/规范,
    这套标准规范了数据库厂商如果要Java程序使用这个数据库,
   
   
   那么你这个数据库厂商必须要实现JDBC规范,而JDBC规范规定了,
       如何连接到数据库,如果操作数据库等一系列的标准/接口(代码),
     
     
     从而使得程序开发人员不用在使用不同的数据库的时候,
       要自己写对应的数据库驱动程序,并且在更新的时候可能要重写,
   
   
   因为数据库厂商在实现JDBC标准的时候就写好了驱动程序,
    所以开发人员只是需要到数据库厂商的官网下载这个驱动程序
   
   
   因为Java程序连接数据库就是靠这个驱动程序搭建连接的,
    从而可以通过Java代码操作数据库
   
   
◆小结;JDBC和数据库是相互依赖的关系,
JDBC要依赖数据库厂商实现这个标准才可以通过Java代码操作数据库,
否则程序员要自己写对应的数据库驱动程序。    

数据库厂商要是想要Java程序使用这个数据库那么必须要实现这个JDBC标准,
因为维护方便,开发效率提升,成本下降等。。。。。。

---------------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 开发条件 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
       
JDBC-开发条件;
1.主机地址(什么方式登录)
a)必须要有的

2.用户名
a)必须要有

3.密码
a)必须要有
4.端口
a)必须要有

5.连接的数据库
a)可选的


◆◆◆URL范式;
    "jdbc:mysql://localhost:3306/数据库名","用户名","密码"

---------------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 开发步骤 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
   
JDBC-开发步骤;
1.下载对应的数据库驱动程序
2.将驱动程序的架包拷到MyEclipse工具中
3.注册驱动程序
4.创建连接 ---> 获取到连接对象
5.创建Statement接口或下面的子接口 ---> 通过连接接口对象的方法创建
6.发送SQL语句
7.处理结果 ---> 影响行数和结果数据
8.关闭连接

    
    
    导包 ---> 加载驱动 ---> 创建连接 ---> 创建Statement对象
                      ---> 发送SQL语句 ---> 处理结果 ---> 关闭连接
                       
    代码;
    1.注册驱动程序
    Class.forName("com.mysql.jdbc.Driver");
   
   
    2.通过驱动程序管理类获取到连接数据库接口对象
   
    Connection connection = DriverManager.getConnection("url","user","password");       
           
    a)url是指连接服务器的协议,连接方式,端口等。。。。
   
      代码;
      jdbc:mysql://localhost:3306/数据库名(可写/不写)
   
       
    3.通过连接数据库对象获取到Statement接口对象(声明数据库语句和发送)
   
    Statement st = connection.createStatement();
   
   
    4.调用Statement接口的方法发送数据库语句给数据库,返回一个影响了几行的数据的值
   
    int num = st.executeUpdate(C/D/U/I);    ---> 对数据库的进行C/D/U/I操作
    ResultSet rs = st.executeQuery("Select"); ---> 查询数据库的数据,
    返回一个结果集。
   
    5.关闭连接(必须关闭,避免数据库负载过重而死机等情况)
   
    a)后开先关
   
    st.close();
    connection.close();

—————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 核心接口 ↓↓↓↓↓↓↓↓↓↓↓——————————————————————————————————————————————       
              
           
JDBC核心接口;
↓↓↓↓↓↓↓↓↓ 以下的接口都是位于Java.sql.*包下↓↓↓↓↓↓↓↓↓


+--0顶--> Driver ---> 注册数据库驱动的接口,JDBC顶层接口。
|
| a)connect(String url,Perproty info); ---> 可以通过这个方法注册驱动
|
|
| 说明;这是一个注册数据库驱动接口也是一个JDBC的顶层接口,
| 想要通过JDBC操作数据库,都要第一时间加载这个接口,
| 也就是实现这接口的对象,才可以注册数据库驱动。
|      
|     ◆因为JDBC操作数据库都是通过数据库驱动这个媒介的。
|      
|      
|      
|---1子--->  |--- Connection  ---> 连接数据库接口
|  
|   a)createStatement();  --->   创建Statement对象,
|   用于发送数据库操作语句,
|   用于操作数据库的数据。
|  
|   b)prepareStatement(String sql); --->   创建PrepareStatement对象,
|   以及定义预编译语句。
|  
|   c)prepareCall(String sql); --->  创建CallableStatement对象,
|   以及定义预编译语句,
|   ◆可以执行
|  
|  
|  
|---1子--->↓  |--- Statement   ---> 发送··◆静态··数据库语言的操作数据语句给数据库软件执行。    
 |
 | a)executeUpdate(String sql);  ---> 定义SQL语句(C/D/U/I)发送给
 |           (DDL&DML)             MySQL数据库
 |
 | b)executeQuery(String sql);   ---> 定义SQL语句(S)发送给MySQL数据库
 |      (DQL)
 |   
 |   
 |   
 |--2子-->↓ |--- PreparedStatement ---> 发送··◆预编译( 动态)··数据库语言的操作语句
|     给数据库软件执行 
|
| a)executeUpdate();   ---> 发送···预编译好的···SQL语句
|  (DDL&DML)   (C/D/U/I)给MySQL数据库
|  
|  
| b)executeQuery();   --->  发送···预编译好的···SQL语句(S)
|    (DQL)  给数据库软件执行。
|  
| c)setXX(int index,X); ---> 设置某一个预定义值

|   
+--3子-->   |--- CallableStatement  ---> 发送···预编译好(动态)···数据库语言
     的操作语句给数据库软件执行。
          ◆可以发送调用存储过程的语句   


|--- ResultSet ---> 返回一个查询语句的结果集

a)next()  --->  将获取到的结果集进行指针获取

b)getObject()  --->  可以获取到任意类型的值

c)getXX()  --->  可以获取到指定类型的值

   ◆◆◆◆◆注;CallableStatement ---> PreparedStatement ---> Statement 子接口
   
    ◆所以CallableStatement拥有父接口和间接父接口的功能,
     并且本身的功能就是用于操作存储过程的

◆◆◆注;JDBC的接口都是位于Java.sql.*和javax.sql.*
使用JDBC与数据库进行交互的基本都是接口,
较少使用使用实现类进行交互。

●但是可以通过DriverManager驱动管理类获取到连接数据库接口对象             
           
--------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 连接驱动三种方式 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
              
JDBC连接驱动三种方式;
     方式一;---> 通过Java_API下的Driver接口的connect(url,proprety info)
          
      a.通过MySQL架包下的Driver实现类,获取到Java_API下的Driver接口对象

  代码;
  Driver driver = new com.mysql.jdbc.Derver();       
       
       b.通过Driver接口的connect()方法获取到连接数据库接口对象
       
       1)因为connect方法要求传入一个Properties对象,
       而这个Perprotise对象是封装了MySQL数据库登录的用户和密码的
       
        Properties p = new Properties();
   
    p.setProperty("user","用户名");
    p.setProperty("Password","密码");
   
2)调用connect()方法,获取到连接数据库接口对象
String url = "jdbc:mysql://localhost:3306/day16";
Connection connection = driver.connect(url,p);

c)关闭连接
connection.close();

顺序;
        Java_API.Driver ---> Properties ---> Driver.connect() ---> Connection
        
      方式二;通过DriverManager管理驱动接口注册驱动程序
     
      a)获取到Java_API下的Driver接口对象
      Driver driver = new com.mysql.jdbc.Driver();    
           
       b)调用管理驱动类的方法,传入驱动程序对象注册驱动程序
       DriverManager.registerDriver(driver);    
           
       c)再通过DriverManger类的方法获取到连接数据库对象
       Connection connection - DriverManager.getConnection(url,user,password);
           
       d)关闭连接
       connection.close();
           
顺序;
Java_API.Driver ---> DriverManager.registerDriver()
       ---> DriverManager.getConection ---> Conenction 

方式三;通过反射直接加载MySQL架包下的Driver类对象

a)获取到MySQL架包下的Driver类对象,从而注册驱动
Class.forName("com.mysql.jdbc.Driver");

b)通过DriverManager驱动管理类方法
Connection connection = DriverManager.getConnection(url,user,password);
                                                  
◆◆◆◆◆为什么可以通过加载MySQL架包下的Driver类就可以注册驱动  
 
  因为在Driver类有一段静态代码块,
  只要通过反射获取到MySQL.Driver运行时类对象就会,
  自动调用Java.sql.DriverManager驱动管理类的,
  registerDriver方法传入一个MySQL.Driver接口对象,
  注册驱动,因为MySQL.Driver类实现了->+
  +--------------------|
  |---->java.sql.Driver接口
 
 static {
 try {
 
java.sql.DriverManager.registerDriver(new Driver());
     
     } catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
     }
}               

-----------------------------↓↓↓↓↓↓↓↓↓ JDBC —— Statement接口实现代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
            
JDBC_Statement接口代码解析;
   1.通过加载MySQL架包下的Driver类,
       从而加载Java_API下的Driver驱动接口对象注册驱动
   
    Class.forName("com.mysql.jdbc.Driver");
   
   2.通过驱动管理类对象获取到连接数据库接口对象,
    并且定义连接数据库的参数。
    Connection connection = DriverManager.getConection(url,user,password);
   
   3.通过连接数据库接口对象调用createStatement()方法创建Statement接口对象
   
    Statement st = connection.createStatement();
   
   5.通过调用Statement的方法发送SQL语句给数据库从而操作数据库的数据
   
    a)int st.executeUpdate(C/D/U/I);  ---> 定义DDL和DML语句
     并且发送给数据库
                       
       b)ResultSet st.executeQuery(Select);
       ---> 定义DQL语句
       发送给数据库    
     并且返回一个结果集
        
        6.遍历获取到的结果集

while(result.next()){
result.get类型("字段名")
      ---> 获取当前列指定的字段值

result.get类型(int index);
      ---> 获取指定字段位置的值
}

   7.关闭连接(后开先关)
   
    st.close();
    connection.close();
       
------------------------↓↓↓↓↓↓↓↓↓ JDBC —— PreparedStatement接口实现代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
       
JDBC_PreparedStatement接口代码解析;
   1.通过加载MySQL架包下的Driver类,
        从而加载Java_API下的Driver驱动接口注册驱动
   
    Class.forName("com.mysql.jdbc.Driver");
   
       2.通过驱动管理类对象获取到连接数据库接口对象,
    并且定义连接数据库的参数。
   
    Connection connection = DriverManager.getConection(url,user,password);
   
       3.通过连接数据库接口对象的方法定义预编译的SQL语句,
       并且获取到PreparedStatement对象
       
       PreparedStatement prepare = connection.preparedStatement(C/D/U/I ?);
   
   4. 给预编译的SQL语句的预留值赋值
   
    a)prepare.set类型(int index,值); ---> 指定预留值的赋值
   
   5.调用方法发送给数据库
   
    a)int prepare.executeUpdate(); ---> 发送DDL和DML语句
   
    ======直接发送,无需定义形参======
   
    b)ResuleSet prepare.executeQuery(); ---> 发送DQL语句 
   
   
   6.获取到结果集数据
   
while(result.next()){
result.get类型("字段名")
      ---> 获取当前列指定的字段值

result.get类型(int index);
      ---> 获取指定字段位置的值
}

   7.关闭连接(后开先关)
   
    prepared.close();
    connection.close();
       
------------------------↓↓↓↓↓↓↓↓↓ JDBC —— CallableStatement接口实现代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
                   
JDBC_CallableStatement接口实现代码;
   1.加载MySQL架包下的Driver类,
    从而加载Java_API下的Driver驱动接口注册驱动
Class.forName("com.mysql.jdbc.Driver");

   2.通过驱动管理类获取到连接数据库接口对象
    Connection connection = DriverManager.getConnection(url,user,password);

   3.通过连接数据库接口对象的方法定义预编译语句
    获取到CallableStatement对象
CallableStatement callable = connection.prepareCalla(S ?);
   
   4.定义输出值
   
    a)
     =====如果是获取输出值的话要先注册一个输出值=====
   
     callable.registerParameter(int index,java.sql.Types.类型);
    --->预编译值的位置
   --->类型
   
   5.调用方法发送给数据库
     
    a)
    =====存储过程的··输入··值是返回一个结果集
     
      Result callable.executeQuery();
   
    b)
    =====存储过程的··输出··值是可以直接获取的
      String callable.getString(int index)
          ---> 获取到预编译的值    
   
  6.遍历结果集
 
while(result.next()){
result.get类型("字段名")
      ---> 获取当前列指定的字段值

result.get类型(int index);
      ---> 获取指定字段位置的值
}

   7.关闭连接(后开先关)
   
    prepared.close();
    connection.close();
       
          
   
◆◆◆◆◆注;如果是要通过JDBC创建存储过程要注意换行的问题,  ---> /n
因为存储过程是换行执行的。
  
------------------------↓↓↓↓↓↓↓↓↓ JDBC —— Statement和PreparedStatement的区别 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
       
+------------------------------------------------+            
| 语法        |   效率       |     安全性   |
+------------------------------------------------+        
      Statement  是一个静态语法      效率低       可注入的              
        
      PreparedStatement  是一个预编译的      效率高           不可注入的     
                                          |
          |
                          ↓
 1=1 这个是恒等于可以用于做恶意操作
 1<>1
 
 如;
   select * from student where id=1 OR 1=1
 
 
◆◆◆注;效率的话在MySQL体现的不明显

———————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 批处理 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————
                   
JDBC批处理;
  为什么?
   当要一次发送N条语句到数据的时候可以提高效率,
   因为如果一条一条发送会使得用户体验差
 
  作用;
  使用提高效率,因为一次性发送N条语句可以提高效率
 
  特点;
  一次性发送N条语句
                  
  方法;
  addBatch();      ---> 将语句添加到批处理语句空间中
  executeBatch();  ---> 发送所有的批处理空间的语句
  clearBatch();    ---> 情况批处理空间的语句
   
   
                 
◆◆◆注这个空间就是软件的内存缓存              

----------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 批处理实现代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
       
批处理实现代码解析;
  1.加载MySQL架包下的Driver类,
    从而加载Java_API下的Driver驱动接口注册驱动
Class.forName("com.mysql.jdbc.Driver");

  2.通过驱动管理类获取到连接数据库接口对象
Connection connection = DriverManager.getConnection(url,user,password);
            
      3.通过连接数据库接口对象的方法定义预编译的SQL语句,
       并且获取到PreparedStatement对象
     
       PreparedStatement prepare = connection.preparedStatement(C/D/U/I ?);
  
  
  4.定义输出值,并且进行批处理操作
 
  for(int i = 0; i < 10000; i++){
  prepare.setInt(i);      ---> 给预编译语句添加值
 
  prepare.addBatch();    ---> 将这条语句添加到批处理空间中
 
  if(i % 1000 == 0){     ---> 每一次发送1000条
    
    prepare.executeBatch() ---> 发送批处理空间的语句给数据库
    
    prepare.clearBatch() ---> 清空批处理空间的语句
  }
  }     
     
      5.关闭连接
      
      prapare.close();
      connection.close();
         
—————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 获取自增长值 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————
                         
JDBC获取自增长的值;
代码;
1.在定义预编译语句的是添加一个形参Statement.RETURN_GENERIC_KEYS
PreparedStatement prepare = conenciton.getPrepareStatement(sql,Statement.RETURN_GENERIC_KEYS);

2.通过getGenericKey() 获取到自增长的值的结果集
ResultSet result = prepare.getGenericKey();

3.遍历
。。。。。。。

———————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 文件存取 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————
         
JDBC文件存取;
    为什么可以存?
    因为数据库其实就是类似通过IO的技术存储到硬盘的,
    而存储到数据库本质是存储到硬盘
   
    存的是什么文件?
       文本文件
       二进制文件

    存储类型;      
      文本文件;
       text  Mediumtext  longtext
        ↓↓↓     ↓↓↓        ↓↓↓
       64KB     16M        4GB
      
      
      二进制文件;        
   blob  MediumBlob  longBlob
    ↓↓↓     ↓↓↓↓↓↓
    64KB    16M4GB

----------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 实现二进制文件存取代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------              

 JDBC二进制文件存取代码;
◆存;
    1.加载MySQL架包下的Driver类,
    从而加载Java_API下的Driver驱动接口注册驱动
Class.forName("com.mysql.jdbc.Driver");

    2.通过驱动管理类获取到连接数据库接口对象
Connection connection = DriverManager.getConnection(url,user,password);
        
   3.通过连接数据库接口对象的方法定义预编译的SQL语句,
       并且获取到PreparedStatement对象
       
    PreparedStatement prepare = connection.preparedStatement(C/D/U/I ?);
   
   
    4.获取到输入文件流,传入到预编译语句的值 
    prepare.setBlob(1,new FileInputStream("c:/xx..jpg");
   
    ===注;如果是文本文件则是传入FileReader("c:/");
   
   
    5.发送给数据库
    prepare.executeUpdate();
   
   
    6.关闭连接
    prepare.close();
    connection.close();
    
      ◆取;        
     1.加载MySQL架包下的Driver类,
    从而加载Java_API下的Driver驱动接口注册驱动
Class.forName("com.mysql.jdbc.Driver");

    2.通过驱动管理类获取到连接数据库接口对象
Connection connection = DriverManager.getConnection(url,user,password);
           
            3.通过连接数据库接口对象的方法定义预编译的SQL语句,
       并且获取到PreparedStatement对象
       
    PreparedStatement prepare = connection.preparedStatement(Sel ?);
   
    4.调用方法获取到结果集
    ResultSet prepare.executeQuery();
   
    5.遍历结果集获取到数据库的文件输入流
    
    while(result.next()){
    InputStream = result.getBlob().getBinaryStream();
    ---> 获取到文件类型值
       调用方法获取到二进制
           输入流
   
    ===注;如果是文本文件则使用getClob().getCharacterStream();
   
    FileOutputStream fos = new FileOutputStream("c:/x.jpg");
    ◆---> 按照IO流的方式写出
    }


◆◆◆◆◆注;在数据库中是不会存储图片和文件的,
因为数据库的资源是非常宝贵的,
◆因为存储的是文件的路径,
在从数据库中获取到这个文件路径
在从这个路径中加载。。。。。。

◆除非是重要,机密等文件才会存放到数据库等。。。。。

◆◆◆◆◆注;如果在数据库存储的文件本身编码是GBK的,
那么会导致编码不一致的时候会出现乱码,
 因为数据库一般都是设置成UTF-8的,
  所以一般都是改变文件的编码集。

————————————————————————————————————————————↓↓↓↓↓↓↓↓↓ 数据库事务 ↓↓↓↓↓↓↓↓↓↓↓——————————————————————————————————————————————
       
         
JDBC事务;
为什么要有?
SQL语句在JDBC执行的时候是执行到一条语句则发送一条语句都SQL数据库,
那么如何实现N条SQL语句代码发送到数据库的一致同步性?


是什么?
事务是数据库本身的特征,只有数据库支持才有事务概念以及处理,
基本关系型的数据库都支持事务,而非关系型的数据库不一定支持事务 

作用;
使得SQL语句代码执行的一致性,
是一个将多条SQL语句绑定的,
失败一起失败成功一起成功。

特点;
    1.数据库的引擎是InnoDB类型,基本都支持
    2.多条代码一起成功,一起失败。            


方法;
     1.set autocommit = 0 ---> 开启事务处理,关闭自动提交
      ◆这个设置是一个局部的设置,
      不会改变到这个aotocommit的全局变量
     
     2.commit ---> 提交事务,一旦提交了则无法反悔。
     
     3.rollback ---> 回滚事务,一般是回滚到事务的开启点,
      或者是上一个事务的结束点。
     
     
                    
◆◆注;一个事务可以看成是一个小的工作空间,
至于这个工作空间的门是否打开、上锁等。。。。
则是看这个工作空间的···隔离特征···的··级别··的。。。。。

--------------------------------------↓↓↓↓↓↓↓↓↓ 数据库事务的四大特征 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
                          
数据库事务的四大特征;
     一、原子性;事务的每一个元素(SQL语句)都是不可分割的单元,
      要么一起成功,要么一起失败。
     
     
     二、一致性;事务则是让数据库的状态转换成另外的一个状态,
      而这个转换时的状态是一致的。
     
        如;更改前数据库的状态和更改后的数据库状态是一致的。
       而不会更改时出现异常的状态,是更改后的状态。
      也就是出现异常了,还是更改成功了。
     
     
     三、隔离性;多个事务并发操作同一个共享数据的时候,
        每一个事务的操作是不会影响到另外的一个事务的操作。
        
        
     四、持久性;事务一旦提交了,则是永久的保存在硬盘上的,是不可以回滚。
     
--------------------------------------↓↓↓↓↓↓↓↓↓ 数据库事务隔离的级别 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
               
数据库事务隔离的级别;
    为什么要有隔离的级别?
    如果没有隔离的级别的话,
    多个事务共同操作一个共享数据的时候会出现。
   
    a)脏读
    b)不可重复读
    c)幻读
   
   
   
    有几个级别?
    有五个级别。
            
    级别;
      1.read uncommitted  --->   最低级别
      2.read committed    --->   防止脏读
      3.repeatable read   --->   防止不可重复读和脏读
      4.Serializable      --->   防止幻读、不可重复读、脏读
                 
    默认级别;
MySQL默认是 ---> repeatable read
oracle默认是 ---> read committed

    命令;
      set global transaction isolation level 级别
      select @@global.tx_isolation
      
     
--------------------------------------↓↓↓↓↓↓↓↓↓ 数据库事务并发的现象 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

数据库事务并发的现象;
    都是因为隔离级别过低才出现的。
    
    1.脏读;一个事务读取到另一个事务还没有提交的更新数据。
   
    如;A事务更改表数据的时候还没有提交,
    则被B事务获取到了,在这时A事务进行了回滚,
    则会出现一个欺骗的现象。
      
    set read committed; ---> 提高级别
   
    2.不可重复读;一个事务读取到另一个事务的已提交的更新数据
    
    如;A事务在进行第一次查表的时候数据是没有发生更改的,
    而B事务在A事务第一次查表完成之后就立刻更改了表,
    使得A事务在第二次进行查表的时候出现了不一样的数据。
   
    set repeatable read; ---> 提高级别
   
    3.幻读;一个事务读取到另一个事务的已提交了的插入数据
    
    如;A事务在进行第一次查表的时候是没有Id为3的数据的,
    而B事务则在A事务完成第一次查表之后就插入了Id为3的数据
    使得A事务在插入的时候就无法插入了。
   
    可是在查表的时候还是没有改变,只有A事务退出了事务,
    或者是关闭事务(set autocommit=1)才可以看到新的数据。
   
    因为在不可重复读的时候已经提高了级别了。
    
    set serializable; ---> 提高级别
    
-------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 实现事务处理代码解析 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
          
JDBC实现事务处理代码解析;
 需求;客户表单的A向B转账1000,
  而同时A-1000,B+1000,如果中间出现异常则转账失败  

   try{ 
1.加载MySQL架包下的Driver类,从而注册驱动
Class.forName("com.mysql.jdbc.Driver");
 
2.通过管理驱动类对象获取到连接数据库接口对象
Connection connection = DriverManager.getConnection(url,user,password);
 
3.开启事务处理
connection.setAutoCommit(false);
 
4.通过连接数据库接口对象定义预编译语句并且获取到PreparedStatement对象
PreparedStatement prepare_A = conneciton.prepareStatement("C/D/U/I ?-1000");
PreparedStatement prepare_B = connection.prepareStatement("C/D/U/I ?-1000");

5.给预编译语句赋值
prepare_A.setXX(int index,XX);
prepareB.setXX(int index,XX)

6.调用方法发送
prepare_A.executeUpdate();

■■■ 模拟出现异常 ■■■
   int i = 10/0;

prepare_B.executeUpdate();
 
7.提交
connection.commit();

//关闭连接
 prepare_A.close();
 prepare_B.close();
 connection.close();
 

8.出现异常
}catch(Exception e){
9.如果出现了异常则进行一个回滚的操作
connection.rollback();
}finally{


}
       
            
◆◆◆◆◆注;如果在数据库定义字段的时候,
字段名是关键字的可以使用( ` ` ) 反引号来进行转义,位于( ! )左边的符号

———————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 优化 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————
           
JDBC优化;
为什么要有?
因为Java程序是通过JDBC规范来连接到数据库的从而达到操作数据库的目的
而在每一次连接数据库的时候都要耗费大量的时间以及大量的数据库资源,
因为用户每一次连接数据库,数据库都要分配资源为这个用户创建连接,
当用户关闭连接的时候,数据库还要为这个关闭耗费资源,而当
用户再次连接到数据库的时候,又要在此创建连接,
      +<----------------------◆◆◆◆◆◆周而复始的创建和关闭。。。。。。。
      |
      +-----> 解决;可以通过连接池的概念来解决这个问题。。。。。。

—————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 数据库连接池 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————

数据库连接池;
   为什么要有?
    因为每当数据库要为每一个连接都要不断的创建新的连接,会耗费大量的资源。
    ◆从而使得用户体验差,而且很容易使得数据库出现内存溢出等。。。
       
   是什么?
    数据库连接池就是已经创建好与数据库之间的连接的,
    并且这个连接的个数,时间等......用户可以自己指定。
       
   作用;
    1.使得连接的效率提高
    2.对数据库的··运行··资源保护更好了
    3.使得数据库更加安全
    4.用户体验好
        
   特点;
    1.每一个厂商的连接池可能都是自己实现的,从而不一样
    2.如果想要Java程序可以使用,那么必须要实现javax.sql.DataSource接口
  
   ◆◆◆◆◆注;数据库连接池如果想要让Java程序使用那么必须要实现javax.sql.DataSource接口
   
   ◆◆重◆◆注;B/S结构开发的数据库连接池是位于···服务器端···的,而不是客户端的。
   
---------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 数据库连接池原理 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
      
数据库连接池原理;
 1.数据库会在内存中会提前创建好N个连接,存放在一个容器中(集合)
 2.用户访问服务器数据库资源的时候,
  数据库会从内存中取出一个连接分配给这个用户
 
 3.而这个用户则会一直使用这个连接访问服务器数据库资源
 4.用户关闭连接
 5.数据库则会把这个连接进行一个回收放回到连接池的容器中
 
----------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 数据库连接池构造基本思想 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
   
数据库连接池构造基本思想;
 1.要有个容器存放这些已经与数据库创建了连接的对象
 2.初始化容器的连接对象个数
 3.用户每次取都是从容器中取出的,所有每次日期都要进行--
 4.超过了初始化连接对象个数是否需要扩容
 5.用户回收的方法
 6.进行回收,存放回容器中    
     a)要设计一个通用的回收方法,close()
     i)可以通过静态反射
     ii)可以通过动态反射
   
------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 数据库连接池建立要素 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

数据库连接池连接要素;
1.初始化连接参数
2.连接池初始化连接个数
3.连接池分配连接的最大连接个数      (保护数据库)
4.等待连接池分配连接的最大等待时间

—————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 开源数据库连接池 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————

开源数据库连接池;
 为什么要有?
  如果数据库连接池是由java开发程序员编写的会使得数据库连接不安全,
  因为java开发程序员是不会每时每刻的去更改这个连接池的,
  而如果是使用开源组织的连接池会更加的安全,
   因为开源组织的连接池是由开源组织开发的
    而开源组织会不断的优化。
    
    
 是什么?
  是一个创建数据库连接池的较为可靠一个工具
 
 
 作用;
  1.使得数据库的连接效率更高
  2.数据库更加安全
  3.用户体验更好
 
 
 特点;
  1.想让java程序使用,必须要实现javax.sql.DataSource接口
  2.每一个连接池原理都是类似的,只不过实现的方法可能不一样
 
 
     流行的开源连接池;
1.DBCP ---> Apache开发的,也是Tomcat使用连接池的组件

   --->导包;
        commons-dbcp.jar
        commons-pool.jar
   
        
2.C3P0 ---> 开源组织,也是Hibernate和Spring等在使用的

   --->导包;
        c3p0-0.9.1.2.jar
        
 
◆◆◆◆◆注;DBCP和C3P0的基本区别;
   1.C3P0有自动回收空闲连接功能
       2.DBCP没有自动回收空闲连接功能
  
-----------------------------↓↓↓↓↓↓↓↓↓ JDBC —— DBCP连接池基本创建 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------
    
DBCP连接池基本创建;

方式一;直接设置参数  ---> 硬编码

      1.导包;                 ---> 需要导入2个包
       commons-dbcp.jar
   commons-pool.jar    

      2.创建DBCP架包下的实现了DataSource连接池接口的BasicDataSource对象
       
       BasicDataSource bds = new BasicDataSource();

      3.设置数据库连接基本属性
       
       a)数据库基本连接参数;
       
         bds.setDriverClassName("xxx");
         bds.setUrl("xxx");
         bds.setUsername("xxx");
         bds.setPassword("xxx");
       
       b)设置连接池部分基本属性
       
         bds.setInitialSize(number); ---> 初始化的个数  
         bds.setMaxActive(number);   ---> 连接池最大连接个数
         bds.setMaxWait((long)[S]);  ---> 最大等待时间       


      4.通过BasicDataSource的方法返回一个Connection连接数据库接口对象
      
         bds.getConnection();
         
      5.回收连接
     
         bds.close();
      
      6.关闭连接   ---> 最好自定义关闭连接的方法
         。。。。。。。。。。。。

方式二;通过加载properties配置文件

1.创建一个xx.properties文件
。。。。。。
   ◆注;在properties文件中#是注释


2.在properties文件中定义连接数据库参数

   a)数据库连接基本参数
     
driverClassName=xxx
url=xxx
username=xxx
password=xxx

   b)数据库连接池部分基本属性
   
    initialSize(number);   ---> 初始化连接个数
    maxActive(number);     ---> 最大连接个数
    maxWait((long)[s]);    ---> 最大等待时间


4.创建一个properties类对象

Properties pro = new Properties();


5.加载properties文件

pro.load(类.class.getResourceAsStream("/当前路径properties文件"));

   
3.创建一个BasicDataSource工厂类对象BasicDataSourceFatory对象,
在调用createDataSource(Properties)的方法传入一个Properties的对象

DataSource ds = new BasicDataSourceFactory().createDataSource(pro);

-----------------------------↓↓↓↓↓↓↓↓↓ JDBC —— C3P0连接池基本创建 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

C3P0连接池基本创建;

方式一;直接设置参数 ---> 硬编码

    1.导包
    ---> c3p0-0.9.1.2.jar
    
    2.创建C3P0架包下的实现了DataSource连接池接口的ComboPooledDataSource对象
 
  CombolPooledDataSource cpds = new ComboPooledDataSource()
 
  3.调用方法设置连接池参数
   
    a)连接数据库基本参数
     
     cpds.setDriverClass(xxx);
    cpds.setJdbcUrl(xxx);
     cpds.setUser(xxx);
     cpds.setPassword(xxx);
     
    b)设置连接池的部分基本属性
      
     cpds.setInitialPoolSize(number);  ---> 连接池的初始化连接个数
     cpds.setMaxPoolSize(number);      ---> 连接池的最大连接个数
     cpds.setCheckoutTimeout(number);  ---> 获取连接池连接的
     最大等待时间
 
 
    4.调用方法获取到连接池的Connction对象
     
     cpds.getConnection();

    5.回收连接
   
     cpds.close();

    6.关闭连接 ---> 建议自己写一个关闭的方法
     
     cpds.close();
   
     
方式二;通过C3P0定义的xml文件加载初始化参数

1.创建一个在当前路径下的名为;【 c3p0-config.xml 】 文件
。。。。。。。。

a)在这个XML文件中设置初始化信息

<c3p0-config>
<default-config>
//连接数据库基本信息

<property name="dirverClass">xxx</property>
<property name="jdbcUrl">xxx</property>
<property name="user">xxx</property>
<property name="password">xxx</property>

//连接池基本信息
<property name="initialPoolSize">number</property>
<property name="maxPoolSize">number</property>
<property name="checkoutTimeout">number</property>
</default-config>

<named-config name="">
<property named="xxx"></property>
。。。。。。
</named-config>
</c3p0-config>

 
  说明;<c3p0-config>是一个默认的根标签
       <default-config>是一个默认的连接属性
       -=-当有多个连接池的时候,
          用户没有指定连接池的要
          使用的属性
          则会默认使用<default-config>
          标签中设置的属性
       
       <named-config name="">当有多个连接池的时候
       可以指定连接池的在文件中的配置属性
  信息,通过name属性来指明。
       
       <property name="属性名">是设置连接池的属性和值
       
    ◆注;<default-config>只能有一个
          <named-config name="">可以有多个,因为有多个连接池的情况
 
          
2.创建C3P0架包下实现DataSource连接池接口的ComboPooledDataSource对象

ComboPooledDataSource cpds = new ComboPooledDataSource(可写/不写);
 
   ◆◆◆◆◆注;在启动的时候会自动
   在···当前的路径···下搜索名
   为c3p0-config.xml文件
   并且加载这个文件的设置的连接池属性
   
   而如果在创建这个对象的时候在形参中
   ···写入···c3p0-config.xml文件下的
   <named-config>标签的name属性值,
   则会默认使用这个标签下设置的属性。
   
   而如果没有写则默认使用<default-config>标签下的设置的属性

————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 元数据 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————

JDBC常用的元数据;
为什么要有?
  有了元数据可以就通过获取到一些参数,
  通过获取到的参数设置某些值等。。。
 
是什么?
JDBC元数据就是一些类


作用;
    为了写出更加通用的代码
    
    
特点;
     1.都是为了写出更加通用的代码而存在的
     2.基本都是一些接口

----------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— 常用的元数据 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

JDBC常用的元数据;
1.数据库元数据;
---> 获取数据库的基本信息
   
  如;数据库名称 ---> getDatabaseProductName()
      数据库版本 ---> getDatabaseVersion();
      数据库对应的驱动 ---> getDriverName();
    。。。。。。
     
--->  Connection获取DatabaseMetaData接口对象
  
2.参数元数据;
---> 获取数据库的参数信息

  如;参数名
      参数个数 ---> getParamterCount();
      参数类型 ---> ......
 
---> 一般用于在预定义赋值用的,
因为在调用这个接口的getParameterCount()方法的时候,
 是根据预编译语句的预编译值符号来定义预编译的语句的值。
        
---> PreparedStatement获取ParameterMetaData接口对象       



3.结果集元数据;
---> 获取到结果集的信息

   如;字段名  ---> getColumnName(number);
       字段数量 ---> getColumnCount();
       字段类型 ---> getColumnTyle(number);
       
---> 一般使用在获取到的结果集迭代的时候获取到不确定的值
 
---> ResultSet获取ResultSetMetaData接口对象
 
 
◆◆◆◆◆注;因为元数据获取到的实现是由数据库驱动实现的,
  而这些方法是否可用,是否与预知的用法一样是看实现的。
  
     虽然连接数据库接口/标准是由SUN公司规定的,
      但是具体的实现是由数据库厂商实现的,
      ◆◆所以当通过方法获取到的和预知结果
      ◆◆不一样的时候要查资料。


 ◆◆◆案例;通过元数据可以制作通过的数据库DDL/DML语句的方法和DQL语句的方法

在做DQL返回的数据的时候最好封装成一个javaBean对象,
而这个封装可以通过反射,暴力反射等获取。
       
——————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— DBUtil框架 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————

JDBC-DBUtil;
  为什么要有?
  因为常用的方法如果每次都要重新写的话,
  那么会使得开发效率低下。
 
 
  是什么?
   DBUtil是由Apache开源组织对JDBC进行简单封装的一个工具类
   
   
  作用;
  可以简化JDBC程序的开发,
  而不会影响到程序的性能。
 
  特点;
       里面封装的都是方法
        这些方法都是JDBC常用的方法
       
-------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— DBUtil使用过程 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

       
DBUtil使用过程;
1.创建主类QueryRunner对象,
传入一个DataSource连接池接口对象,
通过连接池接口对象和数据库进行一个连接。

QueryRunner qr = new QrueryRunner(new ComboPooledDataSource());
 
 
 
2.调用执行DDL/DML数据库语句方法

qr.update(String sql,Object...parame);



3.调用执行DQL数据库语句方法

Object qr.query(String sql,ResultSetHandler rsh,Object...parame);

--------------------------↓↓↓↓↓↓↓↓↓ JDBC —— DBUtil_ResultSetHandler类 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

DBUtil常用类;
    1.QueryRunner ---> 是DBUtil下的主类 ◆
    
    
    ▲ResultSetHandler接口,将结果集封装成不同的对象。
    ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
    
    2.BeanHandler ---> 是用于将数据封装成一个对象,
    而这个对象的属性···必须···要
    ◆和要封装的字段··◆个数要一样
 
    ---> 返回的是这个传入的对象
    
    代码;
    类 = query(String sql,new BeanHandler(类.class),Object...param); 
   
    3.BeanListHandler ---> 是用于将多个数据封装一个个的对象,
    并且将这个多个对象存放到集合中
    而这个对象的属性···必须要
    和要封装的字段··◆个数一样。
   
      ---> 返回的是这个传入的对象的List集合

代码;
List<类> = query(String sql,new BeanListHandler(类.class),Object...param);

    4.ArrayHandler ---> 是用于将数据封装成一个对象
    而这个对象的属性可以和要
    封装的字段的个数··◆不一样
       
       ---> 返回的是一个Object[]数组 
   
    代码;
    Object[] = query(String sql,new ArrayHandler(),Object...param);

    5.ArrayListHandler ---> 是用于将多个数据封装成多个对象
    并且将这多个对象存放到集合中
    而这个对象的属性可以和要
    的字段的个数··◆不一样
   
       ---> 返回的是Object[]数组类型的一个List集合
       
    代码;
    List(Object[]) = query(String sql,new ArrayListHandler(),Object...param);   
 
    6.ScalarHanderl ---> 是用于处理聚合查询语句的(count(*),min(*)......)
       
       ---> 返回的是一个Object可以转换成对应的包装类
代码;
Object number  = query(String sql,new ScalarHandler(),Object...param);

------------------------------↓↓↓↓↓↓↓↓↓ JDBC —— DBUtil之事务 ↓↓↓↓↓↓↓↓↓↓↓-------------------------------------------

DBUtil事务;
   在使用DBUtil工具类的时候,
    如果要使用事务则在创建QueryRunner对象的时候不用传参,
    而是在调用方法的时候,传入一个Connection对象。
   
   
     代码;
         1.创建一个无参QueryRunner对象
         
         QueryRunner qr = new QueryRunner();

         2.获取到一个Connection连接数据库接口对象
         a)
          Connection connection = new CombolPooledDataSource().getConnection();
         b)
          Connection connection = new BasicDataSourceFactory().
          createDataSource(Properties).
          getConenction();


   3.开启事务处理

    connection.setAutoCommit(false);

         4.调用执行DDL/DML语句的方法,传入一个Connection对象与数据库建立连接
     
         qr.update(connection,String sql_1,Obejct...param);
         qr.update(connection,String sql_2,Object...param);
         
         5.提交事务
         connection.commit;
         
         6.事务回滚(出现异常)
         connection.rollback;  
 
—————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 分页 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————

分页设计的关键;
将整个分页的数据设计成一个javaBean;

private List<Student> list; // 当前页数据
private int pageFrist; // 首页
private int perviousPage; // 上一页
private int nextPage; // 下一页
private int lastPage; // 尾页 / 总页数
private int curPage; // 当前页
private int countRecord; // 总记录数
private int curRecord; // 当前页面数据库条数


还有相关的算法; 
1.设置首页
2.设置上一页,当前页是否是首页,如果是首页则为1,
如果不是为首页则当前页-1

3.设置下一页,当前页是否未末页,如果不为末页则当前页+1

4.尾页/总页数;总记录条数%每页条数==0  
等于的话则总记录数/每页条数 : 总记录数/每页条数+1

—————————————————————————————————————↓↓↓↓↓↓↓↓↓ JDBC —— 基本学习过程 ↓↓↓↓↓↓↓↓↓↓↓————————————————————————————————————————————


---> JDBC基本开发(发送SQL语句)(S/P/C) ---> 注册驱动、Connection、preparedStatiment、callableStatement 
 
---> 因为基本开发每次发送SQL语句慢 ---> 批处理(addBatch/executeBatch/clearBatch)
 
---> 但是在发送DDL/DML语句的时候不知道主键的自增长的值 ---> 获取自增长的值(statement_GENERIC_KEYS)  
 
---> 因为有一些文件可能比较机密要存放到数据库 ---> 文件存取(text/clob/mediumnclob,blob/mediumnblob)
 
---> 有写业务要求达到同步性 ---> 事务处理 
 
---> 每一次都要与数据库进行连接对数据库不好,对用户体验也不好 ---> 连接池(DBCP/C3P0)     
 
---> 为了可以写出更加通用的代码(字段不可预知个数等.....) ---> 常用三种元数据 
 
---> 因为有一些JDBC的代码实在是太常用了 ---> JDBCUtil框架
 

小结;越来简单,越来越通用。。。。。。        

 

 

 

 

 

 

     

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值