序言
MyBatis,大家都知道,半自动的ORM框架,原来叫ibatis,后来好像是10年apache软件基金组织把它托管给了goole code,就重新命名了MyBatis,功能相对以前更强大了。它相对全自动的持久层框架Hibernate,更加灵活,更轻量级,这点我还是深有体会的。
MyBatis的一个强大特性之一就是动态sql能力了,能省去我们很多串联判断拼接sql的痛苦,根据项目而定,在一定的场合下使用,能大大减少程序的代码量和复杂程度,不过还是不是过度太过复杂的使用,以免不利于后期的维护和扩展。
动态sql
动态sql提供了对sql语句的灵活操作,通过表达式进行判断,对sql进行拼接/组装.
if
对查询条件进行判断,如果输入参数不为空才进行查询条件的拼接.
mapper
会自动处理第一个AND(MyBatis还提供了自定义行为的元素,详细可参考MyBatis文档).
UserDAO
PHP">List selectUser(User user) throws Exception;
Client
PHP">
由于id与name为null,因此这两个条件不会拼接在sql中,这一点可以调试时日志中看出.
choose/when/otherwise
有些时候,我们并不想用到所有的条件语句,而只想从中选择一二.针对这种情况,MyBatis提供了元素,他有点像Java中的switch.
PHP">
set
用于动态更新语句的解决方案为,set元素可以被用于动态包含需要更新的列,而舍去其他的.
PHP">
WHERE id = #{id};
foreach
使用foreach可以实现向sql中传递数组或List:
传入List
PHP">sql">SELECT * FROM user WHERE (id = ? OR id = ? OR id = ?);
SELECT * FROM user WHERE id IN (?,?,?);
因此其foreach的定义也有如下两种方案:
PHP">sql">
PHP">sql">
元素 描述
collection sql解析的参数名
index 循环下标
item 单个元素的名
open 循环开始输出
close 循环结束输出
separator 中间分隔输出
传递List作为parameterType时,sql解析参数名固定为list.
UserDAO
PHP">sql"> selectUser(List ids) throws Exception;
批量插入用户案例
mapper
PHP">sql">
UserDAO
PHP">sql"> users) throws Exception;
Client
PHP">sql">
传入数组
mapper
PHP">sql">
与List类似,传递数组作为parameterType时,sql解析参数名固定为array.
UserDAO
PHP">sql"> selectUser(Integer[] ids) throws Exception;
sql片段
可以将一段公共的sql语句抽取出来,作为一个sql片段,供其他sql调用:
PHP">sql">sql id="user_where">
经验:最好基于单表定义sql片段,而且在sql片段中不要包含/之类的标签,这样可以保证sql片段重用度更高.
关联查询
数据模型分析思路
每张表的数据内容:分模块对每张表记录的内容进行熟悉,相当于学习系统需求/功能. 每张表重要的字段:非空字段/外键字段等. 表与表之间的数据库级别关系: 外键关系. 表与表之间的业务关系:建立在某个业务的基础上去分析.
订单/商品数据模型
表内容
user: 购买商品的用户信息 order: 用户创建的订单 orderdetail: 订单详细(购买商品信息) item: 商品信息 表与表之间的业务关系:
user/order:
user -> order: 一对多 order -> user: 一对一 order/orderdetail:
order -> orderdetail:一对多 orderdetail -> order:一对一 orderdetail/item:
orderdetail -> item:一对一 item -> orderdetail:一对多
‘一对一'查询
由以上分析可知主查询为order表,而order -> user关系为一对一,因此使用resultMap将查询结果的订单信息映射到Order中,将用户信息映射到Order中的User属性.
PO: 改造User
PHP">sql">
PO: 新增Order,将User组合到Order中:
PHP">sql">
mapper
OrderDAO
PHP">sql">
Client
PHP">sql">
‘一对多'查询
需求: 查询订单及订单明细的信息(一对多).
PO: 定义OrderDetail,并在Order中添加List orderDetails订单明细属性:
mapper
元素 描述
ofType 指定关联查询结果集中的对象类型OrderDAO
‘多对多'查询
由于User表与Item表没有直接关联,因此只能通过Order表与OrderDetail表进行关联.
思路:
1) 将用户信息映射到User中.
2) 在User中添加List订单列表属性,将用户创建的订单映射到orders.
3) 在Order中添加List订单明细列表属性,将订单的明细映射到orderDetails.
4) 在OrderDetail中添加Item属性,将订单明细所对应的商品映射到item.
PO: Item
mapper
<div class="jb51code">
<pre class="brush:sql;">
<code class=" hljs java"><code class=" hljs vbnet"><code class=" hljs mathematica"><code class=" hljs cs"><code class=" hljs applescript"><resultmap id="user_item_map" type="com.fq.domain.User">
<id column="id" property="id">
<result column="username" property="username">
<result column="birthday" property="birthday">
<result column="sex" property="sex">
<result column="address" property="address">
<collection property="orders" oftype="com.fq.domain.Order">
<id column="order_id" property="id">
<result column="id" property="userId">
<result column="order_create_time" property="createTime">
<result column="order_note" property="note">
<result column="order_number" property="number">
<collection property="orderDetails" oftype="com.fq.domain.OrderDetail">
<id column="order_detail_id" property="id">
<result column="order_id" property="orderId">
<result column="item_id" property="itemId">
<result column="order_item_num" property="itemNumber">
<association property="item" javatype="com.fq.domain.Item">
<id column="item_id" property="id">
<result column="item_create_time" property="createTime">
<result column="item_detail" property="detail">
<result column="item_name" property="name">
<result column="item_price" property="price">
<result column="item_pic" property="pic">