首页 > 数据库 >【JDBC】使用PreparedStatement操作数据库

【JDBC】使用PreparedStatement操作数据库

时间:2022-11-14 19:33:21浏览次数:73  
标签:JDBC String rs 数据库 SQL PreparedStatement user sql password

1.对数据库调用的不同方式

java.sql包下有3个接口
image

  • Statement:用于执行静态SQL语句。
  • PreparedStatement:SQL语句被预编译并存储在此对象中。
  • CallableStatement:用于执行SQL存储过程。

image

2.使用Statement操作数据库

获取到connect对象后,创建statement对象,执行sql

Statememt st = connect.createStatememt();
ResultSet rs = st.executeQuery("select * from table");

(1)使用Statememt操作表的弊端

  • 对于有参数的SQL语句需要拼串。
String sql = "SELECT user,password FROM user_table WHERE USER = '" + userName
+ "' AND PASSWORD = '" + password
+ "'";
  • 存在SQL注入问题

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

public class StatementTest {
    @Test
    public void login(){
        Scanner scanner = new Scanner(System.in);
        System.out.println("用户名:");
        String userName = scanner.nextLine();
        System.out.println("密 码:");
        String password = scanner.nextLine();

        String sql = "SELECT user,password FROM user_table WHERE user = '"+userName+"' AND password = '"+password+"'";
        User user = getUser(sql, User.class);
        if (user!=null){
            System.out.println("登录成功!");
        }else {
            System.out.println("用户名或密码错误!");
        }
    }

    public <T> T getUser(String sql,Class<T> clazz){
        //放到外面是因为在finally中要用
        T t = null;
        Connection connect = 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.获取连接
            connect = DriverManager.getConnection(url, user, password);

            //5.创建statement对象
            st = connect.createStatement();

            //6.执行sql,得到结果集
            rs = st.executeQuery(sql);

            //7.获取结果集的元数据
            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.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 {
		//关闭资源
		JDBCUtils.closeResource(conn, ps, rs);
	}
	return null;
	}
}

3.ResultSet和ResultSetMetaData

(1)ResultSet

执行executeQuery()方法返回结果集,是一个ResultSet对象,相当于一张数据表,有一个指针指向第一行记录。使用next()方法检测下一行是否有效,若有效返回true并移动到下一行。相当于Iterator对象的hasNext()和next()方法的结合体。
当指向一行时,通过索引或列名获取该列的值。getInt(1),getString("name")

Java与数据库交互涉及到的相关Java Api中的索引都从1开始。

image

(2)ResultSetMetaData

用于获取ResultSet对象中列的类型和属性信息的对象

ResultSetMetaData rsmd = resultSet.getMetaData();

常用方法

getColumnName(int column);	//获取指定列名称
getColumnLabel(int column);	//获取指定列别名,没有别名则获取列名
getColumnCount();	//有多少列
getColumnTypeName(int column);	//列的数据库类型名称
getColumnDisplaySize(int column); 	//列的最大标准宽度,以字符为单位
isNullable(int column);	//列中的值是否可以为null
isAutoIncrement(int column);	//是否为指定列进行自动编号

例如表结构
image

SQL语句为,如果balance不选,则columnCount为2

SELECT user,password,balance FROM user_table WHERE user = 'AA' AND password = '123456'

image

两者之间的联系
image

4.PrepareStatement操作数据库

image

PrepareStatement是Statement的子接口。

public interface PreparedStatement extends Statement

获取对象,表示一条预编译过的SQL语句

PrepareStatement ps = connect.prepareStatement(sql);

SQL语句中的参数用英文问号表示,调用prepareStatement对象的setXxx(1,value)方法设置这些参数,1表示索引(从1开始),value表示值。

    @Test
    public void login(){
        Scanner scanner = new Scanner(System.in);
        System.out.print("请输入用户名:");
        String user = scanner.nextLine();
        System.out.print("请输入密码:");
        String password = scanner.nextLine();

//        String sql = "SELECT user,password FROM user_table WHERE user = ? AND password = ? ";
        String sql = "SELECT user,password FROM user_table WHERE user = ? and password = ?;";
        User returnUser = getUser(User.class, sql, user, password);
        if (returnUser!=null){
            System.out.println("登录成功");
        }else {
            System.out.println("用户名或密码错误");
        }
    }

    public <T> T getUser(Class<T> clazz,String sql,Object... args){
        Connection connect = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            connect = JDBCUtil.getConnection();
            ps = connect.prepareStatement(sql);
            //遍历参数并设置值
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i+1,args[i]);
            }
            //ps.execute();//增删改执行这个
            rs = ps.executeQuery();     //产生单个结果集
            ResultSetMetaData rsmd = rs.getMetaData();
            int columnCount = rsmd.getColumnCount();
            if (rs.next()){
                T t = clazz.newInstance();
                for (int i = 0; i < columnCount; i++) {

                    Object columnValue = rs.getObject(i + 1);   //列值
                    String columnLabel = rsmd.getColumnLabel(i + 1);    //列别名

                    //通过反射获取对象属性
                    Field field = clazz.getDeclaredField(columnLabel);

                    //允许客户端拥有超级权限,不会去检查Java语言权限控制(private之类的)
                    field.setAccessible(true);
                    field.set(t,columnValue);      //给对象t的属性设值
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JDBCUtil.closeResource(connect,ps,rs);
        }
        return null;
    }

5.其他

(1)ORM思想

  • 一张数据库表对应一个Java类
  • 表中的一条记录对应Java类的一个对象
  • 表中的一个字段对应Java类的一个属性

写sql时注意别名

(2)Java与SQL对应数据类型

Java类型 SQL类型
boolean BIT
byte TINYINT
short SMALLINT
int INTEGER
long BIGINT
String CHAR,VARCHAR,LONGVARCHAR
byte array BINARY,VAR BINARY
java.sql.Date DATE
java.sql.Time TIME
java.sql.Timestamp TIMESTAMP

(3)PrepareStatement的好处

① 可以防止SQL注入
② 预编译SQL语句可以重复使用,不同参数也不用重新编译(Statement每次执行都需要)
③ 不需要拼串

参考
1.field.setAccessible(true) 简介
2.PreparedStatement是如何防止SQL注入的?

标签:JDBC,String,rs,数据库,SQL,PreparedStatement,user,sql,password
From: https://www.cnblogs.com/zhishu/p/16874755.html

相关文章

  • Asterisk realtime 之SIP用户动态写入mysql 数据库(2)
    提供通信服务器和客户端解决方案,包括视频电话,调度系统,会议系统等VOIP行业资讯和技术趋势请参考:www.voip123.cn接上一篇文章,SIP用户写入mysql数据库,asterisk自动查找数......
  • 【网关开发】3.openresty lua使用lmdb数据库
    背景网关的高可用是比较重要的内容,即使etcd数据库挂掉,也可以根据现有的数据提供负载均衡应用所以采用几级缓存的形式cache-->lmdb-->etcd这里使用的是kong提供的插件......
  • NodeJS搭建简易的后台服务(连接MSSQL数据库)
    一、环境搭建去官网NodeJS下载,这个同时还附带好用的包管理器NPM,方便后续下载管理各种包。一路安装完毕后,我们来创建自己的第一个应用。NodeJS是在服务器上执行的JS脚本,......
  • Oracle 数据库 19c Home 克隆
             众所周知,oracle数据库软件堆栈以部署起来复杂而著称,早期oracle8i/9i/10g/11g时代,数据库软件环境部署占据dba相当大的工作量,稍不慎很容易部署失败,造......
  • TDSQL携手金蝶云·苍穹,发布“国产数据库联合解决方案”
    11月11日,腾讯云数据库与金蝶云·苍穹发布“国产数据库联合解决方案”,腾讯云数据库全面支持苍穹平台的技术与应用设计,通过一体化的“PaaS+SaaS”解决方案,一站式解决企业国......
  • spring boot 微服务在进行数据库操作时总是报错Connections reset
    在前端对后台进行数据请求时,访问二,三次后台服务器就报Connectionreset必须重启后才能进行再次访问。最后发现在配置文件中添加如下:spring:r2dbc:pool:ma......
  • sqlserver数据库 去除字段中空格,换行符,回车符
    使用REPLACE函数:特殊字符在SqlServerManagementStudio查询中显示为空格,但实际不是空格。在C#中能清晰的看到类似:\r\n的字符.​SQL中可以使用Replace函数来对某个字段里的......
  • 巨蟒python全栈开发数据库前端8:jQuery框架2
    数据可视化推荐网站(都是JavaScript写的):​​echart网站:​​​​https://echarts.baidu.com/​​聚宽网站我们要多用心也是可以做前端的!!! 回顾:1.jquery介绍2.jq......
  • Oracle数据库,笔录!
    Oracle数据库,PL/SQL编程笔录PL/SQL:是Oracle对SQL语言过程的程序化拓展基本语法结构:[declare...声明变量]begin...程序块[Exception......
  • 第三章 关系数据库标准语言SQL
    3.1SQL概述(略)3.2学生-课程数据库3.3数据定义数据库>模式>表、视图和索引一个数据库管理系统的实例中可以建立多个数据库,一个数据库中可以建立多个模式,一个模......