JDBC
1、简介
JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成。JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序。
Java 具有坚固、安全、易于使用、易于理解和可从网络上自动下载等特性,是编写数据库应用程序的杰 出语言。所需要的只是 Java应用程序与各种不同数据库之间进行对话的方法。
JDBC可以在各种平台上使用Java,如Windows,Mac OS和各种版本的UNIX。 JDBC库包括通常与数据库使用相关的下面提到的每个任务的API。
- 连接数据库。
- 创建SQL或MySQL语句。
- 在数据库中执行SQL或MySQL查询。
- 查看和修改生成的记录。
2、JDBC体系结构
JDBC API支持用于数据库访问的两层和三层处理模型,但通常,JDBC体系结构由两层组成:
- JDBC API:这提供了应用程序到JDBC管理器连接。
- JDBC驱动程序API:这支持JDBC管理器到驱动程序连接。
JDBC API使用驱动程序管理器和特定于数据库的驱动程序来提供与异构数据库的透明连接。
3、JDBC核心组件
DriverManager: 此类管理数据库驱动程序列表。使用通信子协议将来自java应用程序的连接请求 与适当的数据库驱动程序匹配。
Driver:此接口处理与数据库服务器的通信,我们很少会直接与Driver对象进行交互。而是使用 DriverManager对象来管理这种类型的对象。
Connection:该界面具有用于联系数据库的所有方法。连接对象表示通信上下文,即,与数据库 的所有通信仅通过连接对象。
Statement:使用从此接口创建的对象将SQL语句提交到数据库。除了执行存储过程之外,一些派 生接口还接受参数。
ResultSet:在使用Statement对象执行SQL查询后,这些对象保存从数据库检索的数据。它作为一 个迭代器,允许我们移动其数据。
SQLException:此类处理数据库应用程序中发生的任何错误。
4、CRUD语法介绍
SQL 是一种标准化的语言,它允许你在数据库上执行操作,如创建项目,查询内容,更新内容,并删除条目等操作。
Create, Read, Update, and Delete 通常称为CRUD操作。
详细语法请看:
4.1 查询
import java.sql.*;
public class Demo1 {
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
// executeQuery(sql)执行查询
resultSet = statement.executeQuery("select * from emp2");
//4. 取出结果集信息
// 判断是否有下一条数据
while (resultSet.next()) {
// 取出数据: resultSet.getXXX("列名"); xxx表示数据类型
System.out.println("姓名:" + resultSet.getString("ename")+",工资:"+
resultSet.getDouble("sal")+",雇佣日期:"+resultSet.getDate("hiredate"));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
4.2 插入|修改|删除
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
// 返回结果为受影响的行数 executeUpdate(sql)执行增删改时使用
// 插入一行数据
int result = statement.executeUpdate("insert into emp2(ename,hiredate,sal) values('aa','2021-1-1',2000)");
// 修改
int result = statement.executeUpdate("update emp2 set sal=8888");
// 删除
int result = statement.executeUpdate("delete from emp2 where ename='aa'");
//4. 取出结果集信息
if (result>0) {
System.out.println("执行成功!");
} else {
System.out.println("执行失败!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
5、使用步骤
构建JDBC应用程序涉及以下六个步骤:
- 导入包:需要包含包含数据库编程所需的JDBC类的包。大多数情况下,使用import java.sql.*就足够 了。
- 注册JDBC驱动程序:要求初始化驱动程序,以便可以打开与数据库的通信通道。
- 打开连接:需要使用DriverManager.getConnection()方法创建一个Connection对象,该对象表 示与数据库的物理连接。
- 执行查询:需要使用类型为Statement的对象来构建和提交SQL语句到数据库。
- 从结果集中提取数据:需要使用相应的ResultSet.getXXX()方法从结果集中检索数据。
- 释放资源:需要明确地关闭所有数据库资源,而不依赖于JVM的垃圾收集。
6、JDBC链接步骤
建立JDBC连接所涉及的编程相当简单。这是简单的四个步骤
- 导入JDBC包:将Java语言的import语句添加到Java代码中导入所需的类。
- 注册JDBC驱动程序:此步骤将使JVM将所需的驱动程序实现加载到内存中,以便它可以满足您的JDBC 请求。
- 数据库URL配置:这是为了创建一个格式正确的地址,指向要连接到的数据库。
- 创建连接对象:最后,调用DriverManager对象的getConnection()方法来建立实际的数据库连 接。
Class.forName();
注册驱动程序最常见的方法是使用Java的Class.forName()方法,将驱动程序的类文件动态加载到内存 中,并将其自动注册。
try {
Class.forName("com.mysql.cj.jdbc.Driver");
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
DriverManager.registerDriver()
第二种方法是使用静态DriverManager.registerDriver()方法。
try {
Driver myDriver = new com.mysql.cj.jdbc.Driver();
DriverManager.registerDriver( myDriver );
}catch(ClassNotFoundException ex) {
System.out.println("Error: unable to load driver class!");
System.exit(1);
}
数据库URL配置
加载驱动程序后,可以使用DriverManager.getConnection()方法建立连接。为了方便参考,列出三个重载的DriverManager.getConnection()方法
- getConnection(String url)
- getConnection(String url,Properties prop)
- getConnection(String url,String user,String password)
创建数据库连接对象
String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC";
String USER = "username";
String PASS = "password"
Connection conn = DriverManager.getConnection(URL, USER, PASS);
完整的连接地址:
版本1:
jdbc:mysql://localhost:3306/数据库名?
useSSL=false&useUnicode=true&characterEncoding=UTF-8
版本2:
jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC
使用数据库URL和属性对象
DriverManager.getConnection()方法的第三种形式需要一个数据库URL和一个Properties对象
DriverManager.getConnection()方法的第三种形式需要一个数据库URL和一个Properties对象 -
import java.util.*;
String URL = "jdbc:mysql://localhost:3306/yhp2?serverTimezone=UTC";
Properties info = new Properties( );
info.put( "user", "username" );
info.put( "password", "password" );
Connection conn = DriverManager.getConnection(URL, info);
关闭数据库连接
为确保连接关闭,您可以在代码中提供一个“finally”块。一个finally块总是执行,不管是否发生异常。 要关闭上面打开的连接,你应该调用close()方法如下
conn.close();
6.1 JDBC执行SQL语句
一旦获得了连接,我们可以与数据库进行交互。JDBC Statement和PreparedStatement接口定义了使 您能够发送SQL命令并从数据库接收数据的方法和属性。
| 声明 | 用于对数据库进行通用访问。在运行时使用静态SQL语句时很有用。Statement接口不能 接受参数。
| PreparedStatement的 | 当您计划多次使用SQL语句时使用。PreparedStatement接口在运行时接受 输入参数。
6.2 statement
创建语句对象在使用Statement对象执行SQL语句之前,需要使用Connection对象的createStatement()方法创建 一个,如下例所示:
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
创建Statement对象后,您可以使用它来执行一个SQL语句,其中有三个执行方法之一。
- boolean execute(String SQL):如果可以检索到ResultSet对象,则返回一个布尔值true; 否则返 回false。使用此方法执行SQL DDL语句或需要使用真正的动态SQL时。
- int executeUpdate(String SQL):返回受SQL语句执行影响的行数。使用此方法执行预期会影响 多个行的SQL语句,例如INSERT,UPDATE或DELETE语句。
- ResultSet executeQuery(String SQL):返回一个ResultSet对象。当您希望获得结果集时,请使 用此方法,就像使用SELECT语句一样。
- 关闭Statement对象 就像我们关闭一个Connection对象以保存数据库资源一样,由于同样的原因,还应该关闭Statement对象。
一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭Statement对 象。但是,应始终显式关闭Statement对象,以确保正确清理。
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
stmt.close();
}
6.3 SQL注入
就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执 行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意的)SQL命令注入到后台数据库引擎 执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据 库,而不是按照设计者意图去执行SQL语句。比如先前的很多影视网站泄露VIP会员密码大多就是通过 WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击。
登录数据库
public static void main(String[] args) {
Connection connection = null;
Statement statement = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建状态通道(进行sql语句的发送)
statement = connection.createStatement();
String uname = "aaa";
String pass = "123";
resultSet = statement.executeQuery("select * from user2 where username='"+uname+"'and password="+pass);
//4. 取出结果集信息
if (resultSet.next()) {
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
7、PreparedStatement(预状态通道)
该PreparedStatement的接口扩展了Statement接口,它为您提供了一个通用的Statement对象有两 个优点附加功能。 此语句使您可以动态地提供参数。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
JDBC中的所有参数都由?符号,这被称为参数标记。在执行SQL语句之前,必须为每个参数提供值。 所述的setXXX()方法将值绑定到所述参数,其中XXX代表要绑定到输入参数的值的Java数据类型。如果 忘记提供值,将收到一个SQLException。 每个参数标记由其顺序位置引用。第一个标记表示位置1,下一个位置2等等。
关闭PreparedStatement对象就像关闭Statement对象一样,由于同样的原因,还应该关闭PreparedStatement对象。 一个简单的调用close()方法将执行该作业。如果先关闭Connection对象,它也会关闭 PreparedStatement对象。但是,应始终显式关闭PreparedStatement对象,以确保正确清理。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.preparedStatement(SQL);
. . .
}catch (SQLException e) {
. . .
}finally {
pstmt.close();
}
如何避免SQL注入,预状态通道
public static void main(String[] args) {
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from user2 where username=? and password=?";
pps = connection.prepareStatement(sql);
String uname = "aaa";
String pass = " '' or 1=1";
// 给占位符赋值(下标,内容)从1开始
pps.setString(1, uname);
pps.setString(2, pass);
// 执行sql
resultSet = pps.executeQuery();
//4. 取出结果集信息
if (resultSet.next()) {
System.out.println("登录成功!");
} else {
System.out.println("登录失败!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
预状态通道对每一个数据都是以字符串的形式处理的有效的避免了SQL注入的问题。
对比statement和PreparedStatement;
- statement属于状态通道,PreparedStatement属于预状态通道
- 预状态通道会先编译sql语句,再去执行,比statement执行效率高
- 预状态通道支持占位符?,给占位符赋值的时候,位置从1开始
- 预状态通道可以防止sql注入,原因:预状态通道在处理值的时候以字符串的方式处理
8 、ResultSet
SELECT语句是从数据库中选择行并在结果集中查看行的标准方法。该java.sql.ResultSet中的接口表示 结果集数据库查询。
ResultSet对象维护指向结果集中当前行的游标。术语“结果集”是指包含在ResultSet对象中的行和列数据。
如果没有指定任何ResultSet类型,您将自动获得一个TYPE_FORWARD_ONLY。
try {
Statement stmt = conn.createStatement(
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
}catch(Exception ex) {
....
}finally {
....
}
9、Java操作两表关系
四种:双向一对一,一对多,多对一,多对多
多表关系处理数据
(1) 数据库通过外键建立两表关系
(2) 实体类通过属性的方式建立两表关系
实体类要求:类名=表名,列名=属性名
9.1 一对多(老师----》学生)
- 创建数据表
CREATE TABLE `student` (
`stuid` int(11) NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int(11) DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
INSERT INTO `student` VALUES ('1', 'aaa', '3');
INSERT INTO `student` VALUES ('2', 'bb', '1');
INSERT INTO `student` VALUES ('3', 'cc', '3');
INSERT INTO `student` VALUES ('4', 'dd', '1');
INSERT INTO `student` VALUES ('5', 'ee', '1');
INSERT INTO `student` VALUES ('6', 'ff', '2');
DROP TABLE IF EXISTS `teacher`;
CREATE TABLE `teacher` (
`tid` int(11) NOT NULL AUTO_INCREMENT,
`tname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`tid`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `teacher` VALUES ('1', '张三老师');
INSERT INTO `teacher` VALUES ('2', '李四老师');
INSERT INTO `teacher` VALUES ('3', '王五');
- 创建实体类
// 一方
public class Teacher {
private int tid;
private String tname;
private List<Student> list = new ArrayList<Student>();
public List<Student> getList() {
return list;
}
public void setList(List<Student> list) {
this.list = list;
}
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
}
// 多方
public class Student {
private int stuId;
private String stuName;
private int teacherId;
// 多对一:是在多方创建一个存储一方数据的对象
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
}
- 定义dao接口
public interface TeacherDao {
//定义操作方法
//1.定义一个根据老师id查询老师信息(学生的信息)
public Teacher getById(int tid);
}
- 定义实现类
public class TeacherDaoImpl implements TeacherDao {
@Override
public Teacher getById(int tid) {
//操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/yhp3?serverTimezone=UTC";
connection = DriverManager.getConnection(url, userName, passWord);
//3.定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from student s,teacher t where
s.teacherid = t.tid and t.tid =?";
pps = connection.prepareStatement(sql);
//给占位符赋值 (下标,内容) 从1开始
pps.setInt(1, tid);
//执行sql
resultSet = pps.executeQuery();
Teacher teacher = new Teacher();
List<Student> students = new ArrayList<Student>();
while (resultSet.next()) {
//1.取出各自的信息
teacher.setTid(resultSet.getInt("tid"));
teacher.setTname(resultSet.getString("tname"));
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
//2.建立学生和老师之间的关系
students.add(student);
}
teacher.setStudentList(students);
return teacher;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
//5.关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return null;
}
}
public class TeacherDaoImpl implements TeacherDao {
@Override
public Teacher getById(int tid) {
//操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1.加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2.获得链接
String userName = "root";
String passWord = "123456";
String url = "jdbc:mysql://localhost:3306/yhp3?serverTimezone=UTC";
connection = DriverManager.getConnection(url, userName, passWord);
//3.定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from student s,teacher t where
s.teacherid = t.tid and t.tid =?";
pps = connection.prepareStatement(sql);
//给占位符赋值 (下标,内容) 从1开始
pps.setInt(1, tid);
//执行sql
resultSet = pps.executeQuery();
Teacher teacher = new Teacher();
List<Student> students = new ArrayList<Student>();
while (resultSet.next()) {
//1.取出各自的信息
teacher.setTid(resultSet.getInt("tid"));
teacher.setTname(resultSet.getString("tname"));
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
//2.建立学生和老师之间的关系
students.add(student);
}
teacher.setStudentList(students);
return teacher;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
try {
//5.关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
return null;
}
}
- 定义测试类:
public class Test1 {
public static void main(String[] args) {
TeacherDaoImpl dao = new TeacherDaoImpl();
Teacher teacher = dao.getById(1);
System.out.println("老师姓名:"+teacher.getTname());
List<Student> studentList = teacher.getStudentList();
for (Student student: studentList) {
System.out.println("\t studentname="+student.getStuName());
}
}
}
- 数据库查询结果
- 程序运行结果与查询结果一致
9.2 多对一(学生----》老师)
数据表同上
- 实体类
// 多方
public class Student {
private int stuId;
private String stuName;
//外键列一般不生成属性
// private int teacherid;
private int teacherId;
// 多对一:是在多方创建一个存储一方数据的对象
private Teacher teacher;
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
}
// 一方
public class Teacher {
private int tid;
private String tname;
// 在一方创建存储多方数据的集合
private List<Student> studentList;
public int getTid() {
return tid;
}
public void setTid(int tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public List<Student> getStudentList() {
return studentList;
}
public void setStudentList(List<Student> studentList) {
this.studentList = studentList;
}
}
- 接口:
public interface TeacherDao {
// 定义操作方法
// 查询所有的学生(包含老师的信息)
public List<Student> getAll();
}
- 实现类:
@Override
public class TeacherDaoImpl implements TeacherDao {
public List<Student> getAll() {
// 操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "select * from student s,teacher t where s.teacherid=t.tid";
pps = connection.prepareStatement(sql);
// 执行sql
resultSet = pps.executeQuery();
List<Student> students = new ArrayList<Student>();
while (resultSet.next()) {
//1. 取出各自的信息
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
Teacher teacher = new Teacher();
teacher.setTid(resultSet.getInt("tid"));
teacher.setTname(resultSet.getString("tname"));
//2. 建立学生和老师之间的关系
student.setTeacher(teacher);
students.add(student);
}
return students;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}
- 测试类:
public static void main(String[] args) {
TeacherDao dao= new TeacherDaoImpl();
List<Student> students = dao.getAll();
for (Student student : students) {
System.out.println(student.getStuName()+","+student.getTeacher().getTname());
}
}
- 程序运行结果:
9.3 一对一(妻子丈夫)
- 数据表
CREATE TABLE `husband` (
`husid` int(11) NOT NULL AUTO_INCREMENT,
`husname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`husid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `husband` VALUES ('1', '邓超');
DROP TABLE IF EXISTS `wife`;
CREATE TABLE `wife` (
`wifeid` int(11) NOT NULL AUTO_INCREMENT,
`wifename` varchar(255) DEFAULT NULL,
`hid` int(11) DEFAULT NULL,
PRIMARY KEY (`wifeid`),
UNIQUE KEY `uq_wife_hid` (`hid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
INSERT INTO `wife` VALUES ('1', '孙俪', '1');
- 实体类:
public class Husband {
private int husId;
private String husName;
private Wife wife;
public int getHusId() {
return husId;
}
public void setHusId(int husId) {
this.husId = husId;
}
public String getHusName() {
return husName;
}
public void setHusName(String husName) {
this.husName = husName;
}
public Wife getWife() {
return wife;
}
public void setWife(Wife wife) {
this.wife = wife;
}
}
public class Wife {
private int wifeId;
private String wifeName;
private int hid;
private Husband husband;
public int getWifeId() {
return wifeId;
}
public void setWifeId(int wifeId) {
this.wifeId = wifeId;
}
public String getWifeName() {
return wifeName;
}
public void setWifeName(String wifeName) {
this.wifeName = wifeName;
}
public int getHid() {
return hid;
}
public void setHid(int hid) {
this.hid = hid;
}
public Husband getHusband() {
return husband;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
}
- 接口:
public interface WifeDao {
// 查询妻子信息(包含丈夫信息)
public Wife getWife(int wid);
// 查询丈夫信息(包含妻子信息)
public Husband getHus(int hid);
}
- 实现类:
public class WifeDaoImpl implements WifeDao {
@Override
public Wife getWife(int wid) {
// 操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "SELECT * FROM wife w,husband h WHERE w.hid=h.husid and wifeid=?";
pps = connection.prepareStatement(sql);
pps.setInt(1, wid);
// 执行sql
resultSet = pps.executeQuery();
Wife wife = new Wife();
while (resultSet.next()) {
//1. 取出各自的信息
wife.setWifeId(resultSet.getInt("wifeid"));
wife.setWifeName(resultSet.getString("wifename"));
Husband husband = new Husband();
husband.setHusId(resultSet.getInt("husid"));
husband.setHusName(resultSet.getString("husname"));
//2. 建立妻子和丈夫之间的关系
wife.setHusband(husband);
}
return wife;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public Husband getHus(int hid) {
// 操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "SELECT * FROM wife w,husband h WHERE w.hid=h.husid and husid=?";
pps = connection.prepareStatement(sql);
pps.setInt(1, hid);
// 执行sql
resultSet = pps.executeQuery();
Husband husband = new Husband();
while (resultSet.next()) {
//1. 取出各自的信息
Wife wife = new Wife();
wife.setWifeId(resultSet.getInt("wifeid"));
wife.setWifeName(resultSet.getString("wifename"));
husband.setHusId(resultSet.getInt("husid"));
husband.setHusName(resultSet.getString("husname"));
//2. 建立妻子和丈夫之间的关系
husband.setWife(wife);
}
return husband;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}
- 测试类:
public class Test2 {
public static void main(String[] args) {
WifeDaoImpl dao = new WifeDaoImpl();
//1. 通过妻子查询丈夫
Wife wife = dao.getWife(1);
System.out.println(wife.getWifeName()+","+wife.getHusband().getHusName());
//2. 通过丈夫查询妻子
Husband hus = dao.getHus(1);
System.out.println(hus.getHusName()+","+hus.getWife().getWifeName());
}
}
9.4 多对多(科目—学生)
- 数据表:
CREATE TABLE `middle` (
`middleid` int(11) NOT NULL AUTO_INCREMENT,
`stuid` int(11) DEFAULT NULL,
`subid` int(11) DEFAULT NULL,
PRIMARY KEY (`middleid`)
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of middle
-- ----------------------------
INSERT INTO `middle` VALUES ('1', '1', '1');
INSERT INTO `middle` VALUES ('2', '1', '2');
INSERT INTO `middle` VALUES ('3', '1', '3');
INSERT INTO `middle` VALUES ('4', '1', '5');
INSERT INTO `middle` VALUES ('5', '2', '2');
INSERT INTO `middle` VALUES ('6', '3', '2');
INSERT INTO `middle` VALUES ('7', '4', '2');
INSERT INTO `middle` VALUES ('8', '5', '2');
INSERT INTO `middle` VALUES ('9', '6', '2');
-- ----------------------------
-- Table structure for `student`
-- ----------------------------
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`stuid` int(11) NOT NULL AUTO_INCREMENT,
`stuname` varchar(255) DEFAULT NULL,
`teacherid` int(11) DEFAULT NULL,
PRIMARY KEY (`stuid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of student
-- ----------------------------
INSERT INTO `student` VALUES ('1', '张三', '3');
INSERT INTO `student` VALUES ('2', '李四', '1');
INSERT INTO `student` VALUES ('3', '王五', '3');
INSERT INTO `student` VALUES ('4', '赵六', '1');
INSERT INTO `student` VALUES ('5', '花花', '1');
INSERT INTO `student` VALUES ('6', '潇潇', '2');
-- ----------------------------
-- Table structure for `subject`
-- ----------------------------
DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject` (
`subid` int(11) NOT NULL AUTO_INCREMENT,
`subname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`subid`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of subject
-- ----------------------------
INSERT INTO `subject` VALUES ('1', 'java');
INSERT INTO `subject` VALUES ('2', 'ui');
INSERT INTO `subject` VALUES ('3', 'h5');
INSERT INTO `subject` VALUES ('4', 'c');
INSERT INTO `subject` VALUES ('5', 'c++');
INSERT INTO `subject` VALUES ('6', 'c#');
- 实体类:
public class Subject {
private int subid;
private String subname;
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public int getSubid() {
return subid;
}
public void setSubid(int subid) {
this.subid = subid;
}
public String getSubname() {
return subname;
}
public void setSubname(String subname) {
this.subname = subname;
}
}
public class Student {
private int stuId;
private String stuName;
private int teacherId;
// 多对一:是在多方创建一个存储一方数据的对象
private Teacher teacher;
// 配置多对多
private List<Subject> subjects;
public List<Subject> getSubjects() {
return subjects;
}
public void setSubjects(List<Subject> subjects) {
this.subjects = subjects;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
public int getStuId() {
return stuId;
}
public void setStuId(int stuId) {
this.stuId = stuId;
}
public String getStuName() {
return stuName;
}
public void setStuName(String stuName) {
this.stuName = stuName;
}
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
}
- 接口:
public interface SubjectDao {
// 查询某个学生信息(查询出所学学科)
public Student findById(int id);
// 查询某个科目以及对应的学生姓名
public Subject findBySubId(int subId);
}
- 实现类:
public class SubjecDaoImpl implements SubjectDao{
@Override
public Student findById(int id) {
// 操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "SELECT * FROM student s,subject su,middle m where s.stuid=m.stuid and su.subid=m.subid and s.stuid=?";
pps = connection.prepareStatement(sql);
pps.setInt(1, id);
// 执行sql
resultSet = pps.executeQuery();
Student student = new Student();
List<Subject> subjects = new ArrayList<>();
while (resultSet.next()) {
//1. 取出各自的信息
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
Subject subject = new Subject();
subject.setSubid(resultSet.getInt("subid"));
subject.setSubname(resultSet.getString("subname"));
subjects.add(subject);
}
//2. 建立学生和科目之间的关系
student.setSubjects(subjects);
return student;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
@Override
public Subject findBySubId(int subId) {
// 操作数据库
Connection connection = null;
PreparedStatement pps = null;
ResultSet resultSet = null;
try {
//1. 加载驱动
Class.forName("com.mysql.cj.jdbc.Driver");
//2. 获得链接
String username = "root";
String password = "123456";
String url = "jdbc:mysql://localhost:3306/may?serverTimezone=UTC";
connection = DriverManager.getConnection(url, username, password);
//3. 定义sql,创建预状态通道(进行sql语句的发送)
String sql = "SELECT * FROM student s,subject su,middle m where s.stuid=m.stuid and su.subid=m.subid and su.subid=?";
pps = connection.prepareStatement(sql);
pps.setInt(1, subId);
// 执行sql
resultSet = pps.executeQuery();
Subject subject = new Subject();
List<Student> studentList = new ArrayList<>();
while (resultSet.next()) {
//1. 取出各自的信息
Student student = new Student();
student.setStuId(resultSet.getInt("stuid"));
student.setStuName(resultSet.getString("stuname"));
studentList.add(student);
subject.setSubid(resultSet.getInt("subid"));
subject.setSubname(resultSet.getString("subname"));
}
//2. 建立学生和科目之间的关系
subject.setStudents(studentList);
return subject;
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
//5. 关闭资源
if (resultSet != null) {
resultSet.close();
}
if (pps != null) {
pps.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
}
- 测试类:
public class Test3 {
public static void main(String[] args) {
SubjecDaoImpl subjecDao = new SubjecDaoImpl();
// Student student = subjecDao.findById(1);
// System.out.println(student.getStuName());
// List<Subject> subjects = student.getSubjects();
// for (Subject subject : subjects) {
// System.out.println("\t"+subject.getSubname());
// }
Subject subject = subjecDao.findBySubId(2);
System.out.println(subject.getSubname());
List<Student> studentList =subject.getStudents();
for (Student student : studentList) {
System.out.println("\t"+student.getStuName());
}
}
}
- 程序运行结果: