一、MyBatis常用

1、[MyBatis官方文档]:mybatis – MyBatis 3 | 简介

2、[maven包]:Maven Repository: org.mybatis » mybatis (mvnrepository.com)

  1. <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
  2. <dependency>
  3. <groupId>org.mybatis</groupId>
  4. <artifactId>mybatis</artifactId>
  5. <version>3.5.3</version>
  6. </dependency>
  7. <!--mysql-->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.24</version>
  12. </dependency>
  13. <!--junit-->
  14. <dependency>
  15. <groupId>junit</groupId>
  16. <artifactId>junit</artifactId>
  17. <version>4.12</version>
  18. </dependency>

3、mybatis核心配置文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <environments default="development">
  7. <environment id="development">
  8. <transactionManager type="JDBC"/>
  9. <dataSource type="POOLED">
  10. <property name="driver" value="driver"/>
  11. <property name="url" value="url"/>
  12. <property name="username" value="username"/>
  13. <property name="password" value="password"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  17. <mappers>
  18. <mapper resource="com..."/>
  19. </mappers>
  20. </configuration>

4、编写sql语句映射的配置文件 Mapper.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="org.mybatis.example.BlogMapper">
  6. <resultMap id="adminResultMap" type="adminUser">
  7. <result column="admin_user_id" property="adminUserId"/>
  8. </resultMap>
  9. <sql id="admin_filed">
  10. admin_user_id, login_user_name, login_password, nick_name
  11. </sql>
  12. <sql id="updateSql">
  13. <if test="adminUserName!=null">
  14. login_user_name=#{adminUserName},
  15. </if>
  16. <if test="adminUserPwd!=null">
  17. login_password=#{adminUserPwd}
  18. </if>
  19. </sql>
  20. <select id="selectBlog" resultType="Blog">
  21. select * from Blog where id = #{id}
  22. </select>
  23. </mapper>

二、创建第一个MyBatis项目

1、创建一个maven项目

2、导入maven依赖

常用的为mybatis、junit、mysql

3、连接数据库

连接成功后的画面:

4、创建核心配置文件

在resource下创建mybatis-config.xml配置文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <environments default="development">
  7. <environment id="development">
  8. <transactionManager type="JDBC"/>
  9. <dataSource type="POOLED">
  10. <property name="driver" value="com.mysql.jdbc.Driver"/>
  11. <property name="url" value="jdbc:mysql://localhost:3306/databaseName?useSSL=true&amp;useUnicode=true&amp;characterEncoding=UTF8"/>
  12. <property name="username" value="username"/>
  13. <property name="password" value="password"/>
  14. </dataSource>
  15. </environment>
  16. </environments>
  17. <mappers>
  18. <mapper resource="com/qing/dao/UserMapper.xml"></mapper>
  19. </mappers>
  20. </configuration>
  • 11行修改databaseName为自己的数据库名

  • useSSL=true 设置存储安全模式

  • & ;是“&&”的转义

  • useUnicode=true&characterEncoding=UTF-8 设置编码模式 ,必须添加

  • 12行的username为数据库名

  • 13行的password为密码

  • 18-20行为mapper映射,每个mapper配置文件都需要在核心配置文件中添加映射路径

5、编写Mybais工具类 创建数据库连接

  1. public class MybatisUtils {
  2. private static SqlSessionFactory sqlSessionFactory;
  3. //静态代码块
  4. static {
  5. try {
  6. //获取sqlSessionFactory对象
  7. //获取资源文件mybatis-config.xml
  8. String resource = "mybatis-config.xml";
  9. InputStream inputStream = Resources.getResourceAsStream(resource);
  10. sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
  11. } catch (IOException e) {
  12. e.printStackTrace();
  13. }
  14. }
  15. //SqlSession包含了面向数据库执行Sql命令的所有方法
  16. public static SqlSession sqlSession(){
  17. SqlSession sqlSession = sqlSessionFactory.openSession();
  18. return sqlSession;
  19. }
  20. }

6、创建Mapper接口,创建对应的sql映射配置文件

xml文件内容:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.qing.dao.UserMapper">
  6. <select id="getUserList" resultType="com.qing.pojo.User">
  7. select *from mybatis.user
  8. </select>
  9. </mapper>
  • namespace绑定接口
  • id ”getUserList”中对应接口中需实现的方法名
  • resultType定义返回类型为User
  • 一个select标签里面就包含了一个方法,可以在mapper中编写多个select标签

7、使用junit 测试(发现一个问题)

  1. public class UserDaoTest {
  2. @Test
  3. public void test() {
  4. //获得SqlSession对象
  5. SqlSession sqlSession = MybatisUtils.sqlSession();
  6. //执行sql
  7. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  8. List<User> list = mapper.getUserList();
  9. for (User user : list) {
  10. System.out.println(user.toString());
  11. }
  12. }
  13. }

出现问题:配置文件找不到

这是因为 UserMapper配置文件在java代码下,Maven 通常会忽略掉标记为 Sources 的文件夹中的配置文件

解决方法:

1、 第一种:将配置文件放入 resources 文件夹中

2、第二种:在总项目下的pom.xml文件中的build下配置resource,防止资源导出失败(推荐使用

  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/java</directory>
  5. <includes>
  6. <include>**/*.properties</include>
  7. <include>**/*.xml</include>
  8. </includes>
  9. <filtering>true</filtering>
  10. </resource>
  11. <resource>
  12. <directory>src/main/resources</directory>
  13. <includes>
  14. <include>**/*.properties</include>
  15. <include>**/*.xml</include>
  16. </includes>
  17. <filtering>true</filtering>
  18. </resource>
  19. </resources>
  20. </build>

运行成功:

三、mybatis项目注意事项

1、配置文件中,namespace绑定接口时,是使用的 “ . ”

  1. <mapper namespace="com.qing.dao.UserMapper">

2、核心配置文件中,mapper注册配置文件的映射时,是使用的 “ / ”

  1. <mappers>
  2. <mapper resource="com/qing/dao/UserMapper.xml"></mapper>
  3. </mappers>

3、在配置文件中编写sql语句时,必须对应语句的标签,select语句对应select标签,insert语句对应insert标签,update语句对应update标签

  1. <mapper namespace="com.qing.dao.UserMapper">
  2. <select id="getUserList" resultType="com.qing.pojo.User">
  3. select *from mybatis.user
  4. </select>
  5. <select id="getUserById" resultType="com.qing.pojo.User" parameterType="int">
  6. select * from mybatis.user where id=#{id}
  7. </select>
  8. <insert id="addUser" parameterType="com.qing.pojo.User">
  9. insert into mybatis.user(id, name, pwd) values(#{id},#{name},#{pwd});
  10. </insert>
  11. <update id="updateUser" parameterType="com.qing.pojo.User">
  12. update mybatis.user set name=#{name},pwd=#{pwd} where id=#{id};
  13. </update>
  14. <delete id="deleteUser" parameterType="int">
  15. delete from mybatis.user where id=#{id};
  16. </delete>
  17. </mapper>

因为数据库的增删改返回的都是int类型,而select返回的可以为null或者一个对象,如果insert语句使用select标签包含

  1. <select id="addUser" parameterType="com.qing.pojo.User">
  2. insert into mybatis.user(id, name, pwd) values(#{id},#{name},#{pwd});
  3. </select>

那么会出现以下错误:

  1. Mapper method 'com.qing.dao.UserMapper.addUser attempted to return null from a method with a primitive return type (int).
  2. // 映射器方法'com.qing.dao.UserMapper.addUser尝试从具有原始返回类型(int)的方法返回null。

4、数据库的增删改都需要提交事务,如果不设置提交事务,即便是执行了方法且成功了,数据库的数据都不会得到更新

  1. sqlSession.commit(); //提交事务

5、核心配置文件的标签顺序

mybatis中核心配置文件的标签顺序是有严格要求的

四、模糊查询

1、在java代码中传递通配符 “%”

  1. List<User> userList = mapper.getUserLike("%宝%");

2、在sql拼接中使用通配符

  1. select * from mybatis.user where name like "%"#{value}"%";

五、优化

1、核心配置文件优化

在resource资源目录下创建一个db.properties文件,存储数据库的链接驱动、账号、密码

db.properties文件内如如下:

  1. driver=com.mysql.jdbc.Driver
  2. url=jdbc:mysql://localhost:3306/databaseName?useSSL=true&useUnicode=true&characterEncoding=UTF-8
  3. username=userName
  4. password=userPwd

核心配置文件内如如下:

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  5. <configuration>
  6. <!-- 引入外部配置文件-->
  7. <properties resource="db.properties"></properties>
  8. <environments default="development">
  9. <environment id="development">
  10. <transactionManager type="JDBC"/>
  11. <dataSource type="POOLED">
  12. <property name="driver" value="${driver}"/>
  13. <property name="url" value="${url}"/>
  14. <property name="username" value="${username}"/>
  15. <property name="password" value="${password}"/>
  16. </dataSource>
  17. </environment>
  18. </environments>
  19. </configuration>

这样使用的好处就是不用在mybatis核心配置文件中将数据库账号密码写死,单独使用一个文件保存,更加灵活。

2、别名优化

优化接口映射文件中的类型,如:”com.qing.pojo.User”

  1. <select id="getUserList" resultType="com.qing.pojo.User">
  2. select *from mybatis.user
  3. </select>

(1)方法一:可以在核心配置文件中配置别名

  1. <typeAliases>
  2. <typeAlias type="com.qing.pojo.User" alias="User"></typeAlias>
  3. </typeAliases>

给com.qing.pojo.User 取了一个别名User

(2)方法二:使用注解,在实体类前添加 “@Alias()”

  1. @Alias("User")
  2. public class User {
  3. }

最后使用时,就直接使用“User”这个别名,而不用使用”com.qing.pojo.User”

  1. <select id="getUserList" resultType="User">
  2. select *from mybatis.user
  3. </select>

3、开启驼峰命名规则映射

  1. <!--开启数据库字段映射为驼峰命名-->
  2. <settings>
  3. <setting name="mapUnderscoreToCamelCase" value="true"/>
  4. </settings>

六、映射器(mappers)

每编写一个dao层接口,都需要在核心配置文件中注册

方法一:绑定对应接口的映射配置文件,如UserMapper.xml

  1. <mappers>
  2. <mapper resource="com/qing/dao/UserMapper.xml"></mapper>
  3. </mappers>

方法二:使用class绑定注册

  1. <mappers>
  2. <mapper class="com.qing.dao.UserMapper"></mapper>
  3. </mappers>

使用class注意点:

  • 接口和它的Mapper配置文件必须同名
  • 接口和它的配置文件必须在同一个包下
  • 如下图

方法三:使用扫描包注册绑定

  1. <mappers>
  2. <package name="com.qing.dao"/>
  3. </mappers>

此方法注意事项与第二种方法一样

七、解决数据库的字段与实体类的属性名不一致

实体类:

  1. private int id;
  2. private String name;
  3. private String password;

数据库字段:

在查询时,就会出现数据库找不到对应的pwd字段值,最后显示为“null”

  1. User{id=1, name='qingfan', pwd='null'}

解决方法

方法一:在数据库查询语句中去别名(不推荐使用)

  1. <select id="getUserById" resultType="User" parameterType="int">
  2. select id,name,pwd as password from mybatis.user where id=#{id}
  3. </select>

方法二: 使用resultMap结果集映射(推荐使用

  1. <resultMap id="UserMap" type="User">
  2. <result property="password" column="pwd"></result>
  3. </resultMap>
  4. <select id="getUserById" resultMap="UserMap">
  5. select id,name,password from mybatis.user where id=#{id}
  6. </select>

第5行使用resultMap代替之前的resultType,第1行给resultMap定义返回类型为User,第2行中的 property 为实体类的属性名,column 为数据库的字段名,相当于给数据库中的字段名pwd起了一个别名password。

八、日志

1、日志工厂

日志工厂有:

  • SLF4J
  • LOG4J(重要)
  • STDOUT_LOGGING(重要)
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • NO_LOGGING
  1. <settings>
  2. <setting name="logImpl" value="STDOUT_LOGGING"/>
  3. </settings>

在核心配置文件的settings标签中设置

2、log4j

  • 使用log4j可以控制每一条日志的输出格式
  • 通过定义每一条日志的信息级别,我们能够更加细致地控制日志的生成过程
  • 通过一个配置文件灵活的配置,不需要修改应用的代码
  • 可以控制日志输出的目的地:控制台,文件,gui等

(1) 导入log4j包

  1. <dependency>
  2. <groupId>log4j</groupId>
  3. <artifactId>log4j</artifactId>
  4. <version>1.2.17</version>
  5. </dependency>

(2) log4j.properties

  1. #将等级为DEBUG的日志信息输出到console和file这两个目的地,console 和file的定义在下面的代码
  2. log4j.rootLogger=DEBUG,console,file
  3. #控制台输出的相关设置
  4. log4j.appender.console=org.apache.log4j.ConsoleAppender
  5. log4j.appender.console.Target = System.out
  6. log4j.appender.console.Threshold=DEBUG
  7. log4j.appender.console.layout = org.apache.log4j.PatternLayout
  8. log4j.appender.console.layout.ConversionPattern= [%c] - %m%n
  9. #文件输出的相关设置 文件名 qing.log
  10. log4j.appender.file = org.apache.log4j.RollingFileAppender
  11. log4j.appender.file.File=./log/qing.log
  12. log4j.appender.file.MaxFileSize=10mb
  13. log4j.appender.file.Threshold=DEBUG
  14. log4j.appender.file.layout=org.apache.log4j.PatternLayout
  15. log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c ]%m%n
  16. #日志输出级别
  17. log4j.logger.org.mybatis=DEBUG
  18. log4j.logger.java.sql=DEBUG
  19. log4j.logger.java.sql.Statement=DEBUG
  20. log4j.logger.java.sql.ResultSet=DEBUG
  21. log4j.logger.java.sql.PreparedStatement=DEBUG

(3) 配置log4j日志的实现

  1. <settings>
  2. <setting name="logImpl" value="LOG4J"/>
  3. </settings>

(4) 输出

  1. import org.apache.log4j.Logger;
  2. import org.junit.Test;
  3. public class TestLog4j {
  4. static Logger logger= Logger.getLogger(TestLog4j.class);
  5. @Test
  6. public void testLog4j(){
  7. logger.info("进入testLog4j");
  8. logger.error("testLog4j错误");
  9. logger.debug("debug!!");
  10. }
  11. }
  • 导包不能导错,需要导入“org.apache.log4j.Logger”
  • 设置日志对象Logger,参数为当前类的class

qing.log文件内容

九、注解开发

  • mybatis注解开发就简化了xml映射配置文件,不用在为每一个接口编写一个xml文件了
  • 使用注解开发,就直接在接口的方法上面,使用@select注解
  • 注解开发虽然使用很简单方便,但对稍微复杂的sql语句就不行了,并且无法解决字段与属性名不一致的问题
  1. public interface UserMapper {
  2. @Select("select *from user")
  3. List<User> getUserList();
  4. }

本质:反射实现

底层:动态代理

使用注解开发时,接口中若有多个参数时:

  • 一个基本的参数类型就对应一个@Param()注解
  • 引用类型不用加@Param
  • 如果只有一个基本类型时,也可以不用使用
  1. @Select("select *from user where id=#{uid}")
  2. User getUserById(@Param("uid") int id);

@Param中的参数名才是传递到sql语句中的属性名,例如使用了“uid”代替“id”

十、LomBok

1、安装lombok插件

安装完成后需重启idea

2、导入lombok依赖

  1. <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
  2. <dependency>
  3. <groupId>org.projectlombok</groupId>
  4. <artifactId>lombok</artifactId>
  5. <version>1.18.12</version>
  6. </dependency>

lombok的注解:

  1. @Getter and @Setter
  2. @FieldNameConstants
  3. @ToString
  4. @EqualsAndHashCode
  5. @AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
  6. @Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
  7. @Data
  8. @Builder
  9. @SuperBuilder
  10. @Singular
  11. @Delegate
  12. @Value
  13. @Accessors
  14. @Wither
  15. @With
  16. @SneakyThrows
  17. @val
  18. @var
  1. @Data //无参构造、get、set、tostring
  2. @NoArgsConstructor //无参构造
  3. @AllArgsConstructor //全参构造
  4. public class User {
  5. private int id;
  6. private String name;
  7. private String password;
  8. }

十一、多对一处理

按语句嵌套查询 子查询

1、数据库

创建teacher表和student表,student表中的tid字段为外键,关联teacher表的id

2、Student类

  1. @Data
  2. public class Student {
  3. private int id;
  4. private String name;
  5. //外键关联 多个学生关联一个老师 多对一
  6. private Teacher teacher;
  7. }

3、修改mapper配置文件位置

不再将映射配置文件放在dao层下,而是放在resources资源文件下,但必须保持接口与配置文件路径一致,如图中:com.qing.dao

4、编写核心配置文件的映射

  1. <mappers>
  2. <mapper class="com.qing.dao.TeacherMapper"></mapper>
  3. <mapper class="com.qing.dao.StudentMapper"/>
  4. </mappers>

5、StudentMapper.xml文件

查询所有的学生信息

根据查询出来的学生的tid,寻找对应的老师

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper
  3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  5. <mapper namespace="com.qing.dao.StudentMapper">
  6. <select id="getStudentList" resultMap="StudentMap">
  7. select *from student
  8. </select>
  9. <resultMap id="StudentMap" type="Student">
  10. <result property="id" column="id"/>
  11. <result property="name" column="name"/>
  12. <!-- 复杂属性,需要单独处理 对象association 集合collection-->
  13. <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
  14. </resultMap>
  15. <select id="getTeacher" resultType="Teacher">
  16. select *from teacher where id=#{tid}
  17. </select>
  18. </mapper>

第14行就根据查询到的tid,映射成一个Teacher对象,这里的property对应student类中的属性teacher对象,tid为数据库中的字段,javaType为指定属性的类型

按查询结果嵌套查询(重要)

  1. <!-- 方式二-->
  2. <select id="getStudentList2" resultMap="StudentMap2">
  3. select s.id,s.name sname,t.name tname from student s,teacher t where s.tid=t.id
  4. </select>
  5. <resultMap id="StudentMap2" type="Student">
  6. <result property="id" column="id"></result>
  7. <result property="name" column="sname"></result>
  8. <association property="teacher" javaType="Teacher">
  9. <result property="name" column="tname"></result>
  10. </association>
  11. </resultMap>

十二、一对多(按结果嵌套)

1、实体类

  1. public class Student {
  2. private int id;
  3. private String name;
  4. private int tid;
  5. }
  1. public class Teacher {
  2. private int id;
  3. private String name;
  4. //一个老师多个学生 一对多
  5. private List<Student> students;
  6. }

2、TeacherMapper.xml文件

  1. <mapper namespace="com.qing.dao.TeacherMapper">
  2. <select id="getTeacher" resultMap="TeacherMap">
  3. select s.id sid,s.name sname,t.name tname,t.id tid from student s,teacher t
  4. where s.tid=t.id and t.id=#{tid}
  5. </select>
  6. <resultMap id="TeacherMap" type="Teacher">
  7. <result property="id" column="tid"></result>
  8. <result property="name" column="tname"/>
  9. <!--students是一个集合,使用ofType获取-->
  10. <collection property="students" ofType="Student">
  11. <result property="id" column="sid"/>
  12. <result property="name" column="sname"/>
  13. <result property="tid" column="tid"/>
  14. </collection>
  15. </resultMap>
  16. </mapper>

十三、动态SQL

1、动态获取ID

  1. public class IDUtils {
  2. public static String getId(){
  3. return UUID.randomUUID().toString().replaceAll("-","");
  4. }
  5. }

2、if、where

  1. <select id="queryBlogIf" parameterType="map" resultType="Blog">
  2. select *from blog
  3. <where>
  4. <if test="title!=null">
  5. title=#{title}
  6. </if>
  7. <if test="author!=null">
  8. and author=#{author}
  9. </if>
  10. </where>
  11. </select>

将要添加的条件放到一个map集合中,使用if标签进行条件判断对sql语句进行追加

where标签可以自动的判断当前的判断条件,如果为第一个判断条件,则会自动去除语句前的and,如上述代码,如果只对author进行限制,那么会自动去掉“ and author=#{author}”的and;反之如果不是第一个判断条件且语句没有and,则会自动添加and

3、choose、when

  1. <select id="queryBlogChoose" parameterType="map" resultType="Blog">
  2. select *from blog
  3. <where>
  4. <choose>
  5. <when test="title!=null">
  6. title=#{title}
  7. </when>
  8. <when test="author!=null">
  9. author=#{author}
  10. </when>
  11. <otherwise>
  12. views=#{views}
  13. </otherwise>
  14. </choose>
  15. </where>
  16. </select>

choose标签会选择一条判断执行,当满足第一条后,就会跳出;如果都没有满足的条件,则会执行otherwise

4、set

  1. <update id="updateBlog" parameterType="map">
  2. update blog
  3. <set>
  4. <if test="title!=null">
  5. title=#{title},
  6. </if>
  7. <if test="author!=null">
  8. author=#{author},
  9. </if>
  10. </set>
  11. where id=#{id}
  12. </update>

使用set标签会自动拼接set,并智能的去除多余的“,”。例如只需要判断title,那么拼接sql语句时,就会自动把后面的“,”去掉

5、sql片段

  1. <sql id="if-title-author">
  2. <if test="title!=null">
  3. and title=#{title}
  4. </if>
  5. <if test="author!=null">
  6. and author=#{author}
  7. </if>
  8. </sql>
  9. <select id="queryBlogIf" parameterType="map" resultType="Blog">
  10. select *from blog
  11. <where>
  12. -- 原代码
  13. <!-- <if test="title!=null">-->
  14. <!-- and title=#{title}-->
  15. <!-- </if>-->
  16. <!-- <if test="author!=null">-->
  17. <!-- and author=#{author}-->
  18. <!-- </if>-->
  19. -- 简化后
  20. <include refid="if-title-author"></include>
  21. </where>
  22. </select>

使用sql片段可以简化冗余的代码,例如上述的两个if判断,就可以使用sql标签将他们提取出来。其中的id作为这一部分代码的标识符,与include标签中的refid对应

6、foreEach

  1. <select id="searchBlogById" parameterType="map" resultType="Blog">
  2. select *from blog
  3. <where>
  4. <foreach collection="ids" item="id" open="and (" close=")" separator="or">
  5. id=#{id}
  6. </foreach>
  7. </where>
  8. </select>

collection为指定的集合,item是集合中的集合项(index为索引),open为指定的开头字符串,close为结尾字符串,separator为分隔符。

当collection为map时,index是键、item是值

上述代码拼接成sql:select *from blog WHERE ( id=? or id=? )

  1. public void test5() {
  2. SqlSession sqlSession = MybatisUtils.sqlSession();
  3. BlogMapper mapper = sqlSession.getMapper(BlogMapper.class);
  4. Map map = new HashMap();
  5. ArrayList<Integer> ids = new ArrayList<>();
  6. ids.add(1);
  7. ids.add(5);
  8. map.put("ids", ids);
  9. List<Blog> blogs = mapper.searchBlogById(map);
  10. for (Blog blog : blogs) {
  11. System.out.println(blog);
  12. }
  13. sqlSession.commit();
  14. }

十四、缓存

1、一级缓存

  • 一级缓存默认开启,只在一次SqlSession中有效
  • 一级缓存也叫本地缓存,默认开启,无法关闭,可以手动清理
  1. sqlSession.clearCache();

可以从上图看到,查询相同的东西时,只需执行一次sql语句,第一次执行的结果就会保存到一级缓存中

而当手动清理缓存后,就会执行两次sql

缓存失效的情况:

  • 查询不同的东西
  • 增删改操作会修改原来的数据,必定会刷新缓存
  • 查询不同的mapper.xml
  • 手动清理缓存

2、二级缓存

  • 二级缓存叫做全局缓存,是基于namespace级别的缓存
  • 一级缓存只作用于一次会话,当会话关闭后,缓存就关闭了,二级缓存就能达到即使会话关闭了,也能将一级缓存的数据保存到二级缓存中
  • 不同的mapper查出的数据会放在自己对应的缓存(map)中

二级缓存的开启:

在核心配置文件的setting中设置

  1. <!-- 显示开启全局缓存-->
  2. <setting name="cacheEnabled" value="true"/>

在对应接口的Mapper.xml的mapper标签中设置

  1. <mapper namespace="com.qing.dao.UserMapper">
  2. <!-- 开启二级缓存-->
  3. <cache/>
  4. </mapper>

也可以自定义参数

  1. <!-- 开启二级缓存-->
  2. <cache eviction="FIFO"
  3. flushInterval="6000"
  4. size="512"
  5. readOnly="true">
  6. </cache>
  • flushInterval:刷新间隔 毫秒
  • size:存储的最大引用
  • readOnly:返回的对象只读

3、自定义缓存

1)导包

  1. <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache -->
  2. <dependency>
  3. <groupId>org.mybatis.caches</groupId>
  4. <artifactId>mybatis-ehcache</artifactId>
  5. <version>1.2.1</version>
  6. </dependency>

2)在Mapper.xml配置文件中添加cache标签

  1. <cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

3)添加ehcache.xml文件

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
  4. updateCheck="false">
  5. <!--
  6. diskStore:为缓存路径,ehcache分为内存和磁盘两级,此属性定义磁盘的缓存位置。参数解释如下:
  7. user.home – 用户主目录
  8. user.dir – 用户当前工作目录
  9. java.io.tmpdir – 默认临时文件路径
  10. -->
  11. <diskStore path="./tmpdir/Tmp_EhCache"/>
  12. <!--defaultCache:默认缓存策略,当ehcache找不到定义的缓存时,则使用这个缓存策略。只能定义一个 -->
  13. <defaultCache
  14. eternal="false"
  15. maxElementsInMemory="10000"
  16. overflowToDisk="false"
  17. diskPersistent="false"
  18. timeToIdleSeconds="1800"
  19. timeToLiveSeconds="259200"
  20. memoryStoreEvictionPolicy="LRU"/>
  21. <cache
  22. name="cloud_user"
  23. eternal="false"
  24. maxElementsInMemory="5000"
  25. overflowToDisk="false"
  26. diskPersistent="false"
  27. timeToIdleSeconds="1800"
  28. timeToLiveSeconds="1800"
  29. memoryStoreEvictionPolicy="LRU"/>
  30. <!--
  31. name:缓存名称。
  32. maxElementsInMemory:缓存最大数目
  33. maxElementsOnDisk:硬盘最大缓存个数。
  34. eternal:对象是否永久有效,一但设置了,timeout将不起作用。
  35. overflowToDisk:是否保存到磁盘,当系统当机时
  36. timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。
  37. 仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
  38. timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。
  39. 仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
  40. diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
  41. diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
  42. diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
  43. memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。
  44. 默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
  45. clearOnFlush:内存数量最大时是否清除。
  46. memoryStoreEvictionPolicy:可选策略有:LRU(最近最少使用,默认策略)、FIFO(先进先出)、LFU(最少访问次数)。
  47. FIFO,first in first out,这个是大家最熟的,先进先出。
  48. LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。
  49. 如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。
  50. LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
  51. -->
  52. </ehcache>

注:若复制xml文件时,“http://ehcache.org/ehcache.xsd”报错,显示为红色,需要进行以下步骤: