Mybatis源码学习(一)复习JDBC

文章目录

  • 一、JDBC概念
  • 二、 JDBC架构
  • 三、JDBC连接步骤
  • 四、完整实例
    • 添加数据
    • 删除数据
    • 修改数据
    • 查找数据
  • 五、JDBCUtil
    • 创建一个 db.properties文件
    • JDBCUtil
  • 六、JDBC的SQL注入问题
  • 七、SQL注入问题解决方案

一、JDBC概念

JDBC(Java Database Connectivity)Java数据库连接,是Java语言中规范客户端程序来访问数据库的应用程序接口,提供了更新数据库的方法。

二、 JDBC架构

JDBC API既支持数据库访问的双层架构(C/S),同时也支持三层架构(B/S)

  • 双层架构(C/S):双层架构中,应用程序直接访问数据源。
  • 三层架构(B/S):三层架构中,引入了中间层服务,应用程序通过中间层来访问数据源,可以使用户更好的进行访问控制。

三、JDBC连接步骤

1. 加载驱动程序

加载MySQL驱动

Class.forName("com.mysql.jdbc.Driver");

加载Oracle驱动

Class.forName("oracle.jdbc.driver.OracleDriver")

2. 获取数据库连接

建立数据库连接:(三个参数分别为url, user, password)

MySQL数据库连接

 Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/user", "root", "root");

Oracle数据库连接

 Connection connection =  DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "root", "root");

3. 创建Statement\PreparedStatement对象

PreparedStatement preparedStatement = connection.prepareStatement(sql);

4.Statement\PreparedStatement传参

preparedStatement.setObject(1, 1);
  • 第一个参数为parameterIndex占位符从1开始逐步递增
  • 第二个参数为对象的值

5.执行

JDBC中有三种执行方式

第一种:executeQuery();适用于查询语句执行,返回ResultSet对象

文档解释为:在这个PreparedStatement对象中执行SQL查询,并返回查询生成的ResultSet对象。

ResultSet resultSet = preparedStatement.executeQuery();

第二种:execute();适用于所有SQL语句,返回boolean 类型

文档解释:在这个PreparedStatement对象中执行SQL语句,该对象可以是任何类型的SQL语句。一些预处理语句返回多个结果;execute方法处理这些复杂的语句以及executeQuery和executeUpdate方法处理的简单语句。

boolean execute = preparedStatement.execute();

第三种:executeUpdate();适用于增删改SQL语句,返回int类型

文档解释:执行PreparedStatement对象中的SQL语句,该对象必须是SQL数据操作语言(DML)语句,如插入、更新或删除;或者不返回任何内容的SQL语句,例如DDL语句。

int update = preparedStatement.executeUpdate();

6.关闭连接

 resultSet.close();
 preparedStatement.close();
 connection.close();

四、完整实例

添加数据

/**
 * @author yly
 * @ClassName Insert 
 * @Date 2020/2/28 14:40
 * @Version 1.0
 **/
public class Insert {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
            connection.setAutoCommit(false);//JDBC中默认是true,自动提交事务
            preparedStatement = connection.prepareStatement("insert into user (name,age) values(?,?)");
            preparedStatement.setString(1, "yly");
            preparedStatement.setString(2, "23");
            preparedStatement.execute();
            connection.commit();
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

JDBC中需要注意的是:

  • JDBC中默认是自动提交事务
  • 如果需要手动提交时需要设置connection.setAutoCommit(false);否则会抛出java.sql.SQLException: Can’t call commit when autocommit=true异常

删除数据

/**
 * @author yly
 * @ClassName Delete
 * @Date 2020/2/28 14:48
 * @Version 1.0
 **/
public class Delete {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
            connection.setAutoCommit(false);//JDBC中默认是true,自动提交事务
            preparedStatement = connection.prepareStatement("delete FROM  user where id = ?");
            preparedStatement.setInt(1, 3);
            preparedStatement.execute();
            connection.commit();
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

修改数据


/**
 * @author yly
 * @ClassName Update
 * @Date 2020/2/28 14:54
 * @Version 1.0
 **/
public class Update {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
            connection.setAutoCommit(false);//JDBC中默认是true,自动提交事务
            preparedStatement = connection.prepareStatement("update user set  name = ? where id = ?");
            preparedStatement.setString(1, "aa");
            preparedStatement.setInt(2, 1);
            preparedStatement.executeUpdate();
            connection.commit();
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

查找数据

/**
 * @author yly
 * @ClassName Select
 * @Date 2020/2/28 15:01
 * @Version 1.0
 **/
public class Select {
    public static void main(String[] args) {
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "zgwbgh959");
            preparedStatement = connection.prepareStatement("select * from user where id =?");
            preparedStatement.setObject(1, 1);
            resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                System.out.println(resultSet.getString(1) + "---" + resultSet.getString(2) + "--" + resultSet.getInt(3));
            }
        }catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if(resultSet!=null){
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (preparedStatement != null) {
                    preparedStatement.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

查找数据注意事项:

  • 查找数据需要用executeQuery()方法执行,为了得到ResultSet对象
  • 查找数据不需要提交事务,所以不需要设置connection.setAutoCommit(false);和connection.commit();

五、JDBCUtil

由于JDBC连接有大量重复代码,所以可以写一个工具类JDBCUtil

创建一个 db.properties文件

mysqlDriver=com.mysql.jdbc.Driver
mysqlURL=jdbc:mysql://localhost:3306/test
mysqlUser=root
mysqlPwd=root
oracleDriver=oracle.jdbc.driver.OracleDriver
oracleURL=jdbc\:oracle\:thin\:@localhost\:1521\:orcl
oracleUser=root
oraclePwd=root

JDBCUtil

public class JDBCUtil {


    static Properties pros = null;   //可以帮助读取和处理资源文件中的信息

    static {   //加载JDBCUtil类的时候调用
        pros = new Properties();
        try {
            pros.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static Connection getMysqlConn() {
        try {
            Class.forName(pros.getProperty("mysqlDriver"));
            return DriverManager.getConnection(pros.getProperty("mysqlURL"),
                    pros.getProperty("mysqlUser"), pros.getProperty("mysqlPwd"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static Connection getOracleConn() {
        try {
            Class.forName(pros.getProperty("oracleDriver"));
            return DriverManager.getConnection(pros.getProperty("oracleURL"),
                    pros.getProperty("oracleUser"), pros.getProperty("oraclePwd"));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void close(ResultSet rs, Statement ps, Connection conn) {
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (ps != null) {
                ps.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void close(Statement ps, Connection conn) {
        try {
            if (ps != null) {
                ps.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public static void close(Connection conn) {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

六、JDBC的SQL注入问题

SQL注入问题是一种恶意的注入攻击,可以执行恶意SQL导致数据库数据丢失,使用SQL注入可以绕过web应用程序的身份验证和授权,直接可以获取到数据库资料。

之前JDBC使用Statement对象执行SQL程序,假如有下面一段程序

public class demo02 {

	public static void main(String[] args) {
		Connection connection = null;
		Statement statement  = null;
		try {
			Class.forName("com.mysql.jdbc.Driver");
		     connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
			statement = connection.createStatement();
			String id= "5 or 1=1 ";
			String sql = "delete from user where id="+id;
			statement.execute(sql);
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}finally {
			try {
				if(connection!=null) {
				connection.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			try {
				if(statement!=null) {
					statement.close();
				}
			} catch (SQLException e) {
				e.printStackTrace();
			}
			
		}
	}
}

其中使用Statement对象直接执行SQL

String id = "5 or 1=1 ";
String sql = "delete from user where id="+id;
statement.execute(sql);

则会导致数据库中的所有数据被删除。

七、SQL注入问题解决方案

现在将Statement对象换成PreparedStatement 对象之后,将SQL中的参数以?占位符的方式表示,可以完美解决SQL注入的问题。

你可能感兴趣的:(MyBatis)