MyBatis--第三天

来源:互联网 发布:android 棋牌游戏源码 编辑:程序博客网 时间:2024/05/21 20:27

动态sql

1.1 什么是动态sql

mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。

 

需求:根据用户的名字的模糊匹配和性别查询

 

 

<select id="findByNameAndSex" parameterType="com.demo3.UserQuery" resultType="com.demo3.User_tbCustomer">

select * from user_tb      where 1=1       

    

<if test="user_tbCustomer!=null anduser_tbCustomer.name!=null and user_tbCustomer.name!=''">

and name like '%${user_tbCustomer.name}%'  

</if>

<if test="user_tbCustomer!=null and user_tbCustomer.sex!=null and user_tbCustomer.sex!=''">

and sex=#{user_tbCustomer.sex}

</if>

</select>

 

改进:

 

<select id="findByNameAndSex" parameterType="com.demo3.UserQuery" resultType="com.demo3.User_tbCustomer">

select * from user_tb     

    

<where>  <!-- where自动添加而且去掉第一个and -->

<if test="user_tbCustomer!=null and user_tbCustomer.name!=null and user_tbCustomer.name!=''">

and name like '%${user_tbCustomer.name}%'  

</if>

<if test="user_tbCustomer!=null and user_tbCustomer.sex!=null and user_tbCustomer.sex!=''">

and sex=#{user_tbCustomer.sex}

</if>

</where>

</select>

 

接口方法:public List<User_tbCustomer> findByNameAndSex(UserQuery userQuery);

测试

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

User_tbMapper user_tbMapper = sqlsession.getMapper(User_tbMapper.class);

User_tbCustomer user_customer=new User_tbCustomer();

user_customer.setName("");  //关闭该功能测试

user_customer.setSex("");   ////关闭该功能测试

UserQuery uq=new UserQuery();

uq.setUser_tbCustomer(user_customer);

List<User_tbCustomer> list = user_tbMapper.findByNameAndSex(uq);

System.out.println(list.size());

 

 

1.2 sql片段

 

1.2.1 需求

将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。

方便程序员进行开发。

 

1.2.2 定义和引用sql片段

mapper.xml

<select id="findByNameAndSex" parameterType="com.demo3.UserQuery" resultType="com.demo3.User_tbCustomer">

select * from user_tb     

 <!-- 引用sql片段 -->

<include refid="user_where"></include>

</select>

<!-- 封装sql条件,以便重用 -->

<sql id="user_where">

<where>  <!-- where自动添加而且去掉第一个and -->

<if test="user_tbCustomer.name!=null and user_tbCustomer.name!=''">

and name like '%${user_tbCustomer.name}%'  

</if>

<if test="user_tbCustomer.sex!=null and user_tbCustomer.sex!=''">

and sex=#{user_tbCustomer.sex}

</if>

</where>

</sql>

 

 

1.3 foreach

 

sql传递数组或Listmybatis使用foreach解析

 

1.3.1 需求

 

查询id1或者10或者16的用户信息

 

两种方法:

SELECT * FROM user_tb WHERE id=1 OR id=10 OR id=16 (不效率)

SELECT * FROM user_tb WHERE id IN(1,10,16)

 

步骤:

 1 在包装类中封装一个List<Integer>

private List<Integer>ids;

public List<Integer> getIds() {

return ids;

}

public void setIds(List<Integer> ids) {

this.ids = ids;

}

2 mapper.xml

<select id="findByIds" parameterType="com.demo3.UserQuery" resultType="com.demo3.User_tbCustomer">

select * from user_tb

<where>

<if test="ids!=null and ids!=''">

<!--

collection:集合名

item:代表遍历中的每个元素

open:..开始

close:..结束

separator:分隔符

 -->

<foreach collection="ids" item="id" open="id in (" close=")" separator=",">

#{id}

</foreach>

</if>

</where>

</select>

 

3 接口

public List<User_tbCustomer> findByIds(UserQuery userQuery);

 

测试

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

User_tbMapper user_tbMapper = sqlsession.getMapper(User_tbMapper.class);

UserQuery uq=new UserQuery();

List<Integer> ids=new ArrayList<Integer>();

ids.add(1);

ids.add(4);

ids.add(11);

ids.add(17);

uq.setIds(ids);

List<User_tbCustomer> list = user_tbMapper.findByIds(uq);

System.out.println(list.size());

 

 

 

现在有两张表

订单表 order_tb

id createtime uid

客户表user_tb

id name sex birthday address

 

分析关系:1个客户可以有多个订单 ,而一个订单只能被一个客户拥有

多:订单   -----  一:客户

以前的hibernate:学生和专业

学生为多 :在学生实体类中封装一个专业对象

专业为一:在专业实体类中封装一个set集合

目的:查出两张表所有数据

 

 

多对一:

mybatis中的配置:

方法1:自动映射:resultType

 

java中:由于查的数据来自于两张表,我们实际的做法:

1 分别写两个bean:User_tb  Order_tb

 2 写一个扩展类继承属性多的那个bean,然后在属性中对另一个属性少的bean的属性封装getset

:

 

3 mapper.xml

<select id="findOrderAndUser1" resultType="com.demo3.User_tbCustomer">

select u.*,o.id as 'oid',o.createtime,o.uid from user_tb u,order_tb o where o.uid=u.id

</select>

 

      4 mapper接口中:

public List<User_tbCustomer> findOrderAndUser1();

 

5 测试:

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

User_tbMapper user_tbMapper = sqlsession.getMapper(User_tbMapper.class);

List<User_tbCustomer> list = user_tbMapper.findOrderAndUser1();

for(User_tbCustomer uc:list){

System.out.println(uc.getId()+uc.getName()+uc.getSex()+uc.getBirthday()+uc.getAddress()+"--"+uc.getOid()+uc.getCreatetime()+uc.getUid());

}

 

注意:

 

这样查出的订单对象是null,只能写具体的属性,不能封装对象

方法2:手动映射

回顾hibernate的学生和科目 是在学生类中写了一个Major major对象去替换以前的majorid

而在mybatis中,uid(外键)不能省

步骤:

Order_tb中封装User_tb,Order_tb中的uid也不能省

 

2 mapper.xml

<!--

type:最终输出的类型

 id:唯一标识

-->

<resultMap type="com.beans.Order_tb" id="orderAndUserResultMap">

<id column="oid" property="id"/>

<result column="createtime" property="createtime"/>

<result column="uid" property="uid"/>

<!--

association针对对象的映射 多对1

property:属性名(该对象名)

javaType:属性类型

 -->

<association property="user_tb" javaType="com.beans.User_tb">

<!-- 由于我在多表查询中该用户的id查了两次(u.*o.uid),所有这里column可以写iduid -->

<id column="uid" property="id"/>

<result column="name" property="name"/>

<result column="sex" property="sex"/>

<result column="birthday" property="birthday"/>

<result column="address" property="address"/>

</association>

</resultMap>

<select id="findOrderAndUser2" resultMap="orderAndUserResultMap">

select u.*,o.id as 'oid',o.createtime,o.uid from user_tb u,order_tb o where o.uid=u.id

</select>

 

Association可以看做hibernatemany-to-one

3 mapper接口public List<Order_tb> findOrderAndUser2();

4 测试

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

User_tbMapper user_tbMapper = sqlsession.getMapper(User_tbMapper.class);

List<Order_tb> list = user_tbMapper.findOrderAndUser2();

for(Order_tb o:list){

System.out.println(o.getId()+" "+o.getUser_tb().getName());

}

 

 

一对多:

如果是1对多,则需要在user_tb中添加order_tb集合,

既然是集合,则无法用多对一的 resultRype的方法:因为该方法是多对一,在多的实体类(order_tb)中封装一个一的(User_tb)的属性(getset),因为只有一个,而一对多,有多个,封装属性是不对的(你不可能封装多个相同属性)

所以,只能用ResultMap的方法

 

步骤:

1 User_tb中封装List<Order_tb>getset

 

2 mapper.xml

<!--

type:最终输出的类型

 id:唯一标识

-->

<resultMap type="com.beans.User_tb" id="orderAndUserResultMap2">

<id column="id" property="id"/>

<result column="name" property="name"/>

<result column="sex" property="sex"/>

<result column="birthday" property="birthday"/>

<result column="address" property="address"/>

<!--

collection 针对对象的映射1对多

property 属性名(集合名)

ofType:集合中的类型

 -->

<collection property="olist" ofType="com.beans.Order_tb">

<id column="oid" property="id"/>

<result column="createtime" property="createtime"/>

<result column="uid" property="uid"/>

</collection>

</resultMap>

<select id="findOrderAndUser3" resultMap="orderAndUserResultMap2">

select u.*,o.id as 'oid',o.createtime,o.uid from user_tb u,order_tb o where o.uid=u.id

</select>

 

3 mapper接口:

public List<User_tb> findOrderAndUser3();

 

4测试:

String resource="SqlMapConfig.xml";

InputStream is= Resources.getResourceAsStream(resource);

SqlSessionFactory ssf= new SqlSessionFactoryBuilder().build(is);

SqlSession sqlsession=ssf.openSession();

User_tbMapper user_tbMapper = sqlsession.getMapper(User_tbMapper.class);

List<User_tb> list = user_tbMapper.findOrderAndUser3();

for(User_tb u:list){

System.out.println(u.getName()+" "+u.getOlist().size());

}

 

 

 

比较hibernate 和 mybatis

Mybatis的关系映射比hibernate难写,但效率高

resultMap可以实现延迟加载,resultType无法实现延迟加载。