当前位置:   article > 正文

MySQL数据库-JDBC篇_conn对象调用statement和直接用statement

conn对象调用statement和直接用statement

认识JDBC

先了解什么是数据库连接驱动

数据库驱动:是连接应用程序和数据库的关键,我们的程序会通过数据库驱动,来和数据库打交道!!!

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包导入到项目中

第一个JDBC程序(标准的操作步骤)

一、操作步骤
1、pom.xml中导入连接是数据库的jar包,类中加载JDBC驱动;
2、编写用户的账号和密码以及URL路径;
3、驱动连接数据库,返回连接的对象connection;
4、连接对象connection创建执行SQL的对象statement;
5、执行SQL对象调用查询或者更新的方法(executeQuery)执行SQL语句,并且返回一个结果集;
6、释放连接

二、测试代码(其中第一步和第二步的代码是固定的,背过!!!)
数据库表:

IDEA代码:
导入依赖:

  1. <!-- 导入数据库连接驱动的jar包-->
  2. <dependency>
  3. <groupId>mysql</groupId>
  4. <artifactId>mysql-connector-java</artifactId>
  5. <version>5.1.47</version>
  6. </dependency>
  7. </dependencies>

具体代码如下:

  1. import java.sql.*;
  2. // 我的第一个JDBC程序
  3. public class jdbcFirst {
  4. public static void main(String[] args) throws ClassNotFoundException, SQLException {
  5. //1、加载驱动,记住这个加载方式,这是固定的写法
  6. Class.forName("com.mysql.cj.jdbc.Driver");
  7. //2、用户信息和URL,记住这个路径,也是固定写法!!!!!!!!!!
  8. /*useUnicode=true 表示支持中文编码
  9. * characterEncoding=utf8 表示设置字符集编码
  10. * useSSL=true 表示使用安全的连接
  11. * "?" 的作用是连接参数
  12. * "&"表示and 和
  13. * URL 表示唯一定位:
  14. * MySQL公式:协议://主机地址:端口号(默认3306)/数据库名?参数1&参数2&参数3;
  15. * oralce公式: jdbc:oralce:thin@localhost:1521(默认1521):sid
  16. * */
  17. String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
  18. String username = "root";
  19. String password = "root";
  20. //3、连接数据库,返回数据库对象 Connection代表数据库,同样还可以在这个级别上设置自动提交事务,回滚等操作
  21. Connection connection = DriverManager.getConnection(url, username, password);
  22. /*//数据库级别的操作常见如下:
  23. connection.commit(); //提交事务
  24. connection.setAutoCommit(true);// 设置是否自动提交
  25. connection.rollback(); //回滚事务*/
  26. //4、执行SQL对象 statement是用来执行SQL的对象
  27. Statement statement = connection.createStatement();
  28. //5、执行SQL的对象 去执行SQL,可能存在结果,查看返回的结果
  29. String sql1 = "SELECT * FROM users"; //定义查询语句
  30. //注意:statement调用的只有Query 和 update 方法,因为insert 和 delete 都归在了update下,executeUpdate()返回受影响的行数
  31. //statement.execute();//增删改查的语句都可以执行
  32. ResultSet resultSet = statement.executeQuery(sql1);// resultSet只有查询的时候会有,返回一个结果集,链表的形式,结果集中封装了全部的查询的结果
  33. while (resultSet.next()) { //resultSet.next()返回值是一个布尔类型,如果结果集中后面没有数据就返回false
  34. System.out.println("id = " + resultSet.getObject("id"));// getObject是在不知道列数据类型的时候使用,resultSet还可以调用特定类型的方法
  35. System.out.println("name = " + resultSet.getObject("NAME"));
  36. System.out.println("pwd = " + resultSet.getObject("PASSWORD"));
  37. System.out.println("email = " + resultSet.getObject("email"));
  38. System.out.println("birthday = " + resultSet.getObject("birthday"));
  39. System.out.println("=============================================");
  40. }
  41. //6、释放连接,必须要做(连接很占内存,必须释放资源)
  42. resultSet.close();
  43. statement.close();
  44. connection.close();
  45. }
  46. }

抽取JDBC为一个工具类

1、新建一个包,名字叫做utils

2、工具类中将加载驱动的方法写到static静态代码块中,随着类的加载而加载,这样只需要将加载驱动的方法执行一次即可
然后将连接数据库和释放资源的功能写成一个方法,将来直接调用即可

  1. import com.mysql.cj.protocol.Resultset;
  2. import javax.xml.stream.events.StartDocument;
  3. import java.io.IOException;
  4. import java.io.InputStream;
  5. import java.sql.*;
  6. import java.util.Properties;
  7. public class JdbcUtils {
  8. //将我们用到的变量提升一下作用域
  9. private static String driver;
  10. private static String url;
  11. private static String username;
  12. private static String password;
  13. static {
  14. try {
  15. // 1、通过工具类,获取他自己的反射对象,然后获取反射对象的类加载器,调用类加载器的获取资源的方法
  16. InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
  17. //2、创建读取配置文件的对象
  18. Properties properties = new Properties();
  19. //3、调用读取配置文件的方法
  20. properties.load(in);
  21. //4、获取配置文件中的value
  22. driver = properties.getProperty("driver");
  23. url = properties.getProperty("url");
  24. username = properties.getProperty("username");
  25. password = properties.getProperty("password");
  26. //加载JDBC的Driver驱动,因为是放在了静态代码块中,所以只需要加载一次即可
  27. Class.forName(driver);
  28. } catch (IOException | ClassNotFoundException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. //连接数据库方法
  33. public static Connection getConnection() throws SQLException {
  34. //连接数据库
  35. return DriverManager.getConnection(url, username, password);
  36. }
  37. //释放资源方法
  38. public static void release(Connection conn, Statement sta, ResultSet rs) throws SQLException {
  39. if (rs != null) {
  40. rs.close();
  41. }
  42. if (sta != null) {
  43. sta.close();
  44. }
  45. if (conn != null) {
  46. conn.close();
  47. }
  48. }
  49. }

运用工具类完成增删改查

在IDEA中,增删改都直接调用Update方法,查询调用excuteQuery方法
测试表:

一、增删改

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

二、查询

  1. public class testQuery {
  2. public static void main(String[] args) {
  3. Connection conn = null;
  4. Statement sta = null;
  5. ResultSet rs = null;
  6. try {
  7. conn = JdbcUtils.getConnection();
  8. sta = conn.createStatement();
  9. String sql = "SELECT * FROM users";
  10. rs = sta.executeQuery(sql);
  11. while (rs.next()){
  12. System.out.println("id:" + rs.getInt("id"));
  13. System.out.println("NAME:" + rs.getString("NAME"));
  14. System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
  15. System.out.println("email:" + rs.getObject("email"));
  16. System.out.println("birthday:" + rs.getObject("birthday"));
  17. System.out.println("============================");
  18. }
  19. } catch (SQLException throwables) {
  20. throwables.printStackTrace();
  21. } finally {
  22. try {
  23. JdbcUtils.release(conn,sta,rs);
  24. } catch (SQLException throwables) {
  25. throwables.printStackTrace();
  26. }
  27. }
  28. }
  29. }

SQL注入

SQL语句可以实现拼接(也就存在漏洞),如果我们 写的业务中没有屏蔽这种SQL注入问题,程序就会被攻击

下面演示一段SQL注入代码:

  1. public class testLogin {
  2. public static void main(String[] args) {
  3. //主方法中调用登陆的业务,写一个"'or '1 = 1", "'or '1 = 1"的username h和password 这样就会让where条件判断一直保持true
  4. login("'or '1 = 1", "'or '1 = 1");
  5. }
  6. //登陆业务
  7. public static void login(String username, String password) {
  8. Connection conn = null;
  9. Statement sta = null;
  10. ResultSet rs = null;
  11. try {
  12. //获取连接,因为我们将JDBC封装成一个工具类,这里直接调用工具类的方法即可
  13. conn = JdbcUtils.getConnection();
  14. //获取执行sql的对象
  15. sta = conn.createStatement();
  16. //编写需要的SQL语句
  17. String sql = "select * from users where `NAME` = '" + username + "'AND PASSWORD = '" + password + "'";
  18. //凡是增、删和改都用Update这个方法,返回一个int类型受影响的行数
  19. rs = sta.executeQuery(sql);
  20. while (rs.next()) {
  21. System.out.println("id:" + rs.getInt("id"));
  22. System.out.println("NAME:" + rs.getString("NAME"));
  23. System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
  24. System.out.println("email:" + rs.getObject("email"));
  25. System.out.println("birthday:" + rs.getObject("birthday"));
  26. System.out.println("============================");
  27. }
  28. } catch (SQLException throwables) {
  29. throwables.printStackTrace();
  30. } finally {
  31. //当操作结束后,调用释放资源的方法
  32. try {
  33. JdbcUtils.release(conn, sta, rs);
  34. } catch (SQLException throwables) {
  35. throwables.printStackTrace();
  36. }
  37. }
  38. }
  39. }

输出的结果:
写一段拼接的SQL就会将所有的信息全部查询出来

PreparedStatement对象

这个对象可以防止SQL注入,并且效率会更高

一、PreparedStatement对象增删改的代码

  1. public class TestInsert {
  2. public static void main(String[] args) {
  3. Connection conn = null;
  4. PreparedStatement sta = null;
  5. ResultSet rs = null;
  6. try {
  7. conn = JdbcUtils.getConnection();
  8. //value中的问号表示占位符,用prepareStatement方法的优势就是可以最后添加value
  9. String sql = "INSERT INTO users (id,`NAME`,`PASSWORD`,`email`,birthday) VALUES(?,?,?,?,?)";
  10. //区别于 statement
  11. /*1、prepareStatement对象可以直接被数据库conn对象创建,而statement对象还需要conn对象调用createStatement()方法才能创建
  12. * 2、prepareStatement()方法需要传入一个参数,这个参数是预编译的SQL语句,通俗讲是先写SQL,暂时不执行
  13. * 3、提前将写好的SQL放进方法中
  14. * */
  15. sta = conn.prepareStatement(sql);
  16. sta.setInt(1, 4);
  17. sta.setString(2, "10086");
  18. sta.setString(3, "123456789");
  19. sta.setString(4, "244562@qq.com");
  20. //注意:这里的date是先调用SQL的date
  21. //然后调用的是java中的 until下的date,getTime是获取当前时间戳
  22. sta.setDate(5, new java.sql.Date(new Date().getTime()));
  23. //真正的执行方法,区别于statement调用这个方法还需要往里面传入sql,而prepareStatement不需要往里面传SQL语句了
  24. int i = sta.executeUpdate();
  25. if (i > 0 ){
  26. System.out.println(i + "行被插入!");
  27. }
  28. } catch (SQLException throwables) {
  29. throwables.printStackTrace();
  30. } finally {
  31. try {
  32. JdbcUtils.release(conn, sta, rs);
  33. } catch (SQLException throwables) {
  34. throwables.printStackTrace();
  35. }
  36. }
  37. }
  38. }

二、查询代码

  1. public class TestQuery {
  2. public static void main(String[] args) {
  3. Connection conn = null;
  4. PreparedStatement sta = null;
  5. ResultSet rs = null;
  6. try {
  7. conn = JdbcUtils.getConnection();
  8. //value中的问号表示占位符,用prepareStatement方法的优势就是可以最后添加value
  9. String sql = "select * from users where id = ?";
  10. //区别于 statement
  11. /*1、prepareStatement对象可以直接被数据库conn对象创建,而statement对象还需要conn对象调用createStatement()方法才能创建
  12. * 2、prepareStatement()方法需要传入一个参数,这个参数是预编译的SQL语句,通俗讲是先写SQL,暂时不执行
  13. * 3、提前将写好的SQL放进方法中
  14. * */
  15. sta = conn.prepareStatement(sql);
  16. sta.setInt(1,3);
  17. //真正的执行方法,区别于statement调用这个方法还需要往里面传入sql,而prepareStatement不需要往里面传SQL语句了
  18. rs = sta.executeQuery();
  19. if (rs.next()){
  20. System.out.println(rs.getString("NAME"));
  21. }
  22. } catch (SQLException throwables) {
  23. throwables.printStackTrace();
  24. } finally {
  25. try {
  26. JdbcUtils.release(conn, sta, rs);
  27. } catch (SQLException throwables) {
  28. throwables.printStackTrace();
  29. }
  30. }
  31. }
  32. }


三、防止SQL注入的原因

见下面的代码以及注释

  1. public class testLogin {
  2. public static void main(String[] args) {
  3. //主方法中调用登陆的业务
  4. //1、正常的参数
  5. login("10086","123456789");
  6. //2、SQL注入的参数
  7. login("'or '1 = 1", "'or '1 = 1");
  8. }
  9. //登陆业务
  10. public static void login(String username, String password) {
  11. Connection conn = null;
  12. PreparedStatement sta = null;
  13. ResultSet rs = null;
  14. try {
  15. //获取连接,因为我们将JDBC封装成一个工具类,这里直接调用工具类的方法即可
  16. conn = JdbcUtils.getConnection();
  17. //编写需要的SQL语句
  18. String sql = "select * from users where `NAME` = ? and `PASSWORD` = ?";
  19. //获取执行sql的对象,进行预编译
  20. //prepareStatement防止SQL注入的本质在于,他将传进来的参数都当作字符,假设其中存在‘’这种转义字符,会被直接转义
  21. sta = conn.prepareStatement(sql);
  22. //给value赋值
  23. sta.setString(1,username);
  24. sta.setString(2,password);
  25. rs = sta.executeQuery();
  26. while (rs.next()) {
  27. System.out.println("id:" + rs.getInt("id"));
  28. System.out.println("NAME:" + rs.getString("NAME"));
  29. System.out.println("PASSWORD:" + rs.getInt("PASSWORD"));
  30. System.out.println("email:" + rs.getObject("email"));
  31. System.out.println("birthday:" + rs.getObject("birthday"));
  32. System.out.println("============================");
  33. }
  34. } catch (SQLException throwables) {
  35. throwables.printStackTrace();
  36. } finally {
  37. //当操作结束后,调用释放资源的方法
  38. try {
  39. JdbcUtils.release(conn, sta, rs);
  40. } catch (SQLException throwables) {
  41. throwables.printStackTrace();
  42. }
  43. }
  44. }
  45. }

Statement对象

使用statement 对象存在SQL注入的问题,不安全,一般多用PreparedStatement对象!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/777767
推荐阅读
相关标签
  

闽ICP备14008679号