@author:杜勇帅
@email:[email protected]
运行“mysql-5.5.28-winx64.msi”来安装MySQL服务器,参照“MySQL安装详细步骤.doc”就可以装好了
安装好MySQL服务器后,可以通过命令来启动或关闭MySQL服务
Net stop MySQL:停止MySQL服务
Net start MySQL:启动MySQL服务
连接mySQL服务器命令:
其中,-u:用户名,u是username简写
-p:密码,p是password简写
-h:服务器所在的主机,可以用域名或IP地址表示,本机可以是localhost或127.0.0.1
-P:MySQL服务器运行进程占用的端口号,默认是3306
运行资料中的“navicat_forMySQL_11.1.exe”,安装客户端工具navicat。
使用Navicat,第一步是要创建一个和MySQL服务器的连接
连接成功后,可以看到4个自带的数据库,其中mysql数据库里的user表中存储了root用户的信息,密码是加密的,这4个数据库都不要删掉
MySQL中支持自定义数据库,创建数据库方式有2种:
1.使用命令来创建
Create database database_name;
我们可以在navicat中打开命令界面
输入创建数据库的命令:
2.使用navicat的菜单“新建数据库”来创建数据库
选中连接名,右键”新建数据库”,在窗口中输入数据库名和字符集就行了,排序规则不管
1.整数,小数类型
整数:int(integer)和bigint,分别对应java中的int ,long
小数:float(M,D)和double(M,D)
3.字符类型
MySQL中常用的char(n)和varchar(n),长度单位是字符,varchar(n)是最多只能有n个字符,
Char(n)是固定n个字符,如果实际插入的长度不同,会在右侧以空格补齐
2.日期时间类型
Datetime和timestamp都表示日期时间类型,最大的区别是:timestamp类型的字段值会随着其它字段的修改而自动刷新。
语法和oracle是一样的,mysql它支持主键的自动增长(Auto_increment)
create table student( sid int PRIMARY key Auto_increment, sname varchar(10) not null, sex char(1) default '男', email varchar(20) unique);
需要注意:mysql的表中,check约束没有作用
我们也可以不编写代码,直接用navicat工具来建表,”新建表”-->输入每个字段
以下3个命令需要在命令界面里运行:
1) 显示数据库中所有表show tables;
2) 查看某个表的结构: desc tableName;
3) 删除表 drop table tableName;
使用Navacat很方便的导入sql脚本文件中的数据。具体操作如下:
1)新建一个数据库,名称和sql脚本的名称一样
2)选中数据库,右键“运行SQL文件”
3)浏览找到要导入的sql脚本文件,再点击”开始”
1)选中数据库,右键选择”转储sql文件”---》“结构和数据”
2) 指定要保存sql文件的位置
1)Concat函数:可以连接两个或更多的字符串,而oracle中的concat函数只能连接2个字符串
select CONCAT(product_name,'的零售价是',sale_price) 商品零售价 from product;
2)between..and , in都和oracle相同
3)like:模糊查询,2个通配符*和_
-- 查询 id,货品名称,要求货品名称以罗技开头,共4个字符select id,product_name from product where product_name like '罗技__'
3)分页查询
语法: select 字段列表 from 表 limit 首行下标,每页记录数
假设每页显示pageSize条记录,查询的页号是currentPage,分页查询语句:
select 字段列表 from 表 limit (currentPage-1)*pageSize, pageSize
4)where,排序
在where子句中不能用列的别名,order子句中可以用别名
选择id,货品名称,分类编号,零售价,筛选零售价高于399的商品,先按分类编号降序排序(加上别名),再按零售价升序排序select id,product_name,category_id 分类编号,sale_price 零售价 from product where sale_price>399 ORDER by 分类编号 desc,sale_price asc
5)分组查询
Group by子句把数据分成若干个组,如果要对分组后数据进行筛选,要加上having子句,排序子句要在最后面
-- 查询零售价总和大于1500的商品分类编号以及总零售价和,再按零售价总和降序显示select category_id,sum(sale_price) from product GROUP BY category_id having sum(sale_price)>1500 ORDER BY sum(sale_price) desc
Having子句上能够用别名
select category_id,sum(sale_price) 零售价总和 from product GROUP BY category_id having 零售价总和 >1500 ORDER BY sum(sale_price) desc
三种插入数据语法
-- 插入完整记录,如果主键是自增的,给它一个null值insert into student values(null,'Jmky','男','[email protected]',19);-- 插入部分记录,给表的一部分列提供值insert into student(sname,sex,age) values('mik2r','女',28);-- 插入多条记录(批量插入)insert into student(sname,sex,email,age) values('adsf','女','[email protected]',23),('ddef','男','[email protected]',32)
和oracle的修改,删除语法是一致的
通常多表连接时,是需要有外键,通过主外键进行关联查询,Navicat中可以很方便的将某个列设置成外键
内连接查询
使用join on 对两个或多个表进行内连接查询,又叫等值连接
推荐的内连接写法:SELECT 列1,列2... FROM A [INNER] JOIN B ON A.列 = B.列
Inner可以省略, 如果表有了别名,则不能再使用表的真名作为前缀
-- 查询所有商品的编号,名称和分类名称:select t1.id,product_name,category_name from product t1 join product_category t2 on t1.category_id=t2.id
左外连接:left join,返回左表的全部记录,右表中不满足连接条件的行就用null来填充
语法: SELECT
FROM A LEFT [OUTER] JOIN B
ON A.column_name = B.column_name
-- 查询所有商品分类编号,分类名称,商品名,零售价select t1.id,category_name,product_name,sale_price from product_category t1 left JOIN product t2 on t1.id=t2.category_id
右外连接:right join,返回右表的全部记录,左表中不满足连接条件的行就用null来填充
语法: SELECT
FROM A RIGHT [OUTER] JOIN B
ON A.column_name = B.column_name
左外和右外连接可以互换达到相同的查询效果,只需要把表的位置换一下,例如上面的左外连接可以改成:
select t2.id,category_name,product_name,sale_price from product t1 right JOIN product_category t2 on t1.category_id=t2.id
分为*单行单列子查询*,单行多列子查询,多行子查询,
多行子查询里只能使用多行的比较运算符 all,any,inselect * from product where sale_price>ALL(select sale_price from product where category_id=3)
特殊情况下,需要在update或delete语句中嵌套子查询语句,此时外层update或delete语句操作的表不能和子查询中操作的表相同
update product set cutoff=cutoff*0.1 where category_id=(select id from product_category where category_name='无线鼠标' );
-- 创建测试表tclass
create table tclass(
cid int primary key,
cname varchar(20) ,
createtime datetime, -- 创建时间
updatetime timestamp -- 更新时间
);
导入mysql_db数据库,利用已存在的表运行下面的sql语句
-- 查询商品的id,名称,零售价
select id,product_name,sale_price from product;
select DISTINCT category_id from product;
-- 查询所有货品的 id,名称和批发价(批发价=卖价*折扣)
select id,product_name, sale_price*cutoff 批发价 from product;
-- 显示"xxx的零售价是xxx"
select CONCAT(product_name,'的零售价是',sale_price) 商品零售价 from product;
-- 选择 id,货品名称,分类编号为 2,4 的所有货品
select id,product_name,category_id from product where category_id=2 or category_id=4
-- 选择 id,货品名称,批发价不在 300-400 之间的货品
select id,product_name,sale_price from product where sale_price
not BETWEEN 300 and 400;
-- 选择 id,货品名称,分类编号不为 2,4 的所有货品
select id,product_name,category_id from product where category_id not in (2,4);
-- 查询 id,货品名称,要求货品名称以罗技开头,共4个字符
select id,product_name from product where product_name like '罗技__';
-- 每页显示5条,查询第2页的商品数据
-- select 字段列表 from 表 limit 首行下标,每页记录数
select * from product limit 5,5
-- 每页显示7条,查询第3页的商品数据
select * from product limit 14,7;
-- 选择id,货品名称,分类编号,零售价并且按零售价降序排序
select id,product_name,category_id,sale_price from product ORDER BY sale_price DESC;
-- 选择id,货品名称,分类编号,零售价,筛选零售价高于399的商品,先按分类编号降序排序(加上别名),再按零售价升序排序
select id,product_name,category_id 分类编号,sale_price 零售价 from product
where sale_price>399 ORDER by 分类编号 desc,sale_price asc;
-- 查询商品分类编号为4的总商品数量
select count(*) from product where category_id=4
-- 查询分类编号为4的商品的最大零售价,平均零售价
select max(sale_price),avg(sale_price) from product where category_id=4;
-- 对于count()来说,count(*)不会忽略空值字段,
-- count(字段名)是统计字段不为空的总记录数,会跳过值为null的记录
select count(category_id) from product
-- 查询零售价总和大于1500的商品分类编号以及总零售价和,再按零售价总和降序显示
select category_id,sum(sale_price) 零售价总和 from product GROUP BY category_id having
零售价总和 >1500 ORDER BY sum(sale_price) desc;
-- 插入完整记录,如果主键是自增的,给它一个null值
insert into student values(null,'Jmky','男','[email protected]',19);
-- 插入部分记录,给表的一部分列提供值
insert into student(sname,sex,age) values('mik2r','女',28);
-- 插入多条记录(批量插入)
insert into student(sname,sex,email,age) values('adsf','女','[email protected]',23),
('ddef','男','[email protected]',32)
-- update student set sname='李四',age=28;
-- 查询所有商品的编号,名称和分类名称:
select t1.id,product_name,category_name from product t1 join product_category t2 on t1.category_id=t2.id;
-- 查两张表
select * from product_category;
select * from product;
-- 查询所有商品分类编号,分类名称,商品名,零售价
-- 左外连接
select t1.id,category_name,product_name,sale_price from product_category t1 left JOIN product t2 on t1.id=t2.category_id;
-- 右外连接
select t2.id,category_name,product_name,sale_price from product t1 right JOIN product_category t2 on t1.category_id=t2.id;
-- 查询每个商品分类的名称和父分类名称(所属分类的名称)
-- 把商品分类表product_category看成2张表,表1存储商品分类自身信息,表2存父分类的信息
select t1.category_name 商品分类名称, t2.category_name 父分类名称 from product_category t1 join product_category t2 on t1.parent_id=t2.id
-- 查询零售价比罗技MX1100更高的所有商品信息。
-- 1)查询罗技MX1100的零售价
select sale_price from product where product_name='罗技MX1100'
-- 2)查询零售价比上面结果更高的商品
select * from product where sale_price>550
-- 嵌套第1个sql到第2个sql中,把sql1的结果作为sql2的条件使用
select * from product where sale_price>( select sale_price from product where product_name='罗技MX1100');
-- 查询分类编号和折扣与罗技M100相同的所有商品信息。
-- sql1:查询罗技M100的分类编号和折扣
select category_id,cutoff from product where product_name='罗技M100'
-- sql2:查询分类编号和折扣都与sql1中的两列相同的商品
select * from product where (category_id,cutoff)=(select category_id,cutoff from product where product_name='罗技M100');
-- 查询零售价比分类编号为3的商品零售价都高的商品
-- sql1:查分类编号是3的商品零售价
select sale_price from product where category_id=3;
-- 多行子查询里只能使用多行的比较运算符 all,any,in
select * from product where sale_price>ALL(select sale_price from product where category_id=3)
-- 查询零售价比分类编号为3的平均零售价要高的商品信息
select * from product where sale_price>(select avg(sale_price) from product where category_id=3)
-- 修改零售价与罗M相同的商品的信息,将其折扣扩大为原来的2倍
update product set cutoff=cutoff*0.1 where category_id=(select
id from product_category where category_name='无线鼠标'
);
-- 数学函数
select floor(-9.92)
select CHAR_LENGTH('你好123'),LENGTH('你好123')
select left('helloworld',3);
-- SUBSTRING(s,n,len):截取字符串s,从第n个位置截取长度为len的子字符串
select SUBSTR('helloworld',3,5);
-- 日期函数
select CURRENT_DATE() 日期, CURRENT_TIME() 时间,NOW() 日期时间
-- 计算7天后的日期
select ADDDATE(CURRENT_DATE(),7);
-- 返回日期中的年和月
select year(CURRENT_DATE()) 年,month(CURRENT_DATE()) 月;
select DAYOFMONTH('2018-07-09');
-- if函数
select IF(3>2,'aaa','bbb');
-- ifnull函数,空值替代函数
select IFNULL(null,'hello');
-- 查询商品编号,名称,库存数量
select t1.id,product_name,IFNULL(store_num,0) from product t1 left join product_stock t2 on t1.id=t2.product_id;
-- 加密函数password()
select password('123');
-- 加密函数md5()
select md5('123')
-- ENCODE(str,pass_str)加密
select ENCODE('123','xxoo');
-- DECODE(crypt_str,pass_str)解密
select DECODE(';vx','xxoo')
利用下面的截图,自己去创建表并插入测试数据
1)学生表student
2)课程表course (tno:外键,老师编号)
3)分数表score (cno:外键,课程编号)
4)教师表teacher
表建好后,完成如下的需求:
1. 查询教师所有的单位都不重复的depart列
2.查询Score表中成绩在60到80之间的所有记录。
3. 查询Score表中成绩为85,86或88的记录。
4. 查询Student表中“95031”班或性别为“女”的同学记录。
5. 以Class降序查询Student表的所有记录。
6. 以Cno升序、Degree降序查询Score表的所有记录。
7. 查询“95031”班的学生人数。
8.查询Score表中的最高分的学生学号和课程号。
9. 查询每门课的课程名及平均成绩
10.查询Score表中至少有5名学生选修的且课程编号以3开头的课程的平均分数。
11. 查询所有学生的Sno、Cname和Degree列
12. 查询“95031”班学生的平均分。
(答案)
建表(略)不会Navicat有傻瓜式操作,sql用的比较普遍,就不详解了
表建好后,完成如下的需求:
1. 查询教师所有的单位都不重复的depart列
select distinct depart from teacher
2.查询Score表中成绩在60到80之间的所有记录。
select * from Score where degree between 60 and 80;
3. 查询score表中成绩为85,86或88的记录。
select * from score where degree in(85,86,88);
4. 查询Student表中“95031”班或性别为“女”的同学记录。
select * from student where class='95031' or ssex='女';
5. 以class降序查询Student表的所有记录。
select *from Student order by class desc;
6. 以Cno升序、Degree降序查询Score表的所有记录。
select * from Score order by cno, degree desc;
7. 查询“95031”班的学生人数。 select COUNT(*) from Student where class='95031';
8.查询Score表中的最高分的学生学号和课程号。
select Sno,Cno from Score where Degree=(select MAX(Degree) from Score);
9. 查询每门课的课程名及平均成绩
select cname,AVG(degree) FROM course join score on score.cno=course.cno GROUP BY cname;
10.查询Score表中至少有5名学生选修的且课程编号以3开头的课程的平均分数。
select cno,AVG(degree) FROM score GROUP BY cno HAVING COUNT(cno) > 5 AND
cno LIKE '3%';
11. 查询所有学生的Sno、Cname和Degree列
Select t1.Sno,t2.Cname, t1.degree from score t1 join course t2 on t1.cno=t2.cno
12. 查询“95031”班学生的平均分。
select AVG(degree) from Student t1 join Score t2 on t1.Sno=t2.Sno and class='95031'
1.索引
关于索引的优化,注意以下几点:
1)使用like做模糊查询时,关键字xxx要写在通配符的前面,即’xxx%’或’xxx_’,否则是不会走索引的
例如:
explain select * from t_employee where ename like '张%'explain select * from t_employee where ename like '张_'
2)不要在建立了索引的列上做数学运算,否则会导致索引失效而进行全表扫描
explain select * from t_employee where ceil(salary)>7200;
3)在查询条件中使用如下运算符会用到索引: =,<, in(对普通索引有效,对组合索引无效),
对于不以通配符开头的like查询也会用到索引
实际开发中,表的数据量通常都是5-10W行级别的,此时如果不在合适的列上创建索引,将导致任何查询都会走全表扫描,会极大的影响查询效率。任何的网站或者系统都会考虑使用索引来优化查询。
如果在SQL语句中确实要用到不等值的判断,就要考虑使用等价的SQL来代替,目的是让MySQL去使用索引,避开全表扫描
-- 避免在查询语句中使用不等号,否则会导致索引失效explain select * from t_employee where ename<>'张三丰';-- 使用等价的sql查询名字不是张三丰的人,用到了索引explain select * from t_employee where eid>1;
避免在 where 子句中使用 or 来连接条件,很可能会导致引擎放弃使用索引而走全表扫描(如果在where子句中的字段是唯一或普通索引中的字段时,会走索引;如果字段是组合索引中的字段,就不走索引)
-- 用主键列查询,走索引explain select * from t_employee where eid =1 or eid=5;-- 用组合索引中的列查询,不走索引explain select * from t_employee where salary=5000 or salary=7500
在where子句中慎用in和not in,因为如果where中的字段是组合索引中的字段时,会让引擎放弃索引而走全表扫描
-- 用组合索引中的列查询,不走索引explain select * from t_employee where salary in(5000,7500)
使用union all语句来合并两个结果集,代替上面的in(a,b)子句
explain select * from t_employee where salary=5000union all(select * from t_employee where salary=7500)
使用模糊查询时,关键字必须在最前面,即头匹配,例如”xxx%”或”xxx_”,否则是不走索引的
如果在where子句中对字段进行运算,会导致索引失效而走全表扫描
例如下面的sql没有走索引
select * from t_employee where salary/200=36;
改成select * from t_employee where salary=200*36;就走索引了
不要把字段放在函数中去操作,这样导致索引失效,如下:
select * from t_employee where CHAR_LENGTH(ename)=2 and SUBSTRING(ename,1,1)='张';
改造成下面的sql,就能走索引了
select * from t_employee where ename like '张_'
例如,在t_emloyee表上有组合索引
create index index_salary_age on t_employee(salary,age);
此时,下面的sql不走索引
select * from t_employee where age=25;
如果用到了多表且是在某个范围内的查询,建议用exists来代替in,例如
select num from a where num in(select num from b);等价于下面的SQL:select num from a where exists (select 1 from b where b.num=a.num)
在实际项目中,不要写select * from 表,因为实际项目中表的字段通常有10个以上,如果写select *就意味着每个字段都要被扫描,应该根据项目的需求来写字段,多个字段名用逗号隔开即可。例如查询员工的编号,姓名,工资信息
select eid,ename,salary from t_employee;
其实还没完,后面在高级阶段还会深入学习SQL优化,涉及到MyCat分库分表技术
基于MVC分层思想将项目划分成多个不同的包,每个包又叫层。
MVC:即Model (模型)+ View(视图)+Controller(控制器),是将项目划分成不同包,不同的包都属于MVC中的一个组件,共3个组件
Model :模型,包含数据模型和业务模型,数据模型就是项目中封装对数据操作的类,在项目中通常就是dao层+entity层充当数据模型的角色.业务模型就是封装实现具体业务功能的类,这些类是service层中的(暂时不写service层)
View:视图,即显示给用户看的界面,如html页面,jsp页面,可以用控制台充当View
Controller:控制器,接收客户端的请求并返回响应给客户端,后面学的Servlet充当控制器
数据库参数配置代码(首先要在数据库建好对应的数据表:如mysqldb为表名)
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/mysqldb
user=root
password=root
JdbcUtil代码
/**
* jdbc操作数据库的工具类,封装通用的代码
*
* @author lujun
*
*/
public class JdbcUtil {
// 数据库驱动类
private static String driver;
// 数据库服务器的地址
private static String url;
// 连接服务器的用户名
private static String user;
// 连接服务器的用户密码
private static String password;
// 加载驱动只需要加载一次,可以放到静态代码块中
static {
try {
// 对db.properties文件的读取
Properties prop = new Properties();
// 加载文件,并转换为输入流,从流中读取数据
InputStream stream = JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties");
prop.load(stream);
// 调用getProperty(String key),根据key获取相应的value
url = prop.getProperty("url");
user = prop.getProperty("user");
password = prop.getProperty("password");
driver = prop.getProperty("driver");
// 加载驱动
Class.forName(driver);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// 获取一个连接
public static Connection getConnection() {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
// 关闭资源
public static void closeAll(ResultSet rs, Statement stmt, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/*
* 通用增删改方法 参数1:要执行的DML语句(insert,update,delete语句)
* 参数2:给DML语句中的?赋的一组值,把占位符值统一放到可变参数中,可变参数可以当成数组用
* 返回值:执行增删改影响数据库的行数,如果成功,返回1,失败返回0
*/
public static int executeUpdate(String sql, Object... params) {
int count = 0;
// 创建连接
Connection conn = JdbcUtil.getConnection();
//执行预编译SQL的操作对象
PreparedStatement stmt = null;
try {
// 创建预编译的statement
stmt = conn.prepareStatement(sql);
// 给占位符?赋值
for (int i = 0; i < params.length; i++) {
stmt.setObject(i + 1, params[i]);
}
count = stmt.executeUpdate();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 关闭资源
JdbcUtil.closeAll(null, stmt, conn);
}
return count;
}
/*public static void main(String[] args) {
Connection connection = JdbcUtil.getConnection();
System.out.println(connection);
}*/
}
然后创建数据类Student(代码略),接下来创建dao层接口,定义抽象方法
//插入数据
int insert(Student stu);
//修改数据
int update(Student stu);
//删除
int delete(int sid);
//全查询(查询所有记录)
List queryAll();
//查询一个记录
Student queryById(int sid);
创建dao接口实现类StudentDaoImpl
@Override
public int insert(Student stu) {
// TODO Auto-generated method stub
String sql = "insert into student(sname,sex,age) values(?,?,?)";
int count = JdbcUtil.executeUpdate(sql, stu.getSname(), stu.getSex(), stu.getAge());
return count;
}
@Override
public int update(Student stu) {
// TODO Auto-generated method stub
String sql = "update student set sname=?,sex=?,age=? where sid=?";
Object[] params = { stu.getSname(), stu.getSex(), stu.getAge(), stu.getSid() };
// int count = JdbcUtil.executeUpdate(sql,
// stu.getSname(),stu.getSex(),stu.getAge(),stu.getSid());
int count = JdbcUtil.executeUpdate(sql, params);
return count;
}
@Override
public int delete(int sid) {
// TODO Auto-generated method stub
String sql = "delete from student where sid=?";
int count = JdbcUtil.executeUpdate(sql, sid);
return count;
}
@Override
public List queryAll() {
// TODO Auto-generated method stub
List list = new ArrayList<>();
String sql = "select * from student";
// 手动处理结果集
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = null;
ResultSet rs = null;
// 预编译SQL的操作对象
try {
stmt = conn.prepareStatement(sql);
rs = stmt.executeQuery();
while (rs.next()) {
// 调用rs.getXxx(字段的索引)或rs.getXxx("字段的名称")
int sid = rs.getInt(1);
String sname = rs.getString("sname");
String sex = rs.getString("sex");
int age = rs.getInt("age");
// 封装到Student对象上
Student stu = new Student(sname, sex, age);
stu.setSid(sid);
list.add(stu);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcUtil.closeAll(rs, stmt, conn);
}
return list;
}
@Override
public Student queryById(int sid) {
// TODO Auto-generated method stub
Student stu = null;
String sql = "select * from student where sid=?";
// 手动处理结果集
Connection conn = JdbcUtil.getConnection();
PreparedStatement stmt = null;
ResultSet rs = null;
// 预编译SQL的操作对象
try {
stmt = conn.prepareStatement(sql);
// 给?赋值
stmt.setInt(1, sid);
rs = stmt.executeQuery();
if (rs.next()) {
// 调用rs.getXxx(字段的索引)或rs.getXxx("字段的名称")
int stuid = rs.getInt(1);
String sname = rs.getString("sname");
String sex = rs.getString("sex");
int age = rs.getInt("age");
// 封装到Student对象上
stu = new Student(sname, sex, age);
stu.setSid(sid);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
JdbcUtil.closeAll(rs, stmt, conn);
}
return stu;
}
最后编写测试类
```a public static void main(String[] args) { showMenu(); }
public static void showMenu() {
// 声明保存用户信息的变量
String sname = null;
String sex = null;
int age = 0;
int sid = 0;
System.out.println("----学生信息管理系统----");
System.out.println("请选择:1.显示所有学生 2.根据id查询一个学生 3.添加学生 4.修改学生 5.删除学生 6.退出");
Scanner sc = new Scanner(System.in);
System.out.print("请输入一个数字(1-6):");
int choice = Integer.parseInt(sc.nextLine());
switch (choice) {
case 1:
MyTest.getAll();
showMenu();
break;
case 2:
System.out.print("请输入要查询的学生编号:");
int id = Integer.parseInt(sc.nextLine());
MyTest.getStudentById(id);
showMenu();
break;
case 3:
System.out.print("请输入学生的姓名:");
sname = sc.nextLine();
System.out.print("请输入学生的性别:");
sex = sc.nextLine();
System.out.print("请输入学生的年龄:");
age = Integer.parseInt(sc.nextLine());
// 封装学生对象
Student stu = new Student(sname, sex, age);
// 调用添加学生的方法
MyTest.addStudent(stu);
showMenu();
break;
case 4:
System.out.print("请输入要修改的学生的编号:");
sid = Integer.parseInt(sc.nextLine());
System.out.print("请输入学生的姓名:");
sname = sc.nextLine();
System.out.print("请输入学生的性别:");
sex = sc.nextLine();
System.out.print("请输入学生的年龄:");
age = Integer.parseInt(sc.nextLine());
// 封装一个学生对象
Student stu2 = new Student(sname, sex, age);
stu2.setSid(sid);
// 调用修改学生的方法
MyTest.updateStudent(stu2);
showMenu();
break;
case 5:
System.out.print("请输入要删除的学生的编号:");
sid = Integer.parseInt(sc.nextLine());
// 调用删除学生的方法
MyTest.deleteStudent(sid);
showMenu();
break;
case 6:
// 结束虚拟机进程
System.exit(0);
break;
default:
System.out.println("输入错误,请重新输入");
showMenu();
break;
}
}
// 显示所有学生
public static void getAll() {
StudentDao stuDao = new StudentDaoImpl();
List list = stuDao.queryAll();
System.out.println("学生编号t姓名t性别t年龄");
for (Student stu : list) {
System.out.println(stu.getSid() + "t" + stu.getSname() + "t" + stu.getSex() + "t" + stu.getAge());
}
}
// 根据id查询一个学生
public static void getStudentById(int id) {
StudentDao stuDao = new StudentDaoImpl();
Student stu = stuDao.queryById(id);
if (stu == null) {
System.out.println("id错误,查无此人!");
} else {
System.out.println("学生编号t姓名t性别t年龄");
System.out.println(stu.getSid() + "t" + stu.getSname() + "t" + stu.getSex() + "t" + stu.getAge());
}
}
// 添加一个学生
public static void addStudent(Student stu) {
StudentDao stuDao = new StudentDaoImpl();
int i = stuDao.insert(stu);
if (i > 0) {
System.out.println("添加成功!");
} else {
System.out.println("添加失败!");
}
}
// 修改一个学生
public static void updateStudent(Student stu) {
StudentDao stuDao = new StudentDaoImpl();
int i = stuDao.update(stu);
if (i > 0) {
System.out.println("修改成功!");
} else {
System.out.println("修改失败!");
}
}
// 删除一个学生
public static void deleteStudent(int id) {
StudentDao stuDao = new StudentDaoImpl();
int i = stuDao.delete(id);
if (i > 0) {
System.out.println("删除成功!");
} else {
System.out.println("删除失败!");
}
}
```
安装:
将资料中apache-tomcat-7.0.78-windows-x64.zip解压到一个没有中文及空格的目录下(解压就算装好了,就能使用了)
启动tomcat
进入到解压目录里的bin目录下,双击运行startup.bat文件,出现如下界面,就是启动成功
启动完成后在浏览器地址栏上输入http:// localhost:8080 ,会看到如下界面
停止tomcat服务器
运行bin目录下的shutdown.bat,就可以关闭tomcat服务器
bin目录:存放可执行文件
Conf目录:存放与服务器相关的配置文件,在此目录下有如下几个重要文件:
Server.xml:配置整个服务器信息。例如修改端口号,添加虚拟主机等;
在conf/server.xml中修改端口号:找到server.xml中的Connector节点,
然后修改它的port属性,如下所示:
改了端口号后,需要重新启动tomcat服务器
Web.xml:部署描述符文件,这个文件中注册了很多 MIME 类型,即文档类型。
Web.xml中注册不同的MIME类型,在浏览器下载web资源时,会用到对应的
MIME类型(mime-type)
jpg image/jpeg
Context.xml:此文件中配置了
WEB-INF/web.xml,是表明我们自己开发的web项目中的web.xml文件改了以后, 不用手动重启tomcat服务器,因为此文件总是被扫描(Watched),一旦发现文件被改后,会自动重启服务器
webapps: 此目录存放web项目,我们自己开发的web项目必须存放到webapps目录下,才可以被外界访问。
1)在tomcat服务器的webapps目录下创建目录hello,这时hello就是web应用了.
2)在hello目录下编写静态资源文件hello.html
3)启动tomcat服务器
4).在浏览器中输入http://localhost:8088/hello/hello.html,成功访问到了页面
注意:
1)访问tomcat服务器下某个具体资源的完整路径:
http://*域名或IP:* 端口号/项目名/xxx.html(xxx.jsp)
http://域名或IP: 端口号映射的是tomcat服务器的webapps目录的绝对路径, 如:D:apache-tomcat-7.0.78webapps
2)http协议默认的端口号是80,所以如果tomcat服务器的端口号也是80,就可以省略端口号不写,例如:http://localhost/hello/hello.html
3).只有当tomcat的端口号是80时,才可以省略端口号不写
4)在Eclipse中配置了tomcat服务器后,Eclipse的package Explore里会出现一个名为Servers的项目,这个项目不能删掉,我们可以直接在servers下面修改server.xml,它会自动的和conf/server.xml同步
步骤参考资料中的”使用Eclipse开发web应用程序.docx”去做.
如果是创建动态页面,需要选择New--->JSP File
按照向导一步步的往后走,就能把页面创建出来了.
默认Eclipse第一次新建的jsp页面使用ISO-8859-1编码,此时页面上不能保存中文内容.
可以在Eclipse中做全局设置,Windows-->Preferences-->Web-->JSP Files,在右侧选择UTF-8编码即可
创建了web项目后,在package Explorer和project Explorer两个不同的透视图中的结构是不一样,切换透视图的方法是点击右侧的打开透视图的图标,选择”java”就是package Explorer
客户端给服务器发送请求时,请求方法有GET,POST, PUT,DELETE,PATCT等,但是浏览器默认只支持GET和POST请求,PUT,DELETE,PATCT请求在springmvc的restful技术里会学到。
1)GET请求将请求参数追加在url的后面,格式:?参数名=值&参数名2=值2...
POST请求是将请求参数放到Form体内提交的,在URL上面看不到参数
现阶段,只有当表单的method=”post”时,发送的请求才是POST请求,其它情况下提交的请求都是GET请求,常用的GET请求:
1)点击超链接发送的请求
2)在地址栏中输入url直接访问
3)
请求图片文件
4)请求js文件
5)请求css文件
注意:1)form表单的method属性默认值是GET,如果省略method不写,发送的就是GET请求
2)在实际项目中,查询或者删除的需求,就发送GET请求(查询分为全查询和根据id查询),添加或修改的需求,就发送POST请求
3)超链接发送GET请求,需要自己拼接请求参数,格式:?参数名=值&参数名2=值2...
按快捷键F12或者在浏览器窗口上右键”检查”,就可以打开网络面板
在NetWork下面可查看请求消息:请求行,请求头,请求体
请求体:只有当请求方法是POST时,才有请求体,请求体就是Form Data,请求体中是POST请求的参数数据
如果请求方法是GET,没有请求体,请求参数都被解析成查询字符串,可以在查询字符串里看到请求参数
200:代表一切正常,服务器返回正常的结果
404:资源找不到,即请求的url是错误的
500:服务器内部错误,即服务器端的程序有错误
例如:
<% out.print(10/0); %>
运行时,报500错误
1)创建web项目,导入mysql的驱动包,直接把jar包拷贝到WEB-INFlib目录中即可,会自动把jar添加到构建路径
细节:把三级包建好,要想包与包之间有层次感,需要将包布局方式改成垂直布局
显示效果
2)在index.jsp上放一个超链接,点击后跳转到列表页面list.jsp
显示所有学生
3)在list.jsp页面上调用Dao里的全查询方法,将获取的集合进行遍历,每循环一次就生成一行在表格中
<%-- 可以使用jsp表达式来代替脚本, jsp表达式语法:<%=java表达式%> --%> <% //创建StudentDao的对象 StudentDao stuDao = **new** StudentDaoImpl(); List list = stuDao.queryAll(); **for** (Student stu : list) { %> <% } %> 编号姓名性别年龄<%=stu.getSid() %><%=stu.getSname() %><%=stu.getSex() %><%=stu.getAge() %>
编号
姓名
性别
年龄
<%-- 可以使用jsp表达式来代替脚本, jsp表达式语法:<%=java表达式%> --%>
<%
//创建StudentDao的对象
StudentDao stuDao = new StudentDaoImpl();
List list = stuDao.queryAll();
for (Student stu : list) {
%>
<%=stu.getSid() %>
<%=stu.getSname() %>
<%=stu.getSex() %>
<%=stu.getAge() %>
<%
}
%>
注意:1).<%=xxx %>是jsp表达式的语法,表达式不能以;结尾的
2). Jsp脚本和表达式不能相互嵌套,只能彼此隔离
3)欢迎页就是配置在web.xml中的页面,当访问欢迎页时,可以省略页面名称不写
index.jsp index.html
在访问index.jsp页面时,由于它是欢迎页,访问时可以省略index.jsp
4)如果仅仅是修改了jsp页面上的代码,不需要重启服务器,只要刷新jsp页面即可