zoukankan      html  css  js  c++  java
  • JDBC

    JDBC介绍JDBC

    (Java DataBase Connectivity)就是Java数据库连接,说白了就是用Java语言来操作数据库。原来我们操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句。

    JDBC中的核心类有

    ●DriverManager(驱动管理器)的作用有两个:

    1)注册驱动:这可以让JDBC知道要使用的是哪个驱动;
    2)获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。

    Connection对象表示连接

    与数据库的通讯都是通过这个对象展开的:它最为重要的一个方法就是用来获取Statement对象;

     ●Statement

    是用来向数据库发送SQL语句的,这样数据库就会执行发送过来的SQL语句:

    1)int executeUpdate(String sql):执行更新操作(insert、update、delete等);
    2)ResultSet executeQuery(String sql):执行查询操作,数据库在执行查询后会把查询结果,查询结果就是ResultSet;

    ResultSet

    对象表示查询结果集,只有在执行查询操作后才会有结果集的产生。结果集是一个二维的表格,有行有列。操作结果集要学习移动ResultSet内部的“行光标”,以及获取当前行上的每一列上的数据:

    boolean next():使“行光标”移动到下一行,并返回移动后的行是否存在;
    
    XXX getXXX(int col):获取当前行指定列上的值,参数就是列数,列数从1开始,而不是0。

    mysql数据库的驱动jar包

    mysql-connector-java-5.1.13-bin.jar;

    JDBC访问数据库的步骤

    加载驱动 【DriverManager】

    1. JDBC实际上就是定义了一系列的接口和类,集成在java.sql和javas.sql包中
    2. 需要使用不同厂商提供的DriverManager来管理jdbc驱动
    3. 不同的驱动是用来连接不同类型的数据库的

    操作
        1.添加jar包到项目中
        2.使用反射原理来获取驱动
            Class.forName("com.mysql.jdbc.Driver");//反射

    获取Connection链接

    1.使用刚刚加载好的驱动来获取管理驱动

    2. 获取的俩接种有三各参数需要注意

    1.url
        jdbc:mysql://localhost:3306/colin_mysql【咱们自己要连接的数据库的名字】
        jdbc:mysql:///colin_mysql
    2. user
        root
    3. password
        1234

    操作:

    //根据DrivateManager来调用获取链接的方法       
    String url = "jdbc:mysql://localhost:3306/colinemp";
         url是我们数据库的地址  最后使我们要连接的数据库名

    String user = "root";
    String password = "1234";

    Connection con = DriverManager.getConnection(url, user, password);

    创建Statement  ['steɪtm(ə)nt] 执行SQL语句

    1. 根据刚刚创建的连接,生成一个执行sql 语句的状态对象

    2. 准备好sql语句

    1.增 insert
    2. 删 delete
    3. 改 update
    使用的是executeUpdate  ['eksɪkjuːt] (sql语句) 来执行的sql语句的。
    返回的是一个int值【也就是这条sql语句执行后影响的数据条数
    (有数据条数被影响那就说明成功,没有被影响的话那就说明失败)】

    4.查询 select
    使用的是executeQuery   ['kwɪri](sql语句 ) 来执行的查询的sql语句。
    返回的是一个ResultSet结果集。我们需要遍历来获取数据库的信息   
    循环判断结果集还是否存在下一条数据【如果存在就将数据库中的数据使用结果集对象来获取通过列名
    (需要注意的是在关闭数据库释放资源的时候也要把结果集关闭掉)】

    操作:

    增删改
    //
    statement对象用来发送sql语句 他是根据连接对象来生成的一个状态 stt = con.createStatement();//打开状态通道 String sql ="insert into dept values(50,'后勤部','天津')"; 准备一个sal语句【增删改】 //调用方法来处理语句 int i = stt.executeUpdate(sql); 逻辑判断 if(i>0){ System.out.println("添加成功"); }else{ System.out.println("添加失败"); }

    查询

    //statement对象用来发送sql语句 他是根据连接对象来生成的一个状态
    stt = con.createStatement();
    String sql = "select * from dept";
    准备sql语句
    // 只有在进行查询的时候我们使用的是executeQuery()
    rs = stt.executeQuery(sql);
    //遍历结果集 获取信息
    while(rs.next()){//判断是否存在下一条数据
    int id = rs.getInt("deptno");//可以写列的名字 也可以写列的下标 1
    String name = rs.getString("deptname");//下标是 2
    System.out.println(id+" --- "+name);
    }



    4. 返回ResultSet 查询结果

    1.只有在查询的时候才会用到。
    2. 需要通过遍历结果集来获取数据库中相应的信息

    5. 关闭数据库,释放资源

    1. 在关闭之前首要要做的是否空判断。
    2. 在做查询时注意也需要将结果集进行关闭。

    操作:

    增删改
    //释放资源
    try {
        if(stt != null){
        stt.close();
        }
        if(con != null){
        con.close();
        }
    } catch (SQLException e) {
    e.printStackTrace();
    }
    
    
    查询
    //释放资源
    try {
        if(rs!= null){
        rs.close();
        }
        if(stt != null){
        stt.close();
        }
        if(con != null){
        con.close();
        }
        需要注意的是 rs结果集也是需要我们进行一个关闭操作的
    } catch (SQLException e) {
    e.printStackTrace();
    }

    sql注入

    关于sql语句中信息显示是否安全

    如果我们从控制台输入信息 直接放入了sql语句中,是一种非常不安全的行为

    当我们使用变量拼接sql语句的时候,会出现一种情况

     直接修改sql语句 【手动拼接sql语句 改变了sql语句原来的逻辑顺序【语意】】完成了一个不需要正确密码和用户名的正确登陆得到数据信息

    例如:

     select * from Student where s_id="1" or 1=1 and s_sex="男" or 1=1;
    这种就是直接篡改的语义,从而跳过数据库的验证,直接进行操作的方法

    预编译PreparedStatement

    它是Statement接口的子接口;

    强大之处:

    ●防SQL攻击;
    ●提高代码的可读性、可维护性;
    ●提高效率

    使用

    1.使用Connection的prepareStatement(String sql):即创建它时就让它与一条SQL模板绑定;
        select * from user where name = ? and pass = ?;
            sql语句模板【?就是占位符】
    2.调用PreparedStatement的setXXX()系列方法为问号设置值

    3.调用executeUpdate()或executeQuery()方法,但要注意,调用没有参数的方法; 建议大家在今后的开发中,无论什么情况,都去需要PreparedStatement,而不是使用Statement。

    代码示例

    //1.加载驱动
        Class.forName("com.mysql.jdbc.Driver");
    //2.获取连接
        String url ="jdbc:mysql://localhost:3306/colinemp";
        String user ="root";
        String password = "1234";
        con = DriverManager.getConnection(url, user, password);
    //3.开启通道发送sql语句
        String sql = "select * from user where name =? and pass = ? ";
            sql语句模板
                问号是占位符的意思
        pstt = con.prepareStatement(sql);
            得到预先状态通道
    //4.键盘录入信息
        Scanner input = new Scanner(System.in);
        System.out.println("请输入用户名:");
        String name = input.next();
        System.out.println("请输入用户密码:");
        String pass = input.next();
    //5.给问号占位符添加值
        pstt.setString(1, name);
        pstt.setString(2, pass);
    //执行
        rs =  pstt.executeQuery();
            执行查询操作
        while(rs.next()){
        int i = rs.getInt("id");
        String name1 = rs.getString("name");
        String pass1 = rs.getString("pass");
        System.out.println(i+"------"+name1+"------"+pass1);
        }
    //释放资源
        try {
            if(rs != null){
            rs.close();
            }
            if(pstt!= null){
            pstt.close();
            }
            if(con!= null){
            con.close();
            }
            } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            }

    使用的时候可已将重复的操作,封装成一个util方法

    Statement(状态通道)和PreparedStatement(预状态通道)的区别:

    创建方式不同

        Statement sta=con.createStatement();
        状态通道
    
    
       PreparedStatement pps=con.prepareStatemnt(sql);
        预状态通道
        对sql语句进行预编译并且支持占位符
        在执行sql语句方法中不需要再添加sql语句了。
        用于解决sql注入的问题
        常用

    执行sql的时机不同

       状态通道是在调用executeUpdate()和executeQuery()方法时传入sql
       预状态通道是在创建对象时就已经传入sql语句

    预状态通道支持占位符的使用,注:赋值时,下标从1开始

    项目分包

    entity

    实体包【存放的都是实体类】javabean

    utils

    工具包【存放的都是工具类】

    dao(数据持久化层)

    dao层【dao包】 【创将一个实体类就相应的要创建一个该实体类的dao类】

    单元测试

    在你的项目目录下创建一个dictory(根目录下面)

    之后点击新创建的目录右键 mark Dictory  选择test那项

     之后进入你要测试的类中,用idea中的快捷键 ctrl+shift+t

    选择JUnit4,在勾选你要测试的方法,之后点击run

     事物

    con.setAutoCommit(false);//取消自动提交事务

    con.commit();//提交事务

    con.rollback();//回滚事务,回到数据修改前的状态

    //专门为用户表服务的业务逻辑处理层   [该类中的方法发和dao中的方法是一样的]
    public class AccountService {
        private Connection con = null;
        AccountDao dao = new AccountDao();
    
        public boolean  account(double mon,String namein,String nameout){
            try {
                //获取链接对象
                con = JDBCUtil.getCon();
                con.setAutoCommit(false);//取消自动提交
                
                 boolean booout =  dao.accountJian(mon, nameout);
                boolean booin =  dao.accountJia(mon, namein);
                if(booout && booin){
                    return true;
                }
            
                 
                 con.commit();//手动提交事务
                
            } catch (Exception e) {
                try {
                    con.rollback();//事务回滚
                } catch (SQLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
                e.printStackTrace();
            }
            
            return false;
        }
    }

     事务的特性

    原子性

    原子性是指事务实施一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生

    一致性

    事务前后数据的完整性必须保持一致

    隔离性

    事物的隔离性是指多个用户并发访问数据库时,一个用户的事务不能被其他用户的事物所干扰,

    多个并发事务之间数据要互相隔离

    持久性

    持久性是指一个事物一旦被提交,他对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该

    对其有任何影响

    PreparedStatement的批处理

    当你有10条SQL语句要执行时,一次向服务器发送一条SQL语句,这么做效率上很差!处理的方案是使用批处理,即一次向服务器发送多条SQL语句,然后由服务器一次性处理。

    批处理只针对更新(增、删、改)语句,批处理没有查询什么事儿!

    批处理的三个方法

    void】     addBatch(String sql):添加一条语句到“批”中;
    int[]】     executeBatch():执行“批”中所有语句。返回值表示每条语句所影响的行数据;
    void】     clearBatch():清空“批”中的所有语句。

    代码

    con = JdbcUtils.getConnection();
        连接对象
    String sql = "insert into user values(?,?,?,?)";
        Sql语句模板
    pstt = con.prepareStatement(sql);
    for(int i = 0; i < 10; i++) {
        pstt.setString(1, "S_10" + i);
            设置每一列的值
        pstt.setString(2, "stu" + i);
        pstt.setInt(3, 20 + i);
        pstt.setString(4, i % 2 == 0 ? "male" : "female");
        pstt.addBatch();
            添加批次
        }

    数据库属性文件的使用

     存值方式:key-value

    实现方法

    在src文件夹下创建一个属性文件【jdbc.properties】

    MyDriver=com.mysql.jdbc.Driver
    Url=jdbc:mysql://localhost:3306/C1708A
    Name=root
    Pass=1234

    读取属性文件中的信息

    InputStream in=当前类名.class.getClassLoader().getResourceAsStream("jdbc.properties");
        将属性文件转换成一个流
    
    
    
    接着创建一个properties的对象,在通过这个对象来调用一个load的方法
    Properties pro=new Properties();
    pro.load(in);

    通过key值找value值

    driver=((String) pro.get("mysqldriver")).trim();
    url=((String) pro.get("url")).trim();
    username=((String) pro.get("username")).trim();
    password=((String) pro.get("password")).trim();

    在读取属性文件的过程中有一些内容只需要执行一次

    static{
        加载驱动
    //获取一个资源流                                                              得到本类的加载器。在通过加载器得到一个资源流(小括号中防止的就是想要得到的资源文件)
    InputStream inStream =  JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
    //创建一个属性文件的对象
    Properties pro = new Properties();
    try {
        //使用属性文件类对象调用方法来加载资源流
        pro.load(inStream);
     driver = pro.getProperty("MyDriver");
     url = (String) pro.get("Url");
     name = (String) pro.get("Name");
     pass = (String) pro.get("Pass");
     System.out.println(JDBCUtil.class.getClass());
    System.out.println(driver+"   "+url+"   "+name+"   "+pass);
    //加载驱动
    Class.forName(driver);
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
  • 相关阅读:
    2020春Contest
    HDU Count the string (KMP)
    P1757 通天之分组背包
    L1-050 倒数第N个字符串
    3月份目标
    Division UVa725
    数三角
    luogu P2051 [AHOI2009]中国象棋 dp 状态压缩+容斥
    Codeforces Round #654 (Div. 2) E
    Codeforces Round #654 (Div. 2) D
  • 原文地址:https://www.cnblogs.com/taozizainali/p/11046730.html
Copyright © 2011-2022 走看看