赞
踩
先了解什么是数据库连接驱动
数据库驱动:是连接应用程序和数据库的关键,我们的程序会通过数据库驱动,来和数据库打交道!!!
SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称JDBC
那么这些规范的实现由具体的厂商去做
对于开发人员来说,我们只需要掌握JDBC接口的操作即可!
一、下载
1、下载地址:https://dev.mysql.com/downloads/
2、点击Connerctor/J,选择框起来的选项,表示与平台无关
3、下载这个压缩文件
4、弹出来的界面选择如下:
5、将解压后的文件放在指定的位置
二、导入IDRA
1、在新建的项目下建一个lib目录
2、将我们下载好的jar包复制进来
3、右键lib目录,点击 Add as Library
4、点击OK
5、发现这个jar包是可以展开的,说明我们已经成功将jar包导入到项目中
一、操作步骤
1、pom.xml中导入连接是数据库的jar包,类中加载JDBC驱动;
2、编写用户的账号和密码以及URL路径;
3、驱动连接数据库,返回连接的对象connection;
4、连接对象connection创建执行SQL的对象statement;
5、执行SQL对象调用查询或者更新的方法(executeQuery)执行SQL语句,并且返回一个结果集;
6、释放连接
二、测试代码(其中第一步和第二步的代码是固定的,背过!!!)
数据库表:
IDEA代码:
导入依赖:
- <!-- 导入数据库连接驱动的jar包-->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>5.1.47</version>
- </dependency>
- </dependencies>
具体代码如下:
- import java.sql.*;
-
- // 我的第一个JDBC程序
- public class jdbcFirst {
- public static void main(String[] args) throws ClassNotFoundException, SQLException {
- //1、加载驱动,记住这个加载方式,这是固定的写法
- Class.forName("com.mysql.cj.jdbc.Driver");
-
- //2、用户信息和URL,记住这个路径,也是固定写法!!!!!!!!!!
- /*useUnicode=true 表示支持中文编码
- * characterEncoding=utf8 表示设置字符集编码
- * useSSL=true 表示使用安全的连接
- * "?" 的作用是连接参数
- * "&"表示and 和
- * URL 表示唯一定位:
- * MySQL公式:协议://主机地址:端口号(默认3306)/数据库名?参数1&参数2&参数3;
- * oralce公式: jdbc:oralce:thin@localhost:1521(默认1521):sid
- * */
- String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
- String username = "root";
- String password = "root";
-
- //3、连接数据库,返回数据库对象 Connection代表数据库,同样还可以在这个级别上设置自动提交事务,回滚等操作
- Connection connection = DriverManager.getConnection(url, username, password);
- /*//数据库级别的操作常见如下:
- connection.commit(); //提交事务
- connection.setAutoCommit(true);// 设置是否自动提交
- connection.rollback(); //回滚事务*/
-
- //4、执行SQL对象 statement是用来执行SQL的对象
- Statement statement = connection.createStatement();
-
- //5、执行SQL的对象 去执行SQL,可能存在结果,查看返回的结果
- String sql1 = "SELECT * FROM users"; //定义查询语句
- //注意:statement调用的只有Query 和 update 方法,因为insert 和 delete 都归在了update下,executeUpdate()返回受影响的行数
- //statement.execute();//增删改查的语句都可以执行
- ResultSet resultSet = statement.executeQuery(sql1);// resultSet只有查询的时候会有,返回一个结果集,链表的形式,结果集中封装了全部的查询的结果
- while (resultSet.next()) { //resultSet.next()返回值是一个布尔类型,如果结果集中后面没有数据就返回false
- System.out.println("id = " + resultSet.getObject("id"));// getObject是在不知道列数据类型的时候使用,resultSet还可以调用特定类型的方法
- System.out.println("name = " + resultSet.getObject("NAME"));
- System.out.println("pwd = " + resultSet.getObject("PASSWORD"));
- System.out.println("email = " + resultSet.getObject("email"));
- System.out.println("birthday = " + resultSet.getObject("birthday"));
- System.out.println("=============================================");
- }
- //6、释放连接,必须要做(连接很占内存,必须释放资源)
- resultSet.close();
- statement.close();
- connection.close();
-
- }
-
- }

1、新建一个包,名字叫做utils
2、工具类中将加载驱动的方法写到static静态代码块中,随着类的加载而加载,这样只需要将加载驱动的方法执行一次即可
然后将连接数据库和释放资源的功能写成一个方法,将来直接调用即可
- import com.mysql.cj.protocol.Resultset;
-
- import javax.xml.stream.events.StartDocument;
- import java.io.IOException;
- import java.io.InputStream;
- import java.sql.*;
- import java.util.Properties;
-
- public class JdbcUtils {
- //将我们用到的变量提升一下作用域
- private static String driver;
- private static String url;
- private static String username;
- private static String password;
-
- static {
- try {
- // 1、通过工具类,获取他自己的反射对象,然后获取反射对象的类加载器,调用类加载器的获取资源的方法
- InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
- //2、创建读取配置文件的对象
- Properties properties = new Properties();
- //3、调用读取配置文件的方法
- properties.load(in);
- //4、获取配置文件中的value
- driver = properties.getProperty("driver");
- url = properties.getProperty("url");
- username = properties.getProperty("username");
- password = properties.getProperty("password");
-
- //加载JDBC的Driver驱动,因为是放在了静态代码块中,所以只需要加载一次即可
- Class.forName(driver);
-
- } catch (IOException | ClassNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- //连接数据库方法
- public static Connection getConnection() throws SQLException {
- //连接数据库
- return DriverManager.getConnection(url, username, password);
- }
-
- //释放资源方法
- public static void release(Connection conn, Statement sta, ResultSet rs) throws SQLException {
- if (rs != null) {
- rs.close();
- }
- if (sta != null) {
- sta.close();
- }
- if (conn != null) {
- conn.close();
- }
- }
- }

在IDEA中,增删改都直接调用Update方法,查询调用excuteQuery方法
测试表:
一、增删改
- public class testInsert {
- public static void main(String[] args) throws SQLException {
- Connection conn = null;
- Statement sta = null;
- ResultSet rs = null;
-
- try {
- //获取连接,因为我们将JDBC封装成一个工具类,这里直接调用工具类的方法即可
- conn = JdbcUtils.getConnection();
- //获取执行sql的对象
- sta = conn.createStatement();
- //编写需要的SQL语句
- String sql = "INSERT INTO users (id,`NAME`,`PASSWORD`,`email`,birthday)" +
- "VALUES (4,'张三','1232456445','12345@qq.com','2023-01-23');";
- //凡是增、删和改都用Update这个方法,返回一个int类型受影响的行数
- int i = sta.executeUpdate(sql);
- if (i != 0){
- System.out.println(i + "条数据插入成功!");
- }
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- //当操作结束后,调用释放资源的方法
- JdbcUtils.release(conn,sta,rs);
- }
- }
- }

二、查询
- public class testQuery {
- public static void main(String[] args) {
- Connection conn = null;
- Statement sta = null;
- ResultSet rs = null;
-
- try {
- conn = JdbcUtils.getConnection();
- sta = conn.createStatement();
- String sql = "SELECT * FROM users";
- rs = sta.executeQuery(sql);
- while (rs.next()){
- System.out.println("id:" + rs.getInt("id"));
- System.out.println("NAME:" + rs.getString("NAME"));
- System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
- System.out.println("email:" + rs.getObject("email"));
- System.out.println("birthday:" + rs.getObject("birthday"));
- System.out.println("============================");
- }
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- try {
- JdbcUtils.release(conn,sta,rs);
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
-
- }

SQL语句可以实现拼接(也就存在漏洞),如果我们 写的业务中没有屏蔽这种SQL注入问题,程序就会被攻击
下面演示一段SQL注入代码:
- public class testLogin {
- public static void main(String[] args) {
- //主方法中调用登陆的业务,写一个"'or '1 = 1", "'or '1 = 1"的username h和password 这样就会让where条件判断一直保持true
- login("'or '1 = 1", "'or '1 = 1");
- }
-
- //登陆业务
- public static void login(String username, String password) {
- Connection conn = null;
- Statement sta = null;
- ResultSet rs = null;
-
- try {
- //获取连接,因为我们将JDBC封装成一个工具类,这里直接调用工具类的方法即可
- conn = JdbcUtils.getConnection();
- //获取执行sql的对象
- sta = conn.createStatement();
- //编写需要的SQL语句
- String sql = "select * from users where `NAME` = '" + username + "'AND PASSWORD = '" + password + "'";
- //凡是增、删和改都用Update这个方法,返回一个int类型受影响的行数
- rs = sta.executeQuery(sql);
- while (rs.next()) {
- System.out.println("id:" + rs.getInt("id"));
- System.out.println("NAME:" + rs.getString("NAME"));
- System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
- System.out.println("email:" + rs.getObject("email"));
- System.out.println("birthday:" + rs.getObject("birthday"));
- System.out.println("============================");
- }
-
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- //当操作结束后,调用释放资源的方法
- try {
- JdbcUtils.release(conn, sta, rs);
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
- }

输出的结果:
写一段拼接的SQL就会将所有的信息全部查询出来
这个对象可以防止SQL注入,并且效率会更高
一、PreparedStatement对象增删改的代码
- public class TestInsert {
- public static void main(String[] args) {
- Connection conn = null;
- PreparedStatement sta = null;
- ResultSet rs = null;
- try {
- conn = JdbcUtils.getConnection();
-
- //value中的问号表示占位符,用prepareStatement方法的优势就是可以最后添加value
- String sql = "INSERT INTO users (id,`NAME`,`PASSWORD`,`email`,birthday) VALUES(?,?,?,?,?)";
-
- //区别于 statement
- /*1、prepareStatement对象可以直接被数据库conn对象创建,而statement对象还需要conn对象调用createStatement()方法才能创建
- * 2、prepareStatement()方法需要传入一个参数,这个参数是预编译的SQL语句,通俗讲是先写SQL,暂时不执行
- * 3、提前将写好的SQL放进方法中
- * */
- sta = conn.prepareStatement(sql);
- sta.setInt(1, 4);
- sta.setString(2, "10086");
- sta.setString(3, "123456789");
- sta.setString(4, "244562@qq.com");
- //注意:这里的date是先调用SQL的date
- //然后调用的是java中的 until下的date,getTime是获取当前时间戳
- sta.setDate(5, new java.sql.Date(new Date().getTime()));
- //真正的执行方法,区别于statement调用这个方法还需要往里面传入sql,而prepareStatement不需要往里面传SQL语句了
- int i = sta.executeUpdate();
- if (i > 0 ){
- System.out.println(i + "行被插入!");
- }
-
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- try {
- JdbcUtils.release(conn, sta, rs);
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
- }

二、查询代码
- public class TestQuery {
- public static void main(String[] args) {
- Connection conn = null;
- PreparedStatement sta = null;
- ResultSet rs = null;
- try {
- conn = JdbcUtils.getConnection();
-
- //value中的问号表示占位符,用prepareStatement方法的优势就是可以最后添加value
- String sql = "select * from users where id = ?";
-
- //区别于 statement
- /*1、prepareStatement对象可以直接被数据库conn对象创建,而statement对象还需要conn对象调用createStatement()方法才能创建
- * 2、prepareStatement()方法需要传入一个参数,这个参数是预编译的SQL语句,通俗讲是先写SQL,暂时不执行
- * 3、提前将写好的SQL放进方法中
- * */
- sta = conn.prepareStatement(sql);
- sta.setInt(1,3);
- //真正的执行方法,区别于statement调用这个方法还需要往里面传入sql,而prepareStatement不需要往里面传SQL语句了
- rs = sta.executeQuery();
- if (rs.next()){
- System.out.println(rs.getString("NAME"));
- }
-
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- try {
- JdbcUtils.release(conn, sta, rs);
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
- }

三、防止SQL注入的原因
见下面的代码以及注释
- public class testLogin {
- public static void main(String[] args) {
- //主方法中调用登陆的业务
- //1、正常的参数
- login("10086","123456789");
- //2、SQL注入的参数
- login("'or '1 = 1", "'or '1 = 1");
- }
-
- //登陆业务
- public static void login(String username, String password) {
- Connection conn = null;
- PreparedStatement sta = null;
- ResultSet rs = null;
-
- try {
- //获取连接,因为我们将JDBC封装成一个工具类,这里直接调用工具类的方法即可
- conn = JdbcUtils.getConnection();
-
- //编写需要的SQL语句
- String sql = "select * from users where `NAME` = ? and `PASSWORD` = ?";
- //获取执行sql的对象,进行预编译
- //prepareStatement防止SQL注入的本质在于,他将传进来的参数都当作字符,假设其中存在‘’这种转义字符,会被直接转义
- sta = conn.prepareStatement(sql);
- //给value赋值
- sta.setString(1,username);
- sta.setString(2,password);
- rs = sta.executeQuery();
- while (rs.next()) {
- System.out.println("id:" + rs.getInt("id"));
- System.out.println("NAME:" + rs.getString("NAME"));
- System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
- System.out.println("email:" + rs.getObject("email"));
- System.out.println("birthday:" + rs.getObject("birthday"));
- System.out.println("============================");
- }
-
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- } finally {
- //当操作结束后,调用释放资源的方法
- try {
- JdbcUtils.release(conn, sta, rs);
- } catch (SQLException throwables) {
- throwables.printStackTrace();
- }
- }
- }
- }
-

使用statement 对象存在SQL注入的问题,不安全,一般多用PreparedStatement对象!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。