☞Mybatis框架从入门到精通视频实战教程☜
>>>学习交流群< < <
一、Mapper代理
前面已经使用MyBatis完成了对Emp表的CRUD操作,都是由SqlSession调用自身方法发送SQL命令并得到结果的,实现了MyBatis的入门。
但是却存在如下缺点:
- 不管是selectList()、selectOne()、selectMap(),都只能提供一个查询参数。如果要多个参数,需要封装到JavaBean中,并不一定永远是一个好办法。
- 返回值类型较为固定
- 只提供了映射文件,没有提供数据库操作的接口,不利于后期的维护扩展。
在MyBatis中提供了另外一种成为Mapper代理(或称为接口绑定)的操作方式。在实际开发中也使用该方式。下面我们就是要Mapper代理的方式来实现对Emp表的CRUD操作吧,还有完成多个参数传递、模糊查询、分页查询、自增主键回填等更多的技能实现。搭建好的项目框架如图所示,相比而言,增加了接口EmployeeMapper。但是却会引起映射文件和测试类的变化。
1.1 使用Mapper代理方式实现查询
- 首先定义接口EmployeeMapper。
public
- 定义映射文件EmployeeMapper.xml,要求映射文件必须和接口名相同。
- 在映射文件中进行配置
<mapper
注意
- 使用Mapper代理方式,namespace必须是接口的全路径名。
- 使用Mapper代理方式,select等映射标签的id必须是接口中方法的名字。
- 使用#{},底层使用PreparedStatement;而是要${},底层使用Statement了,会有SQL注入风险,不建议使用。
- 测试类完成对数据库的相关操作
public
注意:此时对数据库的操作不是由SqlSession发起,不是调用selectList()、selectOne()等方法,而是由EmployeeMapper接口发起,直接调用接口的方法,更容易理解。
EmployeeMapper
这条语句的底层使用了动态代理模式,动态创建一个EmployeeMapper的一个代理对象并赋给接口引用。所以在MyBatis中不需要显式提供Mapper接口的实现类,这也是简单的地方。
关于动态代理设计模式的原理,在Spring中详细讲解。
1.2 使用sql元素重用数据库字段列表
在映射文件中,可以使用sql标签定义SQL语句的一部分,方便SQL语句来引用。
比如最典型的就是数据库表的列名,通常情况下要在select、insert语句中来反复编写,此时就可以使用sql元素编写一次,就可以多次引用了。
引用时要使用include元素来完成。可以看到避免了重复书写,也便于后期修改维护。
<mapper
二、更多的映射
下面继续使用Mapper代理方式完成更多更复杂的数据库操作,涉及多个参数传递、模糊查询、分页查询、自增主键回填等内容。
2.1 多参数传递
在EmployeeMapper接口中定义方法实现同时按照job、deptno两个字段完成信息查询。可以有四种方式来实现。分别为:
- 方式1:直接传递多个参数
映射文件中,参数可以使用param1,param2...表示,或者使用arg0,arg1...表 示,可读性低。
- 方式2:使用Param注解传递多个参数
映射文件中参数可以使用Param注解指定的名称来表示,同时保留使用param1, param2...表示,但是不可以再使用arg0,arg1...表示
- 方式3:使用JavaBean传递多个参数
映射文件中的参数直接使用JavaBean的属性来接收,可读性高。底层调用是相应 属性的getter方法。
- 方式4:使用Map传递多个参数
映射文件中使用相应参数在map中的key来表示。
public
因为映射文件元素的id要保持唯一,所以Mapper接口不允许存在重载的方法。
在映射文件完成SQL语句的编写,关键是参数的接收。
<mapper
在测试类中完成SQL语句的调用和结果输出,这就没有难度了吧。
public
总结:
- 使用Map方式导致了业务可读性的丧失,导致了后续扩展和维护的困难,应该果断放弃使用。
- 直接传递多个参数,会导致映射文件中可读性降低,从可读性考虑,也不推荐使用。
- 如果参数数量<=5个,推荐使用Param注解方式,因为更直观。
- 如果参数数量>5个,推荐使用JavaBean方式。
- 如果涉及到多个JavaBean的参数,可以同时使用Param注解进行标记
2.2 模糊查询
在进行模糊查询时,在映射文件中可以使用concat()函数来连接参数和通配符。另外注意对于特殊字符,比如<,不能直接书写,应该使用字符实体替换。
public
<mapper
2.3 分页参数
MyBatis不仅提供分页,还内置了一个专门处理分页的类RowBounds,其实就是一个简单的实体类。其中有两个成员变量:
- offset:偏移量,从0开始计数
- limit:限制条数
在映射文件中不需要接收RowBounds的任何信息,MyBatis会自动识别并据此完成分页 。从控制台显示的SQL日志中发现,SQL语句中也没有引入分页。这说明是MyBatis先查询出所有符合条件的数据,再根据偏移量和限制条数筛选指定内容。所有仅适用小数据量情况,对于大数据的情况,请自己编写分页类来实现。后续分页专题专门说明。
public
<select
测试类代码:
RowBounds
2.4 自增主键回填
MySQL支持主键自增。有时候完成添加后需要立刻获取刚刚自增的主键,由下一个操作来使用。比如结算购物车后,主订单的主键确定后,需要作为后续订单明细项的外键存在。如何拿到主键呢,MyBatis提供了支持,可以非常简单的获取。
<insert
- useGeneratedKeys:表示要使用自增的主键
- keyProperty:表示把自增的主键赋给JavaBean的哪个成员变量。
以添加Employee对象为例,添加前Employee对象的empno是空的,添加完毕后可以通过getEmpno() 获取自增的主键。
<insert
- order:取值AFTER|BEFORE,表示在新增之后|之前执行<selectKey>中的SQL命令
- keyProperty:执行select @@identity后结果填充到哪个属性中
- resultType:结果类型。
技术扩展
在很多应用场景中需要新增数据后获取到新增数据的主键值,针对这样的需求一般由三种解决方式:
- 主键自定义,用户通过UUID或时间戳等方式生成唯一主键,把这个值当做主键值。在分布式场景中应用较多。
- 查询后通过select max(主键) from 表获取主键最大值。这种方式在多线程访问情况下可能出现问题。
- 查询后通过select @@identity获取最新生成主键。要求这条SQL必须在insert操作之后,且数据库连接没有关闭。