一、maven
maven是Java项目依赖的管理仓库
1.maven的生命周期:
(1)clean:主要是清理工作
(2)default:是构建的核心部分,编译,测试,打包,部署等等,Default生命周期是Maven生命周期中最重要的一个,绝大部分工作都发生在这个生命周期中。
(3)site:生成项目的时候,会产生站点,可以理解为tomcat发布的webapp,作为一个网站
2.maven的核心概念
(1)maven的三个坐标简称GAV
groupId:公司或组织的 id,即公司或组织域名的倒序,通常也会加上项目名称
例如:groupId:com.fs.maven
artifactId:一个项目或者是项目中的一个模块的 id,即模块的名称,将来作为 Maven 工程的工程名
例如:artifactId:auth
version:版本号
例如:version:1.0.0v
(2)pom.xml文件:
项目对象模型,POM 表示将工程抽象为一个模型,再用程序中的对象来描述这个模型。这样我们就可以用程序来管理项目了。我们在开发过程中,最基本的做法就是将现实生活中的事物抽象为模型,然后封装模型相关的数据作为一个对象,这样就可以在程序中计算与现实事物相关的数据。
设置编码:
(3)依赖:
3-1
complie:表示编译范围,指 A 在编译时依赖 B,该范围为默认依赖范围。编译范围的依赖会用在编译,测试,运行,由于运行时需要,所以编译范围的依赖会被打包。
provided:provied 依赖只有当 jdk 或者一个容器已提供该依赖之后才使用。provide 依赖在编译和测试时需要,在运行时不需要。例如:servlet api被Tomcat容器提供了。 runtime:runtime 依赖在运行和测试系统时需要,但在编译时不需要。例如:jdbc 的驱动包。由于运行时需要,所以 runtime 范围的依赖会被打包。 test:test 范围依赖在编译和运行时都不需要,只在测试编译和测试运行时需要。例如:Junit。由于运行时不需要,所以 test 范围依赖不会被打包。 system:system 范围依赖与 provide 类似,但是必须显示的提供一个对于本地系统中 jar 文件的路径。
3-2依赖的传递:
A 依赖 B,B 依赖 C,那么在 A 没有配置对 C 的依赖的情况下,A 里面能不能直接使用 C?以上的前提下,C 是否能够传递到 A,取决于 B 依赖 C 时使用的依赖范围。B 依赖 C 时使用 compile 范围:可以传递,B 依赖 C 时使用 test 或 provided 范围:不能传递,所以需要这样的 jar 包时,就必须在需要的地方明确配置依赖才可以。
(4)maven的继承:
子工程会继承父工程的pom配置文件。
4-1新建子工程
新建之后父工程的pom:
子项目指定父项目工程:
此时依赖才被引入,子项目的依赖不用写版本,版本通过继承可得。
对同一个框架的一组 jar 包最好使用相同的版本,为了方便升级框架,可以将 jar 包的版本信息统一提取出来,统一声明版本号 :在需要的地方使用${}
的形式来引用自定义的属性名,这样子只需要修改一个地方,就可以实现处处生效。
(5)maven的聚合
5-1:聚合其实就是使用一个总工程聚合所有的模块作为一个整体的项目,实际就是module标签。
5-2:build标签 在实际使用 Maven 的过程中,我们会发现 build 标签有时候有,有时候没,这是怎么回事呢?其实通过有效 POM 我们能够看到,build 标签的相关配置其实一直都在,只是在我们需要定制构建过程的时候才会通过配置 build 标签覆盖默认值或补充配置。这一点我们可以通过打印有效 POM 来看到。打印有效 pom mvn help:effective-pom。当默认配置无法满足需求的定制构建的时候,就需要使用 build 标签。
(6)profile
profile含义:项目的每一个运行环境,相当于是项目整体的一个侧面。
通常情况下,我们项目至少有三种运行环境:
开发环境:供不同开发工程师开发的各个模块之间互相调用、访问;内部使用
测试环境:供测试工程师对项目的各个模块进行功能测试;内部使用
生产环境:供最终用户访问——所以这是正式的运行环境,对外提供服务
(7)分页查询
7-1:项目搭建:
web项目结构: WEB-INF -web.xml: web相关的配置: servlet, filter,... web3.0 使用注解替换 -classes: src目录编译生成字节码文件存放在该目录,称为类路径(发布 -lib: 第三方依赖,pom.xml添加依赖(发布时)
web项目要求: 打包方式: war 发布到tomcat,自动解压war servlet+jsp实现web项目,导入 servlet-api jsp-api依赖,scope设置为provided
7-2页面要求:
1.传递当前页码(请求参数)
2.页面需要的数据(查数据库)
3.页容量(后端设定)
4.总页数:总记录数/页容量 %= 0 则不用加1,如果余数不等于0则需要+1
5.当前页码(请求参数)
注意:
Java程序把这五个数据封装作为一个对象。
get请求,通过超链接地址栏访问
post请求:jqury的post方法,注意get里写一个post方法
二、mybatis
解决dao层问题解决方案, 之前dao使用的技术: JDBC
mybatis是一个半自动化的持久层框架,
可以注解配置、映射xml文件中编写动态sql语句。通常使用xml编写sql。
mybatis是对jdbc封装的框架,几乎不需要jdbc操作
mybatis提供面向接口,持久层只需要一个接口,不需要实现类。
一、mybaits工作原理:
(1)JDBC核心对象
- DriverManager,数据库驱动管理对象
- Connection,数据库连接对象
- Statement | PrepareStatement ,操作数据库SQL语句对象
- ResultSet,结果集对象
(2)mybaits核心对象:
1.SqlSession对象,该对象包含了执行SQL语句的所有方法,例如JDBC里面Connection
2.Executor接口,将传递过来的参数动态生成SQL语句,负责查询缓存。
3.MappedStatement对象,该对象负责对SQL封装,用于存储需要映射的SQL语句及参数等信息
4.ResultHandler对象,用户返回结果集合,封装成最红想要的数据类型,可以自定义返回类型
二、配置代码
<!DOCTYPE mapper ...>
<mapper namespace="com.sly.ecs.business.mapper.mission.MissionMapper">
<insert id="insertBatch" parameterType="list" ...>
<select id="selectMission" parameterType="int" resultMap="BaseResultMap" ...>
</mapper>
三、参数:
(1)传入参数的情形:
mapper接口方法的参数是单个:
xml文件用#{ },来 取 值 , 需 要 注 意 { }来取值,需要注意来取值,需要注意{ }要用单引号。
{}中的名称是任意的,因为只有一个参数,无论取值时叫什么,都能够取到值。
mapper接口方法的参数是多个:
会用Map集合保存参数,键是由mybatis框架自动生成
xml文件可以用 arg0 、arg1 。。。 获取对应位置的参数
xml文件可以用 param1 、param2 。。。 获取对应位置的参数
也可以交叉使用,例如 arg0、 param2
mapper接口方法的参数是多个,可以放到一个Map集合里
键是由开发者人为设置。
在xml映射文件里根据人为设置的键获取参数。
mapper接口方法的参数是实体类
xml文件里根据实体类的属性获取属性值。
public final class GenericQueryParam extends LinkedHashMap<String, Object>
implements ListQueryParam { ... }
var param = new GenericQueryParam();
param.fill("signCode", signCode).fill("typeId", typeId).fill("labelId", labelId)
.fill("areaId", areaId).fill("status", status).fill("userId", userId);
(2)获取参数的两种方式:(jdbc原生写法)
${} 字符串拼接。不会带上单引号。注意要手动加上单引号。
#{} 占位符赋值。会带上单引号。不需要手动加上单引号。
示例:
常规方法
username = #{username} AND sign_code = #{signCode}
Mybatis处理模糊查询
role_name LIKE CONCAT('%',#{roleName},'%')
role_name LIKE '%${roleName}%'
role_name LIKE "%"#{roleName}"%"
总结:
sql语法中需要引号的 尽量使用#{},或者${} 手动加上引号。 例如字符串、日期等类型的值。
sql语法中不需要引号的 使用${} ,不用手动加上引号。例如in范围查询、表名、字段、排序关键字。
四、mybatis的CURD
1.添加
//mapper接口方法
void add(Brand brand);
<--配置代码-->
<insert id="add">
insert into tb_brand (brand_name, company_name, ordered, description, status)
values (#{brandName},#{companyName},#{ordered},#{description},#{status});
</insert>
<--测试代码-->
@Test
public void testadd() throws IOException {
//接收参数:
int status = 1;
String companyName = "波导手机";
String brandName = "波导";
String description = "手机中的战斗机";
int ordered = 100;
//封装对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);
brand.setDescription(description);
brand.setOrdered(ordered);
//1.获取SqlSessionFactory
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
//返回一个字节输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取sqlSession对象
// SqlSession sqlSession = sqlSessionFactory.openSession();
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3. 获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
brandMapper.add(brand);
//提交事务
// sqlSession.commit();
//5. 释放资源
sqlSession.close();
}
Mybatis事务:
openSession():默认开启事务,进行增删改后需要使用sqlSession.commit();手动提交事务
openSession(true):可以设置为自动提交事务(默认为false:手动提交事务)
在数据添加成功后,需要获取插入数据库数据的主键的值
2.修改
//mapper接口方法
void update(Brand brand);
//编写SQL语句:编写SQL映射文件
<update id="update">
update tb_brand
set brand_name = #{brandName},
company_name = #{companyName},
ordered = #{ordered},
description = #{description},
status = #{status}
where id = #{id};
</update>
//测试代码
/**
* 修改
* @throws IOException
*/
@Test
public void testUpdate() throws IOException {
//接收参数:
int status = 1;
String companyName = "波导手机";
String brandName = "波导";
String description = "波导手机,手机中的战斗机";
int ordered = 200;
int id = 5;
//封装对象
Brand brand = new Brand();
brand.setStatus(status);
brand.setCompanyName(companyName);
brand.setBrandName(brandName);
brand.setDescription(description);
brand.setOrdered(ordered);
brand.setId(id);
//1.获取SqlSessionFactory
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
//返回一个字节输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3. 获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
int count = brandMapper.update(brand);
System.out.println(count);
//5. 释放资源
sqlSession.close();
}
3.删除
(1)删除一个
//编写SQL语句:编写SQL映射文件
<select id="deleteById">
delete from tb_brand where id = #{id};
</select>
//测试代码
/**
* 根据Id删除一个
* @throws IOException
*/
@Test
public void testDeleteById() throws IOException {
//接收参数:
int id = 9;
//1.获取SqlSessionFactory
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
//返回一个字节输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3. 获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
brandMapper.deleteById(id);
//5. 释放资源
sqlSession.close();
}
(2)批量删除
sql映射文件
<!--
Mybatis会将数组参数封装为一个Map集合。
*默认:array = 数组
*可以使用@Param注解改变map集合的默认key名称
-->
<!-- <delete id="deleteByIds">
delete from tb_brand where id
in
/*
**separator:分隔符
**open:循环开始前的字符
**close:循环结束后的字符
*/
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>;
</delete>-->
<delete id="deleteByIds">
delete from tb_brand where id
in
/*
**separator:分隔符
**open:循环开始前的字符
**close:循环结束后的字符
*/
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>;
</delete>
测试代码
/**
* 根据Id删除一个
* @throws IOException
*/
@Test
public void testDeleteById() throws IOException {
//接收参数:
int id = 9;
//1.获取SqlSessionFactory
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
//返回一个字节输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession(true);
//3. 获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
brandMapper.deleteById(id);
//5. 释放资源
sqlSession.close();
}
4.查询
sql映射文件
<select id="selectByConditionSingle" resultMap="brandResultMap">
<!-- select *-->
<!-- from tb_brand-->
<!-- where-->
<!-- <choose><!–相当于switch–>-->
<!-- <when test="status != null">-->
<!-- status = #{status}-->
<!-- </when><!–相当于case–>-->
<!-- <when test="companyName != null and companyName!= ''">-->
<!-- company_name like #{companyName}-->
<!-- </when><!–相当于case–>-->
<!-- <when test="brandName != null and brandName!= ''">-->
<!-- brand_name like #{brandName}-->
<!-- </when><!–相当于case–>-->
<!-- <otherwise><!–相当于default–>-->
<!-- 1 = 1-->
<!-- </otherwise>-->
<!-- </choose>-->
<!-- </select>-->
select *
from tb_brand
<where>
<choose><!--相当于switch-->
<when test="status != null">
status = #{status}
</when><!--相当于case-->
<when test="companyName != null and companyName!= ''">
company_name like #{companyName}
</when><!--相当于case-->
<when test="brandName != null and brandName!= ''">
brand_name like #{brandName}
</when><!--相当于case-->
</choose>
</where>
</select>
测试代码
@Test
public void testSelectByCondition() throws IOException {
//接收参数:
int status = 1;
String companyName = "华为";
String brandName = "华为";
//处理参数
companyName = "%" + companyName + "%";
brandName = "%" + brandName + "%";
//封装对象
Brand brand = new Brand();
//brand.setStatus(status);
brand.setCompanyName(companyName);
//brand.setBrandName(brandName);
//1.获取SqlSessionFactory
//加载mybatis的核心配置文件,获取SqlSessionFactory
String resource = "mybatis-config.xml";
//返回一个字节输入流
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//2. 获取sqlSession对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//3. 获取Mapper接口的代理对象
BrandMapper brandMapper = sqlSession.getMapper(BrandMapper.class);
//4. 执行方法
// List<Brand> brands = brandMapper.selectByCondition(status, companyName, brandName);
// List<Brand> brands = brandMapper.selectByCondition(brand);
List<Brand> brands = brandMapper.selectByCondition(map);
System.out.println(brands);
//5. 释放资源
sqlSession.close();
}
五、MyBatis参数传递
(1)POJO类型:直接使用,实体类属性名 和参数占位符名称一致
(2)Map集合:直接使用,键名和参数占位符名称一致
(3)Collection:封装为Map集合
(4)List:封装为Map集合
六、mybatis缓存机制
mybatis为减轻数据库压力,提高数据库性能。提供了两级缓存机制:
实体类:
@Data
public class Student implements Serializable {
private Integer stuId;
private String stuName;
private Integer stuAge;
private Double stuSalary;
private Date stuBirth;
private Date createTime;
private Integer courseId;
}
接口studentmapper
public interface StudentMapper {
//通过id查询学生,传递单个参数
Student queryStudentById(Integer id);
//删除一条信息,通过id
Integer delete(Integer id);
}
映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:Mapper接口的全路径,使其和Mapper对应-->
<mapper namespace="com.yjg.mapper.StudentMapper">
<delete id="delete">
DELETE from student where stu_id=${id}
</delete>
<select id="queryStudentById" parameterType="integer" resultType="Student">
select * from student where stu_id=${id}
</select>
</mapper>
测试代码
@Test
public void test1() throws Exception{
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis.xml"));
SqlSession sqlSession1 = sqlSessionFactory.openSession();
//只执行了一条sql语句
StudentMapper mapper1 = sqlSession1.getMapper(StudentMapper.class);
Student student1 = mapper1.queryStudentById(2);
System.out.println(student1);
Student student2 = mapper1.queryStudentById(2);
System.out.println(student2);
sqlSession1.close();
}
运行结果
1.一级缓存:
SqlSession级别的缓存,缓存的数据只在SqlSession内有效。
一级缓存mybatis已近为我们自动开启,不用我们手动操作,而且我们是关闭不了的!!但是我们可以手动清除缓存。
一级缓存是sqlSession级别的缓存。在操作数据库时需要构造sqlSession对象,在对象中有一个基于 PerpetualCache的HashMap本地缓存数据结构,用于缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互不影响的。
2.二级缓存:
mapper级别的缓存,同一个namespace公用这一个缓存,所以对SqlSession是共享的。
二级缓存需要我们手动开启。
二级缓存(全局级别) 是mapper级别的缓存,多个sqlSession去操作同一个Mapper的sql语句,多个sqlSession可以共用二级缓存,二级缓存是跨sqlSession的。
什么时候一级缓存失效?
第一次DQL和第二次DQL之间你做了以下两件事中的任意一件,都会让一级缓存清空:
1.执行了sqlSession的clearCache()方法,这是手动清空缓存。
2.执行了INSERT或DELETE或UPDATE语句。不管你是操作哪张表的,都会清空一级缓存。
Mybatis二级缓存
二级缓存的范围是SqlSessionFactory。
使用二级缓存需要具备以下几个条件:
<setting name="cacheEnabled" value="true"> 这个配置表示启用 MyBatis 的二级缓存功能。默认就是true,⽆需在配置文件设置。
在需要使⽤⼆级缓存的StudentMapper.xml⽂件中添加配置:<cache/>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:Mapper接口的全路径,使其和Mapper对应-->
<mapper namespace="com.yjg.mapper.StudentMapper">
<!-- 默认情况下,二级缓存机制是开启的。-->
<!-- 只需要在对应的StudentMapper.xml文件中添加以下标签。用来表示”我"使用该二级缓存。-->
<cache/>
<delete id="delete">
DELETE from student where stu_id=${id}
</delete>
<select id="queryStudentById" parameterType="integer" resultType="Student">
select * from student where stu_id=${id}
</select>
</mapper>
使⽤⼆级缓存的实体类对象必须是可序列化的,也就是必须实现java.io.Serializable接⼝
二级缓存使用成功,只存在一条select语句,并且缓存第二个命中率不为0