文章目录
1、MySQL 面试高频问题
- MySQL引擎
- InnoDB底层原理
- 索引
- 索引优化
2、ORM层框架—Mybatis
ORM(object/relation mapping),业务实体在程序中为对象,在数据库中为关系数据。mybatis作为中间件将两者关联起来。
3、环境搭建
-
创建需要的数据库
-
项目中导入配置
-
导入
maven
依赖<!-- 父工程--> <groupId>com.kuang</groupId> <artifactId>Mybatis-study</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <!-- 子工程--> <modules> <module>mybatis-01</module> <module>mybatis-02</module> <module>mybatis-03</module> <module>mybatis-04</module> <module>mybatis-05</module> <module>mybatis-06</module> </modules> <!--导入依赖--> <dependencies> <!--mysql驱动--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.2</version> </dependency> <!--junit--> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> </dependencies> <!-- 在 build 中配置 resources,来防止我们的资源导出失败的问题--> <build> <resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>true</filtering> </resource> </resources> </build>
-
配置
mybatis-config.xml
核心配置文件、db.properties
文件<!-- mybatis-config.xml --> <?xml version="1.0" encoding="UTF8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <!-- 核心配置文件 --> <configuration> <!-- 引入外部配置文件--> <properties resource="db.properties"/> <!-- 引入日志--> <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings> <!-- 类型别名 实体类较少时: <typeAliases> <typeAliastype="com.kuang.pojo.User"alias="User"/> </typeAliases> 实体类较多时: <typeAliases> <package name="com.exm.pojo"/> </typeAliases> --> <typeAliases> <package name="com.exm.pojo"/> </typeAliases> <!-- 可以配置多个生产环境--> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> <environment id="test"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <!-- 每一个 Mapper.xml 都需要在 mybatis 核心配置文件中注册!--> <mappers> <mapper resource="mapper/UserMapper.xml"/> </mappers> </configuration> <!-- db.properties--> driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/mybatis?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username=用户名 password=密码
-
编写
mybatisUtils
工具类public class MybatisUtils { private static SqlSessionFactory sqlSessionFactory; static { try { String resource = "mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); } catch (IOException e) { e.printStackTrace(); } } public static SqlSession getSqlSession() { return sqlSessionFactory.openSession(); } }
-
-
编写代码
- 实体类
POJO
mapper
接口以及mapper.xml
(以前是实现接口的类)文件
- 实体类
-
单元测试
4、CRUD
“增、删、改”后需要
commit
使用 #{xx} 表示对传入的数据进行接收
5、万能 Map
使用场景:多个参数使用
map
或者@Param
注解。
5.1 万能Map
-
POJO
public class User { private int id; private String name; private String pwd; // getter/setter方法 }
-
mapper接口
使用 Map 作为参数。
// mapper == dao public interface UserMapper { void add2(Map<String,Object> map); }
-
mapper.xml中的sql
<insert id="add2" parameterType="map"> insert into mybatis.user (id, name, pwd) values (#{userid}, #{username}, #{userpwd}); </insert>
-
test
@Test public void add2Test() { SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); HashMap<String, Object> map = new HashMap<>(); map.put("userid", 18); map.put("username", "阿顿"); map.put("userpwd", "31"); mapper.add2(map); sqlSession.commit(); sqlSession.close(); }
5.2 @Param
- POJO 不变
- mapper 接口
public interface UserMapper{
List<User> select(@Param("id")int id, @Param("name")String name)
}
- mapper.xml
<insert id="select" resultType="User">
SELECT *
FROM user
WHERE id=#{id}
AND name=#{name}
</insert>
6、模糊查询
// 测试类中
List<User> userList = mapper.getUserLike("%李%");
<!-- mapper.xml文件中的sql -->
select * from mybatis.user where name like "%"#{value}"%"
7、ResultMap
ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
如果表的字段名与 java Bean 中的属性不一致,就应该使用。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id" />
<result property="username" column="user_name"/>
<result property="password" column="hashed_password"/>
</resultMap>
<select id="selectUsers" resultMap="userResultMap">
select user_id, user_name, hashed_password
from some_table
where id = #{id}
</select>
property
:User 实体类的属性名。
column
:some_table 的字段名。
8、多对一处理(association)
8.1 测试环境搭建
- 配置
maven
文件、配置mybatis
核心配置文件 - 导入
lombok
插件 - 根据数据库创建实体类
POJO
- 创建每个
POJO
的Mapper
接口 - 建立接口的
Mapper.xml
文件 - 在
mybatis
的核心配置文件中进行mappers
注册 - 进行测试
多个学生对一个老师
实体类
// pojo --> Student 里面的外键设置
public class Student{
private int id;
private String name;
// 多个学生对应一个老师
private Teacher teacherId;
}
public class Teacher() {
private int id;
private String name;
}
8.2 查询方式
8.2.1 按照查询嵌套处理
<!-- 按查询嵌套处理-->
<select id="getStudents" resultMap="studentAndTeacher">
select *
from mybatis.student;
</select>
<resultMap id="studentAndTeacher" type="Student">
<association column="tid" property="teacherId" javaType="Teacher" select="getTeachers"/>
</resultMap>
<select id="getTeachers" resultType="Teacher">
select *
from mybatis.teacher
where id = #{id};
</select>
8.2.2 按照结果嵌套处理
<!-- 按结果嵌套处理-->
<select id="getStudents2" resultMap="getStudent2">
select student.id sid, student.name sname, teacher.name tname
from mybatis.student,
mybatis.teacher
where student.tid = teacher.id;
</select>
<resultMap id="getStudent2" type="Student">
<!--- 学生 --->
<result column="id" property="sid"/>
<result column="name" property="sname"/>
<!--- 老师 --->
<association property="teacherId" javaType="Teacher">
<result column="tid" property="tname"/>
</association>
</resultMap>
按结果查询更简单一点
9、一对多处理(collection)
一个老师对多个学生
实体类
@Data
public class Student {
private int id;
private String name;
private int tid;
}
@Data
public class Teacher {
private int id;
private String name;
// 一个老师对应多个学生
private List<Student> students;
}
9.1 按结果嵌套处理
public interface TeacherMapper {
Teacher getTeacherById(@Param("tid") int id);
}
<select id="getTeacherById" resultMap="teacherAndStudent">
select teacher.id tid, teacher.name tname, student.id sid, student.name sname
from mybatis.student,
mybatis.teacher
where student.tid = teacher.id
and teacher.id = #{tid};
</select>
<resultMap id="teacherAndStudent" type="Teacher">
<!-- 设置老师-->
<result column="tid" property="id"/>
<result column="tname" property="name"/>
<collection property="students" ofType="Student">
<!-- 设置学生-->
<result column="sid" property="id"/>
<result column="sname" property="name"/>
<result column="tid" property="tid"/>
</collection>
</resultMap>
javaType:指定实体类中的属性类型。
ofType:指定映射到
List
或者Map
的POJO
类型
9.2 多对一、一对多 小结
在编写 mapper.xml 前,需要先使用 sql 语句进行测试,然后对照 sql 语句进行编写
10、动态SQL
根据不同的条件生成不同的SQL
1、环境搭建
-
建立数据库中的表
CREATE TABLE `blog`( `id` VARCHAR(50) NOT NULL COMMENT '博客id', `title` VARCHAR(100) NOT NULL COMMENT '博客标题', `author` VARCHAR(30) NOT NULL COMMENT '博客作者', `create_time` DATETIME NOT NULL COMMENT '创建时间', `views` INT(30) NOT NULL COMMENT '浏览量' )ENGINE=INNODB DEFAULT CHARSET=utf8;
-
导入插件和配置
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> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment> </environments> <mappers> <mapper resource="org/mybatis/example/BlogMapper.xml"/> </mappers> </configuration>
-
创建
POJO
实体类 -
创建
Mapper
接口以及Mapper.xml
文件 -
进行测试
2、if 语句
<select id="getBlogByIf" parameterType="map" resultType="Blog">
select * from blog where 1=1
<if test="title != null">
and title like #{title}
</if>
<if test="views != null">
and views like #{views}
</if>
</select>
随机获取ID的工具
public class IdUtils {
public static String getId() {
return UUID.randomUUID().toString().replace("-","");
}
}
3、trim(where、set)
where:不同条件的查询。
<select id="getBlogWhere" parameterType="map" resultType="Blog">
select * from blog
<where>
<if test="title != null">
title like #{title}
</if>
<if test="author != null">
or author like #{author}
</if>
<if test="views != null">
or views like #{views}
</if>
</where>
</select>
set:可以动态更新列,忽略其他不更新的列。
<update id="upBlogBySet" parameterType="map">
update blog
<set>
<if test="title != null">title=#{title},</if>
<if test="author != null">author=#{author},</if>
<if test="views != null">views=#{views}</if>
</set>
where id=#{id}
</update>
4、Choose(when、otherwise)
Choose 相当于 java 中的 switch
<select id="getBlogByChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title">
and title like #{title}
</when>
<when test="author">
and author like #{author}
</when>
<when test="views">
and views like #{views}
</when>
<otherwise>
and 1 = 1
</otherwise>
</choose>
</where>
</select>
5、SQL 片段
提取公共部分,重复使用
-
抽取公共内容
<sql id="if-title-author-views"> <if test="title != null"> title like #{title} </if> <if test="author != null"> or author like #{author} </if> <if test="views != null"> or views like #{views} </if> </sql>
-
在需要使用的地方进行引用
<select id="getBlogWhere" parameterType="map" resultType="Blog">
select * from blog
<where>
<include refid="if-title-author-views"/>
</where>
</select>
6、foreach
步骤:
- 先使用
sql
语句
select * from blog where id = 1 or id = 2 or id = 3;
- 对照
sql
语句进行foreach
编写
<!-- select * from blog where id = 1 or id = 2 or id = 3;-->
<select id="getBlogByForeach" resultType="Blog" parameterType="map">
select * from blog
<where>
<foreach collection="ids" item="id" open="(" separator="or" close=")">
id=#{id}
</foreach>
</where>
</select>
- 进行测试
@Test
public void getBlogByForeachTest() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap<String, Object> map = new HashMap<>();
ArrayList<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(3);
// 此处的 key 就是 collection 中的 ids,因为foreach要从collection取值
map.put("ids",ids);
List<Blog> blog = mapper.getBlogByForeach(map);
for (Blog blog1 : blog) {
System.out.println(blog1);
}
sqlSession.close();
}
11、缓存(了解)
我们在第一次查询数据时,会直接访问数据库,这些数据会被保存在缓存中,当我们在去查询这些数据时,会直接查询缓存下来的数据,不会在直接访问数据库。
1、一级缓存
sqlSession
级别,关闭后就失效。- 一级缓存也叫本地缓存。
- 一级缓存是默认开启的,只在一次SqlSession中有效,即拿到连接到关闭连接这个区间段有效。
- 一个缓存就是一个Map。
2、二级缓存
- 基于namespace级别的缓存,一个名称空间,对应一个二级缓存;
- 二级缓存也叫全局缓存.