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

MyBatis有两种开发方式

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

通过 SqlSessionFactory 创建 SqlSession 来调用增删改查接口,操作 statement 的 id 硬编码来实现,老项目常用这种方式
缺点:重复代码过多,操作 statement 的 id 硬编码将来影响维护。

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

mybatis根据一些规则自动创建接口的实现类的代理对象,通过 sqlSession.getMapper(xxx.class) 的方式生成接口的代理对象,调用相应的方法来执行增删改查,新项目使用这种方式
优点:无需写实现类(自动生成代理),重复代码量减少,便于维护。

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

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

  1. UserMapper.xml 中的 namespace 必须指定为要代理的接口全限定性类名。
  2. UserMapper.xml 中的 statement 的 id 必须指定为要代理的接口中的方法名
  3. UserMapper.xml 中的 statement 的输入参数类型必须和对应方法的参数类型相同
  4. 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 标签主要有两个作用:

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

if 标签的作用:
根据 test 条件是否成立,决定是否添加标签内 SQL。

那么为什么会出现 if,where 标签呢?
是由于业务需求导致的,比如:多条件查询,天猫超市买东西,用户可能根据商品的价格查找,商品的销量,商品的名称… 这些条件是不确定的,所以就有 if 标签来进行判断,动态生成 SQL,简化代码,提高编码效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值