当前位置: 首页 > news >正文

SpringBoot第25讲:SpringBoot集成MySQL - MyBatis 注解方式

SpringBoot第25讲:SpringBoot集成MySQL - MyBatis 注解方式

本文是SpringBoot第25讲,上文主要介绍了Spring集成MyBatis访问MySQL,采用的是XML配置方式;我们知道除了XML配置方式,MyBatis还支持注解方式。本文主要介绍SpringBoot+MyBatis注解方式。

文章目录

  • SpringBoot第25讲:SpringBoot集成MySQL - MyBatis 注解方式
    • 1、准备知识
    • 2、基本查改删操作
      • 2.1、查询操作
        • 1、@Results和@Result注解
        • 2、@Select和@Param注解
        • 3、@ResultMap注解
        • 4、表关联查询
      • 2.2、插入操作
        • 1、@Insert注解
        • 2、返回Insert后实体的主键值
      • 2.3、更新操作
        • 1、@Update 注解
      • 2.4、删除操作
        • 1、@Delete 注解
    • 3、Provider注解
    • 4、进一步理解
      • 4.1、其它注解
      • 4.2、xml方式和注解方式融合
      • 4.3、为什么纯注解方式不是最佳选择?
    • 5、示例源码

1、准备知识

MyBatis的相关知识体系。

具体可以参考 SpringBoot第24讲:SpringBoot集成MySQL - MyBatis XML方式

在构建知识体系时:我们最重要的目标并不是如何使用注解方式,而是要理解:

  1. 对于有原有xml方式改为注解方式(一定要有对比),如何写?
    1. 基本的CRUD怎么用注解写?
    2. 对于复杂的动态SQL如何写?
    3. 对于表关联的如何写?
  2. 为什么xml方式依然是比注解方式使用广泛?
    1. xml方式和注解方式混合使用?
  3. 注解方式是如何工作的呢?

2、基本查改删操作

我们从最基本的增删改操作开始,对比xml方式进行理解。

2.1、查询操作

1、@Results和@Result注解

对于xml配置查询时定义的ResultMap, 在注解中如何定义呢?

<resultMap type="springboot.mysql.mybatis.entity.User" id="UserResult1"><id     property="id"       	column="id"      		/><result property="userName"     column="user_name"    	/><result property="password"     column="password"    	/><result property="email"        column="email"        	/><result property="phoneNumber"  column="phone_number"  	/><result property="description"  column="description"  	/><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/>
</resultMap>

使用注解方式,用@Results注解对应

@Results(id = "UserResult1",value = {@Result(id = true, property = "id", column = "id"),@Result(property = "userName", column = "user_name"),@Result(property = "password", column = "password"),@Result(property = "email", column = "email"),@Result(property = "phoneNumber", column = "phone_number"),@Result(property = "description", column = "description"),@Result(property = "createTime", column = "create_time"),@Result(property = "updateTime", column = "update_time")}
)

2、@Select和@Param注解

对于查询,用@Select注解;对于参数, 使用@Param注解

所以根据用户ID查询用户,使用注解方式写法如下:

String SELECT_USER_SQL = "select u.id, u.password, u.user_name, u.email, u.phone_number, u.description, u.create_time, u.update_time from tb_user u";@Results(id = "UserResult1",value = {@Result(id = true, property = "id", column = "id"),@Result(property = "userName", column = "user_name"),@Result(property = "password", column = "password"),@Result(property = "email", column = "email"),@Result(property = "phoneNumber", column = "phone_number"),@Result(property = "description", column = "description"),@Result(property = "createTime", column = "create_time"),@Result(property = "updateTime", column = "update_time")}
)
@Select({SELECT_USER_SQL, " where id = #{id}"})
User findById1(@Param("id") Long id);

3、@ResultMap注解

xml配置查询时定义的ResultMap是可以复用的,那么我们上面通过@Results定义在某个方法上的,如何复用呢?

比如查询所有用户返回用户实体@Results是和查询单个用户一致的,那么我们可以通过@ResultMap指定返回值对应关系

@ResultMap("UserResult1")
@Select(SELECT_USER_SQL)
User findAll1();

由此你可以猜到,@ResultMap定义在哪个方法上并没有什么关系,因为它会被优先通过注解解析为数据库字段与Java字段的映射关系。

4、表关联查询

用户和角色存在着一对多的关系,上面的查询只是查询了用户的基本信息,如何关联查询(查询用户同时返回角色信息)呢?

我们看下xml配置方式是如何做到的?

<resultMap type="springboot.mysql.mybatis.entity.User" id="UserResult"><id     property="id"       	column="id"      		/><result property="userName"     column="user_name"    	/><result property="password"     column="password"    	/><result property="email"        column="email"        	/><result property="phoneNumber"  column="phone_number"  	/><result property="description"  column="description"  	/><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/><collection property="roles" ofType="springboot.mysql.mybatis.entity.Role"><result property="id" column="id"  /><result property="name" column="name"  /><result property="roleKey" column="role_key"  /><result property="description" column="description"  /><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/></collection>
</resultMap>

使用注解方式, 可以通过@Results+@Many注解

@Results(id = "UserResult",value = {@Result(id = true, property = "id", column = "id"),@Result(property = "userName", column = "user_name"),@Result(property = "password", column = "password"),@Result(property = "email", column = "email"),@Result(property = "phoneNumber", column = "phone_number"),@Result(property = "description", column = "description"),@Result(property = "createTime", column = "create_time"),@Result(property = "updateTime", column = "update_time"),@Result(property = "roles", column = "id", many = @Many(select = "springboot.mysql.mybatis.anno.dao.IRoleDao.findRoleByUserId", fetchType = FetchType.EAGER))}
)

其中findRoleByUserId是通过user表中的id查找Role, 具体方法如下

@Results(id = "RoleResult",value = {@Result(id = true, property = "id", column = "id"),@Result(property = "name", column = "name"),@Result(property = "roleKey", column = "role_key"),@Result(property = "description", column = "description"),@Result(property = "createTime", column = "create_time"),@Result(property = "updateTime", column = "update_time")})@Select("select r.id, r.name, r.role_key, r.description, r.create_time, r.update_time from tb_role r, tb_user_role ur where r.id = ur.user_id and ur.user_id = #{userId}")List<Role> findRoleByUserId(Long userId);

对于一对一的可以使用@One注解。

2.2、插入操作

涉及插入操作的主要注解有:@Insert, @SelectKey等。

1、@Insert注解

对于插入操作,在xml配置可以定义为:

<insert id="save" parameterType="springboot.mysql.mybatis.xml.entity.User" useGeneratedKeys="true" keyProperty="id">insert into tb_user(<if test="userName != null and userName != ''">user_name,</if><if test="password != null and password != ''">password,</if><if test="email != null and email != ''">email,</if><if test="phoneNumber != null and phoneNumber != ''">phone_number,</if><if test="description != null and description != ''">description,</if>create_time,update_time)values(<if test="userName != null and userName != ''">#{userName},</if><if test="password != null and password != ''">#{password},</if><if test="email != null and email != ''">#{email},</if><if test="phoneNumber != null and phoneNumber != ''">#{phoneNumber},</if><if test="description != null and description != ''">#{description},</if>sysdate(),sysdate())
</insert>

特别是,这里通过<if>判断条件更新的情况应该如何在注解中写呢?

可以通过@Insert + <script>

@Insert({"<script> ", "insert into tb_user(\n" +" <if test=\"userName != null and userName != ''\">user_name,</if>\n" +" <if test=\"password != null and password != ''\">password,</if>\n" +" <if test=\"email != null and email != ''\">email,</if>\n" +" <if test=\"phoneNumber != null and phoneNumber != ''\">phone_number,</if>\n" +" <if test=\"description != null and description != ''\">description,</if>\n" +" create_time,\n" +" update_time\n" +" )values(\n" +" <if test=\"userName != null and userName != ''\">#{userName},</if>\n" +" <if test=\"password != null and password != ''\">#{password},</if>\n" +" <if test=\"email != null and email != ''\">#{email},</if>\n" +" <if test=\"phoneNumber != null and phoneNumber != ''\">#{phoneNumber},</if>\n" +" <if test=\"description != null and description != ''\">#{description},</if>\n" +" sysdate(),\n" +" sysdate()\n" +" )", " </script>"})
@Options(useGeneratedKeys = true, keyProperty = "id")
int save(User user);

2、返回Insert后实体的主键值

上述@Options(useGeneratedKeys = true, keyProperty = "id") 表示什么意思呢?

表示,如果数据库提供了自增列生成Key的方式(比如这里的id),并且需要返回自增主键时,可以通过这种方式返回实体。

那么,如果id的自增不使用数据库自增主键时, 在xml中可以使用SelectKey:

<selectKey keyColumn="id" resultType="long" keyProperty="id" order="AFTER">SELECT LAST_INSERT_ID()
</selectKey>

对应着注解:

@SelectKey(statement = "SELECT LAST_INSERT_ID()", keyColumn = "id", keyProperty = "id", resultType = Long.class, before = false)
  • before = false, 相当于XML中的order=“AFTRE”,这是MySql数据库的配置。
  • before = true, 相当于XML中的order=“BEFORE”,这是Oracle数据库的配置。

注意事项:不同的数据库statement的值会不同,上面中的值适用于MySql数据库,使用其他类型的数据库时要注意修改。

2.3、更新操作

涉及更新操作的主要注解有:@Update等。

1、@Update 注解

对于xml的更新操作如下:

<update id="update" parameterType="springboot.mysql.mybatis.xml.entity.User">update tb_user<set><if test="userName != null and userName != ''">user_name = #{userName},</if><if test="email != null and email != ''">email = #{email},</if><if test="phoneNumber != null and phoneNumber != ''">phone_number = #{phoneNumber},</if><if test="description != null and description != ''">description = #{description},</if>update_time = sysdate()</set>where id = #{id}
</update><update id="updatePassword" parameterType="springboot.mysql.mybatis.xml.entity.User">update tb_user<set>password = #{password}, update_time = sysdate()</set>where id = #{id}
</update>

对应的注解写法如下:

@Update({"update tb_user set password = #{password}, update_time = sysdate()", " where id = #{id}"})
int updatePassword(User user);@Update({"<script> ", "update tb_user\n" +" <set>\n" +" <if test=\"userName != null and userName != ''\">user_name = #{userName},</if>\n" +" <if test=\"email != null and email != ''\">email = #{email},</if>\n" +" <if test=\"phoneNumber != null and phoneNumber != ''\">phone_number = #{phoneNumber},</if>\n" +" <if test=\"description != null and description != ''\">description = #{description},</if>\n" +" update_time = sysdate()\n" +" </set>\n" +" where id = #{id}", " </script>"})
int update(User user);

2.4、删除操作

涉及删除操作的主要注解有:@Delete等。

1、@Delete 注解

对于xml的删除操作如下:

<delete id="deleteById" parameterType="Long">delete from tb_user where id = #{id}
</delete><delete id="deleteByIds" parameterType="Long">delete from tb_user where id in<foreach collection="array" item="id" open="(" separator="," close=")">#{id}</foreach>
</delete>

对应的注解写法如下:

@Delete("delete from tb_user where id = #{id}")
int deleteById(Long id);@Delete({"<script> ", "delete from tb_user where id in\n" +"<foreach collection=\"array\" item=\"id\" open=\"(\" separator=\",\" close=\")\">\n" +"#{id}\n" +"</foreach>", " </script>"})
int deleteByIds(Long[] ids);

3、Provider注解

其实你可以发现通过注解方式,对于有一些需要通过动态构建查询条件的操作是非常不方便的。MyBatis的作者们自然就想到了动态构建SQL,动态构建SQL的方式是配合@Provider注解来完成的。

MyBatis提供了4种Provider注解,分别是 @SelectProvider、@InsertProvider、@UpdateProvider 和 @DeleteProvider。

这里以@SelectProvider为例来根据Id查询User:

1、定义包含自定义生成的动态SQL的类,比如UserDaoProvider

/*** @author qiwenjie*/
public class UserDaoProvider {public String findById(final Long id) {SQL sql = new SQL();sql.SELECT("u.id, u.password, u.user_name, u.email, u.phone_number, u.description, u.create_time, u.update_time");sql.FROM("tb_user u");sql.WHERE("id = " + id);return sql.toString();}
}

2、通过@SelectProvider注解关联到定义的类和方法

@ResultMap("UserResult")
@SelectProvider(type = UserDaoProvider.class, method = "findById")
User findById2(Long id);

4、进一步理解

让我们通过几个问题,进一步理解MyBatis注解方式。

4.1、其它注解

  • @CacheNamespace :为给定的命名空间 (比如类) 配置缓存。对应xml中的<cache>
  • @CacheNamespaceRef :参照另外一个命名空间的缓存来使用。属性:value,应该是一个名空间的字 符串值(也就是类的完全限定名) 。对应xml中的<cacheRef>标签。
  • @ConstructorArgs :收集一组结果传递给一个劫夺对象的构造方法。属性:value,是形式参数 的数组。
  • @Arg :单独的构造方法参数 , 是 ConstructorArgs 集合的一部分。属性: id,column,javaType,typeHandler。id 属性是布尔值, 来标识用于比较的属性,和XML元素相似。对应xml中的<arg>标签。
  • @Case :单独实例的值和它对应的映射。属性: value,type,results。Results 属性是结果数组,因此这个注解和实际的 ResultMap 很相似,由下面的 Results 注解指定。对应xml中标签<case>
  • @TypeDiscriminator : 一组实例值被用来决定结果映射的表 现。 属性: column, javaType, jdbcType, typeHandler,cases。cases 属性就是实例的数组。对应xml中标签<discriminator>
  • @Flush: 在MyBatis 3.3以上版本,可以通过此注解在Mapper接口中调用SqlSession#flushStatements()

4.2、xml方式和注解方式融合

xml方式和注解方式是可以融合写的, 我们可以将复杂的SQL写在xml中

比如将resultMap定义在xml中

<resultMap type="springboot.mysql.mybatis.xml.entity.User" id="UserResult3"><id     property="id"       		column="id"      		/><result property="userName"     column="user_name"    	/><result property="password"     column="password"    	/><result property="email"        column="email"        	/><result property="phoneNumber"  column="phone_number"  	/><result property="description"  column="description"  	/><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/><collection property="roles" ofType="springboot.mysql.mybatis.xml.entity.Role"><result property="id" 					column="id"  /><result property="name" 				column="name"  /><result property="roleKey" 			column="role_key"  /><result property="description" 	column="description"  /><result property="createTime"   column="create_time"  	/><result property="updateTime"   column="update_time"  	/></collection>
</resultMap>

在方法中用 @ResultMap

@ResultMap("UserResult3")
@Select("select u.id, u.password, u.user_name, u.email, u.phone_number, u.description, u.create_time, u.update_time from tb_user u")
User findAll1();

4.3、为什么纯注解方式不是最佳选择?

纯注解方式为何很少大规模呢? 说说我的一些看法

  • 1、对于复杂的SQL,特别是按照条件动态生成方式极为不便,即便有<script>代码的阅读体验和维护极为不佳
  • 2、对于复杂的SQL,即便有@Provider方式,这种充其量是一个半成品
    • 不是所见即所得的写法,需要再定义额外的类和方法
    • 动态构建时不便利
    • 函数式编程成为主流,lambda方式才是未来

这也是mybatis-plus等工具改进的地方。

5、示例源码

todo

http://www.lryc.cn/news/106184.html

相关文章:

  • 服务器返回 413 Request Entity Too Large
  • 如何一目了然地监控远程 Linux 系统
  • 9.环境对象和回调函数
  • 51单片机(普中HC6800-EM3 V3.0)实验例程软件分析概览
  • ubuntu18.04 安装php7.4-xdebug
  • java 定时任务不按照规定时间执行
  • Android复习(Android基础-四大组件)—— Activity
  • Linux系统安装部署MongoDB完整教程(图文详解)
  • CSS图片放到<div>里面,自适应宽高全部显示,点击图片跳到新页面预览,点击旋转按钮图片可旋转
  • 二阶段web基础与http协议
  • SpringBoot+Freemark根据html模板动态导出PDF
  • XPath数据提取与贴吧爬虫应用示例
  • 字符串匹配-KMP算法
  • Java面向对象之UML类图
  • 【机器学习】西瓜书学习心得及课后习题参考答案—第4章决策树
  • 2023.8.2
  • windows运行窗口常用快捷键命令
  • HDFS的QJM方案
  • 安装win版本的neo4j(2023最新版本)
  • ChatGPT结合知识图谱构建医疗问答应用 (二) - 构建问答流程
  • 聊天系统登录后端实现
  • Ajax笔记_01(知识点、包含代码和详细解析)
  • Eureka 学习笔记2:EurekaClient
  • Spring引入并启用log4j日志框架-----Spring框架
  • Redis实现延时队列
  • 无限遍历,Python实现在多维嵌套字典、列表、元组的JSON中获取数据
  • 信息学奥赛一本通——1180:分数线划定
  • SpringApplication对象的构建及spring.factories的加载时机
  • 基于传统检测算法hog+svm实现图像多分类
  • slice() 方法,使用 concat() 方法, [...originalArray],find(filter),移出类名 removeAttr()