关于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
原文地址:https://www.cnblogs.com/jascen/p/11354642.html