mybatis实战教程

编程入门 行业动态 更新时间:2024-10-18 14:16:46

mybatis<a href=https://www.elefans.com/category/jswz/34/1769775.html style=实战教程"/>

mybatis实战教程

这是原文链接 原文链接

为了方便查找,这里复制一下,如有侵权,联系删除。
零、mybatis对应xml文件模板

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="zsc.dao.IUserDao"><!-- 配置查询结果的列名和实体类的属性名的对应关系 --><resultMap id="userMap" type="zsc.domain.User"><!-- 主键字段的对应 --><id property="userId" column="id"></id><!-- 非主键字段的对应 --><result property="userName" column="username"></result><result property="userAddress" column="address"></result><result property="userSex" column="sex"></result><result property="userBirthday" column="birthday"></result></resultMap><!--查询所有用户--><select id="findAll" resultMap="userMap">select * from user;</select><!-- 保存用户 --><insert id="saveUser" parameterType="zsc.domain.User"><!-- 配置插入操作后,获取插入的数据id --><selectKey keyProperty="userId" keyColumn="id" resultType="int" order="AFTER">select last_insert_id();</selectKey>insert into user (username,address,sex,birthday) values(#{userName},#{userAddress},#{userSex},#{userBirthday});</insert><!-- 更新用户 --><update id="updateUser" parameterType="zsc.domain.User">update user set username=#{userName},address=#{userAddress},sex=#{userSex},birthday=#{userBirthday} whereid=#{userId};</update><!-- 删除用户 --><delete id="deleteUser" parameterType="int">delete from user where id = #{uid};</delete><!-- 根据id查找用户 --><select id="findById" parameterType="int" resultMap="userMap">select * from user where id = #{uid};</select><!-- 根据用户名称模糊查找 --><select id="findByName" resultMap="userMap" parameterType="String">select * from user where username like #{name};</select><!-- 查找总用户数 --><select id="findTotal" resultType="int">select count(id) from user;</select><!-- 根据queryVo的条件查询用户 --><select id="findUserByVo" parameterType="zsc.domain.QueryVo" resultMap="userMap">select * from user where username like #{user.userName}</select></mapper>

一、mybatis简介
MyBatis是一流的持久性框架,支持自定义SQL,存储过程和高级映射。MyBatis消除了几乎所有的JDBC代码以及参数的手动设置和结果检索。MyBatis可以使用简单的XML或注释进行配置,并将图元,映射接口和Java POJO(普通的旧Java对象)映射到数据库记录。

个人理解mybatis就是在JDBC的基础上做了一层封装,具体概念可以参考mybatis官网:mybatis官网链接

二、mybatis简单入门
对于mybatis的入门,个人是觉得比较简单的,只要实现了对数据库的CURD操作,基本就可以说是入门了,这里用springboot+mybatis的一个简单例子作为入门案例。

(1)数据库创建

--注意:先创建一个数据库,再执行下面的语句DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (`id` int(11) NOT NULL AUTO_INCREMENT,`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名称',`birthday` datetime(0) NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP(0) COMMENT '生日',`sex` char(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '性别',`address` varchar(256) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 51 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '灰太狼', '2020-05-20 21:04:20', '男', '狼堡');
INSERT INTO `user` VALUES (2, '喜羊羊', '2020-05-31 21:03:50', '男', '羊村');
INSERT INTO `user` VALUES (3, '美羊羊', '2020-05-23 21:04:41', '女', '羊村');
INSERThuanc INTO `user` VALUES (4, '懒羊羊', '2020-05-20 21:05:08', '男', '羊村');
INSERT INTO ch`user` VALUES (5, '潇洒哥', '2019-12-11 21:05:50', '男', '古古怪界');
INSERT INTO `user` VALUES (6, '黑大帅', '2019-11-01 21:06:18', '男', '古古怪界');


(2)创建springboot项目
引入如下依赖,下面是本人使用mybatis时常用的一些依赖,像数据源springboot有自己的默认的数据源,但本人更喜欢用Druid这个数据源

        <!-- mybatis-spring-boot-starter :整合--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.1.2</version></dependency><!--Druid--><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.21</version></dependency><!--log4j:日志框架,建议引入--><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><!--mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency>

配置文件(application.yml)

#参考链接:.html
#参考链接:.html
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/test4?userSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8password: 123username: root#切换为druid数据源type: com.alibaba.druid.pool.DruidDataSource#Spring Boot 默认是不注入这些属性值的,需要自己绑定#druid 数据源专有配置initialSize: 5minIdle: 5maxActive: 20maxWait: 60000timeBetweenEvictionRunsMillis: 60000minEvictableIdleTimeMillis: 300000validationQuery: SELECT 1 FROM DUALtestWhileIdle: truetestOnBorrow: falsetestOnReturn: falsepoolPreparedStatements: true#配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入#如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority#则导入 log4j 依赖即可,Maven 地址:: stat,wall,log4jmaxPoolPreparedStatementPerConnectionSize: 20useGlobalDataSourceStat: trueconnectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500#整合mybatis
#type-aliases-package:要扫描的实体类(与数据库表对应)的位置
#mapper-locations:写sql语句的地方,与待会要写持久层接口对应
mybatis:type-aliases-package: com.zsc.domainmapper-locations: classpath:mybatis/mapper/*.xml

(3)增删改查操作
创建实体类

编写持久层接口

编写sql语句

注意:这里有个重点,如果实体类的成员变量名称与数据表的字段名称一模一样的话可以不做数据库表和实体类的映射,mybatis会自动根据字段封装数据,如果有些字段跟数据库表字段名称不一致,则需要做数据库表和实体类的映射,否则会封装不上数据,这里建议把映射都做上去。

关于数据库表和实体类的映射

<!--    id是自己起的一个别名,type为要映射的实体类--><resultMap id = "userMap" type = "com.zsc.domain.User">
<!--        <id></id>标签是主键的映射,<result></result>是非主键的字段映射--><id column="id" property="id"></id><result column="username" property="userName"></result><result column="birthday" property="birthday"></result><result column="sex" property="sex"></result><result column="address" property="address"></result></resultMap>

运行测试

测试查询所有数据,其余测试就不在这里展示

(4)总结

步骤:(1)导入相关依赖(2)创建与数据库表一致的实体类,类的成员变量名字尽量与表字段名称一致,如果不一致,则需要做数据表和实体类的映射(在xml文件配置),这里建议每次都做一下映射(3)创建持久层接口(UserMapper)(4)创建与持久层接口对应的配置文件(xml文件),在里面写sql语句,实现增删改查注意:文件的创建要根据application.yml里面的配置来创建

三、mybatis标签详解
所有的标签


最常用,,,四个标签,分别对应增删查改功能,
(1)增删查改
增删查改主要对应,,,四个标签

实体类

数据库表和实体类映射

< select >

属性	描述
id	在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType	将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap	这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
resultType	从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。
resultMap	外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。
flushCache	将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache	将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout	这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
fetchSize	这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。
statementType	STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType	FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。
databaseId	如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered	这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。
resultSets	这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。

返回一般数据类型(Integrt,String类型等)

返回javabean(实体类)

返回List类型

返回值是 Map<String,Object>(返回一个用户时)

返回值Map<Integer,User>(返回多个用户时)

< insert>
< insert>,< delete>,< update>这三个标签的属性基本类似的

属性	描述
id	在命名空间中唯一的标识符,可以被用来引用这条语句。
parameterType	将会传入这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传入语句的参数,默认值为未设置(unset)。
parameterMap	这是引用外部 parameterMap 的已经被废弃的方法。请使用内联参数映射和 parameterType 属性。
resultType	从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身。可以使用 resultType 或 resultMap,但不能同时使用。
resultMap	外部 resultMap 的命名引用。结果集的映射是 MyBatis 最强大的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃而解。可以使用 resultMap 或 resultType,但不能同时使用。
flushCache	将其设置为 true 后,只要语句被调用,都会导致本地缓存和二级缓存被清空,默认值:false。
useCache	将其设置为 true 后,将会导致本条语句的结果被二级缓存缓存起来,默认值:对 select 元素为 true。
timeout	这个设置是在抛出异常之前,驱动程序等待数据库返回请求结果的秒数。默认值为未设置(unset)(依赖驱动)。
fetchSize	这是一个给驱动的提示,尝试让驱动程序每次批量返回的结果行数和这个设置值相等。 默认值为未设置(unset)(依赖驱动)。
statementType	STATEMENT,PREPARED 或 CALLABLE 中的一个。这会让 MyBatis 分别使用 Statement,PreparedStatement 或 CallableStatement,默认值:PREPARED。
resultSetType	FORWARD_ONLY,SCROLL_SENSITIVE, SCROLL_INSENSITIVE 或 DEFAULT(等价于 unset) 中的一个,默认值为 unset (依赖驱动)。
databaseId	如果配置了数据库厂商标识(databaseIdProvider),MyBatis 会加载所有的不带 databaseId 或匹配当前 databaseId 的语句;如果带或者不带的语句都有,则不带的会被忽略。
resultOrdered	这个设置仅针对嵌套结果 select 语句适用:如果为 true,就是假设包含了嵌套结果集或是分组,这样的话当返回一个主结果行的时候,就不会发生有对前面结果集的引用的情况。 这就使得在获取嵌套的结果集的时候不至于导致内存不够用。默认值:false。
resultSets	这个设置仅对多结果集的情况适用。它将列出语句执行后返回的结果集并给每个结果集一个名称,名称是逗号分隔的。


< update>

< delete>

(2)< resultMap>
< resultMap>最简单的使用方式是用来做数据库表与实体类的映射

属性	描述
property	需要映射到JavaBean 的属性名称。
column	数据表的列名或者标签别名。
javaType	一个完整的类名,或者是一个类型别名。如果你匹配的是一个JavaBean,那MyBatis 通常会自行检测到。然后,如果你是要映射到一个HashMap,那你需要指定javaType 要达到的目的。
jdbcType	数据表支持的类型列表。这个属性只在insert,update 或delete 的时候针对允许空的列有用。JDBC 需要这项,但MyBatis 不需要。如果你是直接针对JDBC 编码,且有允许空的列,而你要指定这项。
typeHandler	使用这个属性可以覆写类型处理器。这项值可以是一个完整的类名,也可以是一个类型别名。

例如上面的例子:

<!--    id是自己起的一个别名,type为要映射的实体类--><resultMap id = "userMap" type = "com.zsc.domain.User">
<!--        <id></id>标签是主键的映射,<result></result>是非主键的字段映射--><id column="id" property="id"></id><result column="username" property="userName"></result><result column="birthday" property="birthday"></result><result column="sex" property="sex"></result><result column="address" property="address"></result></resultMap>


数据库表和实体类映射详解
上面的例子一对多查询说白了就是在User上增加了一个List< article>用于存储一对多存放的用户发表的多篇文章,重点要做其实就是数据库表和该User类的映射,这是重中之重。


在做数据库表和实体类的映射映射值大多数人都认为< resultMap>里面的相关标签的property属性对应实体类的成员变量名,名字必须一致,而column属性对应数据库表的字段,而且名字必须与数据库表的字段一致, 但实际上column属性只是在做映射时起的一个别名而已。

例如

关于< collection>标签,该标签主要用于“一对多”时的映射,例如List< article>的映射,这里主要有property属性和ofType属性,property对应实体类的属性,ofType对应哪一个实体类,< collection>标签里面的id标签和result标签跟上面讲的一样。

(3)动态sql
< if>
简单的条件判断

< where>
主要是用来简化sql语句中where条件判断的,能智能的处理 and or ,不必担心多余导致语法错误


< set>
set 标签是用在更新操作的时候,功能和 where 标签元素差不多,主要是在包含的语句前输出一个 set,然后如果包含的语句是以逗号结束的话将会把该逗号忽略,如果 set 标签最终返回的内容为空的话则可能会出错(update table where id=1)

< choose>
有些时候,我们不想用所有的条件语句,而只想从中择其一二。针对这种情况,MyBatis提供了choose元素,它有点像Java中的switch语句。下面的例子,先看第一个条件userName查找用户,如果满足改条件,就直接跳出choose,只选择这一个条件,其余条件都不看,如果最后所有条件都不满足,就采用< otherwise>的条件。

4)统计分组
mybatis的统计分组个人用起来有点搞不懂,查了很多别人的很多博文,感觉也没那么方便,好像mybatis plus统计分组功能比较方便,其实不过不考虑性能的话,可以有很多的方式进行统计分组,比如将查到的数据直接用java自己处理,或者分多步骤查询数据库等,如果要考虑性能的话,有一种封装成map的方式,虽然也要自己做一下处理。

数据库user表

持久层接口(mapper或dao,这里是UserMapper)

//通过性别对数据进行分组
List<HashMap<String,Object>>  listUserGroupBySex();

UserMapper.xml

    <select id="listUserGroupBySex" resultType="java.util.HashMap">select sex as 'key',count(*) as 'value' from user GROUP BY sex;</select>

运行结果

将查询到的数据转化为map

@Test
public void listUserGroupBySexTest() {List<HashMap<String, Object>> list = userMapper.listUserGroupBySex();list.forEach(System.out::println);Map<String,Integer> mapBySex = new HashMap<>();//最终结果//将查询到的List转换为mapif (list != null && !list.isEmpty()) {for (HashMap<String, Object> hashMap : list) {String key = null;Integer value = null;for (Map.Entry<String, Object> entry : hashMap.entrySet()) {if ("key".equals(entry.getKey())) {key = (String) entry.getValue();} else if ("value".equals(entry.getKey())) {//我需要的是int型所以做了如下转换,实际上返回的object应为Long。value = ((Long)entry.getValue()).intValue();}}mapBySex.put(key, value);}}mapBySex.keySet().forEach(key-> System.out.println(key+":"+mapBySex.get(key)));
}

最终处理结果

四、分页查询
mybatis自己没有集成分页工具,需要借助第三方插件,或者自己sql分页,这里直接借助第三方插件(PageHelp)

导入maven依赖:

<!--只配置当前这一个依赖 PageHelper不生效。-->
<!-- mybatis pager -->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>5.1.10</version>
</dependency>
<!--还需要把这个依赖添加到pom当中  自动排序和分页就好使了-->
<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper-spring-boot-autoconfigure</artifactId><version>1.2.5</version>
</dependency>

application.yml配置

#分页插件
pagehelper:helperDialect: mysql # 根据数据库配置reasonable: truesupportMethodsArguments: trueparams: count=countSql

配置后直接使用

持久层的查询语句不要以;结尾

注意这里有个两个重点:
(1)只有紧接着PageHelper.startPage(pageNum,5); 后的那句sql才会进行分页,再下一句sql则不分页。
(2)持久层的查询语句结尾不要有任何类似“;”的结束符号,不然后面分页查拼接sql会报错

前端代码

<!DOCTYPE html>
<html xmlns:th="">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<div align="center"><table border="1"><tr><th>id</th><th>name</th><th>birthday</th><th>sex</th><th>address</th></tr><tr th:each="user:${pageInfo.getList()}"><td th:text="${user.getId()}"></td><td th:text="${user.getUserName()}"></td><td th:text="${user.getBirthday()}"></td><td th:text="${user.getSex()}"></td><td th:text="${user.getAddress()}"></td></tr></table><p>当前 <span th:text="${pageInfo.pageNum}"></span> 页,总 <span th:text="${pageInfo.pages}"></span> 页,共 <span th:text="${pageInfo.total}"></span> 条记录</p><a th:href="@{/pageHelp}">首页</a><a th:href="@{/pageHelp(pageNum=${pageInfo.hasPreviousPage}?${pageInfo.prePage}:1)}">上一页</a><a th:href="@{/pageHelp(pageNum=${pageInfo.hasNextPage}?${pageInfo.nextPage}:${pageInfo.pages})}">下一页</a><a th:href="@{/pageHelp(pageNum=${pageInfo.pages})}">尾页</a>
</div>
</body>
</html>

分页结果

给出PageHelp常用参数

PageInfo.list	结果集
PageInfo.pageNum	当前页码
PageInfo.pageSize	当前页面显示的数据条目
PageInfo.pages	总页数
PageInfo.total	数据的总条目数
PageInfo.prePage	上一页
PageInfo.nextPage	下一页
PageInfo.isFirstPage	是否为第一页
PageInfo.isLastPage	是否为最后一页
PageInfo.hasPreviousPage	是否有上一页
PageHelper.hasNextPage	是否有下一页

五、复杂查询
(1)一对多查询
给出用户表 user 和文章表 article ,一个用户可以发表多篇文章,一篇文章只属于一个用户。

给定一个场景:要求查询一个用户的信息以及该用户发表的所有文章

实体类

import java.util.Date;
import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {//注意:这里的字段尽量跟数据库表的字段名一致//当然,也可以不一致,后面需要做实体类和数据库表的映射private Integer id;private String userName;private Date birthday;private String sex;private String address;private List<Article> articles;//1个用户有多篇文章
}

持久层接口

/*** 项目的持久层,相当于dao层*/
//@Mapper : 表示本类是一个 MyBatis 的 Mapper
@Mapper
@Repository
public interface UserMapper {//1对多的测试List<User> listUserOneToMany(Integer id);}

对应的UserMapper.xml文件(重点)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.zsc.mapper.UserMapper"><!--    id是自己起的一个别名,type为要映射的实体类--><resultMap id = "userMap" type = "com.zsc.domain.User">
<!--        <id></id>标签是主键的映射,<result></result>是非主键的字段映射--><id property="id" column="id" ></id><result property="userName" column="username"></result><result property="birthday" column="birthday"></result><result property="sex" column="sex"></result><result property="address" column="address"></result><!-- collection 是用于建立一对多中集合属性的对应关系    ofType 用于指定集合元素的数据类型    --><!--这里有个重点,column只能有一个id,不然查询数据时会出现只查询到一条数据的情况--><collection property="articles" ofType="com.zsc.domain.Article" column="user_id"><!--记住一点,<collection>标签里的column并不是与数据库表字段对应,而且自己起的一个别名,将数据库查询到的数据映射或者说是赋值给这个别名,再油这个别名映射到property对应的实体类属性上--><id property="id" column="aid"></id><!--column = "adi"是自己起的一个别名,防止有多个id--><result property="articleTitle" column="article_title"></result><result property="articleContent" column="article_content"></result><result property="userId" column="user_id"></result></collection></resultMap><!--1对多的测试--><select id="listUserOneToMany" resultMap="userMap">SELECTu.id,u.username,u.birthday,u.sex,u.address,a.id as aid,a.article_title,a.article_content,a.user_idfrom user u,article awhere u.id = a.user_id and u.id = #{id};</select></mapper>

注意:有个重点,一对多的情况,要映射List的时候,采用collection表签,且用ofType属性,property固定写法,虽然一对多还有其他的查询方式,但如果时采用这种查方式建议采用上面的方法。

(2)多对一查询
同样给出用户表 user 和文章表 article ,一个用户可以发表多篇文章,一篇文章只属于一个用户。

给定一个场景:要求查询一篇文章的信息以及该文章的作者

这次实体类的主角就应该文章类了

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Article {private Integer id;private String articleTitle;private String articleContent;private Integer userId;private User user;//1篇文章只能属于一个用户
}

持久层接口

import java.util.List;/*** 项目的持久层,相当于dao层*/
//@Mapper : 表示本类是一个 MyBatis 的 Mapper
@Mapper
@Repository
public interface ArticleMapper {List<Article> listArticle(Integer id);
}

对应的ArticleMapper.xml文件(重点)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.zsc.mapper.ArticleMapper"><!--    id是自己起的一个别名,type为要映射的实体类--><resultMap id = "articleMap" type = "com.zsc.domain.Article"><!--        <id></id>标签是主键的映射,<result></result>是非主键的字段映射--><id property="id" column="id"></id><result property="articleTitle" column="article_title"></result><result property="articleContent" column="article_content"></result><result property="userId" column="user_id"></result><!-- collection 是用于建立一对多中集合属性的对应关系    ofType 用于指定集合元素的数据类型    --><!--这里有个重点,column只能有一个id,不然查询数据时会出现只查询到一条数据的情况--><association property="user" javaType="com.zsc.domain.User"><id property="id" column="uid"></id><!--记住一点,<collection>标签里的column并不是与数据库表字段对应,而且自己起的一个别名,将数据库查询到的数据映射或者说是赋值给这个别名,再油这个别名映射到property对应的实体类属性上--><result property="userName" column="username"></result><result property="birthday" column="birthday"></result><result property="sex" column="sex"></result><result property="address" column="address"></result></association></resultMap><select id="listArticle" resultMap="articleMap">SELECTa.id,a.article_title,a.article_content,a.user_id,u.id as uid,u.username,u.birthday,u.sex,u.addressfrom user u,article awhere u.id = a.user_id and a.id = #{id};</select>
</mapper>

对于多对一的关系,跟一对多的区别,这里指代码的写法上,就是文章类的成员变量有一个private User user;而用户类则是一个List,所以,这里主要处理Article类里面的成员变量user的映射,这里的映射不是采用collection标签,而是采用association标签,property对应实体类属性,javaType对应哪一个实体类。

注意:这里的映射不是采用collection标签,而是采用association标签,property对应实体类属性,javaType对应哪一个实体类。

查询结果

3)多对多查询
多对多查询在mybatis里实现的方式跟一对多的方式差不多,只不过是要涉及到3张表的联合查询,同样要处理List,下面给出案例。

要求查询一条评论的所有信息包括谁发过这条评论

实体类

import java.util.List;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Comment {private Integer id;private String commentContent;private List<User> userList;//1条评论可以属于多个用户
}

持久层接口

import java.util.List;/*** 项目的持久层,相当于dao层*/
//@Mapper : 表示本类是一个 MyBatis 的 Mapper
@Mapper
@Repository
public interface CommentMapper {List<Comment> listComment(Integer id);
}

持久层对应的CommentMapper.xml(重点)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis//DTD Mapper 3.0//EN"".dtd">
<mapper namespace="com.zsc.mapper.CommentMapper"><!--    id是自己起的一个别名,type为要映射的实体类--><resultMap id = "commentMap" type = "com.zsc.domain.Comment"><id property="id" column="id"></id><result property="commentContent" column="comment_content"></result><!-- collection 是用于建立一对多中集合属性的对应关系    ofType 用于指定集合元素的数据类型    --><!--这里有个重点,column只能有一个id,不然查询数据时会出现只查询到一条数据的情况--><collection property="userList" ofType="com.zsc.domain.User"><id property="id" column="uid"></id><!--记住一点,<collection>标签里的column并不是与数据库表字段对应,而且自己起的一个别名,将数据库查询到的数据映射或者说是赋值给这个别名,再油这个别名映射到property对应的实体类属性上--><result property="userName" column="username"></result><result property="birthday" column="birthday"></result><result property="sex" column="sex"></result><result property="address" column="address"></result></collection></resultMap><select id="listComment" resultMap="commentMap">select * from user u,comment c,user_comment ucwhere u.id = uc.user_idAND c.id = ucment_idAND ucment_id = #{id}</select></mapper>

这里的查询涉及到3个表的查询

查询结果

同理也可以查询User表,因为是多对多的关系,所以在user类中需要添加private List commentList;,然后持久层对应的UserMapper.xml文件在做一个List的映射,进行3表联立的查询即可

修改后的实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {//注意:这里的字段尽量跟数据库表的字段名一致//当然,也可以不一致,后面需要做实体类和数据库表的映射private Integer id;private String userName;private Date birthday;private String sex;private String address;private List<Article> articles;//1个用户有多篇文章private List<Comment> commentList;//1个用户有多个评论
}

持久层接口

    //多对多的测试List<User> listUserManyToMany(Integer id);

对应的UserMapper.xml及运行结果


(4)< collection>和< association>
其实不论是一对多、多对一、还是多对多,都需要collection标签或是association标签来做实体类与数据库表的映射。
collection主要用来做如下相似情况的实体类的映射

即一个类里面,有一个List集合,集合里面的类型是自定义类型的情况,这时该类与数据库表的映射如下

其中Article类中的自定义类型(User user)的映射必须用association标签,property属性对应自定义类的属性,javaType属性对应哪一个自定义类型

六、批量增删查改
在使用foreach的时候最关键的也是最容易出错的就是collection属性,该属性是必须指定的,但是在不同情况 下,该属性的值是不一样的,主要有一下3种情况:

1.如果传入的是单参数且参数类型是一个List的时候,collection属性值为list
2.如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array
3.如果传入的参数是多个的时候,我们就需要把它们封装成一个Map了,当然单参数也可以封装成map


(1)批量查询用户


(2)批量删除用户

(3)批量插入用户

(4)批量更新用户
关于mybatis的批量更新个人觉得是比较让人恶心的,经过查询,发现目前主要有两种方式,一种是通过接收传进来的参数list进行循环着组装sql,这种跟自己在java中用for循环一条一条插入是一样的,另一种是通过 case when语句变相的进行批量更新,基于效率的考虑,建议采用第二种方式。

第一种方式,这里采用别的博主的代码,这种方式有一个重点就是需要在db链接url后面带一个参数 &allowMultiQueries=true,这个很重要,具体如下。

 <!-- 批量更新第一种方法,通过接收传进来的参数list进行循环着组装sql --><update id="updateBatch" parameterType="java.util.List" ><foreach collection="list" item="item" index="index" open="" close="" separator=";">update standard_relation<set ><if test="item.standardFromUuid != null" >standard_from_uuid = #{item.standardFromUuid,jdbcType=VARCHAR},</if><if test="item.standardToUuid != null" >standard_to_uuid = #{item.standardToUuid,jdbcType=VARCHAR},</if><if test="item.gmtModified != null" >gmt_modified = #{item.gmtModified,jdbcType=TIMESTAMP},</if></set>where id = #{item.id,jdbcType=BIGINT}</foreach></update>

第二种是个人建议用的,因为个人觉得第一种的方式还不如在java代码中用for循环实现,原理一样的,而且效率还低。所以个人喜欢第二种。

<!--通过foreach批量更新用户-->
<update id="updateUserByList">update user<trim prefix="set" suffixOverrides=","><trim prefix="username = case" suffix="end,"><!--对应userMap中的column属性--><foreach collection="list" item="item" index="i"><if test="item.userName != null">when id = #{item.id} then #{item.userName}</if></foreach></trim><trim prefix="birthday = case" suffix="end,"><!--对应userMap中的column属性--><foreach collection="list" item="item" index="i"><if test="item.birthday != null">when id = #{item.id} then #{item.birthday}</if></foreach></trim><trim prefix="sex = case" suffix="end,"><!--对应userMap中的column属性--><foreach collection="list" item="item" index="i"><if test="item.sex != null">when id = #{item.id} then #{item.sex}</if></foreach></trim><trim prefix="address = case" suffix="end,"><!--对应userMap中的column属性--><foreach collection="list" item="item" index="i"><if test="item.address != null">when id = #{item.id} then #{item.address}</if></foreach></trim></trim>where<foreach collection="list" separator="or" item="item" index="i">id = #{item.id}</foreach></update>


更多推荐

mybatis实战教程

本文发布于:2024-03-08 10:02:50,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1720559.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:实战   教程   mybatis

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!