您的位置:首页 > 移动开发

基于mapper的动态代理的开发方式——MyBatis的第二种开发方式

2018-03-27 23:42 816 查看

MyBatis有两种开发方式

1. 原始的 Ibatis 接口实现类的方式

通过 SqlSessionFactory 创建 SqlSession 来调用增删改查接口,操作 statement 的 id 硬编码来实现,老项目常用这种方式

缺点:重复代码过多,操作 statement 的 id 硬编码将来影响维护。

2. 基于mapper的动态代理的开发方式

mybatis根据一些规则自动创建接口的实现类的代理对象,通过 sqlSession.getMapper(xxx.class) 的方式生成接口的代理对象,调用相应的方法来执行增删改查,新项目使用这种方式

优点:无需写实现类(自动生成代理),重复代码量减少,便于维护。

本篇介绍第二种:基于 mapper 的动态代理的开发方式。

基于mapper的动态代理的开发方式需要遵循一些规则:

UserMapper.xml 中的 namespace 必须指定为要代理的接口全限定性类名。

UserMapper.xml 中的 statement 的 id 必须指定为要代理的接口中的方法名

UserMapper.xml 中的 statement 的输入参数类型必须和对应方法的参数类型相同

UserMapper.xml 中的 statement 的返回类型必须和对应方法返回值类型相同

在配置上述四点的时候会遇到几个问题:

mapper.xml 中 statement 的输入参数和返回值类型太长了。

解决:为类起别名,之后就可以在对应的参数和返回值中直接写对应的类名不用加包名。

<typeAliases>
<!-- 批量定义别名 -->
<package name="com.lyu.shopping.sysmanage.entity" />
<package name="com.lyu.shopping.sysmanage.dto" />
<package name="com.lyu.shopping.recommendate.dto" />
</typeAliases>


查询的时候需要给字段后起别名才能与实体类的属性一一对应

解决:开启驼峰命名,之后只要数据库中的表的字段名为 xxx_yyy 即可自动映射java bean 中的 xxxYyy 类。

<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>


MyBatis 主要的两个配置文件:

主配置文件(mybatis-cfg.xml)内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
<!-- 配置一些属性 -->
<settings>
<!-- 开启驼峰命名,映射表字段与 pojo 实体类的属性名 -->
<!-- 例:数据库字段名 user_id 对应实体类属性名 userId -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
<!-- 打印SQL执行过程的日志 -->
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

<typeAliases>
<!-- 单个类起别名 -->
<typeAlias type="全限定性类名" alias="别名" />
<!-- 批量定义别名,为一个包里面的类添加别名 -->
<package name="com.lyu.shopping.sysmanage.entity" />
<package name="com.lyu.shopping.sysmanage.dto" />
<package name="com.lyu.shopping.recommendate.dto" />
</typeAliases>

<!-- 配置pageHelper分页插件 -->
<plugins>
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 设置数据库类型 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六种数据库-->
<property name="dialect" value="mysql"/>
<!-- RowBounds参数offset作为PageNum使用 - 默认不使用 -->
<property name="offsetAsPageNum" value="false"/>
<!-- 使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="false"/>
<!--当设置为true的时候,如果pagesize设置为0 就不执行分页,返回全部结果  -->
<property name="pageSizeZero" value="true"/>
<!--合理化查询 比如如果pageNum<1会查询第一页;如果pageNum>pages会查询最后一页(设置为false返回空)-->
<property name="reasonable" value="false"/>
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name="supportMethodsArguments" value="false"/>
<!-- 总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>

<mappers>
<!-- 需要生成代理的接口所在的包 -->
<package name="com.lyu.shopping.*.mapper"/>
</mappers>
</configuration>


mapper配置文件(UserMapper.xml)内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.lyu.shopping.sysmanage.mapper.AdminMapper">
<!-- 管理员表所有的字段(除去password字段) -->
<sql id="all_admin_columns">
id, login_name, admin_name, password, age, sex, email, mobile,
address, status, gmt_create, gmt_modified, is_deleted delFlag
</sql>

<!-- 通过管理员id获取管理员的详细信息 -->
<select id="getAdminByAdminId" parameterType="long" resultType="admin">
SELECT <include refid="all_admin_columns" />
FROM shopping_sys_admin
WHERE id = #{adminId} AND is_deleted = 0
</select>
</mapper>


其中,namespace 为要代理的接口的全限定性类名,id 为要调用的句柄(类似PreparedStatement),parameterType 为传入的参数类型,resultType 为此次查询返回的类型,以上这两种类型都可以使用别名来定义(前提是在主配置文件中配置了别名)。

注:如果有多个简单类型的参数,就不需要写 parameterType ,在 SQL 中用 #{0}, #{1},… 来接收即可;模糊查询需要用 ${} 拼接符 将 SQL 和参数拼接起来(这也就容易引起注入和效率问题,能用 # 就不要用 $)

关于动态 SQL :

<!-- if标签 -->
<if test="userName != null">
AND user_name = #{userName}
</if>
<!-- where标签 -->
<where>
<if test="userName != null">
AND user_name = #{userName}
</if>
<if test="birthday != null">
AND birthday= #{birthday}
</if>
...
</where>


where 标签主要有两个作用:

添加 where 关键字。

判断第一个条件不加 and(where 标签中可能嵌套多个 if 标签,由于不确定哪个 if 标签能满足条件,所以每个 if 标签中都要加 AND 关键字来预防条件的连接,但是如果第一个条件加上 AND 就不符合 SQL 语法规范,所以 where 就有了这个作用)。

if 标签的作用:

根据 test 条件是否成立,决定是否添加标签内 SQL。

那么为什么会出现 if,where 标签呢?

是由于业务需求导致的,比如:多条件查询,天猫超市买东西,用户可能根据商品的价格查找,商品的销量,商品的名称… 这些条件是不确定的,所以就有 if 标签来进行判断,动态生成 SQL,简化代码,提高编码效率。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: