JDBC_入门到熟练

文章简介

使用java语言连接数据库

一:了解JDBC

首先JDBC是什么?
  表面意思:Java Database Connectivity(java语言连接数据库)。
  本质上来说:SUN公司制定的一套接口(interface);
  这套接口在package.java.sql包下,而这个软件包下有很多接口。
为什么要定义SUN指定这套接口。
   因为每一个数据库的底层实现原理都不一样。
      Oracle有自己的数据库原理
      MYSQL也有自己的数据库原理
      MS SqlServler也有自己的数据库原理
   如果没有这套jdbc接口,那我们每连接一个不同的数据库就需要写一个不同的连接方式,这对我们java程序员来说是痛苦的。为了我们java程序员的方便,sun公司就推出了这么一套接口,而我们程序员就可以面向这个接口写代码,不用关心底层数据库是谁,因为这套接口的实现方式数据库厂家去实现的。我们只需要面向这个接口去调用就可以。
可能也有人会问,那为什么这么多的数据库就要去听你sun公司的来编写实现方式。
  我们众所周知啊,现在java编程语言算的上数一数二,如果程序员在编写代码的时候,需要一套一套的写出各种数据库的连接方式,那这个数据库就会流失很多用户的。

这里可以用一张图来表明他们之间的爱恨情仇

JDBC_入门到熟练_第1张图片

那我们如何查询他们各自的class文件呢。
  SUN公司提供的JDBC接口下的class文件,在我们JDK的package.java.sql包下
  我们自己编写的class文件,这你自己查找没问题吧
  数据库厂家编写的JDBC实现类的class文件,这个需要我们到各大数据库的官网中下载,也就是我们所听说的驱动

二:编写程序模拟JDBC本质

首先模拟SUN公司的JDBC接口

JDBC_入门到熟练_第2张图片

模拟MYSQL数据库厂程序员编写的实现类

JDBC_入门到熟练_第3张图片

模拟Oracle数据库厂程序员编写的JDBC实现类

JDBC_入门到熟练_第4张图片

模拟 MS SqlServler 数据库厂程序员编写的JDBC实现类

JDBC_入门到熟练_第5张图片

模拟java程序员调用JDBC

首先我们先来面向具体编程法

JDBC_入门到熟练_第6张图片
接着就是面向接口编程法

JDBC_入门到熟练_第7张图片
紧接着就是使用反射的方法

JDBC_入门到熟练_第8张图片
最后使用反射的配置文件法

JDBC_入门到熟练_第9张图片
配置文件中的样式

JDBC_入门到熟练_第10张图片
在这里给大家来一段小引用,题外话

大家会发现在这个模拟java程序员开发这里,我写出了四种不同的方法。那我大体的来说一下这些方法。
第一种方法:面向具体编程:本类型的引用指向本类型的对象。   优点:利用新手上手,容易理解
  缺点:后期维护性差,我们这个对象肯定是为了满足客户要求去编写的,而如果使用了面向具体编程,我们的代码也就会被随之锁死。后期维护的时候,如果后期客户的要求变更,我们去更改源码的时候,可能会随之产生一系列的问题,不建议使用。
第二种方法:面向接口编程:父类型的引用指向本类型的对象。
  优点:解耦合、可扩展、利于维护。假如:我定义一个接口,我甚至不知道别人会怎样实现它,我的系统用谁的具体实现都能正常工作,甚至没有具体实现也能正常工作,别人一点都不会影响我,这就是解耦。
  缺点:如果没人具体的实现这个接口,那我就废了。或者我只能在A的具体实现上工作,B的就不行,这就是强耦合。
第三种方法和第四中方法雷同:通过反射机制并将内容写入到配置文件中
  优点:java的反射机制就是增加程序的灵活性,避免将程序写死到代码里。
  缺点:虽然反射机制比较好,但是也不可以滥用。反射机制的暴力访问私有属性和方法实在是没有安全性。容易"暴露"!
  模糊了维护性:你要说它后期不好维护吧,他可以直接修改配置文件中的内容来维护。你说它好维护吧。而我们程序员需要通过源码来观察这个业务的逻辑性,而反射会绕过了源码的技术,模糊程序内的内部逻辑。这个问题小弟实在是想不明白。有明白的大佬,请留言,我多多请教。

三:JDBC:开发前的准备工作

以MYSQL数据库为例:首先先到官网下载所需的jar包
在这里插入图片描述
如果您比较喜欢针对记事本编辑器的开发方式呢,您就需要配置环境变量,
classpath=.;(jar包全路径)
如果是IDEA工具呢,在src目录下创建一个lib目录,将JDBC-jar包复制进去,添加到类库即可。
如图即为添加成功(druid-jar包目前用不到,自行忽略看,假装看不到)

JDBC_入门到熟练_第11张图片

四:JDBC编译六步(需要背会-死记硬背即可)

第一步:获取驱动:(告诉JVM或者java程序,即将连接的是哪个数据库)

* 拆分成俩条语句:更直观的看到多态的效果:面向接口编程。父类型引用指向子类型引用

在这里插入图片描述

   * 合并为一条语句:new Driver()的时候一定要注意Driver的包,是com.sql.jdbc.Driver.

在这里插入图片描述

第二步:获取连接:(表示JVM的进程和数据库进程之间的通道打开了,属于进程之间的通信,使用完一定要关闭通道)。

    * 获取连接后返回的就是连接对象,连接对象就是java.sql.Connection,是一个接口对象

JDBC_入门到熟练_第12张图片

第三部:获取数据库操作对象:(专门执行SQL语句的对象)

    * Statement createStatement()
    * 创建用于向数据库发送SQL语句的对象,返回一个新的默认Statement对象

在这里插入图片描述

第四步:执行SQL语句(DQL、DML…)

    * 编写一条我们需要执行的sql语句,这里以添加为例
    * 增删改,都是使用statement.executeUpdate(),返回的是执行的数据条数
    * 查询就使用,statement,executeQuery(),返回的是查询的结果

在这里插入图片描述

第五步:处理结果集(只有第四步执行的是查询的时候需要用到,而增删改不需要处理)


第六步:释放资源(使用完以后一定要关闭资源,java和数据库之间属于进程间的通信,开启之后一定要关闭)
在这里插入图片描述

注意事项:
第二步的连接数据库 我们定义了一个URL。那么URL是什么。   URL是通信协议    通信协议是通信之前就提前定义好的数据传说格式
   数据包具体是怎么传数据的,格式提前定义好的   就比如说Oracle的URL:

    jdbc:oracle:thin:@localhost:1521:orcl

第六步的释放资源:    释放资源要遵循从小到大一次释放

五:利用JDBC完成增删改查

一:添加
JDBC_入门到熟练_第13张图片
二:删除
JDBC_入门到熟练_第14张图片
三:改
JDBC_入门到熟练_第15张图片
四:查询多条数据
JDBC_入门到熟练_第16张图片
五:查询一条数据
JDBC_入门到熟练_第17张图片

六:JDBC的代码优化

JDBC代码工具类

  在做增、删除、修改、查询都需要获取Connection连接、关闭资源,这些工作是不断的重复在做的事情,所以我们可以把这些工作定义成一个工具类的方法,在工具类中进行连接和关闭,减少我们重复代码的编写。

public JDBCUtils{
//获取连接->这里的获取连接中的URL,userName,passWord因为每次连接都需要调用,直接放在设置成成员属性比较方便。
   private static String url="jdbc:mysql://loclaHost:3306/mydb";
   private static  String userName="root";
   private static  String passWold="lk001228";
Static{
  //静态代码块会在类加载时执行,并且只执行一次
   //会返回SQLException -如果一个数据库访问错误发生,所以try catch
   try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException e) {
            e.printStackTrace();
        }
 }
//获取连接方法
 public static Connection getConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);
        return connection;
    }
//关闭资源方法
 public static void close(Connection conection,Statement statement,ResultSet recultSet(这里的只有在查询的时候才会需要关闭)){
//先来判断是否为空,这里需要try时候,不要把需要关闭得资源,
放在一块try catch,因为如果第一个关闭出错,直接会执行catch中的内容,
第二个就会被跳过,所以,分开try比较好
   try {
            if (recultSet != null) {
               recultSet .close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
  try {
            if (statement != null) {
                statement.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
  try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
 }

通过反射改进获取驱动方式

我们可以到MYSQL提供的 com.mysql.jdbc下查看DIrver这个方法。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
    public Driver() throws SQLException {
    }
    static {
        try {
            DriverManager.registerDriver(new Driver());
        } catch (SQLException var1) {
            throw new RuntimeException("Can't register driver!");
        }
    }
}
我们可以看到这样的一个方法,而我们的连接方法放在了静态代码块中,如果想让一个类的静态代码块执行,只要加载这个类就可以 那么如何加载这个类,很简单 Class.from("com.mysql.jdbc.Driver"); 通过这个反射机制,我们就可以加载这个类,那这个代码的效果就和我们的DirverManager.registerDriver(new Driver());的效果一摸一样。 那为什么这种方式常用,因为这个参数是一个字符串,字符串可以写在配置文件中,以下方法不需要接收返回值,因为我们只想用它的类加载动作。 ## 通过反射中配置文件的方法改进获取驱动方式 //所以我们这里就以配置文件来改进这个加载驱动器代码 首先在src下编写一个xxx.properties配置文件,将文件中的信息如图填写

JDBC_入门到熟练_第18张图片
然后将我们的工具类改成这个样子即可
JDBC_入门到熟练_第19张图片

那我们的main方法就可以这样写
JDBC_入门到熟练_第20张图片
为什么要通过反射的机制改进获取驱动方式呢?
就是为了解耦合,提高代码的灵活性

七:MYSQL注入

SQL注入:一种程序安全隐患
原理:攻击者可以在web应用程序中事先定义好的查询语句的结尾上拼接额外的SQL语句,发送到DBMS,而DBMS对进行编译,正好将用户编译的非法信息编译进去,导致了原sql语句的含义被扭曲了,以此来实现欺骗数据库服务器执行非授权的任意查询,从而进一步达成自己的目的
解决SQL注入问题
方法:
   只要用户提供的信息不参与sql语句的编译过程,问题就解决了。
    即使用户提供的信息中含有sql语句的关键字,但是没有参加编译,不起作用
   要想让用户不参与sql语句的编译,那么必须使用
    java.sql.preparedStatement

这个preparedStatement是一个接口
   这个接口继承了java。Sql。Statement,是属于预编译的数据库操作对象
PreparedStatement的原理是:
   预先对sql语句的框架进行编译,然后再给Sql语句传‘值’

    使用预编译PreparedStatement修改后的代码

    //设置驱动
     Class.forName("com.mysql.jdbc.driver");
     //获取连接
     Connection connection = DriverManager.getConnection(url, userName, password);
    //获取sql语句执行对象、这里的?值得是占位符,一个问好代表一个值,千万不要把占位符?放在单引号中,会被认定为一个普通的字符串。
    String sql = "insert into product (pid,pname,price,flag) values (?,?,?,?) ";
    preparedStatement prepareStatement = Connection.prepareStatement(sql);
    /*这里是使用的具体类型setInt和setString.或者直接使用setObject。
    给?传值,第一个?的下标是1,第二个?的下标是2。JDBC的所有下标都是从1开始。*/
    prepareStatement.setInt(1, 10);
    prepareStatement.setString(2,’杨逸之’);
    prepareStatement.setInt(3, 1000);
    prepareStatement(4,’0’);
     //执行sql语句
     Int row = PrepareStatement.executeUpdate();
     //释放资源
     prepareStatement.close();
     Connection.close();

解决sql注入的关键是什么,用户提供的信息中即使含有sql关键字的信息,但是这些关键字没有参与编译,不起作用。
preparedStatement和Statement的区别
1:Statement会存在SQL注入的问题,但是preparedStatement不会。
2:preparedStatement的执行效率要比Statemen高
  在第二点这里我们需要强调一下。在MYSQL中如果你输入一条语句,是会编译运行的,但是如果第二次输入的语句和第一条语句一摸一样,包括空格、大小写,都一模一样,那是不会编译的,会直接运行。而我们在Statement中的sql语句每次都是不一样的,比如你通过ID查询一条信息。Select * from product where ID=0; 你这次查询0,下次查询1,因为数据不一样,所以得编译一次运行一次。但是在preparedStatement中得sql语句通过ID查询:select*from product where id=?;每次编译执行都是这句话,而ID的值是我们在后期传进去的。所以preparedStatement是编译一次运行多次。
3:在传入值得时候preparedStatement是会检查数据类型,而Statement不会
如图所示,本来pname是String类型的,你使用Int类型,这样编译器会告诉我们出错了。
JDBC_入门到熟练_第21张图片
但是在Statement当中效果如下图
JDBC_入门到熟练_第22张图片
编译器是不会告诉我们出错的。
综上所述,prepareStatement使用比较多。那在什么时候使用Statement的呢?
  业务方面要求必须支持SQL注入的时候,这个时候是必须使用Statement。
举例
客户需区:需要将商品的价格进行升序或者见降序
这里我们首先使用perparedStatement来演示,而使用preparedStatement的sql语句是
String sql="select price from product order by price ?"这种通配符的写法,我们在传值的时候传的是字符串类型,而在mysql中会把我们拼接的字符串解释为
String sql="select price from product order by price ‘asc’ ";是会报出sql语句出错

效果如图显示

JDBC_入门到熟练_第23张图片

运行出错

JDBC_入门到熟练_第24张图片

接下来我们使用Statement操作一下

JDBC_入门到熟练_第25张图片

运行结果

JDBC_入门到熟练_第26张图片
在适当的情况下使用Statement和preparedStatement。这俩个接口各自有各自的用处。并行存在。

八:JDBC中的事务问题

JDBC 事务机制:


1:JDBC当中的事务是自动提交的。什么是自动提交,
  只要是执行任意一条DML语句,则自动提交一次,这是JDBC默认的事务行为。
  但是在实际的业务当中,通常都是N条DML语句共同联合才能完成的,必须保证他们这些DML语句在同一个事务中同时成功或者同时失败。

验证JDBC的事务是否是自动提交
这里我们可以使用转账来演示,账号111中有一万元,账号222有零元。

JDBC_入门到熟练_第27张图片
实现代码,俩条修改语句,将111的金额改为10000,将222的代码改成10000,模拟转账业务。并且在俩条修改语句中添加一个空指针异常

JDBC_入门到熟练_第28张图片
Dug进行调试。

JDBC_入门到熟练_第29张图片

JDBC_入门到熟练_第30张图片
而当我们的运行到空指针异常时候,我们会发现,代码停止运行,并且数据库中的代码已经更改,但是数据库的222并没有修改成10000

JDBC_入门到熟练_第31张图片
这个案例的演示正是符合了我们所期望的JDBC中的事务是自动提价机制。

JDBC事务的处理

这种自动提交的事务机制是我们所不建议的,我们必须保证它们这些DML语句在同一个事务中同时成功或者同时失败。这个时候我们就可以查看Connection这个接口中的setAutoCommit方法。

JDBC_入门到熟练_第32张图片
代码改进之代码中有异常

JDBC_入门到熟练_第33张图片
JDBC_入门到熟练_第34张图片
代码中有错误,但是数据库的数据没有发生变化,这就说明了解决了JDBC事物的自动提交机制。

代码改进之代码中没有异常

JDBC_入门到熟练_第35张图片
JDBC_入门到熟练_第36张图片
转账成功。案例演示成功。

JDBC实现模糊查询

纯属娱乐。
JDBC_入门到熟练_第37张图片

你可能感兴趣的:(java,编程语言,数据库,javascript,spring)