Mybatis-9.28
环境:
- JDK1.8
- Mysql5.7
- maven3.6.1
- IDEA
回顾(必须掌握的知识):
- JDBC
- Mysql
- Java基础(封装,继承等
- Maven
- Junit
SSM框架:配置文件的。 学习最好的方式:看官网文档
Mybatis文档:https://mybatis.org/mybatis-3/
1.简介
1.1 什么是Mybatis
- MyBatis 是一款优秀的持久层框架
- 它支持自定义 SQL、存储过程以及高级映射
- MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
- MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录
- MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为MyBatis
- 2013年11月迁移到Github
注:6之前的在印象笔记
6. 日志
6.1 日志工厂
如果一个数据库操作出现了异常,我们需要排错,日志是最好的助手!
- SLF4J
- LOG4J 【掌握】
- LOG4J2
- JDK_LOGGING
- COMMONS_LOGGING
- STDOUT_LOGGING 【掌握】
- NO_LOGGING
在Mybatis中具体使用哪个日志,在核心配置文件的setting中设定!
STDOUT_LOGGING标准日志输出
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
正确的效果:
错误时:
6.2 LOG4J
什么是LOG4J ?(建议百度)
- Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
- 我们也可以控制每一条日志的输出格式
- 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
- 这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
- 先导入LOG4J 的依赖
<!-- https://mvnrepository.com/artifact/log4j/log4j -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
- 在resources里创建log4j.properties(log4j的配置文件)
#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file
#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold = DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern = [%c] - %m%n
#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File = ./log/Jiang.log
log4j.appender.file.MaxFileSize = 10mb
log4j.appender.file.Threshold = DEBUG
log4j.appender.file.layout = org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern =[%p][%d{yy-MM-dd}][%c]%m%n
#日志输出级别
log4j.logger.org.mybatis = DEBUG
log4j.logger.java.sql = DEBUG
log4j.logger.java.sql.Statement = DEBUG
log4j.logger.java.sql.ResultSet = DEBUG
log4j.logger.java.sql.PreparedStatement = DEBUG
- 配置为log4j为日志的实现
<settings>
<setting name="logImpl" value="LOG4J"/>
</settings>
-
log4j的使用,直接运行刚才的查询
简单使用- 在要使用log4j的类中,导入包: import org.apache.log4j.Logger;
- 日志对象,参数为当前类的class(就在类中定义)
static Logger logger = Logger.getLogger(UserDaoTest.class);
- 日志级别
logger.info("info:进入了testlog4j"); logger.debug("deug:进入了testlog4j"); logger.error("error:进入了testlog4j");
- 在测试类里面是这样的:
package com.jiang.dao; import com.jiang.pojo.User; import com.jiang.utils.MybatisUtils; import org.apache.ibatis.session.SqlSession; import org.junit.Test; import org.apache.log4j.Logger; import org.junit.validator.PublicClassValidator; public class UserDaoTest { static Logger logger = Logger.getLogger(UserDaoTest.class); @Test public void getUserLike(){ SqlSession sqlSession = MybatisUtils.getSQlSession(); logger.info("info:进入了getUserLike"); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.getUserById(1); System.out.println(user); sqlSession.close(); } @Test public void testlog4j(){ logger.info("info:进入了testlog4j"); logger.debug("deug:进入了testlog4j"); logger.error("error:进入了testlog4j"); } }
后来:
7.分页
使用Mybatis实现分页
7.1 使用Limit进行分页
- 接口
//分页
List<User> getUserByLimit(Map<String,Integer> map);
- Mapper.xml
<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);
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("startIndex",1);
map.put("PageSize",3);
List<User> userList = mapper.getUserByLimit(map);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.2 RowBounds分页(了解即可)
不再使用SQL使用分类
- 接口
//分页2
List<User> getUserByRowBoounds();
- mapper.xml
<select id="getUserByRowBoounds" resultMap="UserMap">
select * from mybatis.user
</select>
- 测试
//分页2
@Test
public void getUserByRowBoounds(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//RoeBounds实现
RowBounds rowBounds = new RowBounds(1, 3);
//通过java代码实现分页
List<User> userList = sqlSession.selectList("com.jiang.dao.UserMapper.getUserByRowBoounds",null,rowBounds);
for (User user : userList) {
System.out.println(user);
}
sqlSession.close();
}
7.3分页插件
了解即可,若要使用,百度mybatis pagehelper,看文档
文档链接:https://pagehelper.github.io/
8. 使用注解开发
8.1 关于注解
对于像 BlogMapper 这样的映射器类来说,还有另一种方法来完成语句映射。 它们映射的语句可以不用 XML 来配置,而可以使用 Java 注解来配置。比如,上面的 XML 示例可以被替换成如下的配置:
package org.mybatis.example;
public interface BlogMapper {
@Select("SELECT * FROM blog WHERE id = #{id}")
Blog selectBlog(int id);
}
使用注解来映射简单语句会使代码显得更加简洁,但对于稍微复杂一点的语句,Java 注解不仅力不从心,还会让你本就复杂的 SQL 语句更加混乱不堪。 因此,如果你需要做一些很复杂的操作,最好用 XML 来映射语句。
8.2 使用注解开发
- 注解在接口上实现
@Select("select * from user")
List<User> getUser();
- 需要在核心配置文件中绑定接口!与之前的有所不同注意区分
<!-- 绑定接口-->
<mappers>
<mapper class="com.jiang.dao.UserMapper"/>
</mappers>
- 测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
本质:反射机制实现
底层:动态代理!
最好搞懂mybatis的执行原理(看源码,debug)
8.3
我们可以在工具类创建的时候实现自动提交事务!
public static SqlSession getSQlSession(){
return sqlSessionFactory.openSession(true);
}
编写接口,增加注解
package com.jiang.dao;
import com.jiang.pojo.User;
import org.apache.ibatis.annotations.*;
import java.util.List;
import java.util.Map;
public interface UserMapper {
@Select("select * from user")
List<User> getUser();
/*方法存在多个参数,所有参数前面必须加上@Param("id")这样的注解,例如:
User getUserById(@Param("id") int id,@Param("name")String name);}
*/
@Select("select * from user where id = #{id}")
User getUserById(@Param("id") int id);
@Insert("insert into user(id,name,psw) values (#{id},#{name},#{psw})")
int addUser(User user);
@Update("update user set name = #{name} , psw = #{psw} where id =#{id}")
int updateUser(User user);
@Delete("delete from user where id = #{uid}")
int deleteUser(@Param("uid") int id);
}
测试类
【注意:我们必须要将接口注册绑定到核心配置文件中!!】
import com.jiang.dao.UserMapper;
import com.jiang.pojo.User;
import com.jiang.uitils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.List;
public class UserMapperTest {
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> user = mapper.getUser();
for (User user1 : user) {
System.out.println(user1);
}
sqlSession.close();
}
@Test
public void getUserById(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.getUserById(1);
System.out.println(user);
sqlSession.close();
}
@Test
public void addUser(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
int user = mapper.addUser(new User(9, "姣姣", "1112"));
//因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
sqlSession.close();
}
@Test
public void updateUser(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.updateUser(new User(5,"TAI","99"));
//因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
sqlSession.close();
}
@Test
public void deleteUser(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
//底层主要应用反射
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
mapper.deleteUser(9);
//因为在工具类的时候定义了提交为true,所以这里之后不再设置提交commit!
sqlSession.close();
}
}
关于@Param()注解
- 基本类型的参数或者String类型,需要加上,规范
- 引用类型不需要加
- 如果只有一个基本类型的话可以忽略,但是建议加上
- 在SQL中引用的就好使这里的@Param()中设定的属性名!
#{} / ${} 区别
不懂请自行百度
9. Lombok
Lombok项目是一个Java库,它会自动插入您的编辑器和构建工具中,从而使您的Java更加生动有趣。
永远不要再写另一个getter或equals方法,带有一个注释的您的类有一个功能全面的生成器,自动化您的日志记录变量等等。
使用步骤:
-
在idea中安装Lombok的插件
-
在项目中导入Lombok的jar包
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
- 在实体类上加注解
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@val
@var
experimental @var
@UtilityClass
@Data:无参构造,get、set、toString、hashcode、equals
@AllArgsConstructor:有参构造
@NoArgsConstructor:无参构造
10. 多对一处理(mybatis-06)
- 比如多个学生,对应一个老师
- 学生这边:多个学生关联一个老师【多对一】
- 来时这边:集合,一个老师有很多学生【一对多】
10.1 设计SQL:
10.2 创建相应的实体类
老师:Teacher
package com.jiang.pojo;
import lombok.Data;
@Data //有参
public class Teacher {
private int id;
private String name;
}
学生:Student
package com.jiang.pojo;
import lombok.Data;
@Data //有参
public class Student {
private int id;
private String name;
//学生需要关联一个老师!
private Teacher teacher;
}
10.3 创建实体类相应的接口
老师:TeacherMapper
package com.jiang.dao;
public class TeacherMapper {
@Select("select * from teacher where id = #{tid}")
Teacher getTeacherById(@Param("tid") int id);
}
学生:StudentMapper
package com.jiang.dao;
public interface StudentMapper {
}
10.4 创建接口对应的xml文件
如果Mapper较多,建议将xml文件统一放在resources(新建包com.jiang.dao)里面
老师:TeacherMapper.xml
<?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">
<mapper namespace="com.jiang.dao.TeacherMapper">
</mapper>
学生:StudentMapper.xml
<?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">
<mapper namespace="com.jiang.dao.StudentMapper">
</mapper>
resutType里面写的是返回的类型
- 如果核心配置文件有给包起别名,那么就写别名
- 第一步没有就写全路径
然后在核心配置文件中注册Mappers接口/文件
<mappers>
<mapper class="com.jiang.dao.TeacherMapper"/>
<mapper class="com.jiang.dao.StudentMapper"/>
</mappers>
这里写的地址是class文件的路径
如果用的是resource,写的是 /
10.5 测试环境搭建是否成功
import com.jiang.dao.TeacherMapper;
import com.jiang.pojo.Teacher;
import com.jiang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
public class MyTest {
@Test
public void getTeacherById(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacherById(1);
System.out.println(teacher);
sqlSession.close();
}
}
10.6 按照查询嵌套处理
10.6.1 在StudentMapper中添加方法
//查询所有的学生信息,以及对应的老师的信息
public List<Student> getStudent();
10.6.2 StudentMapper.xml查询语句(子查询)
<!--
思路:
1.查询所有的学生信息,结果返回在Map里面
2.根据查询出来的学生的tid,寻找对应的老师 子查询
-->
<select id="getStudent" resultMap="StudentTeacher">
select * from student
</select>
<resultMap id="StudentTeacher" type="Student">
<result property="id" column="id"/>
<result property="name" column="name"/>
<!--复杂的属性我们需要单个处理
对象:association 多对一
集合:collection 一对多
-->
<association property="teacher" column="tid" javaType="Teacher" select="getTeacherById"/>
</resultMap>
<select id="getTeacherById" resultType="Teacher">
select * from teacher where id = #{tid}
</select>
10.6.3 测试嵌套查询
@Test
public void getStudent(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
查询结果
10.7 按照结果嵌套处理
10.7.1 在StudentMapper中添加方法
public List<Student> getStudent2();
10.7.2 StudentMapper.xml查询语句(联表查询)
<!--按照结果嵌套处理-->
<select id="getStudent2" resultMap="StudentTeacher2">
select s.id sid,s.name sname,t.name tname
from student s,teacher t
where s.tid = t.id
</select>
<resultMap id="StudentTeacher2" type="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<association property="teacher" javaType="Teacher" >
<result property="name" column="tname"/>
</association>
</resultMap>
10.7.3 测试嵌套查询
@Test
public void getStudent2(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> studentList = mapper.getStudent2();
for (Student student : studentList) {
System.out.println(student);
}
sqlSession.close();
}
11. 一对多处理(mybatis-07)
比如:一个老师拥有多个学生
对于来时而言,就是一对多的关系!
11.1 环境搭建(和10一样)
-
依赖
-
配置文件
-
赋值java文件夹下的包
-
创建包并移动成这样
-
清理Mapper/test文件方便工作
-
改变实体类属性
StudentMapper:
package com.jiang.pojo; import lombok.Data; @Data //有参 public class Student { private int id; private String name; private int tid; }
TeacherMapper:
package com.jiang.pojo; import lombok.Data; import java.util.List; @Data //有参 public class Teacher { private int id; private String name; //一个老师拥有多个学生 private List<Student> students; }
-
接口方法
//获取老师 List<Teacher> getTeacher();
-
xml实现
<select id="getTeacher" resultType="Teacher"> select * from teacher </select>
-
test
@Test public void getTeacher(){ SqlSession sqlSession = MybatisUtils.getSQlSession(); TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class); List<Teacher> teacher = mapper.getTeacher(); for (Teacher teacher1 : teacher) { System.out.println(teacher1); } sqlSession.close(); }
整体环境搭建测试完毕
接下来实现一对多
11.2 按结果嵌套查询
11.2.1 TeacherStudent添加方法
//获取指定老师下的所有学生及老师的信息
Teacher getTeacher2(@Param("tid") int id);
11.2.2 TeacherStudent.xml写查询
<!--按结果嵌套查询-->
<select id="getTeacher2" resultMap="TeacherStudent">
select s.id sid,s.name sname, t.name tname,t.id tid
from student s,teacher t
where s.tid = t.id and t.id = #{tid}
</select>
<resultMap id="TeacherStudent" type="Teacher">
<result property="id" column="tid"/>
<result property="name" column="tname"/>
<!--
复杂的属性,我们需要单独处理 javaType="" 制定属性的类型!
集合中的泛型信息,我们使用ofType获取
-->
<collection property="students" ofType="Student">
<result property="id" column="sid"/>
<result property="name" column="sname"/>
<result property="tid" column="tid"/>
</collection>
</resultMap>
11.2.3 测试方法
@Test
public void getTeacher2(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacherList = mapper.getTeacher2(1);
System.out.println(teacherList);
sqlSession.close();
}
11.3 按照查询嵌套处理(子查询)
11.3.1 TeacherStudent添加方法
Teacher getTeacher3(@Param("tid") int id);
11.3.2 TeacherStudent.xml写查询
<select id="getTeacher3" resultMap="TeacherStudent2">
select * from teacher where id= #{tid}
</select>
<resultMap id="TeacherStudent2" type="Teacher">
<collection property="students" javaType="ArrayList" ofType="Student" select="getStudentByTid" column="id"/>
</resultMap>
<select id="getStudentByTid" resultType="Student">
select * from student where tid = #{id}
</select>
11.3.3 测试方法
@Test
public void getTeacher2(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
TeacherMapper mapper = sqlSession.getMapper(TeacherMapper.class);
Teacher teacher = mapper.getTeacher3(1);
System.out.println(teacher);
sqlSession.close();
}
小结
1. 关联-association 【多对一】
2. 结合 -collection 【一对多】
3. javaType & ofType
1.javaType-->用来指定实体类中属性的类型 (如:List<Student>,指的是List)
2.1ofaType-->用指定映射到List或者集合中的pojo类型,泛型中的约束类型 (如:List<Student>,指的是List)
12. 动态SQL
根据不同的条件生成不用的SQL语句
if
choose (when, otherwise)
trim (where,set)
foreach
12.1 搭建环境(mybatis-08)
数据库:
创建一个基础工程:
-
导包(比如Lombok,实体类中要用@Data)
-
编写配置文件和utils
-
编写实体类
package com.jiang.pojo; import lombok.Data; import java.util.Date; @Data public class Blog { private int id; private String name; private String author; private Date create_time; private int vires; }
-
编写实体类对应Mapper接口和Mapper.xml文件
-
注意修改好相关配置的路径(注册Mapper、namespace、别名等)
解决数据库字段与实体类属性名不一致问题
- 在核心配置文件的setting中添加:
<setting name="mapUnderscoreToCamelCase" value="true"/>
12.2 添加工具类:IDutils.java
- 随机生成不重复的id序列
package com.jiang.utils;
import org.junit.Test;
import java.util.UUID;
@SuppressWarnings("all")
public class IDutils {
public static String getId(){
return UUID.randomUUID().toString().replaceAll("-","");
}
@Test
public void test(){
System.out.println(IDutils.getId());
}
}
12.3 插入博客数据
12.3.1 接口写方法
//插入数据
int addBlog(Blog blog);
12.3.2 xml文件写插入
<?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">
<!--configuration 核心配置文件-->
<mapper namespace="com.jiang.dao.BlogMapper">
<insert id="addBlog" parameterType="blog">
insert into blog(id,title,author,create_time,views)
values (#{id},#{title},#{author},#{createTime},#{views})
</insert>
</mapper>
12.3.3 测试插入
import com.jiang.dao.BlogMapper;
import com.jiang.pojo.Blog;
import com.jiang.utils.IDutils;
import com.jiang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;
import java.util.Date;
public class MyTest {
@Test
public void addInitBlog(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
Blog blog = new Blog();
blog.setId(IDutils.getId());
blog.setTitle("Mybatis如此简单");
blog.setAuthor("狂神说");
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
接口方法
//查询博客
List<Blog> queryBlogIF(Map map);
XML
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
<where>
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</where>
</select>
测试
@Test
public void queryBlogIF(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
//添加则查出限定条件的信息
map.put("title","Java如此简单");
map.put("author","狂神说");
List<Blog> blogs = mapper.queryBlogIF(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
choose (when, otherwise)
- 表示至选择when标签中的一个条件
接口方法
List<Blog> queryBlogChoose(Map map);
XML
<select id="queryBlogChoose" parameterType="map" resultType="blog">
select * from blog
<where>
<choose>
<when test="title != null">
title = #{title}
</when>
<when test="author != null">
and author = #{author}
</when>
<otherwise>
and views = #{views}
</otherwise>
</choose>
</where>
</select>
测试
@Test
public void queryBlogChoose(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
//map.put("title","Java如此简单");
map.put("author","狂神说");
map.put("views",9999);
List<Blog> blogs = mapper.queryBlogChoose(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
trim (where,set)
- trim的用法可以查看官方代码
接口方法
//更新博客
int updateBlog(Map map);
XML
<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>
测试
@Test
public void updateBlog(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
HashMap map = new HashMap();
//map.put("title","Java如此简单2");
map.put("author","狂神说2");
map.put("id","412e4f22842f46a7b5f507989000e298");
//map.put("views",9999);
int i = mapper.updateBlog(map);
if (i != 0){
System.out.println("OK!");
}
sqlSession.close();
}
foreach
select * from blog where 1=1 and (id = 1 or id = 2 or id = 3)
接口方法
//查询第1、2、3号blog
List<Blog> queryBlogForeach(Map map);
XMl
<!--
select * from blog where 1=1 and (id = 1 or id = 2 or id = 3)
其实本质就是用这些方法拼凑这些语句出来,但是是动态的
传递一个万能map,这个map存在一个集合
-->
<select id="queryBlogForeach" parameterType="map" resultType="blog">
select * from blog
<where>
<foreach collection="ids" item="id" open="and (" close=")" separator="or">
id = #{id}
</foreach>
</where>
</select>
测试
@Test
public void queryBlogForeach(){
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);
map.put("ids",ids);
List<Blog> blogs = mapper.queryBlogForeach(map);
for (Blog blog : blogs) {
System.out.println(blog);
}
sqlSession.close();
}
SQL片段
把一部分代码提取出来方便复用
1. 使用sql标签抽取公共的部分
2. 在需要使用的地方使用include标签引用即可
<sql id="if-title-author">
<if test="title != null">
and title = #{title}
</if>
<if test="author != null">
and author = #{author}
</if>
</sql>
<select id="queryBlogIF" parameterType="map" resultType="blog">
select * from blog
<where>
<include refid="if-title-author"></include>
</where>
</select>
注:
- 最好基于单表来定义SQL片段
- 不要存在where标签
所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码
动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去拼接组合就可以了
13. 缓存
查询--->连接数据库--->耗资源
解决:一次查询得结果,存在一个可以直接取到的地方!-->内存
再次查询相同数据的时候,直接走缓存,就不用走数据库了
- 可以减少和数据库交互次数,减少系统开销,提高系统效率
- 用在:经常查询并且不经常改变的数据
- 只有两级缓存:
- 一级缓存默认开启(SqlSession级别的,本地缓存)
- 二级缓存需要手动开启和配置,基于namespace级别的缓存
- Mybatis定义了Cache接口,可以通过实现Cache接口来定义二级缓存
一级缓存
- 搭建环境
- 开启日志!
- 测试在一个Session中查询两次相同的记录
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
System.out.println("----------------------------------------------------");
User user2 = mapper.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession.close();
}
- 查看日志输出
缓存失效:
-
查询不同的数据
-
增删改操作,可能会改变原来的数据,所以必定会刷新缓存
-
查询不同的Mapper.xml
-
手动清理
sqlSession.clearCache();
以上好像是一级缓存
二级缓存
-
开启全局缓存(核心配置文件里面的Setting)
<!--显示的开启全局缓存--> <setting name="cacheEnabled" value="true"/>
-
在Mapper.xml中添加开启缓存
<!--在当前Mapper.xml中使用二级缓存--> <cache/>
也可以在查询标签里面自定义开关也可以自定义参数:
<!--在当前Mapper.xml中使用二级缓存--> <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true" />
-
测试
@Test
public void test(){
SqlSession sqlSession = MybatisUtils.getSQlSession();
SqlSession sqlSession2 = MybatisUtils.getSQlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
User user = mapper.queryUserById(1);
System.out.println(user);
sqlSession.close();
UserMapper mapper2 = sqlSession2.getMapper(UserMapper.class);
User user2 = mapper2.queryUserById(1);
System.out.println(user2);
System.out.println(user==user2);
sqlSession2.close();
}
问题:
当只用了< cache />出现了
-
我们需要将实体类序列化,否则就会报错
Error serializing object. Cause: java.io.NotSerializableException: com.jiang.pojo.User
解决:
小结
- 只要开启了二级缓存,在同一个Mapper下就有效
- 所有的数据都会先放在以及缓存中
- 只有当会话提交,或者关闭的时候,才回提交到二级缓存中
自定义缓存
Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存
要在程序中使用ehcache,先要导包!
<!-- 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>
<!--自定义缓存,使用外部包 -->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
在resources创建ehcache.xml自定义缓存
<?xml version="1.0" encoding="UTF-8" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false">
<diskStore path="./tmpdir/Tmp_EhCache"/>
<defaultCache
eternal="false"
maxElementsInMemory="10000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="259200"
memoryStoreEvictionPolicy="LRU"/>
<cache
name="Cloud_user"
eternal="false"
maxElementsInMemory="5000"
overflowToDisk="false"
diskPersistent="false"
timeToIdleSeconds="1800"
timeToLiveSeconds="1800"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
Redis数据库来做缓存!??????