JDBC——Java与数据库结缘下的初代产物


技术的迭代紧跟着时代

基石是一切开始的开始


——Lungcen

目录

JDBC的简介

API的详解

DriveManger(驱动管理类)

Connection(数据库连接对象)

Statement(执行SQL语句方法)

ResultSet(结果集对象) 

PreparedStatement (预编译执行)

数据库连接池



JDBC的简介


JDBC(Java DataBase Connectivity)是Java语言操作的数据库的一套API,也是一个接口

         利用Java代码去操作数据库时,操作不同的关系型数据库,需要不同的对应数据库的代码,所以说,没有JDBC之前,同一套Java代码,不能操作不同的数据库。后来利用一套标准的接口(JDBC)来实现上述的不匹配问题。

        怎么实现的呢?每个数据库的厂商都来实现JDBC接口(又称为驱动)。若使用mysql数据库那就导入mysql驱动,同理,若使用Oracle数据库那就导入Oracle驱动。改变数据库的时候就直接更换驱动就行,就不用更换java的代码。

JDBC的步骤:

第一步:导入对应数据库的驱动jar包

第二步:注册驱动         说明使用的驱动版本

第三步:获取数据库的连接                

第四步:编写执行的SQL语句

第五步:获取执行SQL语句的对象

第六步:执行SQl语句

第七步:处理执行SQL语句所返回的结果

第八步:释放前面创建的资源

 需要注意的是:

1、高版本的驱动必须设置useSSL和时区属性,低版本的不需要,可以写成(jdbc:mysql://localhost:3306/first)

2、执行SQL语句后返回的结果有两种,一种是返回受影响的行数(删除、修改、分页……),一种是返回所查询到结果(查询)

3、最后记得要释放资源

//注册驱动
Class.forName("com.mysql.jdbc.Driver");
//获取连接对象
String url = "jdbc:mysql://localhost:3306/first?useSSL=false
&serverTimezone=Asia/Shanghai";
String username = "root";
String password = "12345";
Connection conn = DriverManager.getConnection(url, username, password);
//编写SQL语句
String sql = "uptate student set age = 18 where id = 1212";
//获取执行sql语句对象
Statement stat = conn.createStatement();
//执行sql语句
int i = stat.executeUpdate(sql);
//处理结果
System.out.println(i);
//释放创建的资源
stat.close();
conn.close();


API的详解


DriveManger(驱动管理类)

        可以 注册驱动 和 获取数据库的连接

既然DriveManger可以注册驱动,那上面为啥使用这个呢? Class.forName("com.mysql.jdbc.Driver")。

这是因为在Driver中有一个静态代码块就在执行DriverManger.registerDriver(new Driver())

所以使用 Class.forName("com.mysql.jdbc.Driver")来注册驱动。

不过在5之后的版本中可以不在代码中写这句,在对应的jar包中有着对应的代码

获取数据库的连接,需要  连接的路径、数据库用户名、数据库密码 

 

对于连接路径url = "jdbc:mysql://127.0.0.1:3306/first" 。要是是本地服务器,可以将ip地址替换为localhost。如下url = "jdbc:mysql://localhost:3306/first"

如果连接的是本机的mysql服务器,同时默认的端口是3306,可简写为url = "jdbc:mysql:///first",中间的ip地址和端口号省略

以目前这样的连接方式并不安全,所以idea会出现一个警告提示来想要你使用SSL的连接方式 。配置参数 useSSL = false 参数来禁用安全连接提示,解决这个警告提示

url = "jdbc:mysql://localhost:3306/first?useSSL=false"

Connection(数据库连接对象)

        可以 获取执行SQL的对象 和 管理事务

获取执行SQl的对象有三种方式

1、普通执行SQl对象: Statement createStatement()

2、预编译SQL执行对象: PreparedStatement prepareStatement(sql)

3、执行存储过程的SQL执行对象: CallableStatement prepareCall(sql)

事务管理的作用:举个例子,假如 A 和 B 交易,A 扫微信给了 B 100块,那么 A 的微信余额就减少100块, B 的微信余额就加上100 。如果事务不出错,那么一切正常,如果在 B 的微信余额加上100块时出现错误,但是前一步 A 的微信余额已经减少100块了,这样运行结束后就会导致总金额出错,莫名其妙的少了100块。

进行事务管理后,只要运行时出错,那么就直接回滚事务,回到执行SQL语句之前。

 MYSQL的事务管理有三个(MYSQL默认是自动提交事务的)

开启事务、BEGIN;

提交事务、COMMIT;

回滚事务、ROLLBACK;

我们使用JDBC就是利用Java来操作数据库,所以JDBC的Connection接口中同样定义了三个一样功能的事务管理,只不过在JDBC中别写成了方法

开启事务、setAutoCommit(boolean autoCommit)

提交事务、commit();

回滚事务、rollback();

执行SQL语句之前 开启事务 ,在执行成功处理结果后 提交事务

那如何回滚事务?那就要理解为啥要回滚事务,肯定是因为SQL语句执行的时候出现问题,那么不就可以使用java自带的异常管理机制(try—catch)在catch中回滚事务

try {
        //开启事务
            conn.setAutoCommit(false);
            int i1 = stat.executeUpdate(sql1);
            int i2 = stat.executeUpdate(sql2);
            System.out.println(i1);
            System.out.println(i2);
        //提交事务
            conn.commit();
        } catch (Exception e) {
        //回滚事务
            conn.rollback();
            e.printStackTrace();
        }

Statement(执行SQL语句方法)

        可以 执行SQL语句

执行SQL 后会获得两种结果:

一种是:executeUptate(sql),执行DML、DDL语句,

        DQL语句(数据的增删改操作)的返回值是DML语句影响的行数

        DDL语句(表和库的增删改查操作)的返回值 有可能是0,但是语句是执行的(例如:删除一个数据库,语句成功执行对于的数据库被删除,但是返回的值是 0 )

一种是:executeQuery(sql),执行DQL语句,

        DQL语句(数据的查操作)的返回值是ResultSet结果集对象(这个对象封装了DQL语句的结果)

ResultSet(结果集对象) 

封装DQL查询语句的结果,那如何从ResultSet中获取查询结果呢?

boolean next():

1、可以将光标从当前位置向前移动一位。

2、判断当前行是否有数据

xxx getXxx(参数):

1、获取数据

2、xxx:数据类型(字符串、整形……)

3、参数分两种:一种是列的编号,从1开始;一种是列的名称

        //注册驱动
        Class.forName("com.mysql.jdbc.Driver");
        //获取连接对象
        String url = "jdbc:mysql://localhost:3306/first?useSSL=false
&serverTimezone=Asia/Shanghai";
        String username = "root";
        String password = "12345";
        Connection conn = DriverManager.getConnection(url, username, password);
        //编写sql语句,平且执行
        String sql = "select * from account";
        Statement stat = conn.createStatement();
        ResultSet rs = stat.executeQuery(sql);
        //遍历结果集,输出内容
        while (rs.next()){
            int id = rs.getInt(1);//也可以是rs。getInt("id"),是你的数据库中表的列名
            String name = rs.getString(2);
            System.out.println(id);
            System.out.println(name);
        }
        //释放资源
        rs.close();
        stat.close();
        conn.close();

        这种方式所获取的内容是散落的,不便于展示在页面上,所以利用Java对象存放数据,再将这些Java对象放到集合中。

        创建一个用来存放数据的类,(Alt + Ins)组合键 可以快速添加set、 get、 toString、 构造方法(无参与有参)

        需要注意的是,按照规范和便捷, 用来存放数据的类的对应属性名字应该和数据库的列名一致,这样更加容易识别编写的代码

public class Account{
        private int id;
        private String name;

        public Account(int id, String name) {
            this.id = id;
            this.name = name;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Account{" +
                    "id=" + id +
                    ", name='" + name + '\'' +
                    '}';
        }
    }

        修改遍历结果集的代码,将获得数据存放到对象中,再将对象放到集合中,这样所获得的数据就不要是散乱的,而是整整齐齐的放到集合中

        //创建集合用来放对象
        List list = new ArrayList<>();
        //遍历结果集,输出内容
        while (rs.next()){
            //实例对象
            Account account = new Account();
            //获取数据
            int id = rs.getInt(1);
            String name = rs.getString(2);
            //将数据存放到对象中
            account.setId(id);
            account.setName(name);
            //将对象添加到集合中
            list.add(account);
        }

PreparedStatement (预编译执行)

        可以 预编译执行SQL语句并执行,用来防止SQL注入问题的手段

        SQL注入:通过操作输入来修改事先定义好的SQL语句,以此达到执行代码对服务器进行攻击的一种方法。

        简单来说就是:在以前,拿到从前端界面获取的用户名和密码,是直接拼接字符串来组成SQL语句去执行的。例如(String sql = "select * from user where username =' " + name + " ' and password = ' " + pwd + " ' "),其中name 和 pwd 是所获取的用户名和密码。所以SQL注入就是,name随便填(假如填 iwruqeoi),pwd填 ' or '1' = '1 

        这样的话,所执行的 sql 就会变成:select * from user where username ='iwruqeoi' and password = ' ' or '1' = '1',这个SQL语句的最后一段是or ’1‘ = ’1‘,是恒为真,故返回值为真。

        所以为了防止SQL注入,现在基本上都是使用预编译来执行SQL语句,它会先执行SQL语句,自动空出?位置的值,后面再把?对应的值给赋值进去。

        这样就把用户名和密码当成一个值,会对一些特殊符号进行转义,而不是像拼接字符串那样,会把密码的字段当成SQL语句的一部分来执行。

        Class.forName("com.mysql.jdbc.Driver");
        String url = "jdbc:mysql://localhost:3306/first?useSSL=false
&serverTimezone=Asia/Shanghai";
        String password = "12345";
        Connection conn = DriverManager.getConnection(url, username, password);
        //假设获取的用户名和密码
        String name = "123123";
        String pwd = "123123";
        //编写sql语句,平且执行
        String sql = "select * from account where username = ? and password = ?";
        //获取pstmt对象
        PreparedStatement pstmt = conn.prepareStatement(sql);

        这里处理来处理SQL语句中的?号

        //设置?的值
        pstmt.setString(1, name);
        pstmt.setString(2, pwd);
        //返回的结果集
        ResultSet rs = pstmt.executeQuery();
        //遍历结果集,输出内容
        while (rs.next()){
            int id = rs.getInt(1);
            String names = rs.getString(2);
        }
        rs.close();
        pstmt.close();
        conn.close();
    }

        PreparedStatement (预编译执行),可以 预编译执行SQL语句, 那么上面的语句是否是通过预编译的方式来执行的呢?

        我的答案是 “并没有”,因为一般情况下预编译是默认关闭的,所以需要再url后面再加上useServerPrepStmts = true。那问题来了,既然没有开启预编译那为啥上面的也可以防止SQl注入,那就需要了解预编译是啥了!

        预编译:我们编写的java代码传入到mysql中去,需要 先检查SQL语法、再编译SQL,最后再执行SQL 。一般情况下都是传入一次就完整的执行一次,而预编译是将SQL语句运行到编译SQL这一步,只要将?的值重新赋值后就执行SQL,这就是预编译。

        所以说预编译只是一个过程,解决SQL注入的是转义一些特殊字符!!


数据库连接池


       是一个容器,负责分配、管理数据库连接

        在正常情况下,每一次与数据库进行连接就需要创建一个“连接”,当结束后就释放掉“连接”,无法做到资源复用,而且在创建和释放“连接”的过程是耗时间耗资源的。

        于是乎就弄了一个容器,可以用来放“连接”,并且事先提前创建一些“连接“放到容器中,等到使用时就直接从容器中拿出来,不用的时候就放进去,而不是需要使用时创建、不用的时候就释放掉。

        假如容器中只有三个”连接“,正好来了三个人拿走了容器中的”连接“,此时来了第四个人,那咋办呢?

        数据库连接池就会对那三个人进行判断是否在用”连接“,不用的话就直接拿回”连接“给第四个人(所以有些界面,你长时间没响应就会自动退掉)

        那么要是都在使用呢?那就让第四个人等待还是申请新的”连接“呢?对于这个问题需要看你设置的连接池最大值,如果没有达到最大值,就新建一个连接,如果已经达到最大值,就等待一定的时间。

        数据库连接池的实现:官方标准接口——(DataSource【获取连接的功能】)利用getConnection()方法实现

常见的数据库连接池有:DBCP、C3P0、Druid

Druid:Druid连接池是阿里巴巴开源的数据库连接池、功能强大、性能优秀

使用步骤;

        1、导入jar包(druid-1.1.12.jar)

        2、定义配置文件(里面是一些数据库的信息和数据池的配置)

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/db1
username=Lungcen  //数据库用户名
password=123456  //数据库密码
initialSize=5  //初始化连接数量
maxActive=10  //最大连接数
maxWait=3000  //最大等待时间

        3、加载配置文件

        4、获取连接池对象

        5、获取连接

 public static void main(String[] args) throws Exception {
        //获取配置文件的方法
        Properties prop = new Properties();
        //加载配置文件
        prop.load(new FileInputStream("src/druid.properties"));
        //获取连接池对象
        DataSource dataSource = DruidDataSourceFactory.createDataSource(prop);
        //获取连接
        Connection conn = dataSource.getConnection();
        //输出连接
        System.out.println(conn);
    }


技术的迭代紧跟着时代

基石是一切开始的开始


——Lungcen

你可能感兴趣的:(JavaWeb学习内容笔记,java,web,idea)