zoukankan      html  css  js  c++  java
  • Java之JDBC

    JDBC的全称为:Java DataBase Connectivity(Java数据库连接)。
    是一种执行SQL语句的Java API,可以为多种关系型数据库提供统一的访问。

    1.JDBC的API

    (1)JDBC入门

    package com.imooc.jdbc.demo1;
    
    import com.mysql.cj.jdbc.Driver;
    import java.sql.*;
    
    public class JDBCDemo1 {
        public void demo1() throws SQLException {  //这里需要接受异常
            //1.加载驱动
            DriverManager.registerDriver(new Driver());
            //2.获取连接
            Connection conn = DriverManager.getConnection("jdbc:mysql://18.0.51.10:3306/jdbctest","root","123456");
            //3.创建执行SQL语句的对象
            String sql = "select * from user";
            Statement stmt = conn.createStatement();
            //4.执行sql语句
            ResultSet resultSet = stmt.executeQuery(sql);
            while (resultSet.next()){
                int uid = resultSet.getInt("uid");
                String name = resultSet.getString("name");
                String mobile = resultSet.getString("mobile");
                String addr = resultSet.getString("addr");
                System.out.println(uid+"  "+name+"  "+mobile+"  "+addr);
            }
            //5.释放资源
            resultSet.close();
            stmt.close();
            conn.close();
        }
    }

    如果数据库中文变成???,需要注意编码方式:
    "jdbc:mysql://18.0.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8"

    (2)JDBC的API——DriverManager的使用

    DriverManager属于驱动管理类。
    主要有两个作用:
    a.注册驱动
    DriverManager.registerDriver(new Driver());
    但是这种方式会导致驱动注册两次。
    因为在这个驱动中有一个静态代码块会注册驱动。所以更好的做法是加载静态代码块。
    实际中会使用如下方式注册:
    Class.forName("com.mysql.cj.jdbc.Driver");

    b.获取连接
    Connection conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest","root","123456");
    jdbc:协议
    mysql:子协议

    (3)JDBC的API——Connection的使用

    Connection主要用来连接对象。
    主要作用:
    a.创建执行SQL语句的对象
      createStatement():创建一个Statement对象来将SQL语句发送到数据库。(执行SQL语句)
      prepareStatement(String sql): 创建一个 PreparedStatement 对象来将参数化的 SQL 语句发送到数据库。(预编译SQL语句)
      prepareCall(String sql):创建一个CallableStatement对象来调用数据库存储过程。(执行SQL中的存储过程)

    b.进行事务的管理
      setAutoCommit():将此连接的自动提交模式设置为给定状态。
      commit():提交事务。
      rollback():回滚

    (4)JDBC的API——Statement的使用

    Statement主要用来执行SQL语句。
    a.执行SQL语句
      execute(String sql):执行SQL,执行select返回true,否则返回false
      executeQuery(String sql):执行SQL中的select语句,返回一个结果集
      executeUpdate(String sql):执行SQL中的insert/update/delete语句,返回一个int类型的值
    b.执行批处理操作
      addBatch(String sql):添加到批处理
      executeBatch():执行批处理
      clearBatch():清空批处理

    (5)JDBC的API——ResultSet的使用

    ResultSet,结果集,就是查询语句接口的封装。
    next():将光标从当前位置向前移动,也就是下一个值。
    针对不同的类型的数据可以使用getXXX()获取数据。通用获取数据的方法getObject()。

    (6)JDBC的资源释放

    jdbc程序运行完后,切记要释放程序在运行过程中,创建的那些与数据库进行交互的对象。
    这些对象通常是ResultSet,Statement和Connection对象。

    每个数据库都有最大连接数,如果没有释放,可能导致无法建立新的数据库连接。
    特别是Connection对象,它是非常稀有的资源,用完必须马上释放,
    如果COnnection不能及时、正确的关闭,极易导致系统宕机。
    Connection的使用原则是尽量晚创建,尽量早的释放。

    常规释放方式:

      resultSet.close();
      stmt.close();
      conn.close();

    但是这种释放方式并不彻底,如果前面代码异常,那么可能无法得到释放。可以使用try-finally关键字:

    package com.imooc.jdbc.demo1;
    
    import com.mysql.cj.jdbc.Driver;
    
    import java.sql.*;
    
    public class JDBCDemo1 {
        public void demo1() {  //这里需要接受异常
            Connection conn = null;
            Statement stmt = null;
            ResultSet resultSet = null;
            try {
                //1.加载驱动
    //          DriverManager.registerDriver(new Driver());
                Class.forName("com.mysql.cj.jdbc.Driver");
                //2.获取连接
                conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest", "root", "123456");
                //3.创建执行SQL语句的对象
                String sql = "select * from user";
                stmt = conn.createStatement();
                //4.执行sql语句
                resultSet = stmt.executeQuery(sql);
                while (resultSet.next()) {
                    int uid = resultSet.getInt("uid");
                    String name = resultSet.getString("name");
                    String mobile = resultSet.getString("mobile");
                    String addr = resultSet.getString("addr");
                    System.out.println(uid + "  " + name + "  " + mobile + "  " + addr);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {  //不论结果如何都会释放连接
                //5.释放资源
                if (resultSet != null){  //需要对情况进行判断,如果可能没有创建连接,当然也无法释放连接
                    try {
                        resultSet.close();
                    }catch (SQLException e){
                        e.printStackTrace();
                    }
                }
                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException e){
                        e.printStackTrace();
                    }
                    stmt = null;
                }
                if (conn != null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    conn = null;  //垃圾回收机制更早回收对象,提前回收
                }
            }
        }
    }

    2.JDBC的CRUD操作

    所谓的CRUD就是数据库的增删改查。

    (1)增删改

    package com.imooc.jdbc.demo1;
    
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class JDBCDemo2 {
        @Test
        public void demo2(){
            Connection conn = null;
            Statement stmt = null;
            try {
                Class.forName("com.mysql.cj.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8", "root", "123456");
                ////String sql = "insert into user value(null,'hao','18972068500','湖北安陆')";
                ////String sql = "update user set mobile='15302723629' where name='ming'";
                //
                String sql = "delete from user where name='xing'";
                stmt = conn.createStatement();
                int i = stmt.executeUpdate(sql);
                if (i > 0){
                    System.out.println("删除成功");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException e){
                        e.printStackTrace();
                    }
                    stmt = null;
                }
                if (conn != null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    conn = null;
                }
            }
        }
    }

    (2)查

    a.查询多条记录

    package com.imooc.jdbc.demo1;
    
    import org.junit.Test;
    
    import java.sql.*;
    
    public class JDBCDemo2 {
        @Test
        public void demo2(){
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;
            try {
                Class.forName("com.mysql.cj.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mysql://148.70.251.10:3306/jdbctest?useUnicode=yes&characterEncoding=utf8", "root", "123456");
                String sql = "select * from user";
                stmt = conn.createStatement();
                rs = stmt.executeQuery(sql);
                while (rs.next()){
                    int uid = rs.getInt("uid");
                    String name = rs.getString("name");
                    String mobile = rs.getString("mobile");
                    String addr = rs.getString("addr");
                    System.out.println(uid+"  "+name+"  "+mobile+"  "+addr);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (rs != null) {
                    try {
                        rs.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    rs = null;
                }
                if (stmt != null) {
                    try {
                        stmt.close();
                    } catch (SQLException e){
                        e.printStackTrace();
                    }
                    stmt = null;
                }
                if (conn != null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    conn = null;
                }
            }
        }
    }

    b.查询单条记录

    if (rs.next()){
        int uid = rs.getInt("uid");
        String name = rs.getString("name");
        String mobile = rs.getString("mobile");
        String addr = rs.getString("addr");
        System.out.println(uid+"  "+name+"  "+mobile+"  "+addr);
    }

    3.JDBC工具类的抽取

    为了简化JDBC的开发,可以将一些重复的代码进行提取。

    (1)抽象工具类

    package com.imooc.jdbc.utils;
    
    import java.sql.*;
    
    public class JDBCUtils {
        private static final String driverClass;
        private static final String ip;
        private static final String port;
        private static final String database;
        private static final String user;
        private static final String password;
        private static final String character;
        private static final String url;
    
        static {  //静态加载
            driverClass = "com.mysql.cj.jdbc.Driver";
            ip = "148.70.251.10";
            port = "3306";
            database = "jdbctest";
            user = "root";
            password = "123456";
            character = "useUnicode=yes&characterEncoding=utf8";
            url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?" + character;
        }
      //加载驱动器
        public static void loadDriver() throws ClassNotFoundException {
            Class.forName(driverClass);
        }
      //获取连接
        public static Connection getConnection() throws Exception{
            loadDriver();
            Connection conn = DriverManager.getConnection(url, user, password);
            return conn;
        }
      //释放连接
        public static void release(Statement stmt,Connection conn){
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                conn = null;
            }
        }
        public static void release(ResultSet rs,Statement stmt,Connection conn){
            if (rs != null) {
                try {
                    rs.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                rs = null;
            }
            release(stmt,conn);
        }
    }

    (2)简单使用

    package com.imooc.jdbc.test;
    
    import com.imooc.jdbc.utils.JDBCUtils;
    import org.omg.Messaging.SYNC_WITH_TRANSPORT;
    
    import java.sql.ResultSet;
    import java.sql.Statement;
    import java.sql.Connection;
    
    public class test {
        public static void main(String[] args) {
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;
            try{
                conn = JDBCUtils.getConnection();  //获取连接
                stmt = conn.createStatement();
                String sql = "select * from user";
                rs = stmt.executeQuery(sql);
                while (rs.next()){
                    int uid = rs.getInt("uid");
                    String name = rs.getString("name");
                    String mobile = rs.getString("mobile");
                    String addr = rs.getString("addr");
                    System.out.println(uid+"  "+name+"  "+mobile+"  "+addr);
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(rs,stmt,conn);  //一次释放
            }
        }
    }

    (3)配置文件优化

    如果我们想在一个配置文件中配置参数,可以将其剥离出来。
    创建jdbc.properties,然后使用类加载器加载配置:

    static {
        //加载属性文件并解析
        Properties props = new Properties();
        //通过类加载器获取
        InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
        try {
            props.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        driverClass = props.getProperty("driverClass");
        ip = props.getProperty("ip");
        port = props.getProperty("prot");
        database = props.getProperty("database");
        user = props.getProperty("user");
        password = props.getProperty("password");
        character = props.getProperty("character");
        url = "jdbc:mysql://" + ip + ":" + port + "/" + database + "?" + character;
    }

    4.SQL注入

    SQL注入的实质是修改了SQL语句。输入了SQL语句的关键字,从而修改了逻辑。
    select * from user where username = “xxx” and password = “xxx”;

    如果我们在输入username的时候进行注入,比如:
    username = “xxx ‘or ‘1=1”

    结果就变成这样了:
    select * from user where username = “xxx ‘or ‘1=1” and password = “xxx”;

    无形之间,就修改SQL语句的逻辑。

    js校验能够拦截一些初级注入,但是可以修改url来突破。
    上述问题还是在于,SQL语句采用的字符串拼接方式。
    在python中采用字符串拼接或者%替换都无法解决SQL注入的问题,一般解决方法有二:
      a.对传入的参数进行编码转义
      b.使用python的MySQLdb模块的execute方法。
        cursor.execute(query, params)
        第一个是参数化的sql语句,第二个是对应的实际的参数值。
        函数内部escape_string方法会对传入的参数值进行相应的处理(主要是转化为字符串)防止sql注入。

    在Java中解决SQL注入漏洞可以使用PreparedStatement。
    PreparedStatement是Statement的子接口,
    它的实例对象可以通过调用Connection.preparedStatement(sql)方法获得,
    相对于Statement对象而言:
      PreperedStatement可以避免SQL注入的问题。
      Statement会使数据库频繁编译SQL,可能造成数据库缓冲区溢出。
      PreparedStatement可对SQL进行预编译,从而提高数据库的执行效率。
      并且PreparedStatement对于sql中的参数,允许使用占位符的形式进行替换,简化SQL语句的编写。
    String sql = "select * from user";
    stmt = conn.createStatement(); //将其类型改为PreparedStatement即可
    //执行sql语句
    resultSet = stmt.executeQuery(sql);

    采用预编译的方式,会将SQL语句的结构固定,你再传入关键字也不会改变SQL语句的结构。
    String sql = “select * from user where username = ? and password = ?”
    pstmt = conn.prepareStatement(sql)
    pstmt.setString(1,username)
    pstmt.setString(2,password)
    pstmt.executeQuery()

  • 相关阅读:
    Myeclipse2013 SVN安装方法以及项目上传到svn服务器
    Gson把json串转换成java实体对象
    使用HttpClient向服务器发送restful post请求
    使用HttpURLConnection向服务器发送post和get请求
    http://www.ibm.com/developerworks/cn/opensource/os-cn-cas/
    CAS单点登录配置[5]:测试与总结
    CAS单点登录配置[4]:客户端配置
    CAS单点登录配置[3]:服务器端配置
    CAS单点登录配置[2]:证书生成
    【Oracle/Java】向三张表各插入百万数据,共用时18分3秒,平均每张表6分钟
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/12515154.html
Copyright © 2011-2022 走看看