Mybatis是什么?

MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

xml是什么?

XML是一种可以描述数据之间层级关系的配置文件。可扩展的标记语言。可以根据程序员的需求自己进行添加标签对数据进行标记。

xml应用场景:作为框架配置文件

xml文件语法:

语法包含:声明、标签、属性、注释、CDATA区、指令(引入其他的文件,比如css)、特殊字符(转义字符)

xml文件的声明:

  1. <?xml version="1.0" encoding="UTF-8" ?>

java解析xml文件

SAX解析:需要使用数据的时候,一层一层的去遍历找正确的值,读取效率很低,但是节约内存
DOM解析:会一次性将xml文件中的所有数据,读取到内存中,生成一个Document文档树对象,读取效率高,但是会消耗内存

  1. <!--DOM解析-->
  2. //步骤1:根据工厂类获取工厂对象
  3. DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
  4. //步骤2:根据工厂类对象获取解析器
  5. DocumentBuilder builder = factory.newDocumentBuilder();
  6. //步骤3:根据解析器,获取文档树对象
  7. Document document = builder.parse(new File("src/xml文件名"));

Junit单元测试

作用:让普通的方法,可以不用主函数的时候,直接自己执行。

当前测试的方法,在方法的上面加@Test注解,这个方法不能加static修饰,也不能有形式参数

想要在测试方法之前执行的方法,在方法的上面加@Before注解,这个方法不能加static修饰,也不能有形式参数
想要在测试方法执行之后,执行的方法,在方法的上面加@After注解,这个方法不能加static修饰,也不能有形式参数

ORM框架Mybatis的基本介绍(包含配置文件)

原生JDBC与Mybatis的对比

  1. public class Demo{
  2. private static String driver = "com.mysql.jdbc.Driver";
  3. private static String url = "jdbc:mysql://localhost:3306/db_shop";
  4. private static String username = "root";
  5. private static String password = "";
  6. static{
  7. //加载驱动
  8. Class.forName(driver);
  9. }
  10. public static void main(String[] args){
  11. try{
  12. Connection conn = ManagerDriver.getConnection(url,username,password);
  13. String sql = "select * from t_user where id = ?";
  14. PreparedStatement ps = conn.prepareStatement(sql);
  15. ps.setInt(1,user.getInt());
  16. ResultSet rs = ps.executeQuery();
  17. while(rs.next()){
  18. }
  19. rs.close();
  20. ps.close();
  21. conn.close();
  22. }catch(Exception e){
  23. }
  24. }
  25. }
  1. 原生jdbc频繁创建链接和释放资源,会增加数据库的链接压力
  2. 原生jdbc写在java代码中,属于硬编码,不利于sql代码维护
  3. jdbc预编译对象中的?也属于硬编码

  4. mybatis使用连接池,用连接池来管理数据库的链接和释放资源

  5. mybatis将sql语句提取到xml配置文件中,修改sql语句只需修改xml配置文件即可。
  6. mybatis实现关系对象映射,存在输入对象映射和输出对象映射。

    mybatis基础

    概念:

    用来解决java对象和数据库之间数据交互的框架,apache公司提供的轻量级的ORM框架。目的:将程序员的所有精力全部放在编写sql语句的思路上,至于执行sql语句,填充占位符和查询的数据与对象进行关联,全部由mybatis框架完成。
    思考.PNG

    基本mybatis配置

    SqlMapConfig.xml

log4j.properties

db.properties

最简单的mybatisDAO(使用mapper代理)

思路:
步骤1:创建xml文件,里面配置增、删、改、查的sql语句
步骤2:将创建的xml文件在SqlMapConfig.xml文件中进行配置加载
步骤3:创建一个接口,接口当中包含方法,只有定义。
要求
1)mapper标签里面的namespace:必须写成对应的Mapper接口的全路径名
2)sql语句里面的id:必须和接口中对应方法的名称一致
3)sql语句里面的parameterType:必须要和接口中方法的形式参数数据类型一致
4)sql语句里面的resultType:必须和接口中方法的返回值数据类型一致
步骤4:创建实现类,实现定义的接口,按照规定进行重写方法。声明工厂类对象,该对象由该类的构造方法进行赋值。(使用MVC三层架构实现
步骤5:编写测试类,在测试类中,创建工厂对象,传递给dao的实现类。

简单的实例代码
步骤1:创建xml文件,里面配置增、删、改、查的sql语句

  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. <!--namespace:必须写成对应的Mapper接口的全路径名 -->
  6. <mapper namespace="com.woniuxy.mall.mapper.UserMapper">
  7. <insert id="insert" parameterType="oldUser">
  8. INSERT INTO t_user(user_id ,user_name,user_psword ,user_phon )
  9. VALUES(#{user_id},#{user_name},#{user_psword},#{user_phon});
  10. </insert>
  11. <!-- 根据电话号码查询用户,只会返回一条数据 -->
  12. <select id="queryUserByTel" parameterType="java.lang.String"
  13. resultType="oldUser">
  14. select * from t_user where user_phon=#{tel}
  15. </select>
  16. </mapper>

步骤2:将创建的xml文件在SqlMapConfig.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. <!-- 加载properties配置文件 -->
  7. <properties resource="db.properties" />
  8. <typeAliases>
  9. <!-- name:包名 自动扫描,定义别名,默认类名 -->
  10. <package name="com.woniuxy.mall.model" />
  11. </typeAliases>
  12. <!-- 使用mybatis需要的数据源和事务配置,后续如果整合spring之后,将不再需要 -->
  13. <environments default="development">
  14. <!-- 配置数据源和事务 -->
  15. <environment id="development">
  16. <!-- 配置事务管理,将事务管理交给mybatis管理 -->
  17. <transactionManager type="JDBC" />
  18. <!-- 配置数据源 -->
  19. <dataSource type="POOLED">
  20. <property name="driver" value="${driverClassName}" />
  21. <property name="url" value="${url}" />
  22. <property name="username" value="${username}" />
  23. <property name="password" value="${password}" />
  24. </dataSource>
  25. </environment>
  26. </environments>
  27. <!-- 加载**.xml配置文件mapper映射 -->
  28. <mappers>
  29. <mapper resource="mapper/UserMapper.xml" />
  30. </mappers>
  31. </configuration>

步骤3:创建一个接口,接口当中包含5个方法,两个查询、增、删、改的方法。只有定义。

  1. package com.woniuxy.mall.mapper;
  2. import com.woniuxy.mall.model.oldUser;
  3. /*
  4. * mapper接口,增删改查与mapper.mal文件对应
  5. */
  6. public interface UserMapper {
  7. /*
  8. * 注册,根据名字和密码,电话
  9. */
  10. public int insert(oldUser user)throws Exception;
  11. /*
  12. * 查询单个查询,登录,根据电话、密码
  13. */
  14. public oldUser queryUserByTel(String tel) throws Exception;
  15. }

步骤4.1:创建Mapper实现类,实现定义的接口,按照规定进行重写方法。声明工厂类对象,该对象由该类的构造方法进行赋值。

  1. package com.woniuxy.mall.dao.imple;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import org.apache.ibatis.io.Resources;
  5. import org.apache.ibatis.session.SqlSession;
  6. import org.apache.ibatis.session.SqlSessionFactory;
  7. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  8. import com.woniuxy.mall.mapper.UserMapper;
  9. import com.woniuxy.mall.model.oldUser;
  10. import com.woniuxy.mall.util.User;
  11. public class UserDaoImpl implements UserMapper {
  12. /*
  13. * 声明会话工厂
  14. */
  15. private static SqlSessionFactory factory;
  16. /*
  17. * 获取流
  18. */
  19. static {
  20. String path = "SqlMapConfig.xml";
  21. try {
  22. InputStream config= Resources.getResourceAsStream(path);
  23. factory = new SqlSessionFactoryBuilder().build(config);
  24. } catch (IOException e) {
  25. // TODO Auto-generated catch block
  26. e.printStackTrace();
  27. }
  28. }
  29. @Override
  30. public int insert(oldUser user) throws Exception {
  31. // TODO Auto-generated method stub
  32. /*
  33. * 开启会话
  34. * 获取mapper反射
  35. */
  36. SqlSession session = factory.openSession();
  37. UserMapper mapper = session.getMapper(UserMapper.class);
  38. int row =mapper.insert(user);
  39. session.commit();
  40. session.close();
  41. return row;
  42. }
  43. @Override
  44. public oldUser queryUserByTel(String tel) throws Exception {
  45. //开启会话
  46. SqlSession sqlSession = factory.openSession();
  47. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
  48. oldUser user = mapper.queryUserByTel(tel);
  49. //关闭会话:
  50. sqlSession.close();
  51. return user;
  52. }
  53. }

步骤4.2:编写Service层接口

  1. package com.woniuxy.mall.service;
  2. import com.woniuxy.mall.model.oldUser;
  3. public interface UserService {
  4. /*
  5. * 注册,根据名字和密码,电话
  6. */
  7. public String insert(oldUser user)throws Exception;
  8. public String login(String tel,String password)throws Exception;
  9. }

步骤4.3:编写Service实现类,关联mapper,进行逻辑判断

  1. package com.woniuxy.mall.service.impl;
  2. import com.woniuxy.mall.dao.imple.UserDaoImpl;
  3. import com.woniuxy.mall.mapper.UserMapper;
  4. import com.woniuxy.mall.model.oldUser;
  5. import com.woniuxy.mall.service.UserService;
  6. import com.woniuxy.mall.util.User;
  7. public class UserServiceImple implements UserService{
  8. @Override
  9. public String insert(oldUser user) throws Exception {
  10. // 新增用户
  11. String pass = user.getUser_psword();
  12. //校验密码是否合法
  13. boolean flag = pass.matches("[A-Z][A-Za-z0-9]{5,9}");
  14. if(flag) {
  15. UserMapper dao = new UserDaoImpl();
  16. int row = dao.insert(user);
  17. if(row>0) {
  18. return "成功";
  19. }else {
  20. return "失败";
  21. }
  22. }else {
  23. return "密码格式有误";
  24. }
  25. }
  26. @Override
  27. public String login(String tel, String password) throws Exception {
  28. UserMapper dao = new UserDaoImpl();
  29. oldUser user = dao.queryUserByTel(tel);
  30. if(user != null) {
  31. //获取数据库中的密码:
  32. String userPass = user.getUser_psword();
  33. //比较
  34. if(userPass.equals(password)) {
  35. return "success";
  36. }else {
  37. return "fail";
  38. }
  39. }else {
  40. return "fail";
  41. }
  42. }
  43. }

步骤5:编写测试类,在测试类中,创建工厂对象,传递给dao的实现类。

  1. package com.woniuxy.mall.controller;
  2. import java.util.Scanner;
  3. import java.util.UUID;
  4. import org.junit.jupiter.api.Test;
  5. import com.woniuxy.mall.model.oldUser;
  6. import com.woniuxy.mall.service.UserService;
  7. import com.woniuxy.mall.service.impl.UserServiceImple;
  8. public class UserController {
  9. // @Test
  10. // public void insert() throws Exception {
  11. // // TODO Auto-generated constructor stub
  12. // System.out.println("注册:");
  13. // Scanner input = new Scanner(System.in);
  14. // System.out.println("请输入账号:");
  15. // String userName = input.next();
  16. // System.out.println("请输入密码:");
  17. // String userpass = input.next();
  18. // System.out.print("请输入电话:");
  19. // String userphon = input.next();
  20. //
  21. // String userId = UUID.randomUUID().toString();
  22. // oldUser user = new oldUser();
  23. // user.setUser_id(userId);
  24. // user.setUser_name(userName);
  25. // user.setUser_psword(userpass);
  26. // user.setUser_phon(userphon);
  27. //
  28. // /*
  29. // * 调用service
  30. // */
  31. // UserService userService = new UserServiceImple();
  32. // String flag = userService.insert(user);
  33. //
  34. // if (flag.equals("成功")) {
  35. // System.out.println("注册成功");
  36. // } else {
  37. // System.out.println("注册失败");
  38. // }
  39. //
  40. // }
  41. @Test
  42. public void login() throws Exception {
  43. System.out.println("登录:");
  44. Scanner in = new Scanner(System.in);
  45. System.out.print("请输入电话号码:");
  46. String tel = in.next();
  47. System.out.print("请输入密码:");
  48. String password = in.next();
  49. //创建Service对象
  50. UserService userService = new UserServiceImple();
  51. String flag = userService.login(tel, password);
  52. if(flag.equals("success")) {
  53. System.out.println("登录成功");
  54. }else {
  55. System.out.println("登录失败");
  56. }
  57. }

使用别名和mapper映射

别名

为什么设置别名

在开发中,一般mapper.xml配置文件中的parameterType和resultType往往对应的名称需要写上model的全路径,而且还是多次被重复使用,可以选择给该路径取一个别名。用别名来替换比较复杂的全路径名

好处:将复杂的全路径可以一次性设置好,后续在任何xxxmapper.xml文件中要使用的时候,直接可以使用简单的别名即可。


别名的设置(在SqlMapConfig.xml配置文件中)

  1. <!-- 设置一个别名,使用包扫描 -->
  2. <typeAliases>
  3. <!-- name:包名 自动扫描,定义别名,默认类名 -->
  4. <package name="com.woniuxy.mall.model" />
  5. </typeAliases>

Mapper映射关系配置(三种方式)

mapper.xml配置文件的方式

  1. <mappers>
  2. <mapper resource="mapper/CommodityMapper.xml"/>
  3. </mappers>

以配置Mapper接口的方式进行配置

  1. <!-- 加载mapper.xml文件 -->
  2. <mappers>
  3. <!--
  4. class:对应接口的全路径名
  5. 要求:
  6. 对应的mapper.java接口文件和mapper.xml配置文件必须放在同一个包下面。
  7. mapper.java接口文件和mapper.xml配置文件的名字必须要一致。
  8. -->
  9. <mapper class="com.woniuxy.mall.mapper.CommodityMapper"/>
  10. </mappers>

以扫描包的形式进行配置

  1. <!-- 加载mapper.xml文件 -->
  2. <mappers>
  3. <!--
  4. name:mapper接口的包名
  5. 规则同上。
  6. -->
  7. <package name="com.woniuxy.mall.mapper"/>
  8. </mappers>

自定义的POJO类(高级查询使用)

POJO类

自定义POJO类,一般指的是高级查询,在想要的数据和传入的条件不再一张表中,通过表所创建的失血模型model已经不能够满足传入参数的需求了,这个时候,就需要使用自定义的POJO类
(个人理解实质就是:在主要查询表的失血模型中添加其他表的失血模型。例如查询购物车表中的商品,在购物车表添加商品作为成员属性)

失血模型配置

  1. public class shoppingCart {
  2. private String shoppingCart_id;
  3. private String user_id;
  4. private String commodity_id;
  5. private String number;
  6. private String total;
  7. //添加商品表
  8. private Commodity commodity;

mapper.xml配置文件(使用resultMap)

  1. <resultMap type="shoppingCart" id="shoppingCartAndCommodity">
  2. <!--
  3. id:在关联里面,能够主要唯一识别一个实体的声明
  4. column:能够唯一识别一个实体的数据库字段名
  5. property:和model里面相对应的属性名
  6. -->
  7. <id column="shoppingCart_id" property="shoppingCart_id" />
  8. <!--
  9. result:关联普通字段和属性的标签
  10. column:数据库字段名
  11. property:对应的model属性名
  12. -->
  13. <result column="user_id" property="user_id" />
  14. <result column="commodity_id" property="commodity_id" />
  15. <result column="number" property="number" />
  16. <result column="total" property="total" />
  17. <!--
  18. collection:关联映射一对多的关系。属性是集合类型声明的
  19. property:关联在Order表中的属性名称
  20. -->
  21. <collection property="commodityList" ofType="commodity">
  22. <id column="commodity_id" property="commodity_id" />
  23. </collection>
  24. </resultMap>
  25. <!-- 查询自己的购物车 -->
  26. <select id="selectshoppingCart" resultMap="shoppingCartAndCommodity">
  27. SELECT shoppingCart_id,user_id ,number,total,c.commodity_name FROM
  28. t_shoppingcart s JOIN t_commodity c ON s.commodity_id = c.commodity_id WHERE user_id =
  29. #{user_id};
  30. </select>

Mapper.java

  1. /*
  2. * 查询自己的购物车。
  3. */
  4. public List<shoppingCart> selectshoppingCart(String user_phon) throws Exception;

mybatis中输入映射和输出映射(重点)

输入映射

目前在mybatis用到的都是parameterType类型,其中可以是简单数据类型,也可以是包装类型(POJO)
parameterType:java.lang.Integer\java.lang.String\POJO模型类。

输出映射

resultType:

1.输出类型为输出的类型为POJO包装类(model失血模型),用的是resultType

2.输出的类型为简单数据类型,resultType,要求:查询的结果集必须是一行一列的数据

resultMap

自定义映射关系:当java中失血模型对象中的字段和数据库中的字段名称不一致的时候,可以使用resultMap方式进行自定义映射关系

resultType和resultMap区别

resultType:会增加一个扩展的模型类,但是,这样可以简化xml配置文件中的繁琐步骤。操作和单表查询操作一致,一对一的映射关系一般推荐使用resultType。

resultMap:需要有关联映射,需要自定义resultMap的配置信息,增加配置的难度,但是,可以用在一对多的关系映射中(较为复杂的关系映射)。

  1. <mapper namespace="com.woniuxy.mall.mapper.CommodityMapper">
  2. <!--商家添加商品 -->
  3. <resultMap type="Commodity"
  4. id="businessInformationAndCommodity">
  5. <!--
  6. id:在关联里面,能够主要唯一识别一个实体的声明
  7. column:能够唯一识别一个实体的数据库字段名
  8. property:和model里面相对应的属性名
  9. -->
  10. <id column="commodity_id" property="commodity_id" />
  11. <!--
  12. result:关联普通字段和属性的标签
  13. column:数据库字段名
  14. property:对应的model属性名
  15. -->
  16. <result column="commodity_name" property="commodity_name" />
  17. <result column="commodity_price" property="commodity_price" />
  18. <result column="commodity_number" property="commodity_number" />
  19. <result column="classtwo_id" property="classtwo_id" />
  20. <result column="businessInformation_id"
  21. property="businessInformation_id" />
  22. <result column="commodity_status" property="commodity_status" />
  23. <result column="commodity_add_time"
  24. property="commodity_add_time" />
  25. <!--
  26. association:用于关联一对一关系映射的标签
  27. property:要映射的模型类中的属性名
  28. javaType:属性名对应的java失血模型全路径,可以使用别名
  29. -->
  30. <association property="businessInformation" javaType="BusinessInformation">
  31. <id column="businessInformation_id" property="businessInformation_id" />
  32. <result column="businessInformation_phone" property="businessInformation_phone" />
  33. </association>
  34. </resultMap>
  35. <insert id="insertCommodity" parameterType="Commodity">
  36. INSERT INTO
  37. t_commodity(commodity_name,
  38. commodity_price,commodity_number,classtwo_id,businessInformation_id,commodity_status,commodity_add_time)
  39. VALUES(#{0},#{1},#{2},#{3},
  40. (SELECT businessInformation_id FROM t_businessinformation WHERE
  41. businessInformation_phone=#{4}
  42. ),#{5},#{6});
  43. </insert>
  44. </mapper>

自定义映射关系:一对一,一对多,多对多(分解成一对多,一对多,一对一的关系)

  1. <将商品添加到购物车 -->
  2. <resultMap type="shoppingCart" id="shoppingCartAndCommodity">
  3. <!--
  4. id:在关联里面,能够主要唯一识别一个实体的声明
  5. column:能够唯一识别一个实体的数据库字段名
  6. property:和model里面相对应的属性名
  7. -->
  8. <id column="shoppingCart_id" property="shoppingCart_id" />
  9. <!--
  10. result:关联普通字段和属性的标签
  11. column:数据库字段名
  12. property:对应的model属性名
  13. -->
  14. <result column="user_id" property="user_id" />
  15. <result column="commodity_id" property="commodity_id" />
  16. <result column="number" property="number" />
  17. <result column="total" property="total" />
  18. <!-- 关联用户 -->
  19. <!--
  20. association:用于关联一对一关系映射的标签
  21. property:要映射的模型类中的属性名
  22. javaType:属性名对应的java失血模型全路径,可以使用别名
  23. -->
  24. <association property="user" javaType="User">
  25. <!--
  26. id:user对应的能够唯一识别的标签
  27. column:对应数据库字段名
  28. property:对应的模型类属性名
  29. -->
  30. <id column="user_id" property="user_id" />
  31. <result column="user_phon" property="user_phon" />
  32. </association>
  33. <!-- 关联商品 -->
  34. <!--
  35. collection:关联映射一对多的关系。属性是集合类型声明的
  36. property:关联在Order表中的属性名称
  37. -->
  38. <collection property="commodityList" ofType="commodity">
  39. <id column="commodity_id" property="commodity_id" />
  40. </collection>
  41. </resultMap>
  42. </resultMap>
  43. <!-- 查询自己的购物车 -->
  44. <!-- 查询自己的购物车 -->
  45. <select id="selectshoppingCart" resultMap="shoppingCartAndCommodity">
  46. SELECT shoppingCart_id ,(SELECT u.user_id FROM t_user u WHERE
  47. u.user_phon=#{user_phon}),number,total,c.commodity_name FROM
  48. t_shoppingcart s JOIN t_user u ON s.user_id = u.user_id JOIN
  49. t_commodity c ON s.commodity_id = c.commodity_id WHERE u.user_phon =
  50. #{user_phon};
  51. </select>

延迟加载(按需加载)

什么是延迟加载

将一条复杂的查询语句,分为多个部分可以分别进行查询,一般以主表开始进行单表的查询数据,什么时候需要进一步的数据需求的时候,再向数据库发送请求。
目的:是为了提高查询效率,因为单表的查询比多表的查询效率要高的多,减轻数据库服务的压力

举例用户查询购物车

1.只需用户信息是,向数据库发出单表查询
2.进一步要求用户购物车信息,再进行延迟加载去查询用户关联的购物车信息,更具用户id查询

mapper.java接口

  1. //查询用户查询购物车,并且使用延迟加载
  2. public List<User> queryOrderAndUserLazy() throws Exception;

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="com.woniuxy.mapper.LazyMapper">
  6. <!--按需求查询查询购物车-->
  7. <select id="queryUserById" resultType="shoppingCart">
  8. SELECT * FROM t_shoppingcart WHERE user_id = #{user_id};;
  9. </select>
  10. <!-- 自定义resultMap -->
  11. <resultMap type="User" id="UserAndshoppingCartLazyLoading">
  12. <id column="user_id" property="user_id"/>
  13. <result column="user_name" property="user_name"/>
  14. <result column="user_phon" property="user_phon"/>
  15. <result column="user_email" property="user_email"/>
  16. <!-- 配置user对应的映射对象,要使用association标签,可以使用延迟加载-->
  17. <association property="shoppingCart" javaType="shoppingCart" select="queryUserById" column="user_id">
  18. </association>
  19. </resultMap>
  20. <!--1.先查询用户-->
  21. <select id="queryUserAndshoppingLazy" resultMap="UserAndshoppingCartLazyLoading">
  22. SELECT * FROM t_user;
  23. </select>
  24. </mapper>

在sqlMapConfig.xml配置文件中开启延迟记载

  1. <!-- 设置延迟加载 -->
  2. <settings>
  3. <setting name="lazyLoadingEnabled" value="true"/>
  4. <setting name="aggressiveLazyLoading" value="false"/>
  5. </settings>

缓存

缓存存在有意义

在mybatis中提供了两种缓存机制,当第一次执行方法要查询数据库中的值,先查询缓存空间是否存在,不存在则去数据库中查询,将查询到的值更新到缓存空间中。
注意
当在代码中如果使用了commit提交事务的操作,那么会将缓存空间里面清空,避免数据的脏读。

一级缓存

一级缓存的作用范围是一次会话,只要会话没有关闭,那么一级缓存就生效,一次会话(一次SqlSession)共享一个一级缓存空间。
第一次查询数据:第一次查询数据的时候,先去缓存空间,缓存空间中还没有值,所以需要去数据库中查找,将查找到的值放置到缓存空间中,供第二次方位直接拿数据。
如果中间任何位置提交了事务(commit),那么mybatis将清空缓存空间。避免脏读。
第二次查询相同的数据:会先检查缓存空间中是否有值,如果有值将不再请求数据库查询,而是直接拿到缓存空间中的数据。
注意:一级缓存根本不用程序去操心,mybatis默认开启一级缓存。

二级缓存(多个会话共用一个二级缓存)

在一个Mapper层面的多个会话,都执行同样的查询语句和结果的时候,第一次需要从数据库中读取,将读取的数据存放的二级缓存区域中,当第二次去查询相同的语句的时候,那么直接拿到缓存空间的值,不再次向数据库发送请求。一旦发生了commit事务的提交,则会清空二级缓存的值。
注意:mybatis不会默认开启二级缓存,需要程序员手动开启二级缓存

测试

步骤1:在SqlMapConfig.xml配置文件中设置二级缓存。

  1. <setting name="cacheEnabled" value="true"/>

步骤2:在对应的mapper中也要开启二缓存。

  1. <!-- 开启二级缓存 -->
  2. <cache/>

步骤3:要对mapper操作的对应的失血模型model对象实现序列化。

  1. public class User implements Serializable{
  2. }

测试代码

  1. @Test
  2. public void test2() throws Exception {
  3. //开启多个会话
  4. SqlSession ss1 = factory.openSession();
  5. SqlSession ss2 = factory.openSession();
  6. SqlSession ss3 = factory.openSession();
  7. //使用不同的会话产生Mapepr对象
  8. CacheMapper cm1 = ss1.getMapper(CacheMapper.class);
  9. User u1 = cm1.queryUserById(1);
  10. //关闭第一个会话
  11. ss1.close();
  12. CacheMapper cm2 = ss2.getMapper(CacheMapper.class);
  13. User u2 = cm2.queryUserById(1);
  14. //关闭第二个会话
  15. ss2.close();
  16. CacheMapper cm3 = ss3.getMapper(CacheMapper.class);
  17. System.out.println("u1:"+u1);
  18. System.out.println("u2:"+u2);
  19. //关闭第三个会话
  20. ss3.close();
  21. }

特别注意:只有当一个会话执行了close方法的之后,才会将查询到的数据存储到二级缓存空间中