• Mybatis总结


    目录

    前言

    Mybatis特性

    ORM对象关系映射

    mybatis的使用 

    用到的依赖

    jdbc.properties

    mybatis初级创建所使用的核心配置文件

    mybatis初级创建使用的映射文件

    打印日志配置文件

    mybatis初级使用测试案例

    日志级别

    lombok依赖

    注解

    properties文件语法

    mybatis传参

    mybatis获取参数值的两种形式

    单值查询

    多值查询

    第一种:使用@Param注解(本质map)

    第二种:使用map集合

    第三种:使用实体类封装

    mybatis的各种查询功能

    查询多条数据

    查询结果为integer类型(不为实体类)的数据

    查询返回值为map集合的单个数据

    查询返回值为map集合的多个数据

    特殊操作 

    模糊查询

    批量删除

    动态设置表名

    获取自增的主键

    处理查询字段名与属性名不一致

    起别名解决

    满足驼峰则开启驼峰命名

    自定义映射解决

    多对一查询

    级联

    association

    分步查询

    一对多查询

    collection

    分步查询

    动态sql

    if和where和trim标签

    set标签

    choose、when、otherwise标签

    forearch标签

    批量添加员工

    批量删除员工

    sql标签

    mybatis注解开发

    mybatis缓存 

    mybatis的一级缓存

    测试一级缓存

    一级缓存失效的情况

    mybatis的二级缓存

    二级缓存开启的条件

    二级缓存失效的情况

    二级缓存测试

    二级缓存相关配置

    设置属性

    mybatis缓存查询顺序

    前言

    简介:MyBatis,封装JDBC,负责访问数据库,完成持久化操作

    Mybatis特性

    • Mybatis是支持定制化SQL、存储过程以及高级映射的优秀持久层框架
    • Mybatis避免了几乎所有JDBC代码和手动设置参数以及获取结果集
    • Mybatis可以使用简单的XML或注解用于配置和原始映射,将接口和java的POJO(plain old java objects,普通的java对象)映射成数据库中的记录
    • Mybatis是一个半自动的ORM(object relation mapping)框架

    ORM对象关系映射

    • 对象:java的实体类对象
    • 关系:关系型数据库
    • 映射:二者之间的对应关系
    Java概念数据库概念
    表名
    属性字段
    对象

    理解:mybatis中通过sql语句查询到的结果与类中的中的属性一一映射;形成一个对象(如果查询到的属性少于pojo对象中的属性,那么pojo对象中多出的属性为默认值)resultType或resultMap中对应的返回值类型与pojo中的类一一映射。

    mybatis的使用 

    用到的依赖

    1. <!--依赖集-->
    2. <dependencies>
    3. <!--mybatis依赖-->
    4. <dependency>
    5. <groupId>org.mybatis</groupId>
    6. <artifactId>mybatis</artifactId>
    7. <version>3.5.7</version>
    8. </dependency>
    9. <!--单元测试依赖-->
    10. <dependency>
    11. <groupId>junit</groupId>
    12. <artifactId>junit</artifactId>
    13. <version>4.12</version>
    14. <scope>test</scope>
    15. </dependency>
    16. <!--mysql数据库依赖-->
    17. <dependency>
    18. <groupId>mysql</groupId>
    19. <artifactId>mysql-connector-java</artifactId>
    20. <version>8.0.30</version>
    21. </dependency>
    22. <!--添加日志依赖-->
    23. <dependency>
    24. <groupId>log4j</groupId>
    25. <artifactId>log4j</artifactId>
    26. <version>1.2.17</version>
    27. </dependency>
    28. <!-- lombok依赖包 -->
    29. <dependency>
    30. <groupId>org.projectlombok</groupId>
    31. <artifactId>lombok</artifactId>
    32. <version>1.18.24</version>
    33. <scope>provided</scope>
    34. </dependency>
    35. </dependencies>

    jdbc.properties

    1. #放前缀就是为了避免重名
    2. jdbc.driver=com.mysql.cj.jdbc.Driver
    3. jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
    4. jdbc.username=root
    5. jdbc.password=root

    mybatis初级创建所使用的核心配置文件

    1. "1.0" encoding="UTF-8" ?>
    2. configuration
    3. PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-config.dtd">
    5. <configuration>
    6. <properties resource="jdbc.properties"/>
    7. <settings>
    8. <setting name="mapUnderscoreToCamelCase" value="true"/>
    9. <setting name="lazyLoadingEnabled" value="true"/>
    10. <setting name="aggressiveLazyLoading" value="false"/>
    11. settings>
    12. <typeAliases>
    13. <package name="cn.tedu.mybatis.pojo"/>
    14. typeAliases>
    15. <environments default="development">
    16. <environment id="development">
    17. <transactionManager type="JDBC"/>
    18. <dataSource type="POOLED">
    19. <property name="driver" value="${jdbc.driver}"/>
    20. <property name="url" value="${jdbc.url}"/>
    21. <property name="username" value="${jdbc.username}"/>
    22. <property name="password" value="${jdbc.password}"/>
    23. dataSource>
    24. environment>
    25. environments>
    26. <mappers>
    27. <package name="cn.tedu.mybatis.mapper"/>
    28. mappers>
    29. configuration>

    mybatis初级创建使用的映射文件

    1. "1.0" encoding="UTF-8" ?>
    2. mapper
    3. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    4. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    5. <mapper namespace="cn.tedu.mybatis.mapper.UserMapper">
    6. <insert id="insertUser">
    7. insert into t_user values(null ,'admin','123456',23,'男','12345@qq.com')
    8. insert>
    9. <update id="updateUser">
    10. update t_user set username='root',password='123' where id=3
    11. update>
    12. <delete id="deleteUser">
    13. delete from t_user where id=3
    14. delete>
    15. <select id="getUserById" resultType="User">
    16. select * from t_user where id=5
    17. select>
    18. <select id="getAllUser" resultType="cn.tedu.mybatis.pojo.User">
    19. select * from t_user;
    20. select>
    21. mapper>

    打印日志配置文件

    1. <?xml version="1.0" encoding="UTF-8"?>
    2. <!--log4j.xml文件内,名字不可改变-->
    3. <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    4. <!--日志配置文件-->
    5. <log4j:configuration>
    6. <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender">
    7. <param name="Encoding" value="UTF-8"/>
    8. <layout class="org.apache.log4j.PatternLayout">
    9. <param name="ConversionPattern" value="%-5p %d{MM-dd HH:mm:ss,SSS} %m (%F:%L) \n"/>
    10. </layout>
    11. </appender>
    12. <logger name="java.sql">
    13. <level value="debug"/>
    14. </logger>
    15. <logger name="org.apache.ibatis">
    16. <level value="info"/>
    17. </logger>
    18. <root>
    19. <level value="debug"/>
    20. <appender-ref ref="STDOUT"/>
    21. </root>
    22. </log4j:configuration>

    mybatis初级使用测试案例

    1. @Test
    2. public void testInsert() throws Exception {
    3. //获取核心配置文件的输入流
    4. InputStream is = Resources.getResourceAsStream("mybatis-config-xml");
    5. //获取sqlsessionFactoryBuilder对象
    6. SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
    7. //获取sqlsessionFactory对象
    8. SqlSessionFactory sf = sfb.build(is);
    9. //获取sqlsession对象——mybatis提供的操作数据可得对象(这里面的true表示自动提交事务,就是不用写后面的commit方法了)
    10. SqlSession sqlSession = sf.openSession(true);
    11. //获取UserMapper的代理实现类对象(通过代理模式来创建UserMapper的代理实现类)
    12. //通过当前mapper接口的全类名找到当前的映射文件
    13. UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    14. //通过调用方法,找到映射文件中的方法
    15. int i = mapper.insertUser();
    16. //提交事务
    17. //sqlSession.commit();
    18. //sqlSession.rollback();回滚事务
    19. System.out.println(i);
    20. //关闭会话
    21. sqlSession.close();
    22. }

    日志级别

    debug(调试)

    注意:配置日志级别,这样在打印日志的时候只会打印相同级别以及高于自己配置的日志级别日志

    lombok依赖

    作用:自动生成Get/Set/toString/无参构造/全参构造/equals/hashcode等方法 

    注解

    • @Data:动态生成get/set/toString等方法
    • @Accessor(chain=true):开启链式加载,重写所有的set方法
    • @NoArgsConstructor:动态生成无参构造
    • @AllArgsContructor:动态生成全参构造

    properties文件语法

    • 注释用#
    • 数据结构类型:key=value(特别注意不能有空格)
    • 字符集编码:程序读取文件时默认采用ISO-8859-1编码
    • 弊端:所有的key都必须完整不能缩进

    mybatis传参

    mybatis获取参数值的两种形式

    • mybatis获取参数值两种方式:${}和#{}
    • ${}的本质就是字符串拼接sql,#{}本质就是占位符赋值
    • ${}使用字符串拼接sql,若为字符串类型或日期类型的字段赋值时需要在${}外面或里面手动加单引号;但是使用#{}使用占位符赋值的方式拼接sql,此时为字符串类型或日期类型的字段进行赋值时,可以自动加单引号,不用手动加

    单值查询

    1. 测试:List<User> user = mapper.getUserByUsername("admin"); (mapper为接口代理对象)
    2. 接口:List<User> getUserByUsername(String username);
    3. 映射文件:select * from t_user where username='${username}'; (为字符串拼接方式)
    4. select * from t_user where username=#{username}; (为占位符方式)

    多值查询

    第一种:使用@Param注解(本质map)

    1. 测试:User user = mapper.checkLogin("admin","123456");
    2. 接口:User checkLogin(@Param("name") String username,@Param("pwd") String password);
    3. 配置文件:select * from t_user where username=#{name} and password=#{pwd}

    第二种:使用map集合

    1. 测试:
    2. HashMap<String, Object> map = new HashMap<String, Object>();
    3. map.put("name", "admin");
    4. map.put("pwd", "123456");
    5. User user = mapper.checkLoginByMap(map);
    6. 接口:User checkLoginByMap(Map<String,Object> map);
    7. 配置文件:select * from t_user where username='${name}' and password=#{pwd};

    第三种:使用实体类封装

    1. 测试:
    2. User user = new User(null,"root","123456",33,"女","123@qq.com");(我有全参构造)
    3. int i = mapper.insertUser(user);
    4. 接口:int insertUser(User user);
    5. 配置文件:insert into t_user values(null,#{username},#{password},#{age},#{gender},#{email})

    mybatis的各种查询功能

    查询多条数据

    1. 测试:List<User> allUser = mapper.getAllUser();
    2. 接口:List<User> getAllUser();
    3. 配置文件:
    4. <select id="getAllUser" resultType="user">
    5. select * from t_user;
    6. </select>

    注意:若sql查询的结果为多条时,一定不能以实体类型作为方法的返回值,否则会抛出异常,若查询结果为1条时,此时可以使用实体类型或list集合类型作为方法的返回值

    查询结果为integer类型(不为实体类)的数据

    1. 测试:Integer count = mapper.getCount();
    2. 接口:Integer getCount();
    3. 配置文件:
    4. <select id="getCount" resultType="java.lang.Integer">
    5. select count(*) from t_user;
    6. </select>

    注意:这里的resultType返回值也可以直接写Integer或int(忽略大小写——本质别名)

    查询返回值为map集合的单个数据

    1. 测试:Map<String, Object> userByIdToMap = mapper.getUserByIdToMap(1);
    2. 接口:Map<String,Object> getUserByIdToMap(@Param("id") Integer id);
    3. 配置文件:
    4. <select id="getUserByIdToMap" resultType="map">
    5. select * from t_user where id=#{id}
    6. </select>

    理解:把通过id查到的数据用map集合进行封装(一条数据转化为一个map)

    查询返回值为map集合的多个数据

    1. 测试:List<Map<String, Object>> allUserToMap = mapper.getAllUserToMap();
    2. 接口:List<Map<String,Object>> getAllUserToMap();
    3. 配置文件:
    4. <select id="getAllUserToMap" resultType="map">
    5. select * from t_user;
    6. </select>
    1. 测试:Map<String, Object> allUserToMap = mapper.getAllUserToMap();
    2. 接口:
    3. @MapKey("id")——把查询到的id作为键,把查询到的对象(也就是一条一条的数据)作为值
    4. Map<String,Object> getAllUserToMap();
    5. 配置文件:
    6. <select id="getAllUserToMap" resultType="map">
    7. select * from t_user;
    8. </select>

    特殊操作 

    模糊查询

    1. 测试:List<User> a = mapper.getUserByLike("a");
    2. 接口:List<User> getUserByLike(@Param("m") String m);
    3. 配置文件:
    4. 方式1
    5. <select id="getUserByLike" resultType="user">
    6. select * from t_user where username like "%"#{m}"%";
    7. </select>
    8. 方式2
    9. <select id="getUserByLike" resultType="user">
    10. select * from t_user where username like "%${m}%";
    11. </select>
    1. 测试:List<User> a = mapper.getUserByLike("%a%");
    2. 接口:List<User> getUserByLike(@Param("m") String m);
    3. 配置文件:
    4. <select id="getUserByLike" resultType="user">
    5. select * from t_user where username like #{m};
    6. </select>

    注意:#{内容}若写在字符串里面则会被当作字符串的一部分,不会被当作占位符

    批量删除

    1. 测试:int i = mapper.deleteMoreUser("1,7");
    2. 接口:int deleteMoreUser(@Param("ids") String ids);
    3. 配置文件:
    4. 方法1
    5. <delete id="deleteMoreUser">
    6. delete from t_user where id in(${ids})
    7. </delete>

    动态设置表名

    1. 测试:List<User> t_user = mapper.getUserList("T_user");
    2. 接口:List<User> getUserList(@Param("tableName") String tableName);
    3. 配置文件:
    4. <select id="getUserList" resultType="user">
    5. select * from ${tableName}
    6. </select>

    主要原因:表名是不能加单引号的,所以不能用#{},因为它默认会为值添加单引号

    获取自增的主键

    1. 测试:
    2. User user = new User(null, "lili", "123456", 23, "男", "12@qq.com");
    3. mapper.insertUser(user);——这里我没为id赋值,但是输出却有id值
    4. 接口:void insertUser(User user);
    5. 配置文件:
    6. <!--获取自增的主键,keyProperty:把获取到自增的主键存储到我们传输过来的实体类对象的对应属性中-->
    7. <insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
    8. insert into t_user values (null ,#{username},#{password},#{age},#{gender},#{email})
    9. </insert>

    处理查询字段名与属性名不一致

    起别名解决

    1. 测试:Emp empByEmpId = mapper.getEmpByEmpId(1);
    2. 接口:Emp getEmpByEmpId(@Param("empId") Integer empId);
    3. 配置文件:
    4. <select id="getEmpByEmpId" resultType="emp">
    5. select emp_id empId,emp_name empName,age,gender from t_emp where emp_id=#{empId}
    6. </select>

    注意:这里起的别名是对应实体类(Emp)中属性的名称

    满足驼峰则开启驼峰命名

    在mybatis-config.xml核心配置文件中设置如下(注意设置标签的顺序问题)

    1. <settings>
    2. <setting name="mapUnderscoreToCamelCase" value="true"/>
    3. settings>

    自定义映射解决

    1. 测试:Emp empByEmpId = mapper.getEmpByEmpId(1);
    2. 接口:Emp getEmpByEmpId(@Param("empId") Integer empId);
    3. 配置文件:
    4. <select id="getEmpByEmpId" resultMap="empResultMap">
    5. select * from t_emp where emp_id=#{empId}
    6. </select>
    7. <!--id:resultMap配置的id(随便写都行)
    8. type:返回值的类型-->
    9. <resultMap id="empResultMap" type="emp">
    10. <!--处理主键映射-->
    11. <!--将字段里的emp_id与对象中的empId映射-->
    12. <id column="emp_id" property="empId"></id>
    13. <!--普通字段的映射-->
    14. <result column="emp_name" property="empName"></result>
    15. </resultMap>

    多对一查询

    1. //所用到的实体类
    2. public class Emp {
    3. private Integer empId;
    4. private String empName;
    5. private Integer age;
    6. private String gender;
    7. private Dept dept;
    8. }

    级联

    1. <select id="getEmpAnddeptByEmpId" resultMap="empAndDeptResultMap">
    2. select t_emp.*,t_dept.* from t_emp left join t_dept on t_emp.dept_id=t_dept.dept_id where t_emp.emp_id=#{empId}
    3. </select>
    4. <resultMap id="empAndDeptResultMap" type="emp">
    5. <id column="emp_id" property="empId"></id>
    6. <result column="emp_name" property="empName"></result>
    7. <result column="dept_id" property="dept.deptId"></result>
    8. <result column="dept_name" property="dept.deptName"></result>
    9. </resultMap>
    10. 注意:dept表为emp表的内部属性

    association

    1. <select id="getEmpAnddeptByEmpId" resultMap="empAndDeptResultMap">
    2. select t_emp.*,t_dept.* from t_emp left join t_dept on t_emp.dept_id=t_dept.dept_id where t_emp.emp_id=#{empId}
    3. </select>
    4. <resultMap id="empAndDeptResultMap" type="emp">
    5. <id column="emp_id" property="empId"></id>
    6. <result column="emp_name" property="empName"></result>
    7. <!--处理多对一映射关系,必须是处理实体类型中的属性-->
    8. <!--javaType用来设置当前属性的类型-->
    9. <association property="dept" javaType="Dept">
    10. <id column="dept_id" property="deptId"></id>
    11. <result column="dept_name" property="deptName"></result>
    12. </association>
    13. </resultMap>

    注意:association标签里还可以有autoMapping属性,若此属性设置为true,则可以使被封装的属性与和属性名称相同的字段进行自动映射(autoMapping设置为true时,若映射的字段和对象的属性一致时则可以省略不写)

    分步查询

    1. 一次查询:
    2. <select id="getEmpAndDeptByStep" resultMap="empAndDeptByStepResultMap">
    3. select * from t_emp where emp_id=#{empId}
    4. </select>
    5. <resultMap id="empAndDeptByStepResultMap" type="emp" autoMapping="true">
    6. <id column="emp_id" property="empId"></id>
    7. <result column="emp_name" property="empName"></result>
    8. <!--select属性表示二次查询sql的id,column表示从第一次查询结果中返回的某个字段作为二次查询的条件-->
    9. <!--fetchType属性在全局开启了延迟加载情况下设置某一条语句立即加载-->
    10. <association property="dept" select="cn.tedu.mybatis.mapper.DeptMapper.getEmpAndDeptByStepTwo"
    11. column="dept_id" autoMapping="true" fetchType="eager">
    12. </association>
    13. </resultMap>
    14. 二次查询:
    15. <select id="getEmpAndDeptByStepTwo" resultType="dept">
    16. select * from t_dept where dept_id = #{deptId}
    17. </select>

    一对多查询

    1. public class Dept {
    2. private Integer deptId;
    3. private String deptName;
    4. private List<Emp> emps;
    5. }

    collection

    1. <select id="getDeptAndEmpByDeptId" resultMap="deptAndEmpResultMap">
    2. select * from t_dept left join t_emp on t_dept.dept_id=t_emp.dept_id where t_dept.dept_id=#{deptId}
    3. </select>
    4. <resultMap id="deptAndEmpResultMap" type="dept" autoMapping="true">
    5. <id column="dept_id" property="deptId"></id>
    6. <!--ofType:设置当前集合中的类型-->
    7. <collection property="emps" ofType="emp" autoMapping="true">
    8. <id column="emp_id" property="empId"></id>
    9. <result column="emp_name" property="empName"></result>
    10. </collection>
    11. </resultMap>

    注意:不管映射不映射,主键一定要写上

    分步查询

    1. 一次查询:
    2. <select id="getDeptAndEmpByStepOne" resultMap="deptAndEmpResultMapByStep">
    3. select * from t_dept where dept_id=#{deptId}
    4. </select>
    5. <resultMap id="deptAndEmpResultMapByStep" type="dept" autoMapping="true">
    6. <id column="dept_id" property="deptId"></id>
    7. <collection property="emps" column="dept_id"
    8. select="cn.tedu.mybatis.mapper.EmpMapper.getDeptAndEmpByStepTwo" autoMapping="true">
    9. <id column="emp_id" property="empId"></id>
    10. </collection>
    11. </resultMap>
    12. 二次查询:
    13. <select id="getDeptAndEmpByStepTwo" resultType="emp">
    14. select * from t_emp where dept_id=#{deptId}
    15. </select>

    动态sql

    Mybatis框架的动态sql技术是一种根据特定条件动态拼接sql语句的功能,它存在的意义就是为了解决拼凑sql语句字符串时的痛点问题

    if和where和trim标签

    1. 测试:
    2. Emp emp = new Emp(null, "张三", 20, "男");
    3. List<Emp> empByCondition = mapper.getEmpByCondition(emp);
    4. 接口:List<Emp> getEmpByCondition(Emp emp);
    5. 配置:
    6. 方法1
    7. <select id="getEmpByCondition" resultType="emp">
    8. select * from t_emp <where>
    9. <if test="empName!=null and empName!=''">
    10. emp_name=#{empName}
    11. </if>
    12. <if test="age!=null and age!=''">
    13. and age=#{age}
    14. </if>
    15. <if test="gender!=null and gender!=''">
    16. and gender=#{gender}
    17. </if>
    18. </where>
    19. </select>
    20. 方法2
    21. <select id="getEmpByCondition" resultType="emp">
    22. select * from t_emp where 1=1
    23. <if test="empName!=null and empName!=''">
    24. and emp_name=#{empName}
    25. </if>
    26. <if test="age!=null and age!=''">
    27. and age=#{age}
    28. </if>
    29. <if test="gender!=null and gender!=''">
    30. and gender=#{gender}
    31. </if>
    32. </select>
    33. 方法3
    34. <select id="getEmpByCondition" resultType="emp">
    35. select * from t_emp
    36. <trim prefix="where" suffixOverrides="and">
    37. <if test="empName!=null and empName!=''">
    38. emp_name=#{empName} and
    39. </if>
    40. <if test="age!=null and age!=''">
    41. age=#{age} and
    42. </if>
    43. <if test="gender!=null and gender!=''">
    44. gender=#{gender}
    45. </if>
    46. </trim>
    47. </select>

    注意:

    • if标签作用:满足sql标签的则进行sql语句的拼接,不满足的则不进行sql语句的拼接
    • where标签功能:自动生成where关键字、处理数据为null时and(数据前面的and,内容后面的and无法去掉)多余问题、若当前标签里没有任何一个标签成立,那么where标签没有任何功能
    • 代码中trim标签解释:最前面加where,在最后面去掉and

    set标签

    1. 测试:
    2. Emp w = new Emp(2, "王五", 23, null);
    3. int i = mapper.updateEmp(w);
    4. 接口:int updateEmp(Emp emp);
    5. 配置文件:
    6. <update id="updateEmp">
    7. update t_emp
    8. <set>
    9. <if test="empName!=null and empName!=''">emp_name=#{empName},</if>
    10. <if test="age!=null and age!=''">age=#{age},</if>
    11. <if test="gender!=null and gender!=''">gender=#{gender}</if>
    12. </set>
    13. where emp_id=#{empId}
    14. </update>

    注意:set标签主要处理多余的逗号问题,也会生成set关键字

    choose、when、otherwise标签

    1. 测试:
    2. Emp emp = new Emp(null, "张三", 20, "男");
    3. List<Emp> empByChoose = mapper.getEmpByChoose(emp);
    4. 接口:List<Emp> getEmpByChoose(Emp emp);
    5. 配置:
    6. <select id="getEmpByChoose" resultType="emp">
    7. select * from t_emp
    8. <where>
    9. <choose>
    10. <when test="empName!=null and empName!=''">emp_name=#{empName}</when>
    11. <when test="age!=null and age!=''">age=#{age}</when>
    12. <otherwise>gender=#{gender}</otherwise>
    13. </choose>
    14. </where>
    15. </select>

    注意:

    • when至少设置1个,otherwhile最多设置1个
    • 选择语句最后只有1个分支被执行

    forearch标签

    批量添加员工

    1. 测试:
    2. Emp emp = new Emp(null, "张三", 20, "男");
    3. Emp emp1 = new Emp(null, "张四", 21, "男");
    4. Emp emp2 = new Emp(null, "张五", 22, "男");
    5. List<Emp> emps = Arrays.asList(emp, emp1, emp2);
    6. mapper.insertMoreEmp(emps);
    7. 接口:void insertMoreEmp(@Param("emps") List<Emp> emps);
    8. 配置文件:
    9. <!--collection里面传@Param里面对应的键,表示要循环的集合或数组;item里面的属性表示用什么表示集合里面的数据;separator表示循环所用分隔符-->
    10. <insert id="insertMoreEmp">
    11. insert into t_emp values
    12. <foreach collection="emps" item="emp" separator=",">
    13. (null,#{emp.empName},#{emp.age},#{emp.gender},null)
    14. </foreach>
    15. </insert>

    注意:如果不写@Param注解,那么如果你的参数是一个list集合,则mybatis会把他以list为键,后以list集合为值放入map集合中;若你的参数是一个数组的话,则mybatis也会把它放入map中,以Array为键,以其参数值为值 

    批量删除员工

    1. 测试:
    2. Integer[] integers = {5,6,7};
    3. mapper.deleteMoreEmp(integers);
    4. 接口:void deleteMoreEmp(@Param("empIds") Integer[] empIds);
    5. 配置文件:
    6. 方式1
    7. <delete id="deleteMoreEmp">
    8. delete from t_emp where emp_id in
    9. (
    10. <foreach collection="empIds" item="empId" separator=",">
    11. #{empId}
    12. </foreach>
    13. )
    14. </delete>
    15. 注意:foreach里面还有2个属性,分别为openclose,分别表示以什么符号开始和以什么符号结束(不写括号时使用)
    16. 方式2
    17. <delete id="deleteMoreEmp">
    18. delete from t_emp where
    19. <foreach collection="empIds" item="empId" separator="or">
    20. emp_id=#{empId}
    21. </foreach>
    22. </delete>

    sql标签

    1. 测试:List<Emp> emps = mapper.selectAll();
    2. 接口:List<Emp> selectAll();
    3. 配置文件:
    4. <!--sql中的id表示sql片段的标识,include标签表示引用sql,refid与sql中id对应-->
    5. <sql id="empColumn">
    6. emp_id,emp_name,age,gender,dept_id
    7. </sql>
    8. <select id="selectAll" resultType="emp">
    9. select <include refid="empColumn"></include> from t_emp;
    10. </select>

    mybatis注解开发

    1. 测试:Emp emp = mapper.getById(1);
    2. 接口:
    3. @Select("select * from t_emp where emp_id=#{id}")
    4. Emp getById(@Param("id") Integer id);

    注意:

    • 可以利用@Select、@Insert、@Update、@Delete等注解来代替映射文件的方式进行数据库操作
    • 注解和映射文件的方式二选1,映射文件方式为主导
    • 注解写法一般只适用于简单操作,关联查询不适用
    • 这些注解之间不可以互相通用,因为会涉及到返回值问题

    mybatis缓存 

    mybatis的一级缓存

    一级缓存是SqlSession级别的,通过同一个SqlSession查询的数据会被缓存,下次查询相同的数据会从缓存中直接获取,不会从数据库重新访问

    注意:一级缓存默认开启

    测试一级缓存

    1. @Test
    2. public void testGetEmpById(){
    3. SqlSession session = SqlSessionUtils.getSession();
    4. CacheMapper mapper = session.getMapper(CacheMapper.class);
    5. Emp empById = mapper.getEmpById(1);
    6. //清空一级缓存
    7. session.clearCache();
    8. Emp empById1 = mapper.getEmpById(1);
    9. System.out.println(empById+"\n"+empById1);
    10. }

    注意:这里我清空一级缓存了,所以会查2次 

    一级缓存失效的情况

    • 不同的SqlSession对应不同的一级缓存
    • 同一个SqlSession,但是查询条件不同
    • 同一个SqlSession两次查询期间执行了任何一次增删改操作(会清空缓存)
    • 同一个SqlSession两次查询期间手动清空了缓存

    mybatis的二级缓存

    二级缓存是SqlSessionFactory级别,通过同一个SqlSessionFactory创建的SqlSessionFactory创建的SqlSession,默认开启,但是需要标识

    二级缓存开启的条件

    • 在核心配置文件中,设置全局配置属性cacheEnabled=“true”(注意:这里默认为true,所以不用配置)
    • 在映射文件中设置标签用于标识(或在接口名上加@CacheNamespace注解)
    • 二级缓存必须在SqlSession关闭或提交之后有效
    • 查询的数据所转换的实体类型必须实现序列化接口

    二级缓存失效的情况

    两次查询之间执行了任意的增删改,会使一级和二级缓存同时失效

    二级缓存测试

    1. @Data
    2. @AllArgsConstructor
    3. @NoArgsConstructor
    4. public class Emp implements Serializable {
    5. private Integer empId;
    6. private String empName;
    7. private Integer age;
    8. private String gender;
    9. }
    接口方法:Emp getEmpById(Integer empId);
    1. <mapper namespace="cn.tedu.mybatis.mapper.CacheMapper">
    2. <cache/>
    3. <select id="getEmpById" resultType="emp">
    4. select * from t_emp where emp_id = #{empId}
    5. </select>
    6. </mapper>
    1. @Test
    2. public void testCache() throws Exception {
    3. InputStream stream = Resources.getResourceAsStream("mybatis-config.xml");
    4. //创建第一个sqlsessionFactory
    5. SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(stream);
    6. SqlSession sqlSession = sqlSessionFactory.openSession(true);
    7. SqlSession sqlSession1 = sqlSessionFactory.openSession(true);
    8. CacheMapper mapper = sqlSession.getMapper(CacheMapper.class);
    9. Emp empById = mapper.getEmpById(1);
    10. System.out.println(empById);
    11. //只有将sqlsession关闭之后保存在一级缓存中的数据才会保存在二级缓存中,二级缓存才能生效
    12. sqlSession.close();
    13. CacheMapper mapper1 = sqlSession1.getMapper(CacheMapper.class);
    14. Emp empById1 = mapper1.getEmpById(1);
    15. System.out.println(empById1);
    16. sqlSession1.close();
    17. }

    注意:只有将sqlsession关闭之后保存在一级缓存中的数据才会保存在二级缓存中,二级缓存才能够生效

    二级缓存相关配置

    前言:这些属性可以在cache标签里面或注解@CacheNamespace()里面设置

    设置属性

    eviction属性:缓存回收策略,默认为LRU

    • LRU:最近最少使用的(移除最长时间不被使用的对象)
    • FIFO:先进先出(按对象进入缓存的顺序来移除他们)
    • SOFT:软引用(移除基于垃圾回收器状态和软引用规则的对象)
    • WEAK:弱引用(更积极地移除基于垃圾收集器状态和弱引用规则的对象)

    flushInterval属性:刷新间隔,单位毫秒(不然只有关闭一级缓存才能刷新)

    默认情况下是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新

    size属性:引用数目,正整数

    代表缓存最多可以存储多少对象,太大容易导致内存溢出

    readOnly属性:只读,true/false

    • true:只读缓存,会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势
    • false:读写缓存,会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false

    mybatis缓存查询顺序

    1. 先查询二级缓存,因为二级缓存可能有其他程序已经查出来的数据,可以拿来直接使用
    2. 如果二级缓存没有命中,在查询一级缓存
    3. 若一级缓存也没有命中,则查询数据库
    4. Sqlsession关闭之后,一级缓存中的数据会写入二级缓存

  • 相关阅读:
    (数据科学学习手札162)Python GIS神器geopandas 1.0版本发布
    H3C防火墙基于IP地址的安全策略配置
    论坛介绍 | COSCon'23 开源治理(G)
    Bracket
    Bert相关面试题整理
    23. 图论 - 图的由来和构成
    [Java]Redission入门使用
    cefsharp119.1.20(cef119.1.2,Chromium119.0.6045.105)版本升级体验及其他H264版本
    Python常见错误(Error)一览大全——初学者必看
    Vue——引入Vue的方法、VM对象和基础指令(面试)
  • 原文地址:https://blog.csdn.net/m0_60027772/article/details/126324311