zoukankan      html  css  js  c++  java
  • 关于JDBC小总结

    JDBC

    JDBC:Java数据库连接。官方定义的一套操作所有关系型数据库的规则,即接口。各个数据库厂商去实现这套接口,提供数据库驱动jar包。我们可以使用这套接口(JDBC)编程,真正执行的代码是驱动jar包中的实现类。

    JDBC的入门

    • 搭建开发环境

    ​ 导入mysql-connector-java-5.1.7-bin.jar包到该项目的lib目录下,并Add As Library

    • 编写程序,在程序中加载驱动数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
    
    • 建立连接
    Connection  conn=DriverManager.getConnection ("jdbc:mysql://localhost:3306/jdbctest","root","123456");
    
    • 定义SQL并创建用于向数据库发送SQL的Statement对象
    String sql="select * from user";
    Statement stmt = conn.createStatement();
    
    • 执行SQL
    ResultSet resultSet = stmt.executeQuery(sql);
     while(resultSet.next()){
       int uid = resultSet.getInt("uid");
       String username = resultSet.getString("username");
       String password = resultSet.getString("password");
       String name = resultSet.getString("name");
       System.out.println(uid+" "+username+" "+password+" "+name);
                }
    
    • 断开与数据库的连接,并释放相关资源
    resultSet.close();
    stmt.close();
    conn.close();
    

    代码实现:

    JDBCDemo1.java

    import org.junit.Test;
    
    import java.sql.*;
    
    public class JDBCDemo1 {
        @Test
        public void demo1() {
            try {
                //加载驱动
                Class.forName("com.mysql.jdbc.Driver");
                //获得连接
                Connection conn =
                        DriverManager.getConnection("jdbc:mysql://localhost:3306/jdbctest", "root", "123456");
                //定义SQL并创建用于向数据库发送SQL的Statement对象
                String sql = "select * from user";
                Statement stmt = conn.createStatement();
                //执行SQL
                ResultSet resultSet = stmt.executeQuery(sql);
                //遍历查询到的结果
                while (resultSet.next()) {
                    int uid = resultSet.getInt("uid");
                    String username = resultSet.getString("username");
                    String password = resultSet.getString("password");
                    String name = resultSet.getString("name");
                    System.out.println(uid + " " + username + " " + password + " " + name);
                }
                //释放资源
                resultSet.close();
                stmt.close();
                conn.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    JDBC对象详解

    DriverManager:驱动管理类

    作用:

    注册驱动

    ​ 在com.mysql.jdbc.Driver类中存在静态代码块

    static {
    	try {
    		java.sql.DriverManager.registerDriver(new Driver());
    	} catch (SQLException E) {
    			throw new RuntimeException("Can't register driver!");
    		 }
    			}
    

    编写代码: Class.forName("com.mysql.jdbc.Driver");注册加载驱动

    获取数据库连接

    方法:static Connection getConnection(String url, String user, String password)

    • url:指定连接的路径 (“jdbc:mysql://ip地址(域名):端口号/数据库名称?编码方式”)
      • 例:(“jdbc:mysql://localhost:3306/jdbctest?characterEncoding=utf-8”)
    • user 用户名
    • password 密码

    Connection:连接对象

    作用:

    创建执行SQL语句的对象

    • Statement createStatement() 执行SQL语句,有SQL的注入漏洞存在
    • PreparedStatement preparedStatement(String sql) 预编译SQL语句,解决SQL的注入漏洞
    • CallableStatement preparedCall(String sql) 执行SQL中的存储过程

    进行事务管理

    • setAutoCommit(boolean autoCommit) 调用该方法设置参数为false,即开启事务

      • 在执行sql之前开启事务
    • commit() 提交事务

      • 当所有sql都执行完提交事务
    • rollback() 回滚事务

      • 在catch中回滚事务

    Statement:执行SQL

    作用:

    执行SQL语句

    • boolean execute(String sql) 返回一个布尔值
    • ResultSet executeQuery(String sql) 用于执行select语句,返回一个结果集
    • int executeUpdate(String sql) 用于执行insert、update、delete语句,返回一个int值,表示影响的行数

    执行批处理操作

    • addBatch 添加到批处理
    • executeBatch 执行批处理
    • clearBatch 清空批处理

    ResultSet:结果集

    作用:

    select语句查询结果的封装,next()方法指向下一行,getObject()获取数据。

    JDBC的工具类的抽取

    为了简化JDBC的开发,对一些重复代码进行提取,并且添加配置文件("xxx.properties"),便于之后的维护更新

    代码实现:

    jdbc.properties

    driverClass=com.mysql.jdbc.Driver
    url=jdbc:mysql:///jdbctest?characterEncoding=utf-8
    username=root
    password=123456
    

    JDBCUtils.java

    import java.io.IOException;
    import java.io.InputStream;
    import java.sql.*;
    import java.util.Properties;
    
    public class JDBCUtils {
        private static final String driverClass;
        private static final String url;
        private static final String username;
        private static final String passsword;
    
        //配置文件的读取,只需要读取一次即可拿到这些值。使用静态代码块
          static {
              //创建Properties集合类
            Properties properties = new Properties();
              //使用字节码文件获取当前类的类加载器以获取资源输入流
            InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            try {
                //加载配置文件
                properties.load(is);
            } catch (IOException e) {
                e.printStackTrace();
            }
              //获取配置文件中的数据
            driverClass = properties.getProperty("driverClass");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            passsword = properties.getProperty("password");
        }
        
    	//注册加载驱动
        public static void loadDriver() throws ClassNotFoundException {
            Class.forName(driverClass);
        }
    	
        //获取数据库连接
        public static Connection getConnection() throws Exception {
            loadDriver();
            Connection conn = DriverManager.getConnection(url, username, passsword);
            return conn;
    
        }
        
        //断开数据库连接,资源释放
        public static void release(Connection conn, Statement stmt) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
        }
    	  //断开数据库连接,资源释放
        public static void release(Connection conn, Statement stmt, ResultSet rs) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;
            }
        }
    }
    

    JDBC的SQL注入漏洞

    JDBCDemo2.java

    import Utils.JDBCUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.Statement;
    
    public class JDBCDemo2 {
        @Test
        /**
         * 测试SQL注入漏洞的方法
         */
        public void demo1() {
            boolean flag = JDBCDemo2.login("aaa' or '1=1", "dsacqwed1");
            if (flag == true) {
                System.out.println("登录成功!");
            } else {
                System.out.println("登录失败!");
            }
        }
    
        public static boolean login(String username, String password) {
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs = null;
            boolean flag = false;
            try {
                conn = JDBCUtils.getConnection();
                // 创建执行SQL语句的对象:
                stmt = conn.createStatement();
                // 编写SQL:
                String sql = "select * from user where username = '" + username + "' and password = '" + password + "'";
                // 执行SQL:
                rs = stmt.executeQuery(sql);
                // 判断结果集中是否有数据。
                if (rs.next()) {
                    flag = true;
                } else {
                    flag = false;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(conn, stmt, rs);
            }
            return flag;
        }
    }
    

    我们要执行的SQL语句为select * from user where username = '" + username + "' and password = '" + password + "' 当我们输入用户名username为aaa' or '1=1时,无论密码输入什么都能登录成功

    产生原因:当我们输入用户名与SQL语句进行字符串拼接,输入的内容也作为了SQL语句的一部分,生成的SQL语句为select * from user where username = ' aaa' or ' 1=1 ' and password = 'dsacqwed1'

    存在关键字or
    select * from user where username = ' aaa'  执行
    ' 1=1 ' and password = 'dsacqwed1'  假
    

    解决SQL注入漏洞问题

    方法:使用PreparedStatement接口

    Statement对象每执行一条SQL语句都会先将SQL语句发送给数据库,数据库先编译SQL,再执行。效率低,且可能造成数据库缓存区的溢出。

    PreparedStatement会先将SQL语句发送给数据库预编译,PreparedStatement会引用着预编译后的结果,可以多次传入不同的参数来给PreparedStatement对象并执行。

    • 减少SQL预编译次数,提高效率
    • 提升了程序的可读性
    • 没有了SQL注入漏洞的安全问题

    解决注入漏洞问题:

    • 编写SQL语句时,参数使用?占位 "select * from user where username = ? and password = ?";

    • 再利用PreparedStatement对象的setXxx(占位符位置(从1开始),实际值)方法设置参数

    /**
    	 * 避免SQL注入漏洞的方法
    	 */
    	public static boolean login(String username,String password){
    		Connection conn = null;
    		PreparedStatement pstmt = null;
    		ResultSet rs = null;
    		boolean flag = false;
    		try{
    			conn = JDBCUtils.getConnection();
    			String sql = "select * from user where username = ? and password = ?";
    			pstmt = conn.prepareStatement(sql);
    			pstmt.setString(1, username);
    			pstmt.setString(2, password);
    			rs = pstmt.executeQuery();
    			if(rs.next()){
    				flag = true;
    			}else{
    				flag = false;
    			}
    		}catch(Exception e){
    			e.printStackTrace();
    		}finally{
    			JDBCUtils.release(conn, pstmt, rs);
    		}
    		return flag;
    	}
    

    JDBC的CURD操作

    JDBCDemo3.java

    import Utils.JDBCUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    
    
    public class JDBCDemo3 {
        @Test
        public void select() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "select * from user where username=?";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "aaa");
                rs = pstmt.executeQuery();
                while (rs.next()) {
                    System.out.println(rs.getString("uid") + " " + rs.getString("username") + " " + rs.getString("password") + " " + rs.getString("name"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(conn, pstmt, rs);
            }
        }
    
        @Test
        public void delete() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "delete from user where username=?";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "xxx");
                int i = pstmt.executeUpdate();
                if (i > 0) {
                    System.out.println("删除成功!");
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(conn, pstmt);
            }
        }
    
        @Test
        public void update() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "update user set username=? where name=?";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "aaa");
                pstmt.setString(2, "Marry");
                int i = pstmt.executeUpdate();
                if (i > 0) {
                    System.out.println("更改成功!");
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(conn, pstmt);
            }
        }
    
        @Test
        public void insert() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            try {
                conn = JDBCUtils.getConnection();
                String sql = "insert into user values(null,?,?,?)";
                pstmt = conn.prepareStatement(sql);
                pstmt.setString(1, "xxx");
                pstmt.setString(2, "666");
                pstmt.setString(3, "小八");
                int i = pstmt.executeUpdate();
                if (i > 0) {
                    System.out.println("添加成功!");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                JDBCUtils.release(conn, pstmt);
            }
        }
    }
    
    

    数据库连接池技术

    数据库连接池:数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;相当于一个容器,存放数据库连接的容器。当系统初始化好后,容器被创建,容器中会申请一些连接对象,当用户来访问数据库时,从容器中获取连接对象,用户访问完之后,会将连接对象归还给容器。

    c3p0技术

    • 实现步骤:

      1. 导入相应jar包

        c3p0-0.9.5.2.jar

        mchange-commons-java-0.2.12.jar

        PS:不要忘记导入mysql-connector-java-5.1.7-bin 驱动包

      2. 定义配置文件

      ​ 文件名只能为: c3p0.properties或者 c3p0-config.xml

      3.创建数据库连接池对象

       ComboPooledDataSource dataSource = new ComboPooledDataSource();
      

    c3p0-config.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <c3p0-config>
    
      <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
    	<property name="jdbcUrl">jdbc:mysql:///jdbctest?characterEncoding=utf-8</property>
    	<property name="user">root</property>
    	<property name="password">123456</property>
    	<property name="initialPoolSize">5</property>
    	<property name="maxPoolSize">20</property>
      </default-config>
      
    </c3p0-config>
    

    定义c3p0工具类 JDBCUtils2.java

    package Utils;
    
    import com.mchange.v2.c3p0.ComboPooledDataSource;
    
    import java.sql.Connection;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    public class JDBCUtils2 {
        //创建数据库连接池对象
        private static final ComboPooledDataSource dataSource = new ComboPooledDataSource();
    	
        //获取连接对象
        public static Connection getConnection() throws SQLException {
            Connection conn = dataSource.getConnection();
            return conn;
        }
    
        public static void release(Connection conn, Statement stmt) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
        }
    
        public static void release(Connection conn, Statement stmt, ResultSet rs) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                stmt = null;
            }
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;
            }
        }
    }
    
    

    JDBCDemo4.java

    package JDBCDemo;
    
    import Utils.JDBCUtils2;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    
    public class JDBCDemo7 {
        @Test
        public void demo1() {
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            try {
                conn = JDBCUtils2.getConnection();
                String sql = "select * from user where uid=?";
                pstmt = conn.prepareStatement(sql);
                pstmt.setInt(1, 1);
                rs = pstmt.executeQuery();
                while (rs.next()) {
                    System.out.println(rs.getInt("uid") + " " + rs.getString("username"));
                }
    
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                JDBCUtils2.release(conn, pstmt, rs);
            }
        }
    }
    
    

    Druid技术

    • 实现步骤

      • 导入jar包 druid-1.0.9.jar

      • 定义配置文件xxx.properties

      • 加载配置文件

      • 获取数据库连接池对象

        DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);

      • 获取连接

      Connection conn=dataSource.getConnection();

    定义Druid工具类 JDBCUtils3.java (提供静态代码块加载配置文件,初始化连接池对象)

    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    import javax.sql.DataSource;
    import java.io.InputStream;
    import java.sql.Connection;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    
    public class JDBCUtils3 {
        private static DataSource dataSource;
    
        static {
            Properties properties = new Properties();
            InputStream is = JDBCUtils3.class.getClassLoader().getResourceAsStream("druid.properties");
            try {
                properties.load(is);
                dataSource = DruidDataSourceFactory.createDataSource(properties);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        public static Connection getConnection() throws SQLException {
            Connection conn = dataSource.getConnection();
            return conn;
        }
    
        public static void release(Connection conn, PreparedStatement pstmt) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                pstmt = null;
            }
        }
    
        public static void release(Connection conn, PreparedStatement pstmt, ResultSet rs) {
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                conn = null;
            }
            if (pstmt != null) {
                try {
                    pstmt.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                pstmt = null;
            }
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                rs = null;
            }
        }
    }
    
    

    配置文件druid.properties

    driverClassName=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/jdbctest?characterEncoding=utf-8
    username=root
    password=123456
    initialSize=5
    maxActive=10
    maxWait=3000
    
  • 相关阅读:
    SSH框架中使用Oracle数据库转换为SQLServer的相关配置和注意事项
    MYSQL性能优化系统整理
    PHP时间处理
    debian9 VirtualBox rc=-1908的错误
    https://snapcraft.io/store
    中文转拼音 pinyin4j的使用
    java对象转数组|数组转对象
    Deflater 压缩解压
    spring的RestTemplate连接池相关配置
    spring获取指定包下面的所有类
  • 原文地址:https://www.cnblogs.com/jascen/p/11354642.html
Copyright © 2011-2022 走看看