MyBatis是一个优秀的持久层框架,它对jdbc的操作数据库的过程进行封装,使开发者只需要关注 SQL 本身,而不需要花费精力去处理例如注册驱动、创建connection、创建statement、手动设置参数、结果集检索等jdbc繁杂的过程代码。Mybatis通过xml或注解的方式将要执行的各种statement(statement、preparedStatement、CallableStatement)配置起来,并通过java对象和statement中的sql进行映射生成最终执行的sql语句,最后由mybatis框架执行sql并将结果映射成java对象并返回。
1.Map和模糊查询
<!--使用Map-->
<update id="updateUser1" parameterType="Map">
update mybatis.user set name=#{oneName},pwd=#{onePwd} where id=#{oneId};
</update>
<!--模糊查询-->
<select id="getUserLike" resultType="User">
select *from mybatis.user where name like "%"#{value}"%"
</select>
//改(使用Map)
@Test
public void updateUser1(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("oneId",4);
map.put("oneName","Mike");
map.put("onePwd","110110");
mapper.updateUser1(map);
sqlSession.commit();
sqlSession.close();
}
//模糊查询
@Test
public void getUserLike(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.getUserLike("李");
for (User user : list) {
System.out.println(user);
}
sqlSession.close();
}
2.ResultMap 结果集映射
resultMap
元素是 MyBatis 中最重要最强大的元素。它可以让你从 90% 的 JDBC ResultSets
数据提取代码中解放出来,并在一些情形下允许你做一些 JDBC 不支持的事情。实际上,在对复杂语句进行联合映射的时候,它很可能可以代替数千行的同等功能的代码。ResultMap 的设计思想是,简单的语句不需要明确的结果映射,而复杂一点的语句只需要描述它们的关系就行了。
<!--结果集映射-->
<resultMap id="UserMap" type="User">
<!--column:数据库中的字段 property:实体类中的属性-->
<result column="pwd" property="password"/>
</resultMap>
<select id="getUserLike" resultMap="UserMap">
select * from mybatis.user where name like "%"#{value}"%"
</select>
3.日志工厂
- SLF4J
- LOG4J [*]
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING [*]
- NO_LOGGING
STDOUT_LOGGING :标准日志输出
<settings>
<!--标准日志工厂-->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
LOG4J :
- 导入依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 配置
<settings>
<!--log4j-->
<setting name="logImpl" value="LOG4J"/>
</settings>
-
测试
public class UserDaoTest { static Logger logger= Logger.getLogger(UserDaoTest.class); @Test public void getUserLike(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); logger.info("测试,进入getUserLike方法成功!"); UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> list = mapper.getUserLike("李"); for (User user : list) { System.out.println(user); } sqlSession.close(); } }
4.分页
方式一:
接口:
//分页
List<User> getUserByLimit(Map<String,Integer> map);
mapper:
<!--分页1-->
<select id="getUserByLimit" parameterType="map" resultMap="UserMap">
select * from mybatis.user limit #{startIndex},#{pageSize}
</select>
测试:
@Test
public void getUserByLimit(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("pageSize",2);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
方式二:
接口:
//RowBounds实现分页
List<User> getUserByRowBounds();
mapper:
<!--分页2-->
<select id="getUserByRowBounds" resultMap="UserMap">
select * from mybatis.user
</select>
测试:
@Test
public void getUserByRowBounds(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
//RowBounds实现
RowBounds rowBounds = new RowBounds(0,3);
List<User> userList = sqlSession.selectList("com.jiutian.dao.UserMapper.getUserByRowBounds", null, rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
5.注解
接口
public interface UserMapper {
@Select("select *from user")
List<User> getUsers();
}
核心配置文件中绑定接口
<mappers>
<mapper class="com.jiutian.dao.UserMapper"/>
</mappers>
@Param()注解
- 基本数据类型或String,要加上
- 引用数据类型不用
- 如果只有一个基本数据类型,建议加上
- 在SQL中引用的就是@Param()中设定的属性名
6.Lombok插件使用
1.下载插件
2.导入jar包
<dependencies>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
</dependencies>
3.pojo类使用
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String password;
}
7.多对一处理
1.pojo类
@Data
public class Teacher {
private int id;
private String name;
}
@Data
public class Student {
private int id;
private String name;
private Teacher teacher;
}
2.接口
public interface StudentMapper {
//查询所有学生及其老师
List<Student> getStudent();
List<Student> getStudent2();
}
3.Mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jiutian.dao.StudentMapper">
<!--方式一:按照查询嵌套处理-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<!--复杂的属性,单独处理: 对象:association 集合:collection-->
<association property="teacher" column="tid" javaType="Teacher" select="selectTeacherById"/>
</resultMap>
<select id="selectTeacherById" resultType="Teacher">
select *from teacher where id=#{tid}
</select>
<!--方式二:按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher2">
select a.id sid,a.name sname,a.tid tid,b.name tname
from student a,teacher b
where a.tid=b.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
</association>
</resultMap>
</mapper>
8.一对多处理
1.pojo类
@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;
}
2.接口
public interface TeacherMapper {
//根据指定id查询老师及其所有学生
List<Teacher> getTeacher(@Param("id") int id);
List<Teacher> getTeacher2(@Param("id") int id);
}
3.Mapper文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jiutian.dao.TeacherMapper">
<!--方式一:按照查询嵌套处理-->
<select id="getTeacher" resultMap="TeacherStudent">
select * from teacher where id=#{id}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="id"/>
<!--复杂的属性,单独处理: 对象:association 集合:collection-->
<collection property="students" column="id" javaType="ArrayList" ofType="Student" select="selectStudentByTeacherId"/>
</resultMap>
<select id="selectStudentByTeacherId" resultType="Student">
select * from student where tid=#{id}
</select>
<!--方式二:按照结果嵌套处理-->
<select id="getTeacher2" resultMap="TeacherStudent2">
select b.id tid,b.name tname,a.id sid,a.name sname
from student a,teacher b
where a.tid=b.id
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<collection property="students" javaType="ArrayList" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
</mapper>
小结
- 关联 - association [多对一]
- 集合- collection [一对多]
- javaType:用来指定实体类中属性的类型
- ofType:用来指定映射到List,集合中的pojo类型,泛型中的约束类型
9.动态SQL
pojo类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Blog {
private String id;
private String title;
private String author;
private Date createTime;
private int views;
}
接口
public interface BlogMapper {
//插入数据
int addBlog(Blog blog);
}
Mapper.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jiutian.dao.BlogMapper">
<insert id="addBlog" parameterType="Blog">
insert into blog (id, title, author, create_time, views)
values (#{id},#{title},#{author},#{createTime},#{views});
</insert>
</mapper>
自动生成id(主键)工具类
public class IdUtils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
@Test
public void test(){
System.out.println(IdUtils.getId());
}
}
测试1
@Test
public void addBlog(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IdUtils.getId());
blog.setTitle("Mybatis如此简单");
blog.setAuthor("jiutian");
blog.setCreateTime(new Date());
blog.setViews(9999);
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("Java如此简单");
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("Spring如此简单");
mapper.addBlog(blog);
blog.setId(IdUtils.getId());
blog.setTitle("微服务如此简单");
mapper.addBlog(blog);
sqlSession.close();
}
if,sql,choose标签使用
//查询博客(if,sql)
List<Blog> queryBlogByIf(Map map);
//查询博客(choose,when)
List<Blog> queryBlogByChoose(Map map);
<sql id="ifTitleAuthor">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogByIf" parameterType="map" resultType="Blog">
select * from mybatis.blog
<where>
<include refid="ifTitleAuthor"></include>
</where>
</select>
<select id="queryBlogByChoose" parameterType="map" resultType="Blog">
select * from blog
<where>
<choose>
<when test="title != null">
and title = #{title}
</when>
<when test="title != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
测试2
@Test
public void queryBlogByIf(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","Java如此简单");
map.put("author","jiutian");
List<Blog> blogs = mapper.queryBlogByIf(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
@Test
public void queryBlogByChoose(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("title","Mybatis如此简单");
//map.put("author","jiutian");
map.put("views",9999);
List<Blog> blogs = mapper.queryBlogByChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
set标签使用
//更新博客 (set)
int updateBlog(Map map);
<update id="updateBlog" parameterType="map">
update blog
<set>
<if test="title != null">
title = #{title},
</if>
<if test="author != null">
author = #{author},
</if>
</set>
where id = #{id}
</update>
测试3
@Test
public void updateBlog() {
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
map.put("id","1");
map.put("title","Java如此简单2");
map.put("author","jiutian2");
mapper.updateBlog(map);
sqlSession.close();
}
foreach标签使用
//查询第1,2,3号博客
List<Blog> queryBlogByForeach(Map map);
//查询第1,2,3号博客
List<Blog> queryBlogByForeach2(Map map);
<!-- select * from blog where id=1 or id=2 or id=3 -->
<select id="queryBlogByForeach" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="" close="" separator="or">
id = #{id}
</foreach>
</where>
</select>
<!-- select * from blog where id in (1,2,3) -->
<select id="queryBlogByForeach2" parameterType="map" resultType="Blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="id in (" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
测试4
@Test
public void queryBlogByForeach(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogByForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
@Test
public void queryBlogByForeach2(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
ArrayList<Integer> ids = new ArrayList<>();
ids.add(1);
ids.add(2);
ids.add(3);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogByForeach2(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
小结:
- choose-when相当于switch-case,并且匹配到一个会"break"结束。
- where会根据情况所需自动前置“WHERE” ,自动去除开头的“AND” 或 “OR”【不能增加】。
- set会根据情况所需自动前置“set” ,自动去除结尾额外的逗号(在使用条件语句给列赋值时引入的)【不能增加】。
- sql配合include使用,可以抽取公共的部分,方便复用。
- foreach可用于对集合进行遍历,collection代表传的集合,item相当于一个循环变量;open,close,separator指定开头与结尾的字符串以及集合项迭代之间的分隔符。并且foreach不会错误地添加多余的分隔符。
10.缓存
MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis 3中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。
默认情况下是没有开启缓存的,除了局部的 session 缓存,可以增强变现而且处理循环依赖也是必须的。要开启二级缓存,你需要在你的 SQL 映射文件中添加一行:
<cache/>
一级缓存
表示SqlSession级别的缓存,默认开启。每次查询的时候会开启一个会话,此会话相当于一次连接,关闭之后自动失效。
测试
@Test
public void queryUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
//mapper.updateUser(new User(2,"okok","121212")); //增删改会刷新一级缓存
//sqlSession.clearCache(); //手动清除缓存
System.out.println("=============================");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession.close();
}
二级缓存
二级缓存是全局范围的缓存,SqlSession关闭之后才会生效。
核心配置文件:
<!--默认是true,可以显示地开启全局缓存-->
<setting name="cacheEnabled" value="true"/>
Mapper.xml文件:
<!--在当前Mapper.xml使用二级缓存,readOnly默认是false,实体类需要序列化-->
<cache/>
测试
@Test
public void queryUserById(){
SqlSession sqlSession = MybatisUtils.getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();
System.out.println("=============================");
SqlSession sqlSession2 = MybatisUtils.getSqlSession();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession2.close();
}
第三方缓存
-
导入jar包
<!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --> <dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.2.1</version> </dependency>
-
在resources目录下加入ehcache.xml
-
Mapper.xml文件
<!--第三方缓存--> <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
小结
- 二级缓存生效的时候,是在一级缓存sqlSession关闭的时候
- 在开启了二级缓存的情况下,先查询二级缓存,再查询一级缓存
- readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓存对象的相同实例。 因此这些对象不能被修改。这就提供了可观的性能提升。而可读写的缓存会(通过序列化)返回缓存对象的拷贝。 速度上会慢一些,但是更安全,因此默认值是 false。