我们可以使用JDBC查询来执行select语句。

1. Statement

    try(Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)){
try(Statement stmt = conn.getStatement()){
try(ResultSet rs = stmt.executeQuery("select * from students where gender=\'M\'")){
while(rs.next()){
long id = rs.getLong(1); //注意:索引从1开始
long classId = rs.getLong(2);
String name = rs.getString(3);
String gender = rs.getString(4);
}
}
}
}

2. SQL注入:

使用Statement拼字符串很容易引发SQL注入的问题。这是因为SQL的参数往往是方法参数传入的。例如一个Login方法需要传入用户名、密码来查询对应的一行user的记录。

User login(String name, String pass){
...
stmt.executeQuery("select * from user where login ='"+name+"' and pass='"+pass+"'"); //select * from user where login = ' ' and pass = '';
...
}

如果用户输入的是程序期待的值,就可以拼出一个正确的SQL。

-- name="Bob", pass="1234"
select * from user where login = 'Bob' and pass = '1234';

但是如果用户输入的是一个精心构造的字符串,就可能拼出意想不到的SQL。这个SQL也是正确的,但它查询的条件并不是设定的意图。

```#sql
-- name = "Bob' or pass=" , pass=" or pass=' "
select * from user where login = 'Bob' or pass=' and pass=' or pass='';
```
## 3 PrepareStatement
为了避免SQL注入,我们要使用PreparedStatement
```#java
User login(String name, String pass){
...
PreparedStatement ps = conn.prepareStatement("select * from user where login = ? and pass=?");
ps.setObject(1, name);//注意,索引从1开始
ps.setObject(2, pass);
...
}
```
始终使用?作为占位符,并把数据连同SQL本身传给数据库,使用PreparedStatement可以保证每次传给数据库的SQL语句都是相同的,只是占位符的数据不同,这样它可以高效利用数据库本身对查询的缓存。所以PreparedStatement比Statement更快更安全。
### 3.1 如何使用PreparedStatement
```#java
try(Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)){
try(PreparedStatment ps = conn.prepareStatement("select * from student where gender = ?")){
ps.setObject(1, "M");
try(ResultSet rs = ps.executeQuery()){
while(rs.next()){
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
}
}
}
}
```
## 4 代码示例
### 4.1 SQL文件init.sql
```#sql
SET NAMES utf8mb4;

-- init tables:

DROP TABLE IF EXISTS students;

DROP TABLE IF EXISTS classes;

-- 指定存储引擎是innodb引擎,表编码是utf8mb4

CREATE TABLE classes (

id BIGINT NOT NULL AUTO_INCREMENT,

name VARCHAR(10) NOT NULL,

PRIMARY KEY (id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE students (

id BIGINT NOT NULL AUTO_INCREMENT,

class_id BIGINT NOT NULL,

name VARCHAR(10) NOT NULL,

gender CHAR(1) NOT NULL,

CONSTRAINT fk_class_id FOREIGN KEY (class_id) REFERENCES classes (id),

PRIMARY KEY (id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- init data:

INSERT INTO classes (name) VALUES ('一班');

INSERT INTO classes (name) VALUES ('二班');

INSERT INTO classes (name) VALUES ('三班');

INSERT INTO classes (name) VALUES ('四班');

INSERT INTO students (class_id, name, gender) VALUES (1, '小明', 'M');

INSERT INTO students (class_id, name, gender) VALUES (1, '小红', 'F');

INSERT INTO students (class_id, name, gender) VALUES (1, '小军', 'M');

INSERT INTO students (class_id, name, gender) VALUES (2, '小白', 'F');

INSERT INTO students (class_id, name, gender) VALUES (2, '小兵', 'M');

INSERT INTO students (class_id, name, gender) VALUES (3, '小王', 'M');

INSERT INTO students (class_id, name, gender) VALUES (3, '小丽', 'F');

###    4.2 执行sql脚本
方法一:打开sh,执行
```#shell
#将init.sql脚本复制到容器内
docker cp init.sql 2202eecd49c9:/home/
docker exec -it csjmysql0828 sh;
mysql -u root -p test0828 < init.sql

方法二:通过Navicat执行:

选择数据库模式,如test0828,选择运行SQL文件

Student.java

package com.feiyangedu.sample.pop3;

public class Student {
public long id;
public long classId;
public String name;
public String gender;
public Student(){}
public Student(long id, long classId,String name,String gender){
this.id = id;
this.classId = classId;
this.name = name;
this.gender = gender;
}
public Student(long classId,String name,String gender){
this.classId = classId;
this.name = name;
this.gender = gender;
}
@Override
public String toString(){ //用于打印Student对象,如<Student id=7,class_id=3,name=小丽,gender=F>
return "<Student id="+id+",class_id="+classId+",name="+name+",gender="+gender+">";
}
}

4.3 获取Student内容JdbcSelect.java

package com.feiyangedu.sample.pop3;

import java.sql.*;
import java.util.ArrayList;
import java.util.List; public class JdbcSelect {
static final String JDBC_URL="jdbc:mysql://localhost:13306/test0828?useSSL=false&characterEncoding=utf8&serverTimeZone=UTC";
static final String JDBC_USER="root";
static final String JDBC_PASSWORD="123456";
public static void main(String[] args) throws Exception{
List<Student> students = getAllStudent();
for(Student student:students){
System.out.println(student);
}
System.out.println( );
for(long i=1;i<=4;i++){
List<Student> list = getStudentsOfClass(i);
System.out.println("Students of class "+i+":");
for(Student student:list){
System.out.println(student);
}
}
}
static List<Student> getAllStudent() throws SQLException{
try(Connection conn = getConnection()){
try(PreparedStatement ps = conn.prepareStatement("select * from students")){
try(ResultSet rs = ps.executeQuery()){
List<Student> list = new ArrayList<>();
while(rs.next()){
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");
String gender = rs.getString("gender");
Student std = new Student(id,classId,name,gender);
list.add(std);
}
return list;
}
}
}
}
static List<Student> getStudentsOfClass(long thrClassId) throws SQLException{
try(Connection conn = getConnection()){
try(PreparedStatement ps = conn.prepareStatement("select * from students where class_id = ?")){
ps.setObject(1,thrClassId);
try(ResultSet rs = ps.executeQuery()){
List<Student> list = new ArrayList<>();
while(rs.next()){
long id = rs.getLong("id");
long classId = rs.getLong("class_id");
String name = rs.getString("name");;
String gender = rs.getString("gender");
Student std = new Student(id,classId,name,gender);
list.add(std);
}
return list;
}
}
}
}
static Connection getConnection() throws SQLException{
return DriverManager.getConnection(JDBC_URL,JDBC_USER,JDBC_PASSWORD);
}
}

4.4 获取计数JdbcSelect2.java

package com.feiyangedu.sample.pop3;

import java.sql.*;

public class JdbcSelect2 {
static final String JDBC_URL = "jdbc:mysql://localhost:13306/test0828?useSSL=false&characterEncoding=utf-8&serverTimeZone=UTC";
static final String JDBC_USER = "root";
static final String JDBC_PASSWORD = "123456";
public static void main(String[] args) throws Exception{
for(int i=1;i<=4;i++){
System.out.println(getNumOfStudent(i));
}
} static long getNumOfStudent(long classId) throws SQLException{
try(Connection conn = getConnection()){
try(PreparedStatement ps = conn.prepareStatement("select count(*) num from students where class_id = ?")){
ps.setObject(1,classId);
try(ResultSet rs = ps.executeQuery()){
while(rs.next()){
long num = rs.getLong("num");
return num;
}
throw new RuntimeException("Empty result set");
}
}
}
}
static Connection getConnection() throws SQLException{
return DriverManager.getConnection(JDBC_URL,JDBC_USER,JDBC_PASSWORD);
}
}

5 JDBC查询总结

使用Statement(不推荐)和PrepareStatement(推荐)进行查询

  • 总是优先使用PrepareStatement
  • 查询结果是ResultSet

廖雪峰Java15JDBC编程-3JDBC接口-2JDBC查询的更多相关文章

  1. 廖雪峰Java15JDBC编程-3JDBC接口-5JDBC连接池

    1. JDBC连接池 1.1 JDBC连接池简介 线程池可以复用一个线程,这样大量的小任务通过线程池的线程执行,就可以避免反复创建线程带来的开销. 同样JDBC可以复用一个JDBC连接 JDBC的连接 ...

  2. 廖雪峰Java15JDBC编程-3JDBC接口-4JDBC事务

    1 数据库事务:Transaction 1.1 定义 若干SQL语句构成的一个操作序列 要么全部执行成功 要么全部执行不成功 1.2 数据库事务具有ACID特性: Atomicity:原子性 一个事务 ...

  3. 廖雪峰Java15JDBC编程-3JDBC接口-1JDBC简介

    JDBC:Java DataBase Connectivity Java程序访问数据库的标准接口 使用Java程序访问数据库的时候,Java代码并不是直接通过TCP连接去访问数据库,而是通过JDBC接 ...

  4. 廖雪峰Java15JDBC编程-3JDBC接口-3JDBC更新

    使用update语句的时候,需要通过JDBC实现update语句的执行,这个时候仍然通过PreparedStatement对象来使用,直接传入update语句,然后通过setObject传入占位符的值 ...

  5. 廖雪峰Java15JDBC编程-2SQL入门-2insert/select/update/delete

    1. INSERT用于向数据库的表中插入1条记录 insert into 表名 (字段1,字段2,...) values (数据1,数据2,数据3...) 示例 -- 如果表存在,就删除 drop t ...

  6. 廖雪峰Java15JDBC编程-2SQL入门-1SQL介绍

    1.SQL:结构化查询语言 Structured Query Language 针对关系数据库设计 各种数据库基本一致 允许用户通过SQL查询数据而不关心数据库底层存储结构 1.1 SQL使用: 可以 ...

  7. 廖雪峰Java15JDBC编程-1关系数据库基础-1关系数据库简介

    1.数据库 1.1 定义 数据库是按照数据结构来组合.存储和管理数据的软件. 1.2 数据库模型 数据库有层次模型.网状模型.关系模型三种模型. 2 关系数据库 关系数据库是建立在关系模型上的数据库, ...

  8. 廖雪峰Java6IO编程-1IO基础-1IO简介

    1.IO简介 IO是指Input/Output,即输入和输出: Input指从外部读取数据到内存,例如从磁盘读取,从网络读取. * 为什么要把数据读到内存才能处理这些数据呢? * 因为代码是在内存中运 ...

  9. 廖雪峰Java6IO编程-2input和output-1inputStream

    1.InputStream 1.1InputStream是所有输入流的超类: int read() * 读取下一个字节,并返回字节(0-255) * 如果已读到末尾,返回-1 * read()方法是阻 ...

随机推荐

  1. CSS3:CSS3 背景

    ylbtech-CSS3:CSS3 背景 1.返回顶部 1. CSS3 背景 CSS3 背景 CSS3中包含几个新的背景属性,提供更大背景元素控制. 在本章您将了解以下背景属性: background ...

  2. canvas前端压缩图片和视频首屏缩略图并上传到服务器

    图片: var img = document.createElement('img') img.src = window.URL.createObjectURL(fileObj.file) // 加载 ...

  3. codeforces round#524 D - Olya and magical square /// 大概算是数学规律题?

    题目大意: t 个测试用例  (1≤t≤103) 给定n k  (1≤n≤10^9,1≤k≤10^18) 表示有一个边长为2^n的正方形格子 每次操作只能将一个格子切割为左上左下右上右下的四等分格子 ...

  4. 如何读懂Web服务的系统架构图

    Web服务的一个重要特点就是流量大.数据多,仅靠一台服务器肯定难以支撑大规模的服务. 所以我们经常会看到诸如以下的一些术语,教人好生不懂: *:系统架构.物理架构.Web服务基础设施 *:应用服务器 ...

  5. CSS Sprites(CSS图像拼合技术)教程、工具集合

    本集合是有一位国外设计师收集整合,并由 oncoding翻译成中文的,感谢他们的辛苦贡献.CSS Sprites技术在国外并不是什么新技术,只不过近两年(尤其08年开始)中国开始流行这个词,大家也开始 ...

  6. iOS组件化开发-发布私有库

    远程索引库 将远程索引库添关联到本地 pod repo 查看本地已关联仓库源 pod repo add 本地索引库名称 远程索引库仓库地址 pod repo update 索引库名称 pod repo ...

  7. GNU 交叉工具链的介绍与使用

    常用工具介绍 名称 归属 作用 arm­linux­as binutils 编译 ARM 汇编程序 arm­linux­ar binutils 把多个.o 合并成一个.o 或静态库(.a) arm­l ...

  8. vue SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode

    在使用vue_cli时出现如下错误: 原因是  node  版本太低 应该升级

  9. not registered via @EnableConfigurationProperties or marked as Spring component

    利用@ConfigurationProperties(prefix = "")来绑定属性时报错: not registered via @EnableConfigurationPr ...

  10. matplotlib 画图颜色参数值及对应色卡

     matplotlib 色卡对应参数值 cnames = { 'aliceblue': '#F0F8FF', 'antiquewhite': '#FAEBD7', 'aqua': '#00FFFF', ...