JDBC学习笔记(1)—B站尚硅谷宋红康

JDBC学习笔记(2)—B站尚硅谷宋红康

文章目录

  • 软件架构方式介绍
  • JavaWeb技术概览
  • 第1章:JDBC概述
    • 1.1 数据的持久化
    • 1.2 Java中的数据存储技术
    • 1.3 JDBC介绍
    • 1.4 JDBC体系结构
    • 1.5 JDBC程序编写步骤
  • 第2章:获取数据库连接
    • 2.4 数据库连接方式举例
      • == 首先将提供的数据库添加到mysql中,如下是原文件 ==
      • 2.4.1 连接方式一
      • 2.4.1 连接方式二
      • 2.4.1 连接方式三
      • 2.4.1 连接方式四
      • 2.4.1 连接方式五(最终版)
    • == 2.1 2.2 2.3大概看看就好了 重点2.4 ==
    • 2.1 要素一:Driver接口实现类
      • 2.1.1 Driver接口介绍
      • 2.1.2 加载与注册JDBC驱动
    • 2.2 要素二:URL
    • 2.3 用户名和密码
  • 第3章:使用PreparedStatement实现CRUD操作
    • 3.1 操作和访问数据库
    • 3.2 使用Statement操作数据表的弊端
    • 3.3 PreparedStatement的使用
      • 3.3.1 PreparedStatement介绍
      • 3.3.2 使用PreparedStatement实现 增insert 操作
      • 3.3.3 JDBCUtils:封装数据库连接和关闭操作
      • 3.3.4 改update 操作
      • 3.3.4 通用的 增删改 操作
      • 3.3.5 Java与SQL对应数据类型转换表
      • 3.3.6 查 select操作
        • 3.3.6.1 针对customers表的 不通用的 查select 操作
        • 3.3.6.2 针对customers表的 通用的 查select 操作
        • 3.3.6.3 针对order表的 通用的 查select 操作
        • 3.3.6.4 图解查操作
        • 3.3.6.5 对应不同的表 通用的 查select 操作
          • 3.3.6.5.1 查找返回一条数据
          • 3.3.6.5.2 查找返回多条数据
    • 3.4 为什么使用PreparedStatement?
    • 3.5 JDBC 小结
  • 章节练习
  • 第4章:操作BLOB类型字段
    • 4.1 MySQL Blob类型
    • 4.2 向数据表中插入、修改、删除、读取Blob类型数据
  • 第5章:批量操作
    • 5.1 批量插入

软件架构方式介绍

JavaWeb技术概览

HTML 结构:浏览器页面的结构(骨架)
CSS  表现:美化页面,让页面更好看
JavaScript 行为:让页面动起来(比如表单验证)
JavaScript的库:jQuery(把JavaScript封装起来,写代码更方便)
前端主流框架:VueTomcat服务器
XML:可以自定义标签,写配置文件三大组件:Servlet:写java代码,与浏览器交互。1.获取用户从浏览器发来的请求2.处理请求3.响应(回复)请求Filter:过滤器(过滤数据)Listener:监听器(监听一些响应的操作)JSP:本质上是Servlet,帮助Servlet实现动态页面,为客户端回传数据。EL表达式:代替jsp中的<%= %>JSTL标签库:代替jsp中的<% %>帮助服务器判断多次请求是否来自于同一个浏览器
(比如淘宝,在首页登陆了,再别的页面也应该是登录状态,不能换一个页面还要重新登录)
浏览器的Cookie:
服务器端Session:Ajax:实现异步请求(多个请求同时进行)
用例1:注册时判断用户名是否重复等
用例2:在百度搜索时,写几个关键词,出现很多提示服务器和浏览器之间传输数据时,可以通过xml,但是现在都是通过JSON(json更简单便捷)

第1章:JDBC概述

1.1 数据的持久化

1.2 Java中的数据存储技术

JDO是对JDBC的封装

1.3 JDBC介绍




JDBC是接口(一组规范)
JDBC驱动是JDBC接口的实现类的集合,有各大数据库厂家完成。

1.4 JDBC体系结构

应用程序接口(英语:Application Programming Interface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。

1.5 JDBC程序编写步骤

第2章:获取数据库连接

2.4 数据库连接方式举例

== 首先将提供的数据库添加到mysql中,如下是原文件 ==

文件名:shangguigu_jdbc_test.sql

DROP TABLE IF EXISTS `customers`;
CREATE TABLE IF NOT EXISTS `customers` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(15) DEFAULT NULL,`email` varchar(20) DEFAULT NULL,`birth` date DEFAULT NULL,`photo` mediumblob,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;INSERT INTO `customers` (`id`, `name`, `email`, `birth`, `photo`) VALUES(1, '汪峰', 'wf@126.com', '2010-02-02', NULL),(2, '王菲', 'wangf@163.com', '1988-12-26', NULL),(3, '林志玲', 'linzl@gmail.com', '1984-06-12', NULL),(4, '汤唯', 'tangw@sina.com', '1986-06-13', NULL),(5, '成龙', 'Jackey@gmai.com', '1955-07-14', NULL),(6, '迪丽热巴', 'reba@163.com', '1983-05-17', NULL),(7, '刘亦菲', 'liuyifei@qq.com', '1991-11-14', NULL),(8, '陈道明', 'bdf@126.com', '2014-01-17', NULL),(10, '周杰伦', 'zhoujl@sina.com', '1979-11-15', NULL),(12, '黎明', 'LiM@126.com', '1998-09-08', NULL),(13, '张学友', 'zhangxy@126.com', '1998-12-21', NULL),(16, '朱茵', 'zhuyin@126.com', '2014-01-16', NULL),(18, '贝多芬', 'beidf@126.com', '2014-01-17', NULL);DROP TABLE IF EXISTS `examstudent`;
CREATE TABLE IF NOT EXISTS `examstudent` (`FlowID` int NOT NULL AUTO_INCREMENT,`Type` int DEFAULT NULL,`IDCard` varchar(18) DEFAULT NULL,`ExamCard` varchar(15) DEFAULT NULL,`StudentName` varchar(20) DEFAULT NULL,`Location` varchar(20) DEFAULT NULL,`Grade` int DEFAULT NULL,PRIMARY KEY (`FlowID`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=gb2312;INSERT INTO `examstudent` (`FlowID`, `Type`, `IDCard`, `ExamCard`, `StudentName`, `Location`, `Grade`) VALUES(1, 4, '412824195263214584', '200523164754000', '张锋', '郑州', 85),(2, 4, '222224195263214584', '200523164754001', '孙朋', '大连', 56),(3, 6, '342824195263214584', '200523164754002', '刘明', '沈阳', 72),(4, 6, '100824195263214584', '200523164754003', '赵虎', '哈尔滨', 95),(5, 4, '454524195263214584', '200523164754004', '杨丽', '北京', 64),(6, 4, '854524195263214584', '200523164754005', '王小红', '太原', 60);DROP TABLE IF EXISTS `order`;
CREATE TABLE IF NOT EXISTS `order` (`order_id` int NOT NULL AUTO_INCREMENT,`order_name` varchar(20) DEFAULT NULL,`order_date` date DEFAULT NULL,PRIMARY KEY (`order_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;INSERT INTO `order` (`order_id`, `order_name`, `order_date`) VALUES(1, 'AA', '2010-03-04'),(2, 'BB', '2000-02-01'),(4, 'GG', '1994-06-28');DROP TABLE IF EXISTS `user`;
CREATE TABLE IF NOT EXISTS `user` (`id` int NOT NULL AUTO_INCREMENT,`name` varchar(10) NOT NULL,`password` varchar(15) NOT NULL DEFAULT '123456',`address` varchar(25) DEFAULT NULL,`phone` varchar(15) DEFAULT NULL,PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;INSERT INTO `user` (`id`, `name`, `password`, `address`, `phone`) VALUES(1, '章子怡', 'qwerty', 'Beijing', '13788658672'),(2, '郭富城', 'abc123', 'HongKong', '15678909898'),(3, '林志玲', '654321', 'Taiwan', '18612124565'),(4, '梁静茹', '987654367', 'malaixiya', '18912340998'),(5, 'LadyGaGa', '123456', 'America', '13012386565');DROP TABLE IF EXISTS `user_table`;
CREATE TABLE IF NOT EXISTS `user_table` (`user` varchar(20) DEFAULT NULL,`password` varchar(20) DEFAULT NULL,`balance` int DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;INSERT INTO `user_table` (`user`, `password`, `balance`) VALUES('AA', '123456', 1000),('BB', '654321', 1000),('CC', 'abcd', 2000),('DD', 'abcder', 3000);

2.4.1 连接方式一

package com.atguigu.connection;import org.junit.jupiter.api.Test;import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Properties;public class ConnectionTest {@Test//数据库连接方式一public void testConnection1() throws SQLException {//1.通过Driver接口来获取数据库连接,Driver就是驱动的意思/*2.如果使用mysql:Driver driver = mysql具体的jdbc接口实现类(即mysql驱动)。需要添加mysql驱动jar包,这里使用:mysql-connector-java-8.0.28.jar。使用哪个实现类?可以将鼠标放在下方Driver上,然后按ctrl+H 或者 ctrl+shift+B,就可以看到Driver接口有哪些实现类。因为我的mysql是高版本,选择com.mysql.cj.jdbc.Driver()注意:mysql高版本要有cj*/Driver driver = new com.mysql.cj.jdbc.Driver();//url:统一资源定位符。//用来标识被注册的驱动。通过url选择正确的驱动程序,从而建立到数据库的正确连接。//通俗说:就是连接到哪个数据库/*jdbc:mysql  协议localhost   ip地址3306        默认端口号test        数据库名(需要将数据库添加到mysql中)*/String url = "jdbc:mysql://localhost:3306/shangguigu_jdbc_test";/*获取mysql数据库连接需要输入自己设置的mysql的用户名和密码:将用户名和密码封装在Properties中。*/Properties info = new Properties();info.setProperty("user","root");info.setProperty("password","abc123");//通过Driver的connect方法获得Connection对象//把鼠标放在connect上就可以看到提示信息,输入什么参数。Connection connection = driver.connect(url, info);System.out.println(connection);}}
1.添加mysql驱动jar包,这里使用:mysql-connector-java-8.0.28.jar
在项目下创建一个lib目录,将jar包添加进去,然后右击jar包点击add as library我用的是IDEA2021


2.4.1 连接方式二

@Test//方式二:方式一的迭代(使程序中不出现第三方的api接口,使程序具有更好的可移植性)public void testConnection2() throws Exception {//1.获取Driver接口的实现类对象:使用反射//这样使用不同的数据库管理系统,只用修改括号里的内容就好了。Class clazz = Class.forName("com.mysql.jdbc.Driver");Driver driver = (Driver) clazz.newInstance();//其他和方式一相同//2.提供要连接的数据库String url = "jdbc:mysql://localhost:3306/shangguigu_jdbc_test";//3.提供连接需要的用户名和密码Properties info = new Properties();info.setProperty("user","root");info.setProperty("password","abc123");//4.获取连接Connection connection = driver.connect(url, info);System.out.println(connection);}

2.4.1 连接方式三

@Test//方式三:使用DriverManager类(驱动管理器)替代Driverpublic void testConnection3() throws Exception{//1.获取Driver接口的实现类对象Class clazz = Class.forName("com.mysql.jdbc.Driver");Driver driver = (Driver) clazz.newInstance();//注册驱动DriverManager.registerDriver(driver);//2.提供3个基本信息String url = "jdbc:mysql://localhost:3306/shangguigu_jdbc_test";String user = "root";String password = "abc123";//3.获取连接Connection connection = DriverManager.getConnection(url,user,password);System.out.println(connection);}

2.4.1 连接方式四

 @Test//方式四:优化方式三public void testConnection4() throws Exception{//1.获取Driver接口的实现类对象//只需要写这一行代码就可以了,因为Driver类中有一个静态代码块,该静态代码块已经将其他代码写好了。//类加载时静态代码块执行。Class.forName("com.mysql.jdbc.Driver");//注意: Class.forName("com.mysql.jdbc.Driver"); 不写也行!//在导入mysql-connector-java-8.0.28.jar包之后,反射获取实现类对象和注册驱动都帮你写好了。//但是在mysql下可以这么做,在其他数据库管理系统下如Oracle,就不能这么做了。所以还是保留这行代码。//2.提供3个基本信息String url = "jdbc:mysql://localhost:3306/shangguigu_jdbc_test";String user = "root";String password = "abc123";//3.获取连接Connection connection = DriverManager.getConnection(url,user,password);System.out.println(connection);}

2.4.1 连接方式五(最终版)

@Test//方式五(最终版):将数据库连接需要的4个配置信息写在配置文件中//在src下创建一个jdbc.propertiespublic void testConnection5() throws Exception{//1.读取配置文件中的4个基本信息//这里使用资源绑定器ResourceBundle/*第一步:使用ResourceBundle.getBundle(Properties文件名 不加扩展名.properties)获得资源绑定器也可以说是将资源绑定器绑定在Properties文件上。第二步:通过getString(key)方法获得文件中的信息。注意:Properties文件必须在src下(类路径下);该文件必须以.properties结尾。*/ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");String driver = resourceBundle.getString("driver");String user = resourceBundle.getString("user");String password = resourceBundle.getString("password");String url = resourceBundle.getString("url");//2.加载驱动Class.forName(driver);//3.获取连接Connection connection = DriverManager.getConnection(url,user,password);System.out.println(connection);}
jdbc.properties:
#顺序随便,变量命名随便,等号左右不要有空格
driver=com.mysql.cj.jdbc.Driver
user=root
password=abc123
url=jdbc:mysql://localhost:3306/shangguigu_jdbc_test

== 2.1 2.2 2.3大概看看就好了 重点2.4 ==

2.1 要素一:Driver接口实现类

2.1.1 Driver接口介绍



2.1.2 加载与注册JDBC驱动

2.2 要素二:URL


2.3 用户名和密码

第3章:使用PreparedStatement实现CRUD操作

3.1 操作和访问数据库

3.2 使用Statement操作数据表的弊端

3.3 PreparedStatement的使用

3.3.1 PreparedStatement介绍

3.3.2 使用PreparedStatement实现 增insert 操作

package com.atguigu2.preparedStatement;import org.junit.jupiter.api.Test;import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.ResourceBundle;//使用PreparedStatement代替Statement实现对数据表的增删改查操作
//增删改和查
public class PreparedStatementCRUDTest {@Test//增操作:向customers表中添加一条数据。public void testInsert(){Connection connection = null;PreparedStatement ps = null;try{//1.获取数据库连接ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");String driver = resourceBundle.getString("driver");String user = resourceBundle.getString("user");String password = resourceBundle.getString("password");String url = resourceBundle.getString("url");Class.forName(driver);connection = DriverManager.getConnection(url,user,password);//2.预编译sql语句//?:占位符。只有这样才能解决sql注入问题。String sql = "insert into customers(name,email,birth) values(?,?,?)";//3.获取PreparedStatement对象(通过Connection的prepareStatement(sql语句)方法)ps = connection.prepareStatement(sql);/*4.填充占位符(通过PrepareStatement的setXXX()方法)如果name是在sql中是字符串类型,则setString(),其他的类似。ps.setString(int parameterIndex,String x);parameterIndex为参数下标,从1开始,1代表第一个占位符;2代表第二个占位符。*/ps.setString(1,"哪吒");ps.setString(2,"nezha@gmail.com");//birth在sql中是date类型,解释看下面SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");java.util.Date utilDate = sdf.parse("2000-01-01");java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());ps.setDate(3,sqlDate);//5.执行insert操作ps.execute();}catch (Exception e){e.printStackTrace();}finally {//6.资源的关闭try {//关闭之前避免出现空指针if (ps!=null){ps.close();}} catch (SQLException e) {e.printStackTrace();}try {//关闭之前避免出现空指针if (connection!=null){connection.close();}} catch (SQLException e) {e.printStackTrace();}}}
}
关于如下几行代码的解释:SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");java.util.Date utilDate = sdf.parse("2000-01-01");System.out.println(utilDate); //Sat Jan 01 00:00:00 CST 2000System.out.println(utilDate.getTime()); //946656000000java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());System.out.println(sqlDate); //2000-01-01ps.setDate(3,sqlDate);1.birth在sql中是date类型,所以ps.setDate(3,这个参数要是Date类型)
2.java中的Date和sql中的Date不同:java中的Date:java.util.Datesql中的Date:java.sql.Date大致区别就是java.util.Date支持日期和时间,而java.sql.Date只支持日期所以要进行转换。
3. getTime()方法获得从1970年1月1日到指定时间之间的毫秒数

3.3.3 JDBCUtils:封装数据库连接和关闭操作

从代码中可以看出,数据库的连接和关闭操作代码不变且一直重复,所以考虑封装。
package com.atguigu3.util;import java.sql.*;
import java.util.ResourceBundle;//封装数据库连接和关闭操作的工具类
public class JDBCUtils {//工具类中一般采用静态方法//获取数据库连接public static Connection getConnection() throws Exception{ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");String driver = resourceBundle.getString("driver");String user = resourceBundle.getString("user");String password = resourceBundle.getString("password");String url = resourceBundle.getString("url");Class.forName(driver);Connection connection = DriverManager.getConnection(url,user,password);return connection;}//关闭资源//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。public static void closeResource(Connection connection, Statement ps){try {//关闭之前避免出现空指针if (ps!=null){ps.close();}} catch (SQLException e) {e.printStackTrace();}try {//关闭之前避免出现空指针if (connection!=null){connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}

3.3.4 改update 操作

@Test//改操作:修改customers表中的一条数据(使用JDBCUtils)public void testUpdate(){Connection connection = null;PreparedStatement ps = null;try{//1.获取数据库的连接connection = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement对象实例String sql = "update customers set name = ? where id = ?";ps = connection.prepareStatement(sql);//3.填充占位符//可以不需要判断变量在sql中的数据类型,直接使用setObjectps.setObject(1,"莫扎特");ps.setObject(2,18);//4.执行ps.execute();}catch (Exception e){e.printStackTrace();}finally {//5.关闭资源JDBCUtils.closeResource(connection,ps);}}

3.3.4 通用的 增删改 操作

同一个数据库中的不同表
 /*通用的 增删改 操作:增删改操作基本上是一样的,不同在于:预编译sql语句和填充占位符。因为不知道有几个占位符,需要填充几个占位符。这里使用可变长度形参来表示要填充的占位符。sql中的占位符个数=可变形参长度*/public void update(String sql,Object ...agrs){Connection connection = null;PreparedStatement ps = null;try{//1.获取数据库连接connection = JDBCUtils.getConnection();//2.预编译sql语句(由形参传入),返回PreparedStatement对象实例ps = connection.prepareStatement(sql);//3.填充占位符for (int i = 0; i < agrs.length; i++) {ps.setObject(i+1,agrs[i]);}//4.执行ps.execute();}catch (Exception e){e.printStackTrace();}finally {//5.释放资源JDBCUtils.closeResource(connection,ps);}}@Test//测试通用的 增删改 操作public void testCommonUpdate(){//删除delete操作String sql1 = "delete from customers where id = ?";update(sql1,3);//改update操作//注意:在mysql中,表名不能和关键字一样,如下面的order表就和关键字order一样了,这样会报错。//解决办法:加着重符`order`,就可以解决冲突;或者通过数据库名.表名的方式来写。String sql2 ="update `order` set order_name = ? where order_id = ?";update(sql2,"DD","2");}

3.3.5 Java与SQL对应数据类型转换表

3.3.6 查 select操作

3.3.6.1 针对customers表的 不通用的 查select 操作

package com.atguigu2.preparedStatement;import com.atguigu3.bean.Customer;
import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;//使用PreparedStatement实现 查select操作
public class PreparedStatementCustomerForQuery {@Testpublic void testQuery1(){Connection connection = null;PreparedStatement ps =null;ResultSet resultSet = null;try{//1.获取数据库连接connection = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement对象实例String sql = "select id,name,email,birth from customers where id = ?";ps = connection.prepareStatement(sql);//3.填充占位符ps.setObject(1,1);//4.执行,并返回结果集resultSet = ps.executeQuery();//5.处理结果集//next():判断结果集的下一条是否有数据,如果有数据返回true,没有数据返回false。//这里演示获取一条数据,使用ifif (resultSet.next()){//获取当前这条数据的各个字段值(查看Java与SQL对应数据类型转换表)int id = resultSet.getInt(1);String name = resultSet.getString(2);String email = resultSet.getString(3);Date birth = resultSet.getDate(4);//输出方法//方式一://System.out.println("id = "+id+",name = "+name+",email = "+email+",birth = "+birth);//方式二:数组形式//Object[] data = new Object[]{id,name,email,birth};//方式三:创建一个Customer类,将数据封装为一个对象(推荐)Customer customer = new Customer(id,name,email,birth);System.out.println(customer);}}catch (Exception e){e.printStackTrace();}finally {//关闭资源//此时多了一个ResultSet,所以回到JDBCUtils重载closeResource()方法。JDBCUtils.closeResource(connection,ps,resultSet);}}
}
package com.atguigu3.bean;import java.util.Date;/*
ORM编程思想(object relational mapping)
一个表对应一个java类
表中的一条数据对应java类的一个对象
表中的一个字段对应java类的一个属性*/
public class Customer {private int id;private String name;private String email;private Date birth;public Customer() {}public Customer(int id, String name, String email, Date birth) {this.id = id;this.name = name;this.email = email;this.birth = birth;}public int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public Date getBirth() {return birth;}public void setBirth(Date birth) {this.birth = birth;}@Overridepublic String toString() {return "Customer{" +"id=" + id +", name='" + name + '\'' +", email='" + email + '\'' +", birth=" + birth +'}';}
}
package com.atguigu3.util;import java.sql.*;
import java.util.ResourceBundle;//封装数据库连接和关闭操作的工具类
public class JDBCUtils {//工具类中一般采用静态方法//获取数据库连接public static Connection getConnection() throws Exception{ResourceBundle resourceBundle = ResourceBundle.getBundle("jdbc");String driver = resourceBundle.getString("driver");String user = resourceBundle.getString("user");String password = resourceBundle.getString("password");String url = resourceBundle.getString("url");Class.forName(driver);Connection connection = DriverManager.getConnection(url,user,password);return connection;}//关闭资源//参数本来应该写PreparedStatement,但是PreparedStatement是Statement是子接口,//所以写Statement范围更大点,既可以传PreparedStatement,也可以传Statement。public static void closeResource(Connection connection, Statement ps){try {//关闭之前避免出现空指针if (ps!=null){ps.close();}} catch (SQLException e) {e.printStackTrace();}try {//关闭之前避免出现空指针if (connection!=null){connection.close();}} catch (SQLException e) {e.printStackTrace();}}public static void closeResource(Connection connection,PreparedStatement ps,ResultSet resultSet){try {//关闭之前避免出现空指针if (resultSet!=null){resultSet.close();}} catch (SQLException e) {e.printStackTrace();}try {//关闭之前避免出现空指针if (ps!=null){ps.close();}} catch (SQLException e) {e.printStackTrace();}try {//关闭之前避免出现空指针if (connection!=null){connection.close();}} catch (SQLException e) {e.printStackTrace();}}
}

3.3.6.2 针对customers表的 通用的 查select 操作

    //针对customers表的 通用的 查select 操作public Customer queryForCustomers(String sql,Object ...args) {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例ps = conn.prepareStatement(sql);//3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i+1,args[i]);}//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集(获取当前这条数据的各个字段值,并将其封装为一个Customer对象)//Customer类中的属性名和表中的列名要一致//获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();//通过元数据获取结果集中的列数int columnCount = rsmd.getColumnCount();//这里演示获取一条数据,使用ifif (rs.next()){//采用空构造方法,然后set方法;而不是含参构造方法,因为不知道传递过来几个参数Customer customer = new Customer();//接下来需要知道结果集中每一列的列名和列值才能设置一个Customer对象//有几列?通过元数据ResultSetMetaData 获取结果集中的列数for (int i = 0; i < columnCount; i++) {//获取列值Object columnValue = rs.getObject(i+1);//获取每个列的列名//String columnName = rsmd.getColumnName(i+1);//由 针对order表的 通用的 查select 操作 (3.3.8) 知道:使用getColumnLabel()方法String columnLabel = rsmd.getColumnLabel(i+1);//为Customer对象的columnLabel属性 赋值为 columnValue (即Customer类中的set方法):通过反射Field field = Customer.class.getDeclaredField(columnLabel);//得到Customer类中的某个属性对象field.setAccessible(true);//可以对该属性对象的set方法进行操作field.set(customer,columnValue);//使用该属性的set方法}return customer;}}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源JDBCUtils.closeResource(conn,ps,rs);}//结果集中什么都没有,返回nullreturn null;}@Test//测试:针对customers表的 通用的 查select 操作public void testQueryForCustomers(){String sql = "select id,name,birth,email from customers where id = ?";Customer customer = queryForCustomers(sql,13);System.out.println(customer);String sql1 = "select name,email from customers where name = ?";Customer customer1 = queryForCustomers(sql1,"周杰伦");System.out.println(customer1);}
如果是select *
String sql = "select * from customers"; 这样是错的。
解决办法:String sql = "select 所有的表中的字段名 from customers";即 String sql = "select id,name,email,birth from customers";

反射机制

3.3.6.3 针对order表的 通用的 查select 操作

这里会出现一个问题:使用通用操作时,若表的字段名和Order类的属性名不一致,则按照上述方法会出错。解决方法:为列的列名起别名(别名按照Order类的属性名来起)
package com.atguigu2.preparedStatement;import com.atguigu3.bean.Customer;
import com.atguigu3.bean.Order;
import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;import java.io.ObjectStreamException;
import java.lang.reflect.Field;
import java.sql.*;public class PreparedStatementOrderForQuery {@Test//针对order表的 查select操作(不通用)public void testQuery1() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句和返回PreparedStatement对象实例String sql = "select order_id,order_name,order_date from `order` where order_id = ?";ps = conn.prepareStatement(sql);//3.填充占位符ps.setObject(1,1);//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集//这里演示获取一条数据,使用ifif (rs.next()){int id = rs.getInt(1);String name = rs.getString(2);Date date = rs.getDate(3);Order order = new Order(id,name,date);System.out.println(order);}}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源JDBCUtils.closeResource(conn,ps,rs);}}/*当表的字段名和类的属性名不同时:1.在声明sql时,使用类的属性名来命名字段的别名2.使用ResultSetMetaData的getColumnLabel()方法来替代getColumnName()方法,获得列的列名的别名。3.说明:没有别名时,getColumnLabel()方法获取的就是列名;所以无论有没有别名,都使用getColumnLabel()方法*///针对order表的 通用的 查select 操作public Order orderForQuery(String sql,Object ...args){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例ps = conn.prepareStatement(sql);//3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i+1,args[i]);}//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集//获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();//获取列数int columnCount = rsmd.getColumnCount();//这里演示获取一条数据,使用ifif (rs.next()){Order order = new Order();for (int i = 0; i < columnCount; i++) {//获取每个列的列值:通过ResultSetObject columnValue = rs.getObject(i+1);//获取每个列的列名:通过ResultSetMetaData//String columnName = rsmd.getColumnName(i+1);//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法String columnLabel = rsmd.getColumnLabel(i+1);//通过反射:为Order对象的columnLabel属性 赋值为 columnValue (即Order类中的set方法)Field field = Order.class.getDeclaredField(columnLabel);field.setAccessible(true);field.set(order,columnValue);}return order;}}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源JDBCUtils.closeResource(conn,ps,rs);}//结果集中什么都没有,返回nullreturn null;}@Test//测试:针对order表的 通用的 查select 操作public void testQueryForCustomers(){String sql = "select order_id orderId,order_name orderName,order_date orderDate from `order` where order_id = ?";Order order = orderForQuery(sql,1);System.out.println(order);}
}
package com.atguigu3.bean;import java.sql.Date;public class Order {private int orderId;private String orderName;private Date orderDate;public Order() {}public Order(int orderId, String orderName, Date orderDate) {this.orderId = orderId;this.orderName = orderName;this.orderDate = orderDate;}public int getOrderId() {return orderId;}public void setOrderId(int orderId) {this.orderId = orderId;}public String getOrderName() {return orderName;}public void setOrderName(String orderName) {this.orderName = orderName;}public Date getOrderDate() {return orderDate;}public void setOrderDate(Date orderDate) {this.orderDate = orderDate;}@Overridepublic String toString() {return "Order{" +"orderId=" + orderId +", orderName='" + orderName + '\'' +", orderDate=" + orderDate +'}';}
}

3.3.6.4 图解查操作

3.3.6.5 对应不同的表 通用的 查select 操作

3.3.6.5.1 查找返回一条数据
package com.atguigu2.preparedStatement;import com.atguigu3.bean.Customer;
import com.atguigu3.bean.Order;
import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;//针对 不同的表 通用的 查 操作
public class PreparedStatementQueryTest {/*String sql:预编译的sql语句Object ...args:(可变形参)填充占位符该方法返回一个类对象(查询结果集表对应一个类,该表的每一条数据对应一个类对象)每个表对应不同的类,所以使用泛型。*/public <T> T getInstance(Class<T> clazz,String sql, Object ...args){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例ps = conn.prepareStatement(sql);//3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i+1,args[i]);}//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集//获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();//获取列数int columnCount = rsmd.getColumnCount();//这里演示获取一条数据,使用ifif (rs.next()){T t = clazz.newInstance();for (int i = 0; i < columnCount; i++) {//获取每个列的列值:通过ResultSetObject columnValue = rs.getObject(i+1);//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法String columnLabel = rsmd.getColumnLabel(i+1);//通过反射:为clazz对象的columnLabel属性 赋值为 columnValue (即clazz类中的set方法)Field field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t,columnValue);}return t;}}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源JDBCUtils.closeResource(conn,ps,rs);}//结果集中什么都没有,返回nullreturn null;}@Test//测试public void testGetInstance(){String sql = "select id,name,email from customers where id = ?";Customer customer = getInstance(Customer.class,sql,12);System.out.println(customer);String sql1 = "select order_id orderId,order_name orderName,order_date orderDate from `order` where order_id = ?";Order order = getInstance(Order.class,sql1,1);System.out.println(order);}
}

泛型

3.3.6.5.2 查找返回多条数据
 //查找返回表中多条记录//返回一个集合对象public <T> List<T> getForList(Class<T> clazz,String sql,Object ...args){Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句(有参数传递),返回PreparedStatement对象实例ps = conn.prepareStatement(sql);//3.填充占位符for (int i = 0; i < args.length; i++) {ps.setObject(i+1,args[i]);}//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集//获取结果集的元数据ResultSetMetaData rsmd = rs.getMetaData();//获取列数int columnCount = rsmd.getColumnCount();//创建集合对象List<T> list = new ArrayList<T>();while (rs.next()){T t = clazz.newInstance();//给t对象指定的属性赋值for (int i = 0; i < columnCount; i++) {//获取每个列的列值:通过ResultSetObject columnValue = rs.getObject(i+1);//获取每个列的列名的别名:通过ResultSetMetaData的getColumnLabel()方法String columnLabel = rsmd.getColumnLabel(i+1);//通过反射:为t对象的columnLabel属性 赋值为 columnValue (即T类中的set方法)Field field = clazz.getDeclaredField(columnLabel);field.setAccessible(true);field.set(t,columnValue);}list.add(t);}//这里return list;写在while外面return list;}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源JDBCUtils.closeResource(conn,ps,rs);}//结果集中什么都没有,返回nullreturn null;}@Test//测试public void testGetList(){String sql = "select id,name,email from customers where id < ?";List<Customer> list = getForList(Customer.class,sql,12);for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//不写占位符,这样就输出全部String sql1 = "select id,name,email from customers";List<Customer> list1 = getForList(Customer.class,sql1);for (int i = 0; i < list1.size(); i++) {System.out.println(list1.get(i));}}

3.4 为什么使用PreparedStatement?

使用PreparedStatement代替Statement原因:1.PreparedStatement是预编译的sql语句,可以解决Statement的拼串和sql注入问题;PreparedStatement首先确定了语法逻辑,然后填充相应的数值;而Statement会连着数值里包含的非法语法一起编译,就会造成对原来语法逻辑的破坏。2.PreparedStatement还可以操作Blob类型的数据,而Statement不行;3.PreparedStatement可以实现跟高效的批量操作:如果访问10000条数据,PreparedStatement会将语法固定,只用填充占位符就好了。

3.5 JDBC 小结

1.获取数据库连接:采用获取数据库连接方式五(包括配置文件jdbc.properties)
2.操作数据库:使用PreparedStatemnet操作数据库
(注意要关闭资源,先开后闭原则)(异常使用try…catch…)
1)通用的 增删改 操作:3.3.4 (包括JDBCUtils工具类 封装数据库的连接和资源的关闭)
2)通用的 查 操作: (包括JDBCUtils工具类 和 表对应的java类)
3.3.6.5.1 返回表中的一条数据
3.3.6.5.2 返回表中的多条数据

章节练习

第4章:操作BLOB类型字段

4.1 MySQL Blob类型

4.2 向数据表中插入、修改、删除、读取Blob类型数据

使用PreparedStatement操作Blob类型的数据,Statement无法操作Blob类型的数据。
package com.atguigu4.blob;import com.atguigu3.bean.Customer;
import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.sql.*;//使用PreparedStatement操作Blob类型的数据
public class BlobTest {@Test//向数据表customers中插入Blob类型的数据//customers表中的photo属性就是Blob类型public void testInsert() throws Exception {//1.获取数据库连接Connection conn = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement对象实例String sql = "insert into customers(name,email,birth,photo) values(?,?,?,?)";PreparedStatement ps = conn.prepareStatement(sql);//3.填充占位符ps.setObject(1,"张三");ps.setObject(2,"zhang@qq.com");ps.setObject(3,"2000-09-08");//photo的大小过大,要以文件的方式传入FileInputStream is = new FileInputStream("img/sea.png");ps.setBlob(4,is);//4.执行ps.execute();//5.关闭资源JDBCUtils.closeResource(conn,ps);}//删除Blob类型的数据,其实就是把整条数据删除掉//修改Blob类型的数据,跟上面的插入操作差不多,修改一下sql语句就好了@Test//查询customers数据表中Blob类型的数据public void testQuery() {Connection conn = null;PreparedStatement ps = null;ResultSet rs = null;InputStream is = null;FileOutputStream fos = null;try{//1.获取数据库连接conn = JDBCUtils.getConnection();//2.预编译sql语句,返回PreparedStatement对象实例String sql = "select id,name,email,birth,photo from customers where id = ?";ps = conn.prepareStatement(sql);//3.填充占位符ps.setObject(1,25);//4.执行,并返回结果集rs = ps.executeQuery();//5.处理结果集if (rs.next()){/*方法一:int id = rs.getInt(1);String name = rs.getString(2);String email = rs.getString(3);Date birth = rs.getDate(4);*///方法二:int id = rs.getInt("id");String name = rs.getString("name");String email = rs.getString("email");Date birth = rs.getDate("birth");Customer customer = new Customer(id,name,email,birth);System.out.println(customer);//获取Blob类型的photo数据,以文件形式保存在本地Blob photo = rs.getBlob("photo");is = photo.getBinaryStream();fos = new FileOutputStream("img/sea1.png");byte[] buffer = new byte[1024];int len;while ((len = is.read(buffer))!=-1){fos.write(buffer,0,len);}}}catch (Exception e){e.printStackTrace();}finally {//6.关闭资源try{if (is!=null){is.close();}}catch (Exception e){e.printStackTrace();}try{if (fos!=null){fos.close();}}catch (Exception e){e.printStackTrace();}JDBCUtils.closeResource(conn,ps,rs);}}
}
注意:

第5章:批量操作

使用PreparedStatement实现批量数据的操作

5.1 批量插入

package com.atguigu4.batchOperation;import com.atguigu3.util.JDBCUtils;
import org.junit.jupiter.api.Test;import java.sql.Connection;
import java.sql.PreparedStatement;/*
使用PreparedStatement实现批量数据的操作update和delete本身就具有批量操作的能力update没有过滤条件,将更改表中所有数据delete没有过滤条件,将删除表中所有的数据但是insert没有这种能力所以考虑:批量插入。如何使用PreparedStatement实现高效的批量插入操作?题目:创建一个goods表,向表中插入20000条数据
create table goods(id int primay key auto_increment,name varchar(25)
);方式一:Statement(一般不使用这个)Connection conn = JDBCUtils.getConnection();Statement st = conn.createStatement();for(int i=1;i<=20000;i++){String sql = "insert into goods(name) values('name_"+ i +"')";st.execute(sql);}*/
public class InsertTest {@Test//方式二:使用PreparedStatementpublic void testInsert1(){Connection conn = null;PreparedStatement ps = null;try{conn = JDBCUtils.getConnection();String sql = "insert into goods(name) values(?)";ps = conn.prepareStatement(sql);for (int i = 1; i <= 20000; i++) {ps.setObject(1,"name_"+ i);ps.execute();}}catch (Exception e){e.printStackTrace();}finally {JDBCUtils.closeResource(conn,ps);}}/*方式二 相较于 方式一 优点:即PreparedStatement优于Statement的地方:在于sql语句方式一内存中会有很多个sql语句,并且每次都会做一次语法检查而方式二只有一个sql语句,每次只是填充占位符。*//*方式三:对方式二的优化,更快一点。1.使用Batch批量处理:addBatch()、executeBatch()、clearBatch()2.mysql默认是关闭批处理的,我们需要一个参数打开批处理。高版本mysql只需要在jdbc.properties配置文件的url后添上:?rewriteBatchedStatements=true方式二花费:27602毫秒方式三花费:782毫秒*/@Testpublic void testInsert2(){Connection conn = null;PreparedStatement ps = null;try{long start = System.currentTimeMillis();conn = JDBCUtils.getConnection();String sql = "insert into goods(name) values(?)";ps = conn.prepareStatement(sql);for (int i = 1; i <= 20000; i++) {ps.setObject(1,"name_"+ i);//1."攒"sqlps.addBatch();if (i%500 == 0){//2.执行batch(有500条sql语句就执行一次)ps.executeBatch();//3.清空batchps.clearBatch();}/*如果是插入19999条数据,不是整数怎么办?没关系,只要添加下面这个代码:if(i==19999){ps.executeBatch();}就好了,最好执行一次就好了。*/}long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end-start));}catch (Exception e){e.printStackTrace();}finally {JDBCUtils.closeResource(conn,ps);}}/*方式四(最终方案):再快点每500条数据执行一次ps.executeBatch();这样就会提交一次。每次提交都会占用一点时间,所以先不提交,都传完以后,最后再提交。*/@Testpublic void testInsert3(){Connection conn = null;PreparedStatement ps = null;try{long start = System.currentTimeMillis();conn = JDBCUtils.getConnection();//设置不允许自动提交数据conn.setAutoCommit(false);String sql = "insert into goods(name) values(?)";ps = conn.prepareStatement(sql);for (int i = 1; i <= 20000; i++) {ps.setObject(1,"name_"+ i);//1."攒"sqlps.addBatch();if (i%500 == 0){//2.执行batch(有500条sql语句就执行一次)ps.executeBatch();//3.清空batchps.clearBatch();}}//提交数据conn.commit();long end = System.currentTimeMillis();System.out.println("花费的时间为:" + (end-start));}catch (Exception e){e.printStackTrace();}finally {JDBCUtils.closeResource(conn,ps);}}
}
PreparedStatement vs Statement

JDBC学习笔记(1)---B站尚硅谷宋红康相关推荐

  1. JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT

    JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT 第一章:JVM虚拟机的介绍 1.1虚拟机的分类 虚拟机通常分为两类:系统虚拟机和程序虚机.其中,系统虚拟机是指完全对物理计算机的仿真,而程序虚 ...

  2. 尚硅谷-宋红康-JVM上中下篇完整笔记-JVM上篇_内存与垃圾回收篇

    前言 一.jvm及java体系结构 1. Java及JVM简介 TIOBE语言热度排行榜 https://www.tiobe.com/tiobe-index/ 世界上没有最好的编程语言,只有最适用于具 ...

  3. 尚硅谷 宋红康 JVM教程_02_字节码与类的加载篇

    本系列相关链接 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇--01 (20210103-20210110) https://blog.csdn.net/wei198621/article/de ...

  4. 尚硅谷-宋红康-MySQL高级性能篇

    尚硅谷-宋红康-MySQL高级性能篇 第1章 Linux下MySQL的安装与使用 1. 安装前说明 1.1 Linux系统及工具准备 二级目录 三级目录 第1章 Linux下MySQL的安装与使用 1 ...

  5. 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇——02

    本系列相关链接 尚硅谷 宋红康 JVM教程_01_内存与垃圾回收篇--01 (20210103-20210110) https://blog.csdn.net/wei198621/article/de ...

  6. JVM从入门到精通(尚硅谷宋红康)

    不动笔墨不读书,先把书读厚,再把书读薄是我学习方式. 所以等理解了再整理一次笔记,目前笔记和视频一一对应. 笔记连载中 <尚硅谷2020最新版宋红康JVM> 第1章:JVM与Java体系结 ...

  7. 尚硅谷 宋红康老师 Java视频全程课程目录

    尚硅谷 Java 语言全程课程目录, 尚硅谷 Java&大数据研究院 宋红康 B站视频链接 已看完,感谢宋红康老师! [视频很长,但看完你一定会收获很多] 30天课程目录 Java 编程基础部 ...

  8. 【MySQL入门到高级之基础篇(参考尚硅谷宋红康老师2022版)】

    文章目录 第一章数据库概述 为什么要使用数据库 数据库与数据库管理系统 数据库的相关概念 数据库与数据库管理系统的关系 常见的数据库管理系统排名(DBMS) 常见的数据库介绍 MySQL介绍 概述 M ...

  9. 02尚硅谷宋红康Java视频笔记之语言概述

    Java基础是学习JavaEE.大数据.Android开发 的基石! I Java基础知识图解 Java基础课程体系 1.1 软件开发介绍 软件开发 软件,即一系列按照特定顺序组织的计算机数据和指令的 ...

最新文章

  1. 通过先序和中序数组生成后续数组
  2. eta 深度学习 参数_深度学习中的参数梯度推导(一)
  3. 微信端 a 链接无法跳转
  4. 学长毕业日记 :本科毕业论文写成博士论文的神操作20170314
  5. 前端学习(3118):react-hello-react的解决类中方法的this
  6. Rsync 同步搭建
  7. wordpress模板-RIPro-V2子主题V1.4-VAN主题
  8. linux工程师如何查询时间,查询Linux系统最后重启时间的三个方法
  9. 计算机毕业设计asp.net的旅游网站(源码+系统+mysql数据库+Lw文档)
  10. SREng日志全分析(一)
  11. 多媒体计算机主要有哪些基本特性,多媒体的特点主要包括哪些?
  12. 根据显卡型号查看相应的驱动
  13. 移动端-安卓-接口测试简介
  14. 【spring MVC】解决spring MVC不支持PUT请求
  15. python做面板回归_Python中的Panel回归
  16. 大数据精准投放+优质内容营销 帮你找到用户更能留住用户!
  17. 数据库第五次作业——查询数据
  18. 计算机图形学(四)几何变换_3_矩阵逆变换
  19. 制度罚则--测试报告模板
  20. 【计算机视觉之三】运用k近邻算法进行图片分类

热门文章

  1. 类型转换及类型转换函数
  2. 【ubuntu查看显卡、配置显卡、cuda、cudnn】
  3. python 小说人物分析_用python分析小说人物关系(二)——实战篇
  4. oracle 按每分钟分组,oracle按每个10分钟进行分组展示数据
  5. Editor.js 使用
  6. 线程实用解析--------(六)Control.Invoke()和Control.BeginInvoke()
  7. SAP FICO 解析成本要素类别
  8. mounted钩子函数_vue中created钩子函数与mounted钩子函数的使用区别
  9. 基于神经网络的滑模鲁棒控制
  10. Per tile sequence quality