MyBatis入门(下,完)

MyBatis入门的下篇,本来想一次性写完的.但是中间因为有点儿事情,就分开写了.基础的东西,就不再介绍了,具体可以看上篇,在我博客里搜索MyBatis就可以了

对于简单的CRUD,我们前面已经完成了,但是有一个特点那就是接口中要么没参数,要么只有一个参数,那么如果有多个参数,该怎么搞呢?其实在MyBatis中,多个参数是要做些小设置的,不是想当然的事儿.

多参数的解决有四种方法:

1.将参数封装到一个HashMap中进行传递

2.将参数封装到一个JavaBean中,并为参数提供getter/setter方法

3.使用@Param注解表示参数传递.

4.使用MyBatis的默认规则

以上的方法,用的比较多的,是第三种,使用注解来配置.其实使用注解,MyBatis底层也是把它封装成HashMap,key对应参数的名字,value对应传入的值.

下面看一个根据用户名和密码查询的例子,有两个参数,一个用户名一个密码.配置文件什么的就不全写了,沿用上篇的.

首先在接口中添加该方法

//根据用户名和密码查询用户public User queryByUsernameAndPasswd(@Param("userName")String username,@Param("password")String password);

@Param(“userName”) 这里就设置了传入参数的参数名,可以在Mapper文件中进行引用.

配置Mapper文件

  <select id="queryByUsernameAndPasswd" resultType="User" >  SELECT * FROM tb_user WHERE user_name=#{userName} and password=#{password}  </select>

因为是查询,所以使用<select>标签,这样就可以使用到前面的注解设置的参数了.如果没有前面的注解,这里是会报错的.因为有两个参数,MyBatis不能对应,他不知道哪个参数对应哪个值.有了注解,就相当于有了HashMap,Map中的key,就是我们注解的内容,Map的value,就是传入的实际的值.所以,它根据Key和Value就可以一一对应上了.

如果不想使用注解,可以使用它的默认规则.其它MyBatis是有默认规则的,你不写注解.它的默认规则会认为你的传入的第一个参数是0,第二个是1,往后依次,或者第一个是param1,第二个是param2,往后依次.

所以,我们这里可以写成

  <select id="queryByUsernameAndPasswd" resultType="User" >  SELECT * FROM tb_user WHERE user_name=#{0} and password=#{1}  </select>

或者

  <select id="queryByUsernameAndPasswd" resultType="User" >  SELECT * FROM tb_user WHERE user_name=#{param1} and password=#{param2}  </select>

都是可以的.至于把参数封装成一个JavaBean和封装到HashMap就不演示了,都是一样的.

然后在测试类中测试.

@Testpublic void testQueryByUsernameAndPassword(){User user = dao.queryByUsernameAndPasswd("zhangsan", "123456");System.out.println(user);}

?

可以看到,结果出来了.

还有一个比较牛逼的就是MyBatis支持动态SQL和SQL片段

先说SQL片段和resultMap吧,这个简单.就是可以在Mapper配置文件中定义SQL片段.SQL片段就是一些公用的东西,可以被别的标签引用到.

看下面的例子.

  <!-- 定义一个resultMap,这个主要是用于数据库的结果集和POJO类的映射和高级查询 -->  <!-- 可以使用autoMapping来控制是否自动映射,自动映射就是下面列出来的,就照列出来的规则映射  没列出来的,使用默认规则映射.如果不开启,所以没有写映射规则的字段,将都是NULL,不会自动使用默认规则映射 -->  <resultMap type="User" id="userResultMap" autoMapping="true" >  <id column="id" property="id" />  <result column="user_name" property="userName" />  </resultMap>    <!-- 使用resultMap -->  <!-- 使用SQL片断  -->  <select id="queryAll" resultMap="userResultMap">  select <include refid="allFields"/> from tb_user  </select>    <!-- 定义一个SQL片断,可以在别处引用,这里把tb_user表中的所有字段都列出来了,如果以后要用,可直接引用 -->  <sql id="allFields" >id,user_name,password,name,age,sex,birthday,created,updated</sql>

上面的内容是Mapper配置文件中的.首先定义了一个resultMap,上面已经讲的很清楚了.不再细说.SQL片段比较神奇,可以把一些公用的抽出来,被其它的引用.定义SQL片段使用<sql>标签,然后起一个名字,具体内容放标签体中就行了.上面是把tb_user中的所有字段,都抽出来了.然后再查询所有的时候,直接使用这个片段,使用片段需要使用<include>标签来引入片段.

使用了resultMap,要把之前的resultType给去掉,换成resultMap

动态SQL就是支持SQL语句的动态拼接了,在拼接的时候,可以使用判断,循环结构,这个就比较强大了.

支持的动态SQL有

1.if

2.choose,when,otherwise

3.where,set

4.foreach

感觉这个玩意儿,跟Struts2的OGNL比较像.

通过这个,来完成几个功能.

接口中代码如下

//根据用户名和密码查询用户public User queryByUsernameAndPasswd(@Param("userName")String username,@Param("password")String password);//根据用户名模糊匹配,如果没有传入用户名,查询所有sex为1的用户public List<User> queryUserByLike(@Param("name")String name);//根据年龄和姓名查找,如果输入了年龄就按照年龄查找,如果输入了姓名,就按照姓名查找public List<User> queryUserByNameAndAge(@Param("name")String name,@Param("age") Integer age);//根据ids查找用户public List<User> queryUserByIds(@Param("ids")List<Integer> ids);

修改Mapper配置文件

<select id="queryUserByLike" resultType="User" >  SELECT * FROM tb_user where sex=1  <if test="name != null and name !=''">  AND name LIKE #{name}  </if>  </select>    <select id="queryUserByNameAndAge" resultType="User">  SELECT * FROM tb_user  <where>  <if test="name !=null and name !='' and age!=null and age!= ''">  AND name LIKE #{name} AND age=#{age}  </if>  <choose>  <when test="name != null and name != ''">  AND name LIKE #{name}  </when>  <otherwise>  AND age=#{age}  </otherwise>  </choose>  </where>  </select>    <select id="queryUserByIds" parameterType="Integer"  resultMap="userResultMap">  SELECT * FROM tb_user where id in  <!-- collections就是传入的参数,item方便下面引用,open表示以什么开始,close表示以什么结束,最后一个指定分隔符  拼接的结果就是 (1,2,3)   -->  <foreach collection="ids" item="id" open="(" close=")" separator="," >  #{id}  </foreach>  </select>

测试代码如下:

@Testpublic void testQueryByLike(){List<User> list = dao.queryUserByLike("%李%");for (User user : list) {System.out.println(user);}}@Testpublic void testqueryUserByNameAndAge(){List<User> list = this.dao.queryUserByNameAndAge("%李%", 21);for (User user : list) {System.out.println(user);}}@Testpublic void testQueryUserByIds(){List<Integer> ids = new ArrayList<Integer>();ids.add(1);ids.add(2);ids.add(3);List<User> list = dao.queryUserByIds(ids);for (User user : list) {System.out.println(user);}}

MyBatis的缓存跟hibernate的缓存理论都是一样的,分为一级缓存和二级缓存.

一级缓存是不能禁用的,而且是默认开启的,只在同一个session有效.当执行insert,update,delete语句的时候,一级缓存会失效.

二级缓存则需要配置,它有一个默认的提供缓存的类,也可以使用第三方的缓存,比如EhCache,Memcached等.二级缓存的是在整个sessionFactory有效,需要缓存的接口,必须失败序列化接口.因为它其实是把查询的结果缓存起来了,如果不实现序列化接口,则在序列化的时候,会报错.因为用的比较少,所以这里就不测试了.

MyBatis的高级查询

在开发中,我们经常会使用到高级查询,包括一对一,一对多,多对多三种.

四张表的对应关系如下图

?

?

?

?

?

?

?

?

?

?

?

需求如下接口中定义的方法

package org.linuxsogood.mybatis.advanceQuery;import org.apache.ibatis.annotations.Param;import org.linuxsogood.mybatis.pojo.Order;public interface AdvanceQuery {//一对一查询:查询订单,并且查询出下单人的信息。public Order queryOrderAndUser(@Param("orderId")String order_id);//一对多查询:查询订单,查询出下单人信息并且查询出订单详情。public Order queryOrderAndUserAndOrderdetail(@Param("orderId")String order_id);//多对多查询:查询订单,查询出下单人信息并且查询出订单详情中的商品数据。public Order queryOrderAndUserAndOrdertetailAndItem(@Param("orderId")String order_id);}

因为MyBatis要手动写SQL语句,不像hibernate那样可以直接写HQL.而且写完SQL语句,如果字段不对应,还要手动去映射或者开自动映射,自动映射也是有一定规则的.如果不符合规则,则必须手动去一个一个映射.

对于一对一的查询结果,我们返回的是Order,而查询还需要用户的信息,Order的POJO类中,并没有用户的信息,所以封装起来还是有点儿麻烦的.这里我们借鉴hibernate中的思想,在Order中定义一个User属性,并提供getter/setter方法.然后再去手动封装即可.MyBatis对这种情况,也提供了支持.

一对一查询,Mapper文件的写法.

<!-- 一对一查询 -->  <select id="queryOrderAndUser" resultMap="orderAndUser" parameterType="String" >  SELECT * from tb_order o LEFT JOIN tb_user u   ON o.user_id=u.id WHERE order_number = #{orderId}  </select>  <!-- 定义一个用于查询一对一的resultMap  --><resultMap type="Order" id="orderAndUser" autoMapping="true" ><id column="id" property="id" /><!-- 手动映射主键 --><result column="user_id" property="userId" /><!-- 联合映射,用来映射对象,property是Order中有一个属性叫user,javaType指定user的类型                    并开启自动映射  --><association property="user" javaType="User" autoMapping="true"><!-- 手动映射user的主键 --><id column="user_id" property="id" /></association></resultMap>

因为这里使用了resultMap,所以在selete标签中,就不能使用resultResult了,resultMap和resultResult不能共存.

结果集中使用了<association>标签来对Order中的user对你做了一个映射.这个是专门用来映射对象属性的.

其中的property是Order中的那个对象属性的变量名,javaType是那个对象属性的类型,也就是是哪个POJO.autoMapping=”true” 开启自动映射,开启了自动映射我们只需要写一个主键的映射,其它的字段会被自动映射上去.这里写自动映射的标签,会报错.但是MyBatis底层已经实现了这个功能,报错可以不用理.DTD文件没有更新的缘故

?

一对多Mapper文件的写法.

 <!-- 一对多查询 --> <select id="queryOrderAndUserAndOrderdetail" resultMap="orderAndUserAndDetail" parameterType="String"> SELECT * FROM tb_order o LEFT JOIN tb_user u  ON o.user_id=u.id LEFT JOIN tb_orderdetail d  ON o.id=d.order_id WHERE order_number=#{orderId} </select>  <!-- 定义一对多查询的resultMap --> <resultMap type="Order" id="orderAndUserAndDetail" autoMapping="true" > <association property="user" javaType="User" autoMapping="true" > <id column="user_id" property="id" /> </association> <!-- 聚合结果集 --> <!-- ofType是List集合中放的数据类型 --> <collection property="orderdetails" javaType="List" ofType="Orderdetail" autoMapping="true" > <id column="id" property="id"/> </collection> </resultMap>

一对多中有一个不太好处理的就是我们返回的,还是Order对象,而我们查询的结果,确是多条的.怎么把这多条结果,放到一个Order中这是一个难题.因为Order和Ordertail的对应关系是一对多,所以我们在Order中定义一个List<Orderdetail>,这个也是hibernate中的思想,MyBatis也对其提供了支持.然后在Mapper中配置的时候,使用<collection>标签聚合结果集即可.

其实多个resultMap中可以使用extends来继承的.我这里没有使用.

<collection>中属性的说明:

property: 这个是指Order中的那个对象属性的名字.

javaType: 这个是指在Order中使用什么容器存放的Orderdetail对象

ofType: 这个是指容器中存放的对象类型.

autoMapping 开启自动映射,同样写上会报错.但是是可以使用的.

我在Order中定义的时候写的是: List<Orderdetail> orderdetails; 跟上面一一对应理解一下.

多对多Mapper的写法.

<!-- 多对多查询  --> <select id="queryOrderAndUserAndOrdertetailAndItem" resultMap="orderAndUserAndDetailAndItem" parameterType="String" > SELECT * FROM tb_order o LEFT JOIN tb_user u  ON o.user_id=u.id LEFT JOIN tb_orderdetail d  ON o.id=d.order_id LEFT JOIN tb_item i ON d.item_id=i.id WHERE order_number=#{orderId}  </select>  <!-- 定义一个多对多查询的resultMap  --> <resultMap type="Order" id="orderAndUserAndDetailAndItem" autoMapping="true"> <association property="user" javaType="User" autoMapping="true" > <id property="id" column="id" /> </association> <collection property="orderdetails" ofType="Orderdetail" javaType="List" autoMapping="true" > <id column="id" property="id" /> <association property="item" javaType="Item" autoMapping="true" > <id property="id" column="id" /> </association> </collection> </resultMap>

只是前两种的一个结合体,没什么好讲的.

补充一下POJO和测试类

测试类

package org.linuxsogood.mybatis.advanceQuery;import static org.junit.Assert.*;import org.apache.ibatis.io.Resources;import org.apache.ibatis.session.SqlSessionFactory;import org.apache.ibatis.session.SqlSessionFactoryBuilder;import org.junit.Before;import org.junit.Test;import org.linuxsogood.mybatis.pojo.Order;public class AdvanceQueryTest {private AdvanceQuery mapper = null;@Beforepublic void setUp() throws Exception {SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsStream("mybatis-config.xml"));this.mapper = factory.openSession().getMapper(AdvanceQuery.class);}@Testpublic void testQueryOrderAndUser() {Order order = this.mapper.queryOrderAndUser("20140921001");System.out.println(order);}@Testpublic void testQueryOrderAndUserAndOrderdetail() {Order orderdetail = this.mapper.queryOrderAndUserAndOrderdetail("20140921001");System.out.println(orderdetail);}@Testpublic void testQueryOrderAndUserAndOrdertetailAndItem() {Order order = this.mapper.queryOrderAndUserAndOrdertetailAndItem("20140921001");System.out.println(order);}}

Order类

package org.linuxsogood.mybatis.pojo;import java.util.List;/** * 订单表 *  */public class Order {    private Integer id;    private Long userId;    private String orderNumber;        private User user;        private List<Orderdetail> orderdetails;    public List<Orderdetail> getOrderdetails() {return orderdetails;}public void setOrderdetails(List<Orderdetail> orderdetails) {this.orderdetails = orderdetails;}public User getUser() {        return user;    }    public void setUser(User user) {        this.user = user;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public Long getUserId() {        return userId;    }    public void setUserId(Long userId) {        this.userId = userId;    }    public String getOrderNumber() {        return orderNumber;    }    public void setOrderNumber(String orderNumber) {        this.orderNumber = orderNumber;    }@Overridepublic String toString() {return "Order [id=" + id + ", userId=" + userId + ", orderNumber="+ orderNumber + ", user=" + user + ", orderdetails="+ orderdetails + "]";}}

Item类

package org.linuxsogood.mybatis.pojo;/** * 商品表 */public class Item {    private Integer id;    private String itemName;    private Float itemPrice;    private String itemDetail;    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }    public String getItemName() {        return itemName;    }    public void setItemName(String itemName) {        this.itemName = itemName;    }    public Float getItemPrice() {        return itemPrice;    }    public void setItemPrice(Float itemPrice) {        this.itemPrice = itemPrice;    }    public String getItemDetail() {        return itemDetail;    }    public void setItemDetail(String itemDetail) {        this.itemDetail = itemDetail;    }    @Override    public String toString() {        return "Item [id=" + id + ", itemName=" + itemName + ", itemPrice=" + itemPrice + ", itemDetail="                + itemDetail + "]";    }        }

Orderdetail类

package org.linuxsogood.mybatis.pojo;public class Orderdetail {        private Integer id;        private Double totalPrice;        private Integer status;    private Integer orderId;    private Integer itemId;    private Item item;    public Item getItem() {return item;}public void setItem(Item item) {this.item = item;}public Integer getOrderId() {return orderId;}public void setOrderId(Integer orderId) {this.orderId = orderId;}public Integer getItemId() {return itemId;}public void setItemId(Integer itemId) {this.itemId = itemId;}public Double getTotalPrice() {        return totalPrice;    }    public void setTotalPrice(Double totalPrice) {        this.totalPrice = totalPrice;    }    public Integer getStatus() {        return status;    }    public void setStatus(Integer status) {        this.status = status;    }    public Integer getId() {        return id;    }    public void setId(Integer id) {        this.id = id;    }@Overridepublic String toString() {return "Orderdetail [id=" + id + ", totalPrice=" + totalPrice+ ", status=" + status + ", orderId=" + orderId + ", itemId="+ itemId + ", item=" + item + "]";}}

User类

package org.linuxsogood.mybatis.pojo;import java.util.Date;public class User implements java.io.Serializable{    private static final long serialVersionUID = 1L;    private Long id;    // 用户名    private String userName;    // 密码    private String password;    // 姓名    private String name;    // 年龄    private Integer age;    // 性别,1男性,2女性    private Integer sex;    // 出生日期    private Date birthday;    // 创建时间    private Date created;    // 更新时间    private Date updated;    public Long getId() {        return id;    }    public void setId(Long id) {        this.id = id;    }    public String getuserName() {        return userName;    }    public void setuserName(String userName) {        this.userName = userName;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public Integer getAge() {        return age;    }    public void setAge(Integer age) {        this.age = age;    }    public Integer getSex() {        return sex;    }    public void setSex(Integer sex) {        this.sex = sex;    }    public Date getBirthday() {        return birthday;    }    public void setBirthday(Date birthday) {        this.birthday = birthday;    }    public Date getCreated() {        return created;    }    public void setCreated(Date created) {        this.created = created;    }    public Date getUpdated() {        return updated;    }    public void setUpdated(Date updated) {        this.updated = updated;    }    @Override    public String toString() {        return "User [id=" + id + ", userName=" + userName + ", password=" + password + ", name=" + name                + ", age=" + age + ", sex=" + sex + ", birthday=" + birthday + ", created=" + created                + ", updated=" + updated + "]";    }}

?

画龙画虎难画骨,知人知面不知心。

MyBatis入门(下,完)

相关文章:

你感兴趣的文章:

标签云: