MySQL基本语法及与JAVA程序建立连接
题目:现在运营想查看所有大学中带有"北京"的用户的信息(device_id,age,university),请你取出相应数据。
示例:用户信息表:user_profile
查看学校名称中含北京的用户_牛客题霸_牛客网
这里查找的是模糊信息,因为不是一个确定的具体的信息,所以查询时不能使用=来比较。
在 SQL 中,LIKE
运算符结合通配符 %
和 _
可以实现模糊查询,用于匹配符合特定模式的字符串。它们的使用场景和规则如下:%用于匹配任意长度的字符串(包括 0 个字符),_用于匹配单个字符。
通过 LIKE
配合 %
和 _
,可以灵活实现各种模糊匹配需求,例如搜索用户名、筛选包含特定关键词的内容等。但是模糊查询(尤其是 %
开头的模式,如 '%abc'
)可能会导致索引失效,不适合在大数据量的表中频繁使用。
题解 | 查看学校名称中含北京的用户_牛客网
题目:现在运营想要找到gpa在3.5以上(不包括3.5)的山东大学用户 或 gpa在3.8以上(不包括3.8)的复旦大学同学进行用户调研,请你取出相应数据,取出的数据按照device_id升序排列
操作符混合运用_牛客题霸_牛客网
先选出gpa在3.5以上(不包括3.5)的山东大学学生和gpa在3.8以上(不包括3.8)的复旦大学同学,然后按照device_id排序即可,虽然牛客上面标的是中等,但其实还是比较简单。
题解 | 操作符混合运用_牛客网
在一张daily_profits表中,存储了公司每天的利润记录。请计算每一种产品每一天的累计利润,并按profit_date升序输出所有字段。
具体要求如下:
- 计算每一天的累计利润。
- 输出结果按profit_date升序排列。
计算每日累计利润_牛客题霸_牛客网
这题最麻烦的地方就是要算出每个profit的累加和,单单凭借sum是无法做到求累加和,遇到求累加问题的时候常常将SUM()配合OVER()和ORDER BY用。
SUM() OVER()
用于计算累加和或分组汇总,但它不像 GROUP BY
那样会合并行,而是为每一行返回汇总结果,同时保留所有原始行的详细信息。它属于 窗口函数,在保留原数据细节的基础上,添加汇总信息。
注意OVER(ORDER BY profit_date)
的作用是:
先按日期排序,再从第一条记录开始,逐行扩大窗口范围,最终实现 “按时间顺序累计” 的效果。如果去掉 ORDER BY profit_date
,写成 SUM(profit) OVER()
,那么窗口范围会变成所有行(整个表的数据),此时计算的就不是 “累计”,而是“所有记录的总利润”。这显然不符合 “累计到当日” 的需求。
然后再将这个值作为cumulative_profit进行输出,最后按照profit_date进行排序。
题解 | 计算每日累计利润_牛客网
题目:现在运营想要分别查看学校为山东大学或者性别为男性的用户的device_id、gender、age和gpa数据,请取出相应结果,结果不去重。
查找山东大学或者性别为男生的信息_牛客题霸_牛客网
题目要求查询的对象是山东大学学生或者性别为男的用户,并先输出山东大学的然后输出性别为男性的。那么就可以使用关键字UNION来拼接,先输出山东大学的然后去拼接性别为男的,但是单单使用UNION是不够的,因为它还会帮我们多做一件事:去除重复。题目不让我们去除重复,所以得用UNION ALL,直接将结果合并。并且UNION需要额外的去重操作(类似 DISTINCT
),会消耗更多的计算资源和时间;而 UNION ALL 只是简单拼接结果,性能更好。
牛客网 - 找工作神器|笔试题库|面试经验|实习招聘内推,求职就业一站解决_牛客网
了解一些基本操作后,还有一个问题,有这么多的数据要在数据库中管理,那么如何建立数据库和JAVA程序的联系呢?
为了方便,先创建一个DBUtil类专门用来创建连接,不过需要先知道本地数据库服务器的地址。
public class DBUtil {static {try {Class.forName("com.mysql.cj.jdbc.Driver");} catch (ClassNotFoundException e) {e.printStackTrace();}}public static Connection getConnection() throws SQLException {/*** 建立连接*/return DriverManager.getConnection(//服务器地址"jdbc:mysql://localhost:3306/tedu?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true","root",//账户"1234"//密码);}
}
创建好这个类后,就可以根据这个类来建立连接。现在尝试完成一个登录数据库的业务。
先让用户输入用户名和密码,然后建立和数据库的连接,写出SQL语句用一个字符串保存,随后执行这个SQL语句。在SQL语句中需要选出username和password,再和用户输入的进行比较,如果移动成功(存在下一行数据),返回true,登录成功;如果已到达结果集末尾(没有更多数据),返回false,登录失败。建立连接的这个操作,应该放到try括号里面,因为使用的是 try-with-resources 语法(Java 7 引入的特性),编译器会自动在代码块结束后(无论正常执行还是抛出异常)调用资源的 close()
方法,这是一种优雅的资源管理方式。
public class LoginUser {public static void main(String[] args) {System.out.println("请输入用户名");Scanner scanner = new Scanner(System.in);String inputName=scanner.nextLine();System.out.println("请输入密码");String inputCode=scanner.nextLine();try (Connection connection = DBUtil.getConnection();){Statement statement = connection.createStatement();String sql="SELECT username,password "+"FROM user "+"WHERE username='"+inputName+"' AND password='"+inputCode+"'";ResultSet rs=statement.executeQuery(sql);if(rs.next()){System.out.println("登录成功");}elseSystem.out.println("登录失败");}catch (SQLException e){e.printStackTrace();}}
}
数据库里面有这几个用户,现在登录试试
当用户名和密码都输入正确的时候就会登录成功。
现在随便输入一个不存在的用户名,再输入以下密码:a' OR '1'='1,会发现居然莫名其妙登录进去了。
这种现象称为SQL 注入攻击,具体来说是利用了 SQL 语句拼接的漏洞,让恶意构造的密码字符串改变了原有的查询逻辑。用户输入的密码会被SQL简单替换为AND password='a' OR '1'='1',不管正确密码是不是字符a,反正OR后面的字符1=字符1一定成立,所以就会登录成功。SQL 注入攻击是 Web 应用中最危险的漏洞之一,其危害不仅限于 “越权登录”,还可能对数据安全、系统稳定性甚至业务连续性造成严重打击。
因此,防范 SQL 注入是 Web 应用安全的 “重中之重”,核心手段是使用预编译语句PreparedStatement,
预编译语句会将 SQL 结构与用户输入分离,自动处理特殊字符,从根本上防止注入。先将带有占位符(?
)的 SQL 结构发送给数据库,数据库提前解析并编译该结构,确定语法、生成执行计划;此时数据库已知晓 SQL 的 固定结构,占位符 ?
仅表示此处将填入数据。再将用户输入作为 纯参数 传递给数据库,数据库会将参数严格按照数据类型填充到占位符中,不会重新解析 SQL 结构。即使用户输入包含单引号(')、关键字(OR
)等特殊字符,数据库也只会将其视为 “字符串的一部分”,而非 SQL 语法的一部分。
public class jdbcDemo7 {public static void main(String[] args) {System.out.println("请输入用户名");Scanner scanner = new Scanner(System.in);String inputName=scanner.nextLine();System.out.println("请输入密码");String inputCode=scanner.nextLine();try(Connection connection = DBUtil.getConnection();){String sql="SELECT id,username,password,age "+"FROM user "+"WHERE username=? AND password=?";//先将预编译SQL语句发送给数据库PreparedStatement ps=connection.prepareStatement(sql);ps.setString(1,inputName);ps.setString(2,inputCode);ResultSet rs=ps.executeQuery();if(rs.next()){System.out.println("登录成功");}else{System.out.println("登录失败");}}catch (SQLException e){e.printStackTrace();}}
}
这样一来,即使输入a' OR '1'='1也不会出现异常登录的情况。
采用预编译SQL不仅能彻底防止 SQL 注入,避免数据泄露、越权等安全事故,还可以缓存执行计划,减少重复解析 / 编译开销,提升高频 SQL 的执行效率,所有涉及用户输入的 SQL 操作(如登录、查询、提交表单)都必须使用预编译 SQL。