• SSM_Mybatis(下)


    目录

    八、增删改查中的细节

     8.1 插入数据的时候获取自增的id-befor方法

    8.1.1 案例准备

     8.2 插入数据的时候获取自增的id-after方法

     8.3 输入映射

    8.3.1 parameterType

    ​8.3.2 通过@Param注解(常用!!!)

    8.3.3 通过map来传递多个参数

    ​8.3.3 通过pojo类传递多个参数

    8.4 #{} 和 ${}的区别--面试中喜欢出的考题

     8.4.1 #{}

     8.4.2 ${}

    ​8.5 输出映射

     8.5.1 输出简单类型

     8.5.2 输出pojo类型

     8.5.3 输出Map类型

     8.5.4 resultMap

    8.6 数据库表中列与实体类属性不一致的处理方式

    8.6.1 使用列别名

    8.6.2 使用resultMap

     九、Mybatis的全局配置文件

    9.1 配置的内容

    9.2 属性(properties)

    9.3 设置 settings

    9.4 类型别名 typeAliases

    9.4.1 Mybatis中已经支持的别名

    ​9.4.2  自定义别名

    9.5 映射器 Mappers

    9.5.1 使用相对于类路径的资源引用

    9.5.2 使用映射器接口实现类的完全限定类名

    9.5.3 将包内的映射器接口实现全部注册为映射器--推荐

    9.6 dataSource标签

    9.7 事务

    9.7.1 默认是需要手动提交事务的 

    9.7.2 自动提交事务

    十、Mybatis中的关系映射

            10.1对一关系的映射 

    10.1.1 添加实体类

    10.1.2 添加对应的mapper接口

    10.1.3 对一映射方式1:通过关联对象打点调用属性的方式

    10.1.4 对一映射方式2:直接引用关联对象的Mapper映射

    10.1.5 对一映射方式3:直接引用关联对象的单独查询的方法

    10.2 对多关系的映射

    10.2.1 方式1:连接查询+引用关联对象的结果映射

    ​十一、动态SQL

    11.1 where标签在select中的使用

    11.2 set标签在update中的使用

    11.2.1 更新的原有写法

    ​11.2.2 使用set标签构建动态的SQL语句

    11.3 forEach标签

    11.3.1 批量添加

    ​11.3.2 批量删除

    ​十二、分页插件

    12.1 jar依赖

    12.2 在Mybatis全局配置文件中添加插件配置 

    12.3 使用插件

    十三、Mybatis缓存

    13.1 缓存作用

    13.2 一级缓存:自动开启,SqlSession级别的缓存 

    13.2.1 一级缓存分析 

    13.2.2 清空缓存的方式

    13.3 二级缓存:Mapper级别的缓存

    ​13.3.1 使用二级缓存步骤 

    13.3.2 二级缓存的禁用 

    13.3.3 缓存的属性配置 

    十四、反向生成插件 

    14.1 插件的配置

    14.2 反向生成插件的使用


    八、增删改查中的细节

    8.1 插入数据的时候获取自增的id-befor方法

    8.1.1 案例准备

    (1)添加一张新表

    1. CREATE TABLE `gamerecord` (
    2. `recordId` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
    3. `homeTeamId` int DEFAULT NULL COMMENT '主队ID',
    4. `gameDate` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '比赛日期',
    5. `score` int DEFAULT NULL COMMENT '得分',
    6. `visitingTeamId` int DEFAULT NULL COMMENT '客队ID',
    7. PRIMARY KEY (`recordId`),
    8. KEY `homeTeamId` (`homeTeamId`),
    9. KEY `visitingTeamId` (`visitingTeamId`),
    10. CONSTRAINT `gamerecord_ibfk_1` FOREIGN KEY (`homeTeamId`) REFERENCES `team` (`teamId`),
    11. CONSTRAINT `gamerecord_ibfk_2` FOREIGN KEY (`visitingTeamId`) REFERENCES `team` (`teamId`)
    12. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

     (2)实体类

    1. package com.lxy.pojo;
    2. import java.util.Date;
    3. public class GameRecord {
    4. private String recordId;
    5. private Integer homeTeamId;
    6. private Date gameDate;
    7. private Integer score;
    8. private Integer visitingTeamId;
    9. public String getRecordId() {
    10. return recordId;
    11. }
    12. public void setRecordId(String recordId) {
    13. this.recordId = recordId;
    14. }
    15. public Integer getHomeTeamId() {
    16. return homeTeamId;
    17. }
    18. public void setHomeTeamId(Integer homeTeamId) {
    19. this.homeTeamId = homeTeamId;
    20. }
    21. public Date getGameDate() {
    22. return gameDate;
    23. }
    24. public void setGameDate(Date gameDate) {
    25. this.gameDate = gameDate;
    26. }
    27. public Integer getScore() {
    28. return score;
    29. }
    30. public void setScore(Integer score) {
    31. this.score = score;
    32. }
    33. public Integer getVisitingTeamId() {
    34. return visitingTeamId;
    35. }
    36. public void setVisitingTeamId(Integer visitingTeamId) {
    37. this.visitingTeamId = visitingTeamId;
    38. }
    39. }

    (3)创建实体类的mapper接口

    1. package com.lxy.mapper;
    2. import com.lxy.pojo.GameRecord;
    3. public interface GameRecordMapper {
    4. int add(GameRecord record);
    5. }

    (4)修改配置文件 

     添加GameRecordMapper.xml文件

    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="com.lxy.mapper.GameRecordMapper">
    6. <insert id="add" parameterType="com.lxy.pojo.GameRecord">
    7. <selectKey keyProperty="recordId" order="BEFORE" resultType="java.lang.String">
    8. select uuid()
    9. selectKey>
    10. INSERT INTO `mybatis`.`gamerecord` (`recordId`, `homeTeamId`, `gameDate`, `score`, `visitingTeamId`)
    11. VALUES (#{recordId}, #{homeTeamId},default, #{score}, #{visitingTeamId})
    12. insert>
    13. mapper>

     (5)测试类

    1. package com.lxy.test;
    2. import com.lxy.mapper.GameRecordMapper;
    3. import com.lxy.pojo.GameRecord;
    4. import com.lxy.util.MybatisUtil;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.junit.Test;
    7. public class GameRecordMapperTest {
    8. private SqlSession sqlSession = MybatisUtil.getSqlSession();
    9. @Test
    10. public void testAdd(){
    11. GameRecordMapper mapper = sqlSession.getMapper(GameRecordMapper.class);
    12. GameRecord record = new GameRecord();
    13. record.setHomeTeamId(1014);
    14. record.setVisitingTeamId(1019);
    15. record.setScore(99);
    16. int add = mapper.add(record);
    17. sqlSession.commit();
    18. System.out.println("add结果"+add);
    19. System.out.println(record.getRecordId());
    20. }
    21. }

    使用before方法能为insert方法添加一个recordId,可以在创建对象的时候不传参数

     8.2 插入数据的时候获取自增的id-after方法

     (1)在TeamMapper接口中添加addAfter方法

    1. package com.lxy.mapper;
    2. import com.lxy.pojo.Team;
    3. import java.util.List;
    4. public interface TeamMapper {
    5. List queryAll();
    6. Team queryById(Integer teamId);
    7. int add(Team team);
    8. int update(Team team);
    9. int del(Integer teamId);
    10. int addAfter(Team team);
    11. }

    (2)在TeamMapper.xml中添加addAfter方法

    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="com.lxy.mapper.TeamMapper">
    6. <insert id="addAfter" parameterType="com.lxy.pojo.Team">
    7. <selectKey keyProperty="teamId" order="AFTER" resultType="java.lang.Integer">
    8. select LAST_INSERT_ID()
    9. selectKey>
    10. INSERT INTO `team` (`teamName`, `location`, `createTime`)
    11. VALUES (#{teamName}, #{location}, #{createTime})
    12. insert>
    13. mapper>

    (3)编写测试类 

    1. @Test
    2. public void testAddAfter(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. Team team = new Team();
    5. team.setTeamName("lxy");
    6. team.setLocation("shanghai");
    7. int i = mapper.addAfter(team);
    8. sqlSession.commit();
    9. System.out.println(i);
    10. System.out.println("新增id:"+team.getTeamId());
    11. }

     虽然没添加id,但是使用after方法可以直接获取自动添加后的id

    8.3 输入映射

    8.3.1 parameterType

    parameterType:接口中方法参数的类型,类型必须是完全限定名或别名(稍后讲别名)。该属性非必须,因为Mybatis框架能自行判断具体传入语句的参数,默认值为未设置(unset)。

    当sql语句中需要多个参数时,就不能使用parameterType方法了。

     (1)首先在TeamMapper接口中添加方法声明

    List queryByRange(int min, int max);

    (2)在TeamMapper.xml中添加节点

    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="com.lxy.mapper.TeamMapper">
    6. <select id="queryByRange" resultType="com.lxy.pojo.Team">
    7. select * from team where teamId >=#{param1} and teamId <=#{param2};
    8. select>
    9. mapper>

    (3)编写测试方法

    1. package com.lxy.test;
    2. import com.lxy.mapper.TeamMapper;
    3. import com.lxy.pojo.Team;
    4. import com.lxy.util.MybatisUtil;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.junit.Test;
    7. import java.util.List;
    8. public class TeamMapperTest {
    9. private SqlSession sqlSession = MybatisUtil.getSqlSession();
    10. @Test
    11. public void testTeamMapper() {
    12. TeamMapper teamMapper = sqlSession.getMapper(TeamMapper.class);
    13. List teams = teamMapper.queryAll();
    14. for (Team t : teams) {
    15. System.out.println(t);
    16. }
    17. }
    18. @Test
    19. public void testAddAfter(){
    20. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    21. Team team = new Team();
    22. team.setTeamName("lxy");
    23. team.setLocation("shanghai");
    24. int i = mapper.addAfter(team);
    25. sqlSession.commit();
    26. System.out.println(i);
    27. System.out.println("新增id:"+team.getTeamId());
    28. }
    29. @Test
    30. public void teamTeamMapper(){
    31. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    32. List teams = mapper.queryByRange(1009, 1019);
    33. teams.forEach(team -> System.out.println(team));
    34. }
    35. }

    测试结果:

    8.3.2 通过@Param注解(常用!!!)

    在方法的形参前面加入@Param("自定义参数名称"),mapper文件中使用#{自定义参数名称}的方式传参。

    (1)TeamMapper接口添加如下内容:

    List queryByRange2(@Param("min") Integer min, @Param("max") Integer max);

    (2)TeamMapper.xml配置文件中添加如下: 

    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="com.lxy.mapper.TeamMapper">
    6. <select id="queryByRange2" resultType="com.lxy.pojo.Team">
    7. select * from team where teamId >=#{min} and teamId <=#{max};
    8. select>
    9. mapper>

     (3)添加测试方法

    1. package com.lxy.test;
    2. import com.lxy.mapper.TeamMapper;
    3. import com.lxy.pojo.Team;
    4. import com.lxy.util.MybatisUtil;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.junit.Test;
    7. import java.util.List;
    8. public class TeamMapperTest {
    9. private SqlSession sqlSession = MybatisUtil.getSqlSession();
    10. @Test
    11. public void teamTeamMapper2(){
    12. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    13. List teams = mapper.queryByRange2(1009, 1019);
    14. teams.forEach(team -> System.out.println(team));
    15. }
    16. }

    测试结果:

    8.3.3 通过map来传递多个参数

    Map 集合可以存储多个值,使用Map向 mapper 文件一次传入多个参数。Map 集合使用 String的 key,Object 类型的值存储参数。 mapper 文件使用 # { key } 引用参数值

    (1)TeamMapper接口添加如下内容:

    List queryByRange3(Map map);
    

    (2)TeamMapper.xml配置文件中添加如下:

    1. <select id="queryByRange3" resultType="com.kkb.pojo.Team">
    2. select * from team where teamId >=#{min} and teamId <= #{max};
    3. select>

    (3)添加测试方法

    1. package com.lxy.test;
    2. import com.lxy.mapper.TeamMapper;
    3. import com.lxy.pojo.Team;
    4. import com.lxy.util.MybatisUtil;
    5. import org.apache.ibatis.session.SqlSession;
    6. import org.junit.Test;
    7. import java.util.HashMap;
    8. import java.util.List;
    9. import java.util.Map;
    10. public class TeamMapperTest {
    11. private SqlSession sqlSession = MybatisUtil.getSqlSession();
    12. @Test
    13. public void teamTeamMapper3(){
    14. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    15. Map map = new HashMap<>();
    16. map.put("min",1009);
    17. map.put("max",1019);
    18. List teams = mapper.queryByRange3(map);
    19. teams.forEach(team -> System.out.println(team));
    20. }
    21. }

    测试结果:

    8.3.3 通过pojo类传递多个参数

     与map传递多个参数类似,要求映射文件中的参数占位符必须和pojo类中的属性完全一致。

    (1)实体类:

    1. package com.lxy.pojo;
    2. public class QueryVO {
    3. private String name;
    4. private Integer min;
    5. private Integer max;
    6. private String location;
    7. public String getName() {
    8. return name;
    9. }
    10. public void setName(String name) {
    11. this.name = name;
    12. }
    13. public Integer getMin() {
    14. return min;
    15. }
    16. public void setMin(Integer min) {
    17. this.min = min;
    18. }
    19. public Integer getMax() {
    20. return max;
    21. }
    22. public void setMax(Integer max) {
    23. this.max = max;
    24. }
    25. public String getLocation() {
    26. return location;
    27. }
    28. public void setLocation(String location) {
    29. this.location = location;
    30. }
    31. }

     (2)TeamMapper接口添加如下内容:

    List queryByCondition(QueryVO vo);

     (3)TeamMapper.xml配置文件中添加如下:

    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="com.lxy.mapper.TeamMapper">
    6. <select id="queryByCondition" resultType="com.lxy.pojo.Team">
    7. select * from team
    8. where teamId>=#{min} and teamId<=#{max}
    9. and teamName like #{name} and location=#{location}
    10. select>
    11. mapper>

    (4)测试类添加方法:

    1. @Test
    2. public void testQueryByCondition(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. QueryVO vo = new QueryVO();
    5. vo.setLocation("北京");
    6. vo.setName("%球队%");
    7. vo.setMin(1001);
    8. vo.setMax(1020);
    9. List teams = mapper.queryByCondition(vo);
    10. teams.forEach(team -> System.out.println(team));
    11. }

     测试结果:

     8.4 #{} 和 ${}的区别--面试中喜欢出的考题

     8.4.1 #{}

    #{}:表示一个占位符,通知Mybatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句, #{…}代替sql 语句的“?”。这个是Mybatis 中的首选做法,安全迅速。

    1. <select id="queryById" parameterType="int" resultType="com.kkb.pojo.Team">
    2. select * from team where teamId=#{id}
    3. select>

     8.4.2 ${}

    ${}:表示字符串原样替换,通知Mybatis 使用$包含的“字符串”替换所在位置。使用 Statement或者PreparedStatement 把 sql 语句和${}的内容连接起来。一般用在替换表名,
    列名,不同列排序等操作。

    例如:根据球队名称,球队位置查询球队列表

     示例:使用不同列作为查询条件

    (1)TeamMapper接口添加如下内容:

    List queryByFiled(@Param("column") String column,@Param("columnValue") String columnValue);
    

    (2)TeamMapper.xml配置文件中添加如下:

    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="com.lxy.mapper.TeamMapper">
    6. <select id="queryByFiled" resultType="com.lxy.pojo.Team">
    7. select * from team where ${column}=#{columnValue}
    8. select>
    9. mapper>

    (3)添加测试方法

    1. package com.lxy.test;
    2. import com.lxy.mapper.TeamMapper;
    3. import com.lxy.pojo.QueryVO;
    4. import com.lxy.pojo.Team;
    5. import com.lxy.util.MybatisUtil;
    6. import org.apache.ibatis.session.SqlSession;
    7. import org.junit.Test;
    8. import java.util.HashMap;
    9. import java.util.List;
    10. import java.util.Map;
    11. public class TeamMapperTest {
    12. private SqlSession sqlSession = MybatisUtil.getSqlSession();
    13. @Test
    14. public void testQueryByFiled(){
    15. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    16. System.out.println("根据球队名称查询:");
    17. List teams = mapper.queryByFiled("teamName","LALALA");
    18. teams.forEach(team -> System.out.println(team));
    19. System.out.println("根据球队位置查询:");
    20. List teams2 = mapper.queryByFiled("location","北京");
    21. teams2.forEach(team -> System.out.println(team));
    22. }
    23. }

    测试结果:

     8.5 输出映射

     resultType: 执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。如果返回的是集合,设置的是集合元素的类型,而不是集合本身。resultType 和 resultMap,
    不能同时使用。

     8.5.1 输出简单类型

    案例:

    (1)TeamMapper接口添加如下内容:

    int getCount();

    (2)TeamMapper.xml配置文件中添加如下:

    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="com.lxy.mapper.TeamMapper">
    6. <select id="getCount" resultType="java.lang.Integer">
    7. select count(teamId) from team
    8. select>
    9. mapper>

    (3)测试类添加方法:

    1. @Test
    2. public void testCount(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. int count = mapper.getCount();
    5. System.out.println("总共的行数:"+count);
    6. }

     8.5.2 输出pojo类型

    案例:参考之前的查询所有球队信息

    List queryAll();
    
    1. <select id="queryAll" resultType="com.lxy.pojo.Team">
    2. select * from team;
    3. select>

     8.5.3 输出Map类型

     当我们只需要查询表中几列数据的时候可以将sql的查询结果作为Map的key和value。一般使用的是Map.


    Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录会抛出TooManyResultsException异常。


    如果有多行,使用List>.

    案例:根据id查询球队名称和位置。

    (1)TeamMapper接口添加如下内容:

    1. Map queryTwoColumn(int teamId);
    2. List> queryTwoColumnList();

    (2)TeamMapper.xml配置文件中添加如下:

    1. <select id="queryTwoColumn" resultType="java.util.HashMap">
    2. select teamName,location from team where teamId=#{id}
    3. select>
    4. <select id="queryTwoColumnList" resultType="java.util.HashMap">
    5. select teamName,location from team
    6. select>

    (3)添加测试类

    1. @Test
    2. public void test08(){
    3. Map map = teamMapper.queryTwoColumn();
    4. System.out.println(map);
    5. }
    6. @Test
    7. public void test09(){
    8. List> list = teamMapper.queryTwoColumnList();
    9. for (Map map : list) {
    10. System.out.println(map);
    11. }
    12. }

     测试结果:

    8.5.4 resultMap

    resultType要求数据库中的列名和实体类中的保持一致

    resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。常用在列名和 java 对象属性名不一样的情况。

    (1)在TeamMapper接口中添加方法 

    List queryAll2();
    

    (2)添加select节点,并定义 resultMap,指定列名和属性的对应关系

    1. <select id="queryAll2" resultMap="baseResultMap">
    2. select * from team;
    3. select>
    4. <resultMap id="baseResultMap" type="com.lxy.pojo.Team">
    5. <id column="teamId" property="teamId" javaType="java.lang.Integer" >id>
    6. <result column="teamName" property="teamName" javaType="java.lang.String">result>
    7. <result column="location" property="location" javaType="java.lang.String">result>
    8. <result column="createTime" property="createTime" javaType="java.util.Date">result>
    9. resultMap>

    (3)添加测试方法

    1. @Test
    2. public void test10(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. List teams = mapper.queryAll2();
    5. teams.forEach(team-> System.out.println(team));
    6. }

    测试结果:

    8.6 数据库表中列与实体类属性不一致的处理方式

    案例准备  创建表:

    1. use mybatis;
    2. DROP TABLE IF EXISTS `users`;
    3. CREATE TABLE `users` (
    4. `user_id` int NOT NULL AUTO_INCREMENT COMMENT '用户id',
    5. `user_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户姓名',
    6. `user_age` int NULL DEFAULT NULL COMMENT '用户年龄',
    7. PRIMARY KEY (`user_id`) USING BTREE
    8. ) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
    9. INSERT INTO `users` VALUES (1, '贾宝玉', 14);
    10. INSERT INTO `users` VALUES (2, '林黛玉', 13);
    11. INSERT INTO `users` VALUES (3, '薛宝钗', 15);
    12. SET FOREIGN_KEY_CHECKS = 1;

    8.6.1 使用列别名

    (1)创建实体类

    1. package com.kkb.pojo;
    2. public class Users {
    3. private Integer userId;
    4. private String userName;
    5. private Integer userAge;
    6. @Override
    7. public String toString() {
    8. return "Users{" +
    9. "userId=" + userId +
    10. ", userName='" + userName + '\'' +
    11. ", userAge=" + userAge +
    12. '}';
    13. }
    14. public Integer getUserId() {
    15. return userId;
    16. }
    17. public void setUserId(Integer userId) {
    18. this.userId = userId;
    19. }
    20. public String getUserName() {
    21. return userName;
    22. }
    23. public void setUserName(String userName) {
    24. this.userName = userName;
    25. }
    26. public Integer getUserAge() {
    27. return userAge;
    28. }
    29. public void setUserAge(Integer userAge) {
    30. this.userAge = userAge;
    31. }
    32. }

    (2)创建UsersMapper接口

    1. public interface UsersMapper {
    2. Users queryByID(int userId);
    3. }

    (3)映射文件UsersMapper.xml

    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="com.lxy.mapper.UsersMapper">
    6. <select id="queryByID" resultType="com.lxy.pojo.Users">
    7. select user_id as userId,user_name as userName,user_age as userAge from users where user_id=#{id};
    8. select>
    9. mapper>

    (4)编写测试类

    1. package com.lxy.test;
    2. import com.lxy.mapper.UsersMapper;
    3. import com.lxy.pojo.Users;
    4. import com.lxy.util.MybatisUtil;
    5. import org.junit.Test;
    6. public class TestUsersMapper {
    7. private UsersMapper usersMapper = MybatisUtil.getSqlSession().getMapper(UsersMapper.class);
    8. @Test
    9. public void test01(){
    10. Users users = usersMapper.queryByID(1);
    11. System.out.println(users);
    12. }
    13. }

    测试结果:

    8.6.2 使用resultMap

    (1)接口UsersMapper.java添加方法

    Users queryByID2(int userId);
    

    (2)映射文件UsersMapper.xml添加如下内容:

    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="com.lxy.mapper.UsersMapper">
    6. <select id="queryByID" resultType="com.lxy.pojo.Users">
    7. select user_id as userId,user_name as userName,user_age as userAge from users where user_id=#{id};
    8. select>
    9. <select id="queryByID2" resultMap="baseMap">
    10. select * from users where user_id=#{id};
    11. select>
    12. <resultMap id="baseMap" type="com.lxy.pojo.Users">
    13. <id column="user_id" property="userId"/>
    14. <result column="user_name" property="userName"/>
    15. <result column="user_age" property="userAge"/>
    16. resultMap>
    17. mapper>

    (3)测试类

    1. package com.lxy.test;
    2. import com.lxy.mapper.UsersMapper;
    3. import com.lxy.pojo.Users;
    4. import com.lxy.util.MybatisUtil;
    5. import org.junit.Test;
    6. public class TestUsersMapper {
    7. private UsersMapper usersMapper = MybatisUtil.getSqlSession().getMapper(UsersMapper.class);
    8. @Test
    9. public void test01(){
    10. Users users = usersMapper.queryByID(1);
    11. System.out.println(users);
    12. }
    13. @Test
    14. public void test02(){
    15. Users user = usersMapper.queryByID2(1);
    16. System.out.println(user);
    17. }
    18. }

    测试结果: 

     九、Mybatis的全局配置文件

    案例中使用的 mybatis.xml就是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">

    9.1 配置的内容

    MyBatis 的配置文件包含了会深深影响 MyBatis 行为的设置和属性信息。 配置文档的顶层结构如下:

    configuration(配置)
            properties--属性:加载外部的配置文件,例如加载数据库的连接信息
            Settings--全局配置参数:例如日志配置
            typeAliases--类型别名
            typeHandlers----类型处理器
            objectFactory-----对象工厂
            Plugins------插件:例如分页插件
            Environments----环境集合属性对象
                    environment(环境变量)
                            transactionManager(事务管理器)
                            dataSource(数据源)
    Mappers---映射器:注册映射文件用

    9.2 属性(properties)

    属性可以在外部进行配置,并可以进行动态替换。我们既可以在 properties 元素的子元素中设置(例如DataSource节点中的properties节点),也可以在 Java 属性文件中配置这些属性。


    数据源中有连接数据库的四个参数数据,我们一般都是放在专门的属性文件中,mybatis的全局配置文件直接从属性文件中读取数据即可。

    (1)在 resources 目录创建 jdbc.properties 文件,文件名称可以自定义。

    1. jdbc.driver=com.mysql.cj.jdbc.Driver
    2. jdbc.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT
    3. jdbc.username=root
    4. jdbc.a=???

    (2)mybatis的全局配置文件引入属性文件

    <properties resource="jdbc.properties"/>
    

    (3)使用属性文件中的值

    1. <dataSource type="POOLED">
    2. <property name="driver" value="${jdbc.driver}"/>
    3. <property name="url" value="${jdbc.url}"/>
    4. <property name="username" value="${jdbc.username}"/>
    5. <property name="password" value="${jdbc.password}"/>
    6. dataSource>

    9.3 设置 settings

    MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为.例如我们配置的日志就是应用之一。其余内容参考mybatis – MyBatis 3 | 配置

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

    9.4 类型别名 typeAliases

    类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。

    9.4.1 Mybatis中已经支持的别名

    下面是一些为常见的 Java 类型内建的类型别名。它们都是不区分大小写的,注意,为了应对原始类型的命名重复,采取了特殊的命名风格。

     9.4.2  自定义别名

    1. <typeAliases>
    2. <typeAlias type="com.lxy.pojo.Team" alias="Team"/>
    3. <package name="com.lxy.pojo"/>
    4. typeAliases>

    9.5 映射器 Mappers

    配置有多种方式:

    9.5.1 使用相对于类路径的资源引用

    1. 语法:<mapper resource=""/>
    2. 使用相对于类路径的资源,从 classpath 路径查找文件
    3. 例如:<mapper resource="com/lxy/mapper/TeamMapper.xml" />

    9.5.2 使用映射器接口实现类的完全限定类名

    1. 语法:<mapper class=""/>
    2. 使用的mapper接口的完全限定名
    3. 要求:接口和映射文件同包同名
    4. 例如<mapper class="com.lxy.mapper.GameRecordMapper"/>

    9.5.3 将包内的映射器接口实现全部注册为映射器--推荐

    1. 语法:<package name=""/>
    2. 指定包下的所有Mapper接口
    3. 如:<package name="com.lxy.mapper"/>
    4. 注意:此种方法要求 Mapper接口名称和 mapper 映射文件名称相同,且在同一个目录中。

    9.6 dataSource标签

    Mybatis 中访问数据库支持连接池技术,而且是采用的自己的连接池技术。在 Mybatis 的 mybatis.xml配置文件中,通过来实现 Mybatis 中连接池的配置。MyBatis 在初始化时,根据的 type 属性来创建相应类型的的数据源 DataSource。

    Mybatis 的数据源分为三类:

    UNPOOLED: 不使用连接池的数据源
    POOLED:使用连接池的数据源
    JNDI:使用JNDI实现的数据源
    前两个数据源都实现javax.sql.DataSource接口

     

    9.7 事务

    9.7.1 默认是需要手动提交事务的 

    Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection对象的 commit(), rollback() .Connection 对象的 setAutoCommit()方法来设置事务提交方式的。自动提交和手工提交、

    <transactionManager type="JDBC"/>
    

    该标签用于指定 MyBatis所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。

    (1)JDBC:使用JDBC的事务管理机制,通过Connection对象的 commit()方法提交,通过rollback()方法 回滚。默认情况下,mybatis将自动提交功能关闭了,改为了手动提交,观察日志可以看出,所以我们在程序中都需要自己提交事务或者回滚事务。

    (2)MANAGED:由容器来管理事务的整个生命周期(如Spring容器)。

    9.7.2 自动提交事务

    SqlSessionFactory的openSession方法由重载,可以设置自动提交的方式。
    如果sqlSession = SqlSessionFactory.openSession(true);参数设置为true,再次执行增删改的时候就不需要执行session.commit()方法,事务会自动提交。 

    十、Mybatis中的关系映射

    表结构如图: 

    10.1对一关系的映射 

    10.1.1 添加实体类

    1. package com.lxy.pojo;
    2. public class Player {
    3. private Integer playerId;
    4. private String playerName;
    5. private Integer playerNum;
    6. private Integer teamId;
    7. //多对一的体现:多方持有一方的对象 要有get方法
    8. private Team team1;//关联对象--多个球员可以属于同一个球队;
    9. private Team team2;//关联对象--多个球员可以属于同一个球队;
    10. private Team team3;//关联对象--多个球员可以属于同一个球队;
    11. public Integer getPlayerId() {
    12. return playerId;
    13. }
    14. public void setPlayerId(Integer playerId) {
    15. this.playerId = playerId;
    16. }
    17. public String getPlayerName() {
    18. return playerName;
    19. }
    20. public void setPlayerName(String playerName) {
    21. this.playerName = playerName;
    22. }
    23. public Integer getPlayerNum() {
    24. return playerNum;
    25. }
    26. public void setPlayerNum(Integer playerNum) {
    27. this.playerNum = playerNum;
    28. }
    29. public Integer getTeamId() {
    30. return teamId;
    31. }
    32. public void setTeamId(Integer teamId) {
    33. this.teamId = teamId;
    34. }
    35. public Team getTeam1() {
    36. return team1;
    37. }
    38. public void setTeam1(Team team1) {
    39. this.team1 = team1;
    40. }
    41. public Team getTeam2() {
    42. return team2;
    43. }
    44. public void setTeam2(Team team2) {
    45. this.team2 = team2;
    46. }
    47. public Team getTeam3() {
    48. return team3;
    49. }
    50. public void setTeam3(Team team3) {
    51. this.team3 = team3;
    52. }
    53. @Override
    54. public String toString() {
    55. return "Player{" +
    56. "playerId=" + playerId +
    57. ", playerName='" + playerName + '\'' +
    58. ", playerNum=" + playerNum +
    59. ", teamId=" + teamId +
    60. ", team1=" + team1 +
    61. ", team2=" + team2 +
    62. ", team3=" + team3 +
    63. '}';
    64. }
    65. }

    10.1.2 添加对应的mapper接口

    1. package com.lxy.mapper;
    2. import com.lxy.pojo.Player;
    3. public interface PlayerMapper {
    4. Player queryById(int playerId);
    5. Player queryById1(int playerId);
    6. Player queryById2(int playerId);
    7. Player queryById3(int playerId);
    8. }

    10.1.3 对一映射方式1:通过关联对象打点调用属性的方式

    要求:两表的连接查询

    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="com.lxy.mapper.PlayerMapper">
    6. <resultMap id="baseResultMap" type="com.lxy.pojo.Player">
    7. <id column="playerId" property="playerId">id>
    8. <result column="playerName" property="playerName">result>
    9. <result column="playerNum" property="playerNum">result>
    10. <result column="teamId" property="teamId">result>
    11. resultMap>
    12. <select id="queryById1" resultMap="joinTeamResult1">
    13. select * from player p inner join team t
    14. on p.teamId=t.teamId where playerId=#{id}
    15. select>
    16. <resultMap id="joinTeamResult1" type="Player" extends="baseResultMap">
    17. <result column="teamId" property="team1.teamId">result>
    18. <result column="location" property="team1.location">result>
    19. <result column="teamName" property="team1.teamName">result>
    20. <result column="createTime" property="team1.createTime">result>
    21. resultMap>
    22. mapper>

    编写测试类:

    1. package com.lxy.test;
    2. import com.lxy.mapper.PlayerMapper;
    3. import com.lxy.pojo.Player;
    4. import com.lxy.util.MybatisUtil;
    5. import org.junit.Test;
    6. public class TestPlayerMapper {
    7. PlayerMapper playerMapper= MybatisUtil.getSqlSession().getMapper(PlayerMapper.class);
    8. @Test
    9. public void test01(){
    10. Player player = playerMapper.queryById1(1);
    11. System.out.println(player);
    12. }
    13. }

     测试结果:

    10.1.4 对一映射方式2:直接引用关联对象的Mapper映射

     要求:1、两表的连接查询
                2、关联对象中已经存在被引用的resultMap

    1. <select id="queryById2" resultMap="joinTeamResult2">
    2. select * from player p inner join team t
    3. on p.teamId=t.teamId where playerId=#{id}
    4. select>
    5. <resultMap id="joinTeamResult2" type="Player" extends="baseResultMap">
    6. <association property="team2" javaType="Team"
    7. resultMap="com.lxy.mapper.TeamMapper.baseResultMap"/>
    8. resultMap>

     测试类:

    1. package com.lxy.test;
    2. import com.lxy.mapper.PlayerMapper;
    3. import com.lxy.pojo.Player;
    4. import com.lxy.util.MybatisUtil;
    5. import org.junit.Test;
    6. public class TestPlayerMapper {
    7. PlayerMapper playerMapper= MybatisUtil.getSqlSession().getMapper(PlayerMapper.class);
    8. @Test
    9. public void test01(){
    10. Player player = playerMapper.queryById1(1);
    11. System.out.println(player);
    12. }
    13. @Test
    14. public void test02(){
    15. Player player = playerMapper.queryById2(1);
    16. System.out.println(player);
    17. }
    18. }

    测试结果:

    10.1.5 对一映射方式3:直接引用关联对象的单独查询的方法

    要求:1、不需要两表的连接查询
               2、关联对象中已经存在被引用的查询方法

    1. <select id="queryById3" resultMap="joinTeamResult3">
    2. select * from player where playerId=#{id}
    3. select>
    4. <resultMap id="joinTeamResult3" type="Player" extends="baseResultMap">
    5. <association property="team3" javaType="Team"
    6. select="com.lxy.mapper.TeamMapper.queryById" column="teamId"/>
    7. resultMap>

    测试类:

    1. package com.lxy.test;
    2. import com.lxy.mapper.PlayerMapper;
    3. import com.lxy.pojo.Player;
    4. import com.lxy.util.MybatisUtil;
    5. import org.junit.Test;
    6. public class TestPlayerMapper {
    7. PlayerMapper playerMapper= MybatisUtil.getSqlSession().getMapper(PlayerMapper.class);
    8. @Test
    9. public void test01(){
    10. Player player = playerMapper.queryById1(1);
    11. System.out.println(player);
    12. }
    13. @Test
    14. public void test02(){
    15. Player player = playerMapper.queryById2(1);
    16. System.out.println(player);
    17. }
    18. @Test
    19. public void test03(){
    20. Player player = playerMapper.queryById3(1);
    21. System.out.println(player);
    22. }
    23. }

    测试结果: 

    10.2 对多关系的映射

    修改实体类Team.java:

    1. public class Team {
    2. private Integer teamId;
    3. private String teamName;
    4. private String location;
    5. private Date createTime;
    6. //一对多的体现:一方持有多方的对象
    7. private List playerList1;//关联对象--一个球队可以拥有多个球员
    8. private List playerList2;//关联对象--一个球队可以拥有多个球员

    TeamMapper.java接口添加方法:

    1. public interface TeamMapper {
    2. Team queryById1(int teamId);
    3. Team queryById2(int teamId);

    PlayerMapper.java接口中添加方法:

    1. public interface PlayerMapper {
    2. List queryByTeamId(int teamId);

    10.2.1 方式1:连接查询+引用关联对象的结果映射

    TeamMapper.xml添加:

    1. <select id="queryById1" resultMap="joinResult1">
    2. select * from team t join player p
    3. on t.teamId=p.teamId where t.teamId=#{id};
    4. select>
    5. <resultMap id="joinResult1" type="Team" extends="baseResultMap">
    6. <collection property="playerList1" javaType="java.util.ArrayList" ofType="player"
    7. resultMap="com.lxy.mapper.PlayerMapper.baseResultMap"/>
    8. resultMap>

    添加测试类:

    1. @Test
    2. public void test11(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. Team team = mapper.queryById1(1001);
    5. System.out.println(team);
    6. }

    测试结果:

    10.2.2 方式2:引用关联对象的单独查询的方法

     TeamMapper.xml添加:

    1. <select id="queryById2" resultMap="joinResult2">
    2. select * from team where teamId=#{id};
    3. select>
    4. <resultMap id="joinResult2" type="Team" extends="baseResultMap">
    5. <collection property="playerList2" javaType="java.util.ArrayList" ofType="player"
    6. select="com.lxy.mapper.PlayerMapper.queryByTeamId" column="teamId"/>
    7. resultMap>

    PlayerMapper.xml添加如下内容:

    1. <select id="queryByTeamId" resultType="Player">
    2. select * from player where teamId=#{id}
    3. select>

    测试类:

    1. @Test
    2. public void test12(){
    3. TeamMapper mapper = sqlSession.getMapper(TeamMapper.class);
    4. Team team = mapper.queryById2(1001);
    5. System.out.println(team);
    6. }

    测试结果:

    十一、动态SQL

    动态 SQL 是 MyBatis 的强大特性之一。如果你使用过 JDBC 或其它类似的框架,你应该能理解根据不同条件拼接 SQL 语句有多痛苦,例如拼接时要确保不能忘记添加必要的空格,还要注意去掉列表最后一个列名的逗号。利用动态 SQL,可以彻底摆脱这种痛苦。

    使用动态 SQL 并非一件易事,但借助可用于任何 SQL 映射语句中的强大的动态 SQL 语言,MyBatis 显著地提升了这一特性的易用性。

    之前学习过 JSTL,所以动态 SQL 元素会让你感觉似曾相识。在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少

    11.1 where标签在select中的使用

    (1)原先的多条件查询做法

    1. /* 原有的多条件分析:都是通过java中的字符串拼接实现
    2. String sql="select * from team where 1 = 1 ";
    3. // 如果用户输入了名称,就模糊查询
    4. and teamName like '%?%'
    5. // 如果用户输入了日期,按照日期区间查询
    6. and createTime> ? and createTime< ?
    7. //如果输入了地区,按照地区查询
    8. and location =?";*/
    9. if(vo.getName()!=null && !"".equals(vo.getName().trim())){
    10. sql+=" and teamName like '%"+vo.getName().trim()+"%'";
    11. }
    12. if(vo.getBeginTime()!=null ){
    13. sql+=" and getEndTime>"+vo.getBeginTime();
    14. }
    15. if(vo.getBeginTime()!=null ){
    16. sql+=" and createTime<="+vo.getEndTime();
    17. }
    18. if(vo.getLocation()!=null && !"".equals(vo.getLocation().trim())){
    19. sql+=" and location ="+vo.getLocation().trim();
    20. }

    (2)自己封装的查询条件类QueryTeamVO.java

    1. package com.lxy.pojo;
    2. import java.util.Date;
    3. public class QueryTeamVO {
    4. private String name;
    5. private Date beginTime ;
    6. private Date endTime;
    7. private String location;
    8. public String getName() {
    9. return name;
    10. }
    11. public void setName(String name) {
    12. this.name = name;
    13. }
    14. public Date getBeginTime() {
    15. return beginTime;
    16. }
    17. public void setBeginTime(Date beginTime) {
    18. this.beginTime = beginTime;
    19. }
    20. public Date getEndTime() {
    21. return endTime;
    22. }
    23. public void setEndTime(Date endTime) {
    24. this.endTime = endTime;
    25. }
    26. public String getLocation() {
    27. return location;
    28. }
    29. public void setLocation(String location) {
    30. this.location = location;
    31. }
    32. }

    (3)TeamMapper.java接口添加:

    List queryByVO(QueryTeamVO vo);
    

    (4)TeamMapper.xml映射文件添加:

    1. <select id="queryByVO" parameterType="QueryVO" resultMap="baseResultMap">
    2. select * from team
    3. <where>
    4. <if test="name!=null ">
    5. and teamName like concat(concat('%',#{name}),'%')
    6. if>
    7. <if test="beginTime!=null ">
    8. and createTime>=#{beginTime}
    9. if>
    10. <if test="endTime!=null ">
    11. and createTime<=#{endTime}
    12. if>
    13. <if test="location!=null ">
    14. and location=#{location}
    15. if>
    16. where>
    17. select>

    (5)测试方法

    1. package com.lxy.test;
    2. import com.lxy.mapper.TeamMapper;
    3. import com.lxy.pojo.QueryTeamVO;
    4. import com.lxy.pojo.Team;
    5. import com.lxy.util.MybatisUtil;
    6. import org.junit.Test;
    7. import java.util.Date;
    8. import java.util.List;
    9. public class TestSql {
    10. private TeamMapper mapper = MybatisUtil.getSqlSession().getMapper(TeamMapper.class);
    11. @Test
    12. public void test01(){
    13. QueryTeamVO vo = new QueryTeamVO();
    14. vo.setName("球");
    15. vo.setEndTime(new Date());
    16. vo.setLocation("北京");
    17. List teams = mapper.queryByVO(vo);
    18. teams.forEach(team -> System.out.println(team));
    19. }
    20. }

    测试结果: 

    11.2 set标签在update中的使用

    之前的做法如果没给其余属性赋值,那么null值会直接覆盖之前属性的值,所以并不合理

    11.2.1 更新的原有写法

    TeamMapper.java接口中的方法:

    int update(Team team);

    TeamMapper.xml映射文件对应的内容:

    1. <update id="update" parameterType="com.kkb.pojo.Team">
    2. update team set teamName=#{teamName},location=#{location},createTime=#{createTime}
    3. where teamId=#{teamId}
    4. update>

     测试类中添加测试方法:

    1. @Test
    2. public void test2(){
    3. Team team=new Team();
    4. team.setTeamId(1055);
    5. team.setTeamName("lina");
    6. int update = teamMapper.update(team);
    7. MybatisUtil.getSqlSession().commit();
    8. System.out.println(update);
    9. }

    测试结果:

    11.2.2 使用set标签构建动态的SQL语句

    TeamMapper.java接口中添加方法:

    int update1(Team team);
    

    TeamMapper.xml映射文件对应的内容:

    1. <update id="update1" parameterType="com.lxy.pojo.Team">
    2. update team
    3. <set>
    4. <if test="teamName!=null">
    5. teamName=#{teamName}
    6. if>
    7. <if test="location!=null">
    8. location=#{location},
    9. if>
    10. <if test="createTime!=null">
    11. createTime=#{createTime},
    12. if>
    13. where teamId=#{teamId}
    14. set>
    15. update>

    测试类:

    1. @Test
    2. public void test02(){
    3. Team team=new Team();
    4. team.setTeamId(1020);
    5. team.setTeamName("lina");
    6. int update = mapper.update1(team);
    7. MybatisUtil.getSqlSession().commit();
    8. System.out.println(update);
    9. }

    测试结果: 

    11.3 forEach标签

    11.3.1 批量添加

     TeamMapper.java接口中添加方法:

    void addList(List list);

    TeamMapper.xml映射文件对应的内容: 

    1. <insert id="addList" parameterType="arrayList">
    2. insert into team (teamName,location) values
    3. <foreach collection="list" item="t" separator=",">
    4. (#{t.teamName},#{t.location})
    5. foreach>
    6. insert>

    编写测试类:

    1. @Test
    2. public void test03(){
    3. List list=new ArrayList<>();
    4. for(int i=1;i<=3;i++){
    5. Team team=new Team();
    6. team.setTeamName("lina"+i);
    7. team.setLocation("bj"+i);
    8. list.add(team);
    9. }
    10. mapper.addList(list);
    11. MybatisUtil.getSqlSession().commit();
    12. }

    测试结果:

    11.3.2 批量删除

     TeamMapper.java接口中添加方法:

    void delList(List list);
    

    TeamMapper.xml映射文件对应的内容: 

    1. <delete id="delList" >
    2. delete from team where teamId in
    3. <foreach collection="list" item="teamId" separator="," open="(" close=")">
    4. #{teamId}
    5. foreach>
    6. delete>

     编写测试类:

    1. @Test
    2. public void test04(){
    3. List list = new ArrayList<>();
    4. list.add(1021);
    5. list.add(1022);
    6. list.add(1023);
    7. mapper.delList(list);
    8. MybatisUtil.getSqlSession().commit();
    9. }

    测试结果:

    十二、分页插件

    12.1 jar依赖

    1. <dependency>
    2. <groupId>com.github.pagehelpergroupId>
    3. <artifactId>pagehelperartifactId>
    4. <version>5.1.10version>
    5. dependency>

    12.2 在Mybatis全局配置文件中添加插件配置 

    1. <plugins>
    2. <plugin interceptor="com.github.pagehelper.PageInterceptor">
    3. plugin>
    4. plugins>

    12.3 使用插件

    1. @Test
    2. public void test5() {
    3. // PageHelper.startPage 必须紧邻查询语句,而且只对第一条查询语句生效
    4. PageHelper.startPage(2,5);
    5. List teams = mapper.queryAll();//查询语句结尾不能有分号
    6. teams.forEach(team-> System.out.println(team));
    7. PageInfo info=new PageInfo<>(teams);
    8. System.out.println("分页信息如下:");
    9. System.out.println("当前页:"+info.getPageNum());
    10. System.out.println("总页数:"+info.getPages());
    11. System.out.println("前一页:"+info.getPrePage());
    12. System.out.println("后一页:"+info.getNextPage());
    13. System.out.println("navigatepageNums:"+info.getNavigatepageNums());
    14. for (int num : info.getNavigatepageNums()) {
    15. System.out.println(num);
    16. }
    17. }

     测试结果:

    PageInfo.java的部分源码:

    1. package com.github.pagehelper;
    2. import java.util.Collection;
    3. import java.util.List;
    4. /**
    5. * 对Page结果进行包装
    6. *

    7. * 新增分页的多项属性,主要参考:http://bbs.csdn.net/topics/360010907
    8. *
    9. * @author liuzh/abel533/isea533
    10. * @version 3.3.0
    11. * @since 3.2.2
    12. * 项目地址 : http://git.oschina.net/free/Mybatis_PageHelper
    13. */
    14. @SuppressWarnings({"rawtypes", "unchecked"})
    15. public class PageInfo extends PageSerializable {
    16. //当前页
    17. private int pageNum;
    18. //每页的数量
    19. private int pageSize;
    20. //当前页的数量
    21. private int size;
    22. //由于startRow和endRow不常用,这里说个具体的用法
    23. //可以在页面中"显示startRow到endRow 共size条数据"
    24. //当前页面第一个元素在数据库中的行号
    25. private int startRow;
    26. //当前页面最后一个元素在数据库中的行号
    27. private int endRow;
    28. //总页数
    29. private int pages;
    30. //前一页
    31. private int prePage;
    32. //下一页
    33. private int nextPage;
    34. //是否为第一页
    35. private boolean isFirstPage = false;
    36. //是否为最后一页
    37. private boolean isLastPage = false;
    38. //是否有前一页
    39. private boolean hasPreviousPage = false;
    40. //是否有下一页
    41. private boolean hasNextPage = false;
    42. //导航页码数
    43. private int navigatePages;
    44. //所有导航页号
    45. private int[] navigatepageNums;
    46. //导航条上的第一页
    47. private int navigateFirstPage;
    48. //导航条上的最后一页
    49. private int navigateLastPage;

    十三、Mybatis缓存

    13.1 缓存作用

     缓存是一般的ORM 框架都会提供的功能,目的就是提升查询的效率和减少数据库的压力。将经常查询的数据存在缓存(内存)中,用户查询该数据的时候不需要从磁盘(关系型数据库文件)上查询,而是直接从缓存中查询,提高查询效率,解决高并发问题。

    MyBatis 也有一级缓存和二级缓存,并且预留了集成第三方缓存的接口。

    Mybatis的缓存结构体系:

     

    13.2 一级缓存:自动开启,SqlSession级别的缓存 

    在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。

    一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

    当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。


    Mybatis默认开启一级缓存,存在内存中(本地缓存)不能被关闭,可以调用clearCache()来清空本地缓存,或者改变缓存的作用域。

    13.2.1 一级缓存分析 

    工作原理图:

    当用户发起第一次查询team=1001的时候,先去缓存中查找是否有team=1001的对象;如果没有,继续向数据中发送查询语句,查询成功之后会将teamId=1001的结果存入缓存中;


    当用户发起第2次查询team=1001的时候,先去缓存中查找是否有team=1001的对象,因为第一次查询成功之后已经存储到缓存中,此时可以直接从缓存中获取到该数据,意味着不需要再去向数据库发送查询语句。


    如果SqlSession执行了commit(有增删改的操作),此时该SqlSession对应的缓存区域被整个清空,目的避免脏读。

    前提:SqlSession未关闭。

    测试:

    1. @Test
    2. public void test13(){
    3. Team t1=sqlSession.selectOne("com.lxy.mapper.TeamMapper.queryById",1001);//第一次查询,先查缓存,此时缓存中没有,继续向数据库发送查询语句
    4. System.out.println(t1);//查询完毕之后数据被自动存入缓存区域
    5. Team t2=sqlSession.selectOne("com.lxy.mapper.TeamMapper.queryById",1001);//第二次查询,因为缓存中已经有了该数据,可以直接获取,不需要发送查询语句
    6. System.out.println(t2);
    7. MybatisUtil.closeSqlSession();//关闭连接,缓存清空
    8. sqlSession=MybatisUtil.getSqlSession();//再次获取连接,此时缓存为空
    9. Team t3=sqlSession.selectOne("com.lxy.mapper.TeamMapper.queryById",1001);//新连接下第一次查询,肯定发送查询语句
    10. System.out.println(t3);//查询完毕之后数据被自动存入缓存区域
    11. int num=sqlSession.delete("com.lxy.mapper.TeamMapper.del",10000);
    12. sqlSession.commit();//提交之后缓存被整个清空
    13. System.out.println("删除结果:"+num);
    14. Team t4=sqlSession.selectOne("com.lxy.mapper.TeamMapper.queryById",1001);//第二次查询,因为缓存已经被上一次的提交清空了,所以还是需要发送查询语句
    15. System.out.println(t4);
    16. sqlSession.close();
    17. }

     测试结果:

    13.2.2 清空缓存的方式

    1、 session.clearCache( ) ;
    2、 execute update(增删改) ;
    3、 session.close( );
    4、 xml配置 flushCache="true" ;
    5、 rollback;
    6、 commit。

    13.3 二级缓存:Mapper级别的缓存

    多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。 

    二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace。

    不同的sqlSession两次执行相同namespace下的sql语句参数相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。

    Mybatis默认没有开启二级缓存,需要在setting全局参数中配置开启二级缓存。

    如果缓存中有数据就不用从数据库中获取,大大提高系统性能。

    二级缓存原理图:

    13.3.1 使用二级缓存步骤 

    二级缓存是mapper范围级别的,默认不启用。

    1、在Mybatis框架的全局配置文件中开启二级缓存

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

    2、在需要二级缓存的Mapper中添加缓存标志

    3、实体类必须实现Serializable接口

    4、测试二级缓存

    如果两个session不是从同一个Factory获取,那么二级缓存将不起作用。

    1. @Test
    2. public void test2() {
    3. SqlSession sqlSession1 = MybatisUtil.getSqlSession();
    4. Team t1 = sqlSession1.selectOne("com.lxy.mapper.TeamMapper.queryById", 1001);//先查缓存,没有,先数据库,查询完毕写入二级缓存
    5. System.out.println(t1);
    6. MybatisUtil.closeSqlSession();//关闭连接,一级缓存清空,二级缓存存在
    7. SqlSession sqlSession2 = MybatisUtil.getSqlSession();
    8. Team t2 = sqlSession2.selectOne("com.lxy.mapper.TeamMapper.queryById", 1001);//先查缓存,有,直接获取,不需要查询数据库
    9. System.out.println(t2);
    10. MybatisUtil.closeSqlSession();//关闭连接,一级缓存清空,二级缓存存在
    11. SqlSession sqlSession3 = MybatisUtil.getSqlSession();
    12. int num = sqlSession3.delete("com.lxy.mapper.TeamMapper.del", 10000);//删除成功
    13. System.out.println("删除的结果:" + num);
    14. sqlSession3.commit();//提交之后清空二级缓存
    15. MybatisUtil.closeSqlSession();//关闭连接,缓存清空
    16. SqlSession sqlSession4 = MybatisUtil.getSqlSession();
    17. Team t3 = sqlSession4.selectOne("com.lxy.mapper.TeamMapper.queryById", 1001);先查缓存,曾经有,但是上一个提交已经清空了缓存,所以只能去数据库中查询,查询完毕写入二级缓存
    18. System.out.println(t3);
    19. MybatisUtil.closeSqlSession();//关闭连接,缓存清空
    20. }

    13.3.2 二级缓存的禁用 

    对于变化比较频繁的SQL,可以禁用二级缓存。


    在开始了二级缓存的XML中对应的statement中设置useCache=false禁用当前Select语句的二级缓存,意味着该SQL语句每次只需都去查询数据库,不会查询缓存。


    useCache默认值是true。对于一些很重要的数据尽不放在二级缓存中。

    13.3.3 缓存的属性配置 

    1. <cache>
    2. <property name="eviction" value="LRU"/>
    3. <property name="flushInterval" value="60000"/>
    4. <property name="size" value="1024"/>
    5. <property name="readOnly" value="true"/>
    6. cache>

    源码:

    1. @Documented
    2. @Retention(RetentionPolicy.RUNTIME)
    3. @Target(ElementType.TYPE)
    4. public @interface CacheNamespace {
    5. Classextends Cache> implementation() default PerpetualCache.class;
    6. Classextends Cache> eviction() default LruCache.class;
    7. long flushInterval() default 0;
    8. int size() default 1024;
    9. boolean readWrite() default true;
    10. boolean blocking() default false;
    11. Property[] properties() default {};
    12. }
    13. /**属性介绍:
    14. 1.映射语句文件中的所有select语句将会被缓存;
    15. 2.映射语句文件中的所有CUD操作将会刷新缓存;
    16. 3.缓存会默认使用LRU(Least Recently Used)算法来收回;
    17. 3.1、LRU – 最近最少使用的:移除最长时间不被使用的对象。
    18. 3.2、FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    19. 3.3、SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    20. 3.4、WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    21. 4.缓存会根据指定的时间间隔来刷新(默认情况下没有刷新间隔,缓存仅仅调用语句时刷新);
    22. 5.缓存会存储列表集合或对象(无论查询方法返回什么),默认存储1024个对象。
    23. 6.缓存会被视为是read/write(可读/可写)的缓存,意味着检索对象不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。
    24. **/

    如果想在命名空间中共享相同的缓存配置和实例,可以使用cache-ref 元素来引用另外一个缓存。

    1. <cache-ref namespace="com.lxy.mapper.TeamMapper" />
    2. //引用TeamMapper命名空间中的cache。

    十四、反向生成插件 

    14.1 插件的配置

    在pom.xml文件中的中中添加如下插件配置:

    1. <plugin>
    2. <groupId>org.mybatis.generatorgroupId>
    3. <artifactId>mybatis-generator-maven-pluginartifactId>
    4. <version>1.3.5version>
    5. <configuration>
    6. <configurationFile>src/main/resources/generatorConfig.xmlconfigurationFile>
    7. <overwrite>trueoverwrite>
    8. configuration>
    9. <dependencies>
    10. <dependency>
    11. <groupId>org.mybatis.generatorgroupId>
    12. <artifactId>mybatis-generator-coreartifactId>
    13. <version>1.3.5version>
    14. dependency>
    15. dependencies>
    16. plugin>

    generatorConfig.xml内容:

    其内容需要自己改一部分

    1. "1.0" encoding="UTF-8"?>
    2. generatorConfiguration
    3. PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
    4. "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
    5. <generatorConfiguration>
    6. <classPathEntry
    7. location="D:\repository\mysql\mysql-connector-java\8.0.23\mysql-connector-java-8.0.23.jar" />
    8. <context id="MyBatis" targetRuntime="MyBatis3">
    9. <commentGenerator>
    10. <property name="suppressAllComments" value="true" />
    11. commentGenerator>
    12. <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
    13. connectionURL="jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT"
    14. userId="root"
    15. a="???">
    16. jdbcConnection>
    17. <javaTypeResolver>
    18. <property name="forceBigDecimals" value="false" />
    19. javaTypeResolver>
    20. <javaModelGenerator targetPackage="org.xzk.pojo"
    21. targetProject="src\main\java">
    22. <property name="trimStrings" value="true" />
    23. javaModelGenerator>
    24. <sqlMapGenerator targetPackage="org.xzk.mapper"
    25. targetProject="src\main\resources">
    26. sqlMapGenerator>
    27. <javaClientGenerator type="XMLMAPPER"
    28. targetPackage="org.xzk.mapper"
    29. targetProject="src\main\java">
    30. javaClientGenerator>
    31. <table tableName="team">
    32. <property name="useActualColumnNames" value="true"/>
    33. table>
    34. <table tableName="player">
    35. <property name="useActualColumnNames" value="true"/>
    36. table>
    37. <table tableName="gameRecord">
    38. <property name="useActualColumnNames" value="true"/>
    39. table>
    40. context>
    41. generatorConfiguration>

    注意只能运行一次,运行完毕显示BUILD SUCCESS即为成功。

     如果想重新生成,需要将之前生成的删除掉

    14.2 反向生成插件的使用

    1.使用时需要注意,生成后所使用的mapper需要在mybatis.xml中注册

    2.使用时还需注意,如果其他数据库的表名和你需要生成的表名相同,那么你有可能会生成两个baseResultMap,使用时一点会报错

    1. package com.lxy.test;
    2. import com.lxy.util.MybatisUtil;
    3. import org.junit.Test;
    4. import org.xzk.mapper.TeamMapper;
    5. import org.xzk.pojo.Team;
    6. import org.xzk.pojo.TeamExample;
    7. import java.util.List;
    8. /**
    9. * 测试反向生成的内容
    10. */
    11. public class TestGenerator {
    12. private TeamMapper mapper = MybatisUtil.getSqlSession().getMapper(TeamMapper.class);
    13. @Test
    14. public void test1(){
    15. Team team = mapper.selectByPrimaryKey(1001);
    16. System.out.println(team);
    17. }
    18. @Test
    19. public void test2(){
    20. Team team = new Team();
    21. team.setTeamName("LALALA");
    22. team.setLocation("bjjj");
    23. int i = mapper.insertSelective(team);
    24. MybatisUtil.getSqlSession().commit();
    25. System.out.println(i);
    26. }
    27. @Test
    28. public void test3(){
    29. //理解为为多条件、排序等服务的类
    30. TeamExample example = new TeamExample();
    31. //理解为盛放条件的容器
    32. TeamExample.Criteria criteria = example.createCriteria();
    33. //向容器中添加条件
    34. criteria.andTeamNameLike("%队%");
    35. //criteria.andTeamIdBetween(1001,1020);
    36. example.setOrderByClause("teamId asc");
    37. List teams = mapper.selectByExample(example);
    38. for (Team team : teams) {
    39. System.out.println(team);
    40. }
    41. }
    42. }

    如果你读到了这里,那请给博主点个攒吧!如果你有什么问题,可以在评论区留言,我会及时回答你。

  • 相关阅读:
    IT基础英语
    【Python】绘制 对数函数
    面试官:做过性能优化?我:任务切片!
    Salesforce OmniStudio顾问备考攻略
    数据变更白屏化利器-推送轨迹上线
    Java如何实现大文件分片上传,断点续传和秒传
    【Redis】散列表(Hash)和列表(List)的运用和理解以及Hash和List应用场景对比详解
    第二章 进程的描述与控制
    如何发起一个HTTP请求,发送HTTP请求的几种方式
    eclipse教程
  • 原文地址:https://blog.csdn.net/m0_57209427/article/details/127813961