目录
框架
对技术的封装,将基础的技术进行封装,让程序员可以快速的使用,提高开发效率
java后端框架
mybatis
对jdbc进行封装
spring
对整个java后端构架进行管理的
springweb
对web层(servlet)继续封装
springboot
对spring框架的搭建进行封装
mybatis
背景
原来是apache下面的一个开源项目,名为ibatis,2010年开发团队转移到谷歌旗下,改名为mybatis
Mybatis 中文官网
mybatis – MyBatis 3 | 简介
介绍
mybatis是一款优秀的持久层(数据持久层)框架(数据持久层----dao层 也称为 数据访问层)
mybatis是对jdbc进行的封装,避免了jdbc中手动设置参数,手动映射结果的操作
mybatis将jdbc中的接口进行封装,提供了他自己的类和接口实现
mybatis可以使用xml配置和注解的方式,将数组库中记录自动映射到java对象中
是一直ORM实现(对象关系映射) 可以自动将数据映射到对象中的这种框架,也称为orm框架
mybatis还提供了 动态sql 和 数据缓存
mybatis搭建
1.创建一个maven项目
2.导入mybatis依赖的jar包
<!--mybatis-->
<dependency>
< groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.2</version>
</dependency>
3.在src.main.resources下创建一个全局的mybatis配置文件
配置数据库链接等配置
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 上面都是固定内容,下面才开始改变 -->
<!--mybatis核心全局配置文件-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--java中使用标准驼峰命名,数据库中使用下划线连接命名,可以开启全局设置实现自动转换-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--为类配置别名-->
<typeAliases>
<package name="com.ffyc.mybatispro.model"/>
</typeAliases>
<!--配置数据库链接相关信息-->
<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<!-- type="POOLED" 使用数据库连接池功能,默认创建了10个链接对象,减少频繁创建销毁链接对象 -->
<dataSource type="POOLED">
<!--数据库连接配置-->
<property name="driver" value="com.mysql.cj.jdbc.Driver" />
<property name="url" value="jdbc:mysql://127.0.0.1:3306/ssmdb?serverTimezone=Asia/Shanghai" />
<property name="username" value="数据库的账号" />
<property name="password" value="数据库的密码"/>
</dataSource>
</environment>
</environments>
<!--注册映射文件-->
<mappers>
<mapper resource="mappers/AdminMapper.xml"></mapper>
</mappers>
</configuration>
4.创建数据库,创建表,准备数据
5.创建一个访问接口,定义方法
package com.ffyc.mybatispro.dao;
public interface AdminDao {
Admin findAdminById(int id);
}
6.创建接口对应的映射文件,编写sql
<?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">
<!--
sql映射文件: 主要写sql实现
-->
<mapper namespace="com.ffyc.mybatispro.dao.AdminDao">
<!--id:方法名 ,parameterType:参数类型 ,resultType:返回值类型 -->
<select id="findAdminById" parameterType="int" resultType="Admin">
select * from admin where id = #{id}
</select>
</mapper>
7.测试mybatis
//1.mybatis读取文件
Reader reader = Resources.getResourceAsReader("mybatis.xml");
//2创建SqlSessionFactory, 负责创建SqlSession对象(连接数据库的会话对象,类似Connection)
// SqlSessionFactory对象也只需要创建一个,创建后不需要销毁
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(reader);
//3.创建SqlSession 对象
SqlSession sqlSession = sqlSessionFactory.openSession();
//4.创建接口的代理对象
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
//5.调用
Admin admin = adminDao.findAdminById(1);
//让代理对象帮我们调用映射文件中与此接口中相同名称的方法
System.out.println(admin);
//6.关闭会话对象
sqlSession.close();
搭建补充
1.在idea中安装mybatisX插件
打开Settings找到下图的内容
进入插件市场,搜索mybatisX并下载
2.数据库连接池
链接数据库时,每次访问数据库时创建一个Connection,用完关闭
但当访问量大了后,每次都要创建新的连接对象,用完关闭,比较耗时
使用数据库连接池,在(集合)中事先创建一些连接对象,
用户访问时,直接从池中获取一个链接对象,
用完不销毁,还回到池中,这样减少频繁创建连接对象
3.单元测试
程序员使用的测试方式,以方法为单位测试 使用junit组件实现单元测试
导入junit依赖的jar包
<!--junit-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>provided</scope>
</dependency>
使用方法,在方法名前加上@Test
@Test
public void insert(){
System.out.println("新增");
}
4.#{}与${}的区别
#{}是占位符,是采用预编译方式向sql中传值,可以防止sql注入,如果我们往sql中传值,使用#{}
${}是将内容直接拼接到sql语句中,一般不用于向sql中传值,一般用于向sql动态传递列名
1.底层实现不同:
#{}采用预编译方式,可以防止sql注入,更加安全
${}采用字符串拼接,直接将值拼接到sql中
使用场景不同
#{}一般用于向sql中的列传值
${}一般用于向sql动态传递列名
例如 排序时 order by 后面的列名是可以改变的 例如 select 后面的列名也可以自由选择
参数传递
1.单个参数传递
如上述步骤中所示
2.多个参数传递
2.1 使用@Param("account")来绑定
Admin login1(@Param("acc") String account, @Param("pwd") String password);
在映射文件中
<select id="login1" resultType="Admin">
select * from admin where account = #{acc} and password = #{pwd}
</select>
2.2 使用对象来传递
Admin login(Admin admin);
映射文件中,传递的参数不需要使用对象名.属性名来表示,在{}中写属性名即可
<select id="login" parameterType="Admin" resultType="Admin">
select * from admin where account = #{account} and password = #{password}
</select>
数据库事务
是数据库的一种管理的机制,是对一次连接数据库过程的管理
能保证一次操作中执行的多条sql,要么都成功执行,要么都不执行
增删改查
增加,修改,删除完毕后,都需要手动提交事务
原因:提交数据库事务,当我们的程序代码执行没有任何问题时,才会向数据库发送提交事务操纵,数据库真正执行sql,出现异常则不提交事务
有时一次操作需要向数据库发送多条sql,数据库需要程序最终执行没有问题,向数据库提交事务后,才在数据库中执行sql,确保一次操作中的多条sql,要么都成功,要么都不成功
例如:转账时,我们需要将A账号的存款减去(sql1),再将B账户的存款增加(sql2),但在两个sql中间仍存在一些代码逻辑,这些代码也可能出现异常,若出现异常,我们不能将sql1执行,而sql2不执行,因此使用了事务,当出现异常时,代码中断,无法提交事务,也就不会改变数据库的数据,只有提交了事务,数据库才会真正执行这一次操作中的多条sql
1.增
保存数据后,需要立刻拿到这条数据在数据库的主键
void inserAdmin(Admin admin);
映射文件中,新增数据时需要返回新增数据的主键,因此需要在insert标签中添加下面的属性
useGeneratedKeys="true" 返回自增主键
keyProperty="id" 定义接收的属性 property(类中的属性)
keyColumn="id" 定义主键列 column(数据库中的列)
<insert id="inserAdmin" parameterType="Admin" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
insert into admin(account,password,gender) values(#{account},#{password},#{gender})
</insert>
调用时,需要获取新增数据的主键,并提交数据库事务
@Test
public void insert(){
System.out.println("新增");
Admin admin = new Admin();
admin.setAccount("aaa");
admin.setPassword("123");
admin.setGender("男");
SqlSession sqlSession = MyBatisUtil.getSqlSession();
AdminDao adminDao = sqlSession.getMapper(AdminDao.class);
adminDao.inserAdmin(admin);//保存数据后,拿到这条数据在数据库的主键
System.out.println(admin.getId());
sqlSession.commit();//提交数据库事务
sqlSession.close();
}
2.删
void deleteAdmin(int id);
映射文件中
<delete id="deleteAdmin">
delete from admin where id = #{id}
</delete>
3.改
void updateAdmin(Admin admin);
映射文件中
<update id="updateAdmin" parameterType="Admin">
update admin set account=#{account},password=#{password} where id=#{id}
</update>
关联查询
使用resultMap标签
方式1:多表查询
<resultMap id="studentMap" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--映射关联数据 专业名称 首先会创建一个Major对象,然后将专业名称封装到Major对象中,最后将Major对象封装到Student对象中-->
<association property="major" javaType="Major" >
<result column="mname" property="name"></result>
</association>
</resultMap>
<select id="findStudentById" resultMap="studentMap" >
select
s.id,
s.num,
s.name,
s.gender,
m.name mname
from student s inner join major m on s.majorid=m.id
where s.id=#{id};
</select>
方式2:嵌套查询
先查询主表(学生表),再查询专业表
<resultMap id="studentMap1" type="Student">
<id column="id" property="id"></id>
<result column="num" property="num"></result>
<result column="name" property="name"></result>
<result column="gender" property="gender"></result>
<!--与方法1不同之处-->
<association property="major" javaType="Major" select="findMajorById" column="majorid">
</association>
</resultMap>
<select id="findStudentById1" resultMap="studentMap1" >
select id,num,name,gender,majorid
from student
where id=#{id};
</select>
<!--嵌套查询学生关联的专业-->
<select id="findMajorById" resultType="Major">
select name from major where id = #{majorid}
</select>
关联的结果中包含集合
例如:查询专业时,将查询的多个学生封装到一个集合中,但这种方法在分页时会出现问题
<resultMap id="majorMap" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!--将查询关联到的多条结果封装到集合中-->
<collection property="students" javaType="List" ofType="Student">
<result column="num" property="num"></result>
<result column="sname" property="name"></result>
</collection>
</resultMap>
<select id="findMajor" resultMap="majorMap">
select
m.id,
m.name,
s.num,
s.name sname
from major m left join student s on s.majorid=m.id
</select>
解决方法:分成两次查询
<resultMap id="majorMap1" type="Major">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<!--将查询关联到的多条结果封装到集合中-->
<collection property="students" javaType="List" ofType="student" select="findStudents" column="id"></collection>
</resultMap>
<select id="findMajor1" resultMap="majorMap1">
select id,name from major
</select>
<select id="findStudents" resultType="student">
select num,name from student where majorid=#{id}
</select>
动态SQL
在sql中添加逻辑判断
if标签
标签if中含有test属性,如果test属性的条件成立,就执行if的标签体,反之则不执行
where标签
当where标签中的if语句有条件成立时,就会动态的添加where关键字,还可以删除where后面紧跟着的关键字,例如and or
<select id="teachers" resultType="com.lw.mybatispro.model.Teacher">
select * from teacher
<where>
<if test="num!=null">
num=#{num}
</if>
<if test="name!=null">
and name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</where>
</select>
trim标签
trim: 当条件判断有成立时,可以自定义前缀的关键字和后缀关键字
prefix="where"
prefixOverrides="and|or" 覆盖指定的关键字
查询
<select id="teachers" resultType="com.lw.mybatispro.model.Teacher">
select * from teacher
<trim prefix="where" prefixOverrides="and|or">
<if test="num!=null">
num=#{num}
</if>
<if test="name!=null">
or name=#{name}
</if>
<if test="gender!=null">
and gender=#{gender}
</if>
</trim>
</select>
修改
<update id="updateTeacher">
update teacher
<trim prefix="set" suffixOverrides=",">
<if test="num!=null">
num=#{num},
</if>
<if test="name!=null">
name=#{name},
</if>
<if test="gender!=null">
gender=#{gender}
</if>
</trim>
where id = #{id}
</update>
choose、when、otherwise标签
<choose>
<when test="条件"> </when>
<otherwise> </otherwise>
</choose>
when、otherwise两个标签使用时类似于if else,可以只有when,但不能只有otherwise
<select id="teachers" resultType="com.lw.mybatispro.model.Teacher">
select * from teacher
<trim prefix="where" prefixOverrides="and|or">
<choose>
<when test="name!=null">
name=#{name}
</when>
<otherwise>
name="药老"
</otherwise>
</choose>
</trim>
</select>
foreach标签
当参数是数组或者集合时使用,可以遍历出数组或集合中的内容
属性
item=" "
循环变量,在每次循环过程中代表集合中的一个元素。
collection=" array或list "
参数的类型,当参数是数组时为array,当参数是集合时为list
open=" "
标志着循环的开始,以引号中的内容为开始
separator=" "
每次循环时,加在两个循环之间,作为分隔符
close=" "
标志着循环的结束,结束时以引号中的内容为结尾
<delete id="deleteTeacher">
delete from teacher
where id in
<foreach item="id" collection="array" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
特殊符号处理
1.使用转义字符
< <
> >
" "
’ '
& &
2. 使用 <![CDATA[ ]]>标签
<![CDATA[ ]]>是 XML 语法。在 CDATA 内部的所有内容都会被解析器忽略。
只把有特殊字符的语句放在 <![CDATA[ ]]>标签中
例如 <![CDATA[ age<18 ]]>
xml(可扩展的标记语言) 作用:存储传输数据
缓存
数据缓存,让数据离我们的执行程序更近,让程序能够快速的获取到数据
手机缓存,浏览器缓存,cpu缓存……
访问量大的时候,使用缓存将数据库的内容存到后端程序
12306 访问瓶颈在数据库
适合放入缓存的数据:访问量大的,经常不修改的
有缓存,查询数据
先从缓存中查数据,如果缓存中没有,去数据库查询,查询到后把数据放到缓存中,下次直接从缓存中获取
mybatis 一级缓存
默认是SqlSession级别的,在同一个SqlSession中查询到数据先缓存到SqlSession对象中
第二次查询数据时,先从SqlSession中查询,如果有,直接返回,没有,再去数据库查询
一级缓存生命周期
开始于SqlSession创建
结束于SqlSession关闭
如果期间执行了新增,修改,删除操纵,也会清空当前SqlSession对象中的数据
调用sqlSession.clearCache(),会强制清空一级缓存数据
mybatis 二级缓存
二级缓存是SqlSessionFactory级别的,可以让多个SqlSession共享数据
mybatis默认没有开启二级缓存,使用时需要配置开启
如果开启了二级缓存,当sqlSession关闭时,会将一级缓存中的数据存储到二级缓存中,其他SqlSession就可以在二级缓存中查询到之前sqlSession查询的数据
配置二级缓存配置
第一步:启用二级缓存
在 SqlMapperConfig.xml 中启用二级缓存,如下代码所示,当cacheEnabled 设置为 true 时启用二级缓存,设置为 false 时禁用二级缓存。
<setting name="cacheEnabled" value="true"/>
第二步:对象序列化
将所有的 POJO 类实现序列化接口 Java.io. Serializable。
第三步:配置映射文件
在 Mapper 映射文件中添加<cache />,表示此 mapper 开启二级缓存。
当 SqlSeesion 关闭时,会将数据存入到二级缓存.
useCache="true" 最小的开关 加在具体的执行语句的标签上