JDBC

头像
    阅读 7 分钟

    一、JDBC概述
    1、什么是JDBC、为什么要学习JDBC?

    JDBC(Java DataBase Connectivity)Java数据库连接
    其实就是利用Java语言/Java程序连接并访问数据库的一门技术
    
    虽然之前我们可以通过 cmd或者navicat 连接数据库,也可以对数据库、表、表记录等进行操作。
    但是,将来在开发中更多的是通过程序来连接数据库,如果是Java语言,通过Java程序连接数据库,就必须要学习JDBC这门技术。
    

    2、如何通过Java程序连接mysql数据库?(快速入门)
    创建一个测试类: com.tedu.JdbcTest01

    //1.注册数据库驱动
    //2.获取数据库连接
    //3.获取传输器
    //4.发送SQL语句到服务器执行,并返回结果
    //5.处理执行的结果
    //6.释放资源
    

    3、JDBC API总结

    1)Class.forName("com.mysql.cj.jdbc.Driver");
    将mysql驱动包中的"com.mysql.cj.jdbc.Driver"类加载到内存中,Driver类中的静态代码块就会执行,而在Driver类的静态代码块中有一行代码是用于注册驱动的,因此这行代码可以注册驱动!
    注册驱动: 将mysql驱动交给JDBC程序管理,以便于使用其中的功能
    在JDBC4.0以后的版本中,这一步可以省略,但还是建议加上
    
    2)DriverManager.getConnection(url,user,password) 
        url:指定要连接的是哪一个位置的哪一个库
            jdbc:mysql://localhost:3306/jt_db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        如果连接的数据库端口是3306,端口可以省略不写:
            jdbc:mysql://localhost/jt_db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        如果是连接本机上的数据库,主机名/IP地址可以省略不写:
            jdbc:mysql:///jt_db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        getConnection方法返回一个Connection对象,用于表示Java程序和数据库服务器之间的连接。
    3)Statement stat = conn.createStatement()
        conn.createStatement() -- 用于获取向数据库发送SQL语句的传输器对象
        stat.executeQuery(sql) -- 用于执行查询类型的SQL语句,返回的是一个ResultSet对象
        stat.executeUpdate(sql)  -- 用于执行新增、删除、修改类型的SQL语句,返回一个int值,表示影响的记录行数
    
    4)rs.next() -- 用于将指向数据行的箭头往下挪动一行,并且返回布尔值(true或false),
        true表示箭头往下挪动一行后,指向的行有数据;false表示箭头往下挪动一行后,指向的行没有数据;
    
    5)在ResultSet结果集对象上提供了获取数据的方法,常见的有:
        rs.getInt( colName );
        rs.getInt( colCount );
        rs.getString( colName );
        rs.getString( colCount );
        rs.getDobule( colName );
        rs.getDobule( colCount );
        ...
        rs.getObject( colName );
        rs.getObject( colCount );
        

    二、JDBC的增删改查

    1、新增:往account表中添加一条记录:名称为'lucy',金额是3500
    2、修改:修改account表中名称为'lucy'的金额,将金额改为2000
    3、删除:删除account表中名称为'lucy'的记录
    

    三、junit单元测试框架

    junit(单元测试框架): 可以不用添加main函数,也不用创建类的实例就可以执行一个方法
    能够用单元测试执行的方法必须满足如下条件:
        1)方法必须是公共的(public)
        2)方法必须是非静态的
        3)方法必须是无返回值的(void)
        4)方法必须是无参数的
    如果执行的方法不满足以上任何一个条件,就会报如下错误:
    java.lang.Exception: No tests found matching...
    
    junit(单元测试框架)常用的三个注解: @Test、@Before、@After
    @Test:使用了该注解的方法,每次选中方法名,右键-->Run as-->junit test都可以执行该方法
    @Before:使用了该注解的方法,每次会在@Test标记的方法之前执行。也就是说,每次在执行@Test标记的方法之前都会执行@Before标记的方法
    @After:使用了该注解的方法,每次会在@Test标记的方法之后执行。也就是说,每次在执行@Test标记的方法之后都会执行@After标记的方法
    

    四、PreparedStatement对象

    Statement 传输器
    PreparedStatement 传输器对象
    

    1、模拟用户登录案例

    PreparedStatement对象是Statement传输器对象的子对象
    PreparedStatement对象比Statement对象更加安全,在某些方面执行的效率上也会更高一些!
    下面以一个模拟登录的案例来讲解PreparedStatement对象
    ----------------------------------------------------------
    请登录: 
    请输入用户名: 
    tom'#'
    请输入密码: 
    
    select * from user where username='tom'#'' and password=''
    恭喜您登录成功!
    ----------------------------------------------------------
    请登录: 
    请输入用户名: 
    张飞' or '1=1
    请输入密码: 
    
    select * from user where username='张飞' or '1=1' and password=''
    select * from user where username='tom' or '1=1' and password=''
    恭喜您登录成功!
    ----------------------------------------------------------
    

    2、SQL注入攻击

    SQL注入攻击产生的原因:由于SQL语句中的参数是拼接而来的,其中的参数值(username和password的值)是用户提交过来的,如果用户在提交参数时,在参数中掺杂一些SQL关键字或特殊字符(or、#、-- 、/* */等)就可能会导致SQL语句的语义被篡改,从而执行一些意外的操作(比如用户名或密码错误也可以登录系统或网站)
    delete from user where id=1 or 1=1;
    

    3、如何解决SQL注入攻击问题

    1)可以对用户提交过来的参数进行校验(例如通过正则表达式对用户名和密码进行校验),如果用户名或密码中有类似于 or、#、-- 等符号,就不再登录,直接提示用户输入不合法,请重新登录!
    2)或者使用JDBC中提供的PreparedStatement对象,可以解决SQL注入攻击问题!
    
    PreparedStatement对象是如何解决SQL注入攻击的?
    1)PreparedStatement对象是先将SQL语句的骨架(不包含参数)发送给服务器编译并确定下来。
        String sql = "select * from user where username=? and password=?";
        PreparedStatement stat = conn.prepareStatement(sql);
    2)再将SQL语句中的参数值传递给服务器
        //设置SQL语句中的参数值
        stat.setString( 1, user );
        stat.setString( 2, psw );
        //执行SQL语句,返回执行结果
        ResultSet rs = stat.executeQuery();
    由于前面SQL语句的骨架已经被确定了,因此SQL参数中即使再包含SQL关键字或者特殊符号,也不会影响SQL语句的骨架或语义,只会被当前普通的文本来处理,因此可以防止SQL注入!
    

    五、数据库连接池
    1、什么是连接池?

    池:常量池、线程池、连接池等中的池都是一个容器。是指内存中的一片空间
    连接池:就是将一批连接资源存入到一个容器中。目的是为了实现连接的复用,减少连接创建和关闭的次数,以此来提高程序执行的效率!
    

    2、为什么要使用连接池?

    传统方式中,每次需要连接都是直接创建一个连接(对象/资源),再基于这个创建的连接去访问数据库,最后用完连接还要关闭!
    而每次【创建连接】和【关闭连接】相比使用连接是要消耗大量的时间和资源,导致程序的执行效率非常低下!
    
    为了提高程序执行的效率,我们可以在程序一启动时,就创建一批连接放在一个连接池中,供整个程序共享。
    当用户需要连接时,不用再去创建连接,而是直接从连接池中获取一个连接进行使用,在用完连接后,也不需要关闭,而是直接将连接还回到连接池中。这样一来,用来用去都是连接池中的这一批连接,必然可以实现连接的复用,减少连接创建和关闭的次数。提高程序执行的效率!
    

    3、如何使用c3p0连接池?

    dbcp/c3p0/druid/hikari
    由于所有的连接池技术都实现了SUN公司所提供的DataSource接口
    所以连接池也叫作"数据源"
    
        
    第01步:在程序中创建一个c3p0连接池对象(存放连接的容器)
        ComboPooledDataSource pool = new ComboPooledDataSource();
        
    第02步:设置连接数据库的基本信息(四个参数)
    方式一:将连接数据库的参数通过setXxx方法直接通过java代码写死在程序中
        pool.setDriverClass("com.mysql.cj.jdbc.Driver");
        pool.setJdbcUrl("jdbc:mysql:///jt_db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai");
        pool.setUser("root");
        pool.setPassword("root");
        这种方式不推荐使用,因为这种方式将连接参数写死在程序中了,将来一旦参数发生变化,就需要我们去改程序,改完之后需要对项目重新编译、打包、部署、运行等,会提高维护成本!
        
    方式二:将连接数据库的参数提取到 c3p0.properties(文件名是固定的) 文件中
        并且需要将这个文件放在源码根目录(src根目录)下,文件内容如下:
        -----------------------------------------
        c3p0.driverClass=com.mysql.cj.jdbc.Driver
        c3p0.jdbcUrl=jdbc:mysql:///jt_db?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
        c3p0.user=root
        c3p0.password=root
        -----------------------------------------
        再次强调:这个文件的位置和名字都是固定的,因为底层c3p0会到指定的位置找指定名称的文件,如果没有按照要求去存放文件或者没有按照要求去指定文件名称,都会导致c3p0找不到这个文件,也就无法读取其中的配置信息,必然会导致连不上数据库!
    方式三:将连接数据库的参数提取到 c3p0-config.xml(文件名也是固定的) 文件中
        并且需要将这个文件放在源码根目录(src根目录)下,文件内容如下:
        -----------------------------------------
        <?xml version="1.0" encoding="UTF-8"?>
        <c3p0-config>
            <default-config>
                <property name="driverClass">
                    com.mysql.cj.jdbc.Driver
                </property>
                <property name="jdbcUrl">
                    jdbc:mysql:///jt_db?characterEncoding=utf-8&amp;serverTimezone=Asia/Shanghai
                </property>
                <property name="user">root</property>
                <property name="password">root</property>
            </default-config>
        </c3p0-config>
        -----------------------------------------
        再次强调:这个文件的位置和名字都是固定的,因为c3p0底层会到指定的位置找指定名称的文件,如果没有按照要求去存放文件或者没有按照要求去指定文件名称,都会导致c3p0找不到这个文件,也就无法读取其中的配置信息,必然会导致连不上数据库!
    第04步:从连接池中获取一个连接对象进行使用
        Connection conn = pool.getConnection();
        
    第05步:将用完的连接对象还回到连接池中
        conn.close();
    如果在程序中没有使用任何连接池,需要连接就通过 DriverManager.getConnection获取(创建)一个连接,用完之后,调用conn.close()就是将连接资源关闭。
    如果使用了连接池,通过 连接池对象调用 getConnection方法获取一个连接对象,此时获取的连接对象已经被改造了。用完之后,再调用conn.close()方法是将连接还回到连接池中。也就是说,从连接池中获取的连接对象上的close方法被改造成了还连接到连接池!
    

    4、补充内容:xml文件和properties文件的区别

    相同点:这两种文件在企业开发中都可以作为配置文件使用,而且用的特别多
    不同点:1)xml文件缺点:配置信息多,编写起来比较麻烦,如果需要通过java程序读取,代码也比较麻烦。
    2)xml文件的优点:可以保存有结构的数据(例如在xml文件中保存中国所有的省份以及省份包含的市区)
    3)properties文件缺点:配置信息结构是key/value,无法保存有结构的数据
    4)properties文件优点:配置信息简洁,如果需要通过java程序读取,读取起来也比较方便。
    

    ==================================================
    一、什么是事务?

    事务:简单的说,事务是将一堆的SQL语句绑定在一起执行,结果是要么全都执行成功,要么全都执行失败。而且是都成功了才算成功,但凡有一条执行失败,就按全失败来处理!
    
    举例: 张三(1000)给李四(1000)转账100元
    -- 开启事务(start transaction)
    -- 给张三的账户金额减去100元
    update 账户表 set money=money-100 where name='张三'; -- 1000
    -- 给李四的账户金额加上100元
    update 账户表 set money=money+100 where name='李四'; -- 1000
    -- 提交事务(commit)/ 回滚事务(rollback)
    
    举例: 网上购物
    -- 开启事务
    -- 往订单表中插入一条订单信息(用户、订单号、商品信息、商品数据量、单价、总金额等)
    insert into 订单表 value(....);
    -- 减去商品库存表中的库存数量
    update 商品库存表 set count=count-2 where...
    -- 提交事务/回滚事务
    

    二、事务的四大特性(重要)

    1、原子性:表示事务中的所有操作(SQL)是一个整体,不能被分割,要么全都执行成功,要么全都执行失败!
    
    2、一致性:在事务前后的业务数据之和是保持一致的。
        在转账操作之前,张三账户金额(1000)和李四账户金额(1000)之和为2000元
        在转账操作之后,无论事务提交了还是回滚了,张三和李四的账户金额之和还是2000元。
    
    3、隔离性:是指所有的事务都是隔离开来的,在一个事务中看不到另外一个事务正在进行中的状态!
        事务1: 查询A(1000)和B(1000)的账户总金额 
        
        事务2: -- 开启事务
        A账户减去100元 -- A:900
        B账户加上100元 -- B:1100
        -- 提交事务/回滚事务
        
    4、持久性:在事务提交后,对数据的更新操作才会持久的保存到数据库中
        -- 开启事务
        A账户(1000元)减去100元 -- A:900
        B账户(1000元)加上100元 -- B:1100
        -- 提交事务/回滚事务
    

    三、MySQL中的事务

    在mysql中默认一条SQL语句就是一个事务。
    如果希望将多条SQL放在一个事务中执行,可以手动开启事务,并手动结束事务
    开启事务: start transaction / begin;
    结束事务:提交(commit) 和 回滚(rollback)
    例子:使用转账演示mysql中如何开启事务以及如何结束事务
        -- 开启事务
        start transaction;
        -- A账户减去100元
        update acc set money=money-100 where name='A';
        -- B账户加上100元
        update acc set money=money+100 where name='B';
        select * from acc;
        -- 回滚事务 | 提交事务
        rollback; | commit;
        select * from acc;

    16 声望8 粉丝

    « 上一篇
    MySQL
    下一篇 »
    MAVEN