一文彻底弄明白贾琏欲执事(JDBC)【2】

举报
XiaoLin_Java 发表于 2022/01/06 13:38:01 2022/01/06
【摘要】 五、JDBC之CRUD操作 5.1、Statement对象及其弊端 5.1.1、Statement对象    Statement对象时用于执行静态 SQL 语句并返回它所生成结果的对象。通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。Statement 接口中定义了下列方法用于执行 SQL 语...

五、JDBC之CRUD操作

5.1、Statement对象及其弊端

5.1.1、Statement对象

    Statement对象时用于执行静态 SQL 语句并返回它所生成结果的对象。

在这里插入图片描述

  • 通过调用 Connection 对象的 createStatement() 方法创建该对象。该对象用于执行静态的 SQL 语句,并且返回执行结果。
  • Statement 接口中定义了下列方法用于执行 SQL 语句:
int excuteUpdate(String sql):执行更新操作INSERTUPDATEDELETE
ResultSet executeQuery(String sql):执行查询操作SELECT

5.1.2、使用Statement对象的弊端

    用Statement操作数据表存在弊端:

  1. 存在拼串操作,繁琐
  2. 存在SQL注入问题

    SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法。

public class StatementTest {

	// 使用Statement的弊端:需要拼写sql语句,并且存在SQL注入的问题
	@Test
	public void testLogin() {
		Scanner scan = new Scanner(System.in);

		System.out.print("用户名:");
		String userName = scan.nextLine();
		System.out.print("密   码:");
		String password = scan.nextLine();

		// SELECT user,password FROM user_table WHERE USER = '1' or ' AND PASSWORD = '='1' or '1' = '1';
		String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName + "' AND PASSWORD = '" + password
				+ "'";//字符串拼接过于繁杂
		User user = get(sql, User.class);
		if (user != null) {
			System.out.println("登陆成功!");
		} else {
			System.out.println("用户名或密码错误!");
		}
	}

	// 使用Statement实现对数据表的查询操作
	public <T> T get(String sql, Class<T> clazz) {
		T t = null;

		Connection conn = null;
		Statement st = null;
		ResultSet rs = null;
		try {
			// 1.加载配置文件
			InputStream is = StatementTest.class.getClassLoader().getResourceAsStream("jdbc.properties");
			Properties pros = new Properties();
			pros.load(is);

			// 2.读取配置信息
			String user = pros.getProperty("user");
			String password = pros.getProperty("password");
			String url = pros.getProperty("url");
			String driverClass = pros.getProperty("driverClass");

			// 3.加载驱动
			Class.forName(driverClass);

			// 4.获取连接
			conn = DriverManager.getConnection(url, user, password);

			st = conn.createStatement();

			rs = st.executeQuery(sql);

			// 获取结果集的元数据
			ResultSetMetaData rsmd = rs.getMetaData();

			// 获取结果集的列数
			int columnCount = rsmd.getColumnCount();

			if (rs.next()) {

				t = clazz.newInstance();

				for (int i = 0; i < columnCount; i++) {
					// //1. 获取列的名称
					// String columnName = rsmd.getColumnName(i+1);

					// 1. 获取列的别名
					String columnName = rsmd.getColumnLabel(i + 1);

					// 2. 根据列名获取对应数据表中的数据
					Object columnVal = rs.getObject(columnName);

					// 3. 将数据表中得到的数据,封装进对象
					Field field = clazz.getDeclaredField(columnName);
					field.setAccessible(true);
					field.set(t, columnVal);
				}
				return t;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			// 关闭资源
			if (rs != null) {
				try {
					rs.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}
			if (st != null) {
				try {
					st.close();
				} catch (SQLException e) {
					e.printStackTrace();
				}
			}

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

		return null;
	}
}

在这里插入图片描述

5.2、PreparedStatement

    我们可以通过调用 Connection 对象的 preparedStatement(String sql) 方法获取PreparedStatement对象,PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的 SQL 语句。

    PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用PreparedStatement对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数,第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始),第二个是设置的 SQL 语句中的参数的值。

// 常用方法:
void setXxx(int parameterIndex,Xxx value); //设置第几个占位符的真正参数值.
// Xxx 表示数据类型,比如 String,int,long,Date等.
void setObject(int parameterIndex, Object x); //设置第几个占位符的真正参数值.
int executeUpdate(); //执行DDL/DML语句. 注意:没有参数
// 若当前 SQL是 DDL语句,则返回 0.
// 若当前 SQL是 DML语句,则返回受影响的行数.
ResultSet executeQuery(); //执行DQL语句,返回结果集.
close(); //释放资源

5.3、PreparedStatement vs Statement

  1. PreparedStatement对象比Statement对象的代码的可读性和可维护性。

  2. PreparedStatement能最大可能提高性能。

    • DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。
    • 在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存。这样每执行一次都要对传入的语句编译一次。
  3. PreparedStatement 可以防止 SQL 注入 。

5.4、 ResultSet

    查询需要调用PreparedStatementexecuteQuery()方法,查询结果是一个ResultSet 对象,ResultSet 对象以逻辑表格的形式封装了执行数据库操作的结果集,ResultSet 接口由数据库厂商提供实现。

    ResultSet 返回的实际上就是一张数据表。有一个指针指向数据表的第一条记录的前面。

    ResultSet 对象维护了一个指向当前数据行的游标,初始的时候,游标在第一行之前,可以通过 ResultSet 对象的 next() 方法移动到下一行。调用 next()方法检测下一行是否有效。若有效,该方法返回 true,且指针下移。相当于Iterator对象的hasNext()next()方法的结合体。

    当指针指向一行时, 可以通过调用 getXxx(int index)getXxx(int columnName) 获取每一列的值。*Java与数据库交互涉及到的相关Java API中的索引都从1开始。*例如:

getInt(1), getString("name")

在这里插入图片描述

5.5、CRUD操作

5.5.1、User类

package domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author Xiao_Lin
 * @date 2021/1/2 19:44
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
  //id
  private Integer id;
  //用户名
  private String username;
  //密码
  private String pwd;

  //构造方法的重载
  public User(String username, String pwd) {
    this.username = username;
    this.pwd = pwd;
  }
}

5.5.2、IUserDAO

package dao;

import domain.User;
import java.util.List;

/**
 * @author Xiao_Lin
 * @date 2021/1/2 19:46
 */
public interface IUserDAO {
  public void insert(User user);

  public void delete(Integer id);

  public void update(User user);

  public List<User> selectAll();

  public User selectUserById(Integer id);
}

5.5.3、UserDAOImpl

package dao.impl;

import dao.IUserDAO;

import dao.utils.DaoUtils;
import domain.User;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author Xiao_Lin
 * @date 2021/1/2 19:49
 */

public class UserDAOImpl implements IUserDAO {
  Connection connection = null;
  PreparedStatement ps = null;
  ResultSet rs = null;
  @Override
  public void insert(User user) {
    try {
      connection = DaoUtils.getConnection();
      String sql = "insert into user (username,pwd) values (?,?)";
       ps = connection.prepareStatement(sql);
      ps.setString(1,user.getUsername());
      ps.setString(2,user.getPwd());
      ps.executeUpdate();
      System.out.println("添加成功!!");
    } catch (SQLException e) {
      e.printStackTrace();
    }finally {
      DaoUtils.close(connection,ps,null);
    }
  }

  @Override
  public void delete(Integer id) {
    try {
      connection = DaoUtils.getConnection();
      ps = connection.prepareStatement("delete from user where id = ?");
      ps.setInt(1,id);
      ps.executeUpdate();
      System.out.println("删除成功!!");

    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      DaoUtils.close(connection,ps,null);
    }
  }

  @Override
  public void update(User user) {
    try {
      connection = DaoUtils.getConnection();
       ps = connection.prepareStatement("update user set username = ? , pwd = ? where id = ?");
       ps.setString(1,user.getUsername());
       ps.setString(2,user.getPwd());
       ps.setInt(3,user.getId());
      ps.executeUpdate();
      System.out.println("修改成功");
    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      DaoUtils.close(connection,ps,null);
    }

  }

  @Override
  public List<User> selectAll() {
    List<User> users = new ArrayList<>();
    try {
      connection = DaoUtils.getConnection();
      ps = connection.prepareStatement("select * from user");
      rs = ps.executeQuery();
      while (rs.next()){
        users.add(new User(rs.getInt("id"),rs.getString("username"),rs.getString("pwd")));
      }

    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      DaoUtils.close(connection,ps,rs);
    }
    return users;
  }

  @Override
  public User selectUserById(Integer id) {
    User user = null;
    try {
      connection = DaoUtils.getConnection();
      ps = connection.prepareStatement("select * from user where id = ?");
      ps.setInt(1,id);
      rs = ps.executeQuery();
      while (rs.next()){
        user = new User(rs.getInt("id"),rs.getString("username"),rs.getString("pwd"));
      }

    } catch (Exception e) {
      e.printStackTrace();
    }finally {
      DaoUtils.close(connection,ps,rs);
    }
    return user;
  }
}

5.5.4、DaoUtils

package dao.utils;

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author Xiao_Lin
 * @date 2021/1/2 19:56
 */
public class DaoUtils {
  static Connection connection = null;
  static Properties properties = null;

  static {
    InputStream resourceAsStream = Thread.currentThread().getContextClassLoader()
        .getResourceAsStream("db.properties");
    properties = new Properties();
    try {
      properties.load(resourceAsStream);
      Class.forName(properties.getProperty("DriverClassName"));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static Connection getConnection() throws SQLException {
   connection= DriverManager.getConnection(properties.getProperty("url"),properties.getProperty("username"),properties.getProperty("password"));
    return connection;
  }

  public  static void  close(Connection conn , PreparedStatement ps , ResultSet rs){

    try {
      if(rs!=null){
        rs.close();
      }
    } catch (SQLException e) {
      e.printStackTrace();
    }finally{
      try {
        if(ps!=null){
          ps.close();
        }
      } catch (SQLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }finally{
        try {
          if(conn!=null){
            conn.close();
          }
        } catch (SQLException e) {
          // TODO Auto-generated catch block
          e.printStackTrace();
        }
      }

    }

  }

}

5.5.5、测试类

package dao.impl;


import dao.IUserDAO;
import dao.utils.DaoUtils;
import domain.User;
import java.sql.SQLException;
import java.util.List;
import org.junit.Test;

/**
 * @author Xiao_Lin
 * @date 2021/1/2 20:11
 */
public class UserDAOImplTest {
  IUserDAO userDAO = new UserDAOImpl();
  @Test
  public void insert() {
    userDAO.insert(new User("ghy","123"));

  }

  @Test
  public void delete() {
    userDAO.delete(14);
  }

  @Test
  public void update() {
    userDAO.update(new User(1,"张三","666"));
  }

  @Test
  public void selectAll() {
    List<User> users = userDAO.selectAll();
    users.forEach(System.out::print);
  }

  @Test
  public void selectUserById() {
    User user = userDAO.selectUserById(1);
    System.out.println(user);
  }
}

六、操作BLOB类型字段

6.1、BLOB类型简介

    MySQL中,BLOB是一个二进制大型对象,是一个可以存储大量数据的容器,它能容纳不同大小的数据。**插入BLOB类型的数据必须使用PreparedStatement,因为BLOB类型的数据无法使用字符串拼接写的。**MySQL有四种BLOB类型,他们除了在存储的最大信息量上不同外,除此之外他们是等同的。

    如果在指定了相关的Blob类型以后,还报错:xxx too large,那么在mysql的安装目录下,找my.ini文件加上如下的配置参数: max_allowed_packet=16M。同时注意:修改了my.ini文件之后,需要重新启动mysql服务。

在这里插入图片描述

6.2、插入BLOB类型

//获取连接
Connection conn = JDBCUtils.getConnection();
		
String sql = "insert into customers(name,email,birth,photo)values(?,?,?,?)";
PreparedStatement ps = conn.prepareStatement(sql);

// 填充占位符
ps.setString(1, "张三");
ps.setString(2, "zs@126.com");
ps.setDate(3, new Date(new java.util.Date().getTime()));
// 操作Blob类型的变量
FileInputStream fis = new FileInputStream("zs.png");
ps.setBlob(4, fis);
//执行
ps.execute();
		
fis.close();
JDBCUtils.closeResource(conn, ps);

6.3、修改BLOB类型

Connection conn = JDBCUtils.getConnection();
String sql = "update customers set photo = ? where id = ?";
PreparedStatement ps = conn.prepareStatement(sql);

// 填充占位符
// 操作Blob类型的变量
FileInputStream fis = new FileInputStream("coffee.png");
ps.setBlob(1, fis);
ps.setInt(2, 25);

ps.execute();

fis.close();
JDBCUtils.closeResource(conn, ps);

6.4、从数据库表中读取BLOG类型

String sql = "SELECT id, name, email, birth, photo FROM customer WHERE id = ?";
conn = getConnection();
ps = conn.prepareStatement(sql);
ps.setInt(1, 8);
rs = ps.executeQuery();
if(rs.next()){
	Integer id = rs.getInt(1);
    String name = rs.getString(2);
	String email = rs.getString(3);
    Date birth = rs.getDate(4);
	Customer cust = new Customer(id, name, email, birth);
    System.out.println(cust); 
    //读取Blob类型的字段
	Blob photo = rs.getBlob(5);//这里也可以通过列的索引来读取
	InputStream is = photo.getBinaryStream();
	OutputStream os = new FileOutputStream("c.jpg");
	byte [] buffer = new byte[1024];
	int len = 0;
	while((len = is.read(buffer)) != -1){
		os.write(buffer, 0, len);
	}
    JDBCUtils.closeResource(conn, ps, rs);
		
	if(is != null){
		is.close();
	}
		
	if(os !=  null){
		os.close();
	}
    
}

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。