.超炫酷HTML5 Canvas 3D旋转地球动画
这是一款基于HTML5 Canvas的3D地球模拟动画,动画以太空作为背景,地球在太空中旋转,同时我们也可以拖拽鼠标来从不同的角度观察地球。另外我们也可以通过点击全屏按钮来全屏观看地球旋转动画,记得在很早以前我们也分享过一款基于HTML5 Canvas的地球动画,请看这里。
2.HTML5 Canvas 3D文字动画 支持鼠标滚轮缩放
之前我们已经为大家分享过很多款炫酷和实用的HTML5文字动画特效,最经典的就是这款HTML5 Canvas幻彩火焰文字特效。这次给大家带来的是另外一款基于HTML5 Canvas 3D文字动画,它的特点是按住鼠标左键拖动文字可以旋转文字,从不同角度观察文字;按住鼠标左键可以移动文字;另外滑动鼠标滚轮可以缩放文字大小。
3.HTML5 Canvas五彩烟雾模拟动画
之前我们利用HTML5技术在Canvas上模拟了很多东西,比如最近刚分享的HTML5 Canvas 多种炫酷3D粒子图形动画。这次给大家带来的也是一款基于HTML5 Canvas的动画特效,它模拟了五彩烟雾的流动效果,这在Canvas上实现还是比较简单的。
4.CSS3带头像的垂直彩色菜单
今天我们要给大家分享一款比较特别的CSS3菜单,这款菜单是垂直样式的,而且当鼠标滑过菜单项时,当前菜单项即可显示一个精美的头像,并且在头像旁边显示一些格式化的文字。另外,每一个菜单项的背景色可以动态渲染。
5.HTML5/CSS3 3D立方体拼图 支持方向键旋转
之前我们分享过不少基于HTML5/CSS3和Canvas的3D立方体旋转动画,比如这款超绚丽CSS3多色彩发光立方体旋转动画,也有基于立方体做的菜单应用,比如超实用CSS3 3D菜单 菜单项悬浮凸出立体效果。今天我们要分享的是一款基于HTML5和CSS3的3D立方体拼图应用,一共有8个小立方体组成的3D拼图,我们可以点击立方体或者方向键完成拼图,同时我们也可以让立方体保持旋转。
6.CSS3/SVG实现的任务列表 超酷的按钮点击动画
这是一款外观很漂亮的CSS3/SVG任务列表插件,我们可以在输入框中输入自己需要完成的任务名称,点击添加按钮后即可将任务添加到列表中去。这本来是一件非常普通的功能,但是利用CSS3和SVG,我们在添加按钮点击时出现非常炫酷的动画特效,这样的特效在任务添加到列表和删除列表中都同样会出现,非常不错。甚至我们可以将这款插件修改后变成一款非常华丽的评论插件。
7.CSS3水平滑杆插件 带气泡数值提示
今天我们要给大家介绍一款很酷的水平滑杆插件,和之前分享的jQuery双向滑动杆 设置数值百分比和超可爱的纯CSS3滑动开关按钮类似,基本都是通过CSS3来美化浏览器默认的水平滑杆。今天分享的这款有一个特点,就是滑杆的数值带有气泡提示框,而且它就像气球一样拖动时会左右摇晃。
8.CSS3/SVG自定义单选框Radiobox跳跃选择动画
这又是一款利用CSS3实现的自定义美化版Radiobox单选框,和之前分享的CSS3自定义发光radiobox单选框类似,这款radiobox也是利用CSS3重写radiobox样式实现的。另外,这款自定义单选框还结合了SVG的特性,实现了单选框选中时的跳跃动画。
9.基于HTML5 WebGL的3D星云动画特效
今天我们给大家分享一个基于HTML5 Canvas的星云动画特效,整个画面模拟了一个星系的外观,比如模拟了太阳系,有很多小行星围绕着星系中心旋转,星系中心也显得格外亮丽。这些小星点都是在Canvas上绘制而成,同时我们还可以拖拽鼠标从不同视角观看星云,非常大气。
10.jQuery Select下拉框美化插件 菜单淡如淡出动画
尽管现在的浏览器更新换代后更加强大,浏览器默认控件也逐渐变得美观起来,特别是Select下拉框,已经不再是以前IE6那样的丑陋了。但是今天我们要为大家分享一款基于jQuery的Select下拉框美化插件,它完全重写了浏览器默认的Select下拉框样式,而且在下拉菜单展开时还伴随淡如淡出的动画效果,非常不错。当然我们以前也分享过一些类似的插件,可以看看漂亮实用的Select下拉框美化插件Tether,也可以看看这款jQuery 美化界面的下拉框。
本文固定链接: http://www.i7758.com/archives/2866.html
局一张图
上图是京东的登录页面,这和我们接下来要学习的东西有关系。
form表单就是专门用来实现用户登录、用户注册、信息收集之类的页面的。
日常网购一般都要求我们先登录,输入用户名和密码,点击登录后才可以进行物品的购买,那我们就用form表单来实现一下登录。
form表单中包含了input标签,input标签属于单标签。单标签是相对于双标签来讲的。以前的a标签、p标签、span标签等,都属于双标签,它们的特点是一对一对的,比如a标签,要写成<a></a>。比如p标签,要写成<p></p>,它们都是有一个开始,有一个结束。都是成双入对的。
单标签则没有结束标签,比如上面的input标签,它就没有</input>这样的结束。单标签还有我们之前学的img图片标签,br换行标签等。
input标签只能包含在form标签中,也就是说只要有input出现的地方,必定会有一个form标签包围着它。
而上一篇中的tr和td标签只能包含在table表格标签中,它们是组合。不能分开单独使用。
同样的情况还有li标签,只能包含在ul无序列表标签,ol有序列表标签中,dt标签和dd标签只能包含在dl标签中。
上面代码在浏览器中的效果:
这样一个简易的登录页面就做出来了,是不是很简单啊,我们试着填写用户名和密码来尝试一下登录。
你会发现,你输入的密码并不是明文的,也就是说你输入的密码会以黑点的形式呈现,这是为了安全,如果不这样,你输密码的时候很可能会被你背后的人看到。
那这个是怎么实现的呢?其实你应该已经发现了,input标签里面有个type属性,type设置为password就是以密码形式呈现。type设置为text就是以明文显示,type设置为submit就是一个按钮。
提交按钮的input里面我们还设置了一个value属性,这个属性用来设置,按钮的文字,我们这里设置的是登录,为了加深理解,我们给它改为登入。
浏览器中就会相应地显示为登入:
form表单中除了可以写input外,还可以有select下拉选择标签、textarea文本域标签、button按钮标签(这个按钮和<input type="submit">都是按钮,用的时候看你自己喜好)。
下面通过一个例子来了解上面的各种标签的使用。
案例:添加一篇文章,要求填写文章标题、文章分类、发表频道、文章内容。
浏览器中的效果:
上述代码中form标签中有select标签,这个的作用是产生一个下拉框,供用户选择。
select里面包含option标签,这个就是具体可以选择项。我们这里设置了三个:财经、教育、历史。 同我们前面讲的一样,option必须包含在select里面,而select必须包含在form表单标签中,它们是组合,不能打单独使用。
在这个例子中,我们还是用到了单选。
红框框住的就是我们设置的单选,具体对应代码中的:
单选也是用的input标签,只不过它的type是radio,还有一个要注意的地方就是name属性,我们这里可以选择的项是:新视觉、猎奇、杂说,它们三个的name属性都设置为了:channel。只有设置name都一样,才能单选,否则就成了多选了。
文章内容我们使用到了textarea文本域标签,它和<iniput type="text">的区别是,textarea可以放更多的文字。
textarea标签有两个属性需要说一下,cols代表的是列,rows代表的是行,cols设置的值越大,textarea的框越宽,rows的值设置的越大,textarea的框越高。我们来尝试一下:
先把cols设置成60,textarea就会变宽。
rows设置为30,textarea就会变高 :
form表单中还可以设置多选,我们也来尝试一下:
浏览器中的效果:
红框框住的部分就是我们实现的多选,多选用的也是input标签,type为checkbox
你可以自己动手尝试一下
我们整体的需求都实现了,但是整个页面看起来很不美观,所以我们需要调整一下,我决定采用table表格来调整,把文章标题、请选择分类、内容这些文字性的东西放到一列,input、select等标签放在另一列里面,使整个页面看起来更加整齐。
浏览器中的效果:
经过调整以后,看起来已经不那么丑了,在《做网站需要学习哪些知识》中,我们介绍过美化页面需要用Css和JavaScript,光用html是不可能做到很美观的。
在讲完html后,我们就会讲Css和JavaScript。
HTML 结构:浏览器页面的结构(骨架)
CSS 表现:美化页面,让页面更好看
JavaScript 行为:让页面动起来(比如表单验证)
JavaScript的库:jQuery(把JavaScript封装起来,写代码更方便)
前端主流框架:Vue
Tomcat服务器
XML:可以自定义标签,写配置文件
三大组件:
Servlet:写java代码,与浏览器交互。
1.获取用户从浏览器发来的请求
2.处理请求
3.响应(回复)请求
Filter:过滤器(过滤数据)
Listener:监听器(监听一些响应的操作)
JSP:本质上是Servlet,帮助Servlet实现动态页面,为客户端回传数据。
EL表达式:代替jsp中的<%= %>
JSTL标签库:代替jsp中的<% %>
帮助服务器判断多次请求是否来自于同一个浏览器
(比如淘宝,在首页登陆了,再别的页面也应该是登录状态,不能换一个页面还要重新登录)
浏览器的Cookie:
服务器端Session:
Ajax:实现异步请求(多个请求同时进行)
用例1:注册时判断用户名是否重复等
用例2:在百度搜索时,写几个关键词,出现很多提示
服务器和浏览器之间传输数据时,可以通过xml,但是现在都是通过JSON(json更简单便捷)
1.1 数据的持久化
1.2 Java中的数据存储技术
JDO是对JDBC的封装
1.3 JDBC介绍
JDBC是接口(一组规范)
JDBC驱动是JDBC接口的实现类的集合,有各大数据库厂家完成。
1.4 JDBC体系结构
1.5 JDBC程序编写步骤
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
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类(驱动管理器)替代Driver
public 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.properties
public 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
3.1 操作和访问数据库
3.2 使用Statement操作数据表的弊端
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 2000
System.out.println(utilDate.getTime()); //946656000000
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
System.out.println(sqlDate); //2000-01-01
ps.setDate(3,sqlDate);
1.birth在sql中是date类型,所以ps.setDate(3,这个参数要是Date类型)
2.java中的Date和sql中的Date不同:
java中的Date:java.util.Date
sql中的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 通用的 增删改 操作
同一个数据库中的不同表
/*
通用的 增删改 操作:
增删改操作基本上是一样的,不同在于:预编译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.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 {
@Test
public 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。
//这里演示获取一条数据,使用if
if (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;
}
@Override
public 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();
}
}
}
//针对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();
//这里演示获取一条数据,使用if
if (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);
}
//结果集中什么都没有,返回null
return 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.处理结果集
//这里演示获取一条数据,使用if
if (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();
//这里演示获取一条数据,使用if
if (rs.next()){
Order order = new Order();
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object 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);
}
//结果集中什么都没有,返回null
return 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;
}
@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
", orderDate=" + orderDate +
'}';
}
}
3.3.6.4 图解查操作
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();
//这里演示获取一条数据,使用if
if (rs.next()){
T t = clazz.newInstance();
for (int i = 0; i < columnCount; i++) {
//获取每个列的列值:通过ResultSet
Object 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);
}
//结果集中什么都没有,返回null
return 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++) {
//获取每个列的列值:通过ResultSet
Object 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);
}
//结果集中什么都没有,返回null
return 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));
}
}
使用PreparedStatement代替Statement原因:
1.PreparedStatement是预编译的sql语句,可以解决Statement的拼串和sql注入问题;
PreparedStatement首先确定了语法逻辑,然后填充相应的数值;
而Statement会连着数值里包含的非法语法一起编译,就会造成对原来语法逻辑的破坏。
2.PreparedStatement还可以操作Blob类型的数据,而Statement不行;
3.PreparedStatement可以实现跟高效的批量操作:
如果访问10000条数据,PreparedStatement会将语法固定,只用填充占位符就好了。
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 返回表中的多条数据
章节练习
使用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);
}
}
}
注意
使用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
//方式二:使用PreparedStatement
public 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毫秒
*/
@Test
public 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."攒"sql
ps.addBatch();
if (i%500 == 0){
//2.执行batch(有500条sql语句就执行一次)
ps.executeBatch();
//3.清空batch
ps.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();
这样就会提交一次。
每次提交都会占用一点时间,所以先不提交,都传完以后,最后再提交。
*/
@Test
public 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."攒"sql
ps.addBatch();
if (i%500 == 0){
//2.执行batch(有500条sql语句就执行一次)
ps.executeBatch();
//3.清空batch
ps.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
*请认真填写需求信息,我们会在24小时内与您取得联系。