Java EE SSM框架整合开发(七)MyBatis 配置文件、映射器、动态SQL

384 阅读10分钟

MyBatis 配置文件

MyBatis的核心配置文件mybatis-config.xml配置了很多影响MyBatis行为的信息,这些信息通常只会配置在一个文件中,并且不会轻易改动。与Spring框架整合后,MyBatis的核心配置文件信息将配置到Spring的配置文件中。因此,在实际开发中需要编写或修改MyBatis的核心配置文件的情况不多。

该配置文件的元素节点是有先后顺序的,不可改变

configuration    配置
    properties      可以配置在Java属性配置文件中
    settings        修改MyBatis在运行时的行为方式
    typeAliases     为Java类型命名一个别名(简称)
    typeHandlers    类型处理器
    objectFactory   对象工厂
    plugins         插件
    environments    环境
        transactionManager    事务管理器
        dataSource            数据源
    mappers映射器

示例

<?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>
	<!-- 在使用MyBatis嵌套查询方式进行关联查询时,使用MyBatis的延迟加载在一定程度可以提高查询效率 -->
	<settings>
		<!-- 打开延迟加载的开关 -->
		<setting name="lazyLoadingEnabled" value="true" />
		<!-- 将积极加载改为按需加载 -->
		<setting name="aggressiveLazyLoading" value="false" />
	</settings>

	<mappers><!-- 映射器,告诉 MyBatis到哪里去找映射文件 -->
		<mapper resource="com/mybatis/UserMapper.xml" />
		<mapper resource="com/mybatis/PersonMapper.xml" />
		<mapper resource="com/mybatis/IdCardMapper.xml" />
		<mapper resource="com/mybatis/OrdersMapper.xml" />
	</mappers>
</configuration>

映射器

302839.png

映射器规定了SQL语句的映射规则,有两种实现方法:一是基于接口与XML,一是基于接口与注解(不常用)。XML映射器中常用的元素如下

元素名称描述备注
select查询自定义参数和结果集
insert插入返回一个整数,代表插入的行数
update更新返回一个整数,代表更新的行数
delete删除返回一个整数,代表删除的行数
sql定义sql短语,可以在其他位置引用相当于给表名列名起了别名
resultMap对结果集进行映射,后面会细讲提供映射规则

2.1 select

image.png

示例为接收一个Integer类型的参数,返回一个MyUser类型的对象,结果集自动映射到MyUser属性。

<!-- 根据uid查询一个用户信息 -->
<select id="selectUserById" parameterType="Integer" resultType="com.po.MyUser">
    select * from user where uid = #{uid}
</select>

对于有多个参数传入的情况,有两种实现方式:Map键值对、为结果集建立新的JavaBean

2.1.1使用Map传参

此时接口定义如下:

public List<MyUser> selectAllUser(Map<String, Object> param);

mapper.xml定义如下

<!-- 查询陈姓男性用户信息 -->
<select id="selectAllUser"  resultType="com.po.MyUser" parameterType="map">
    select * from user 
    where uname like concat('%',#{u_name},'%')
    and usex = #{u_sex}
</select>

Map的key为String类型,代表属性名,上述SQL文件中参数名u_name和u_sex是Map的key。Map的value为Object类型,代表属性值,

使用Map不能限定其传递的数据类型,所以业务性不强,可读性较差。

2.1.2 使用JavaBean传参

为结果集建立一个专门的类,类的属性与结果集的列名一一对应 建立的bean如下

package com.pojo;
public class SeletUserParam {
    private String u_name;
    private String u_sex;
    public String getU_name() {
        return u_name;
    }
    public void setU_name(String u_name) {
        this.u_name = u_name;
    }
    public String getU_sex() {
        return u_sex;
    }
    public void setU_sex(String u_sex) {
        this.u_sex = u_sex;
    }
}

接口定义如下

public List<MyUser> selectAllUser(SeletUserParam param);

mapper.xml定义如下

<select id="selectAllUser"  resultType="com.po.MyUser" parameterType="com.pojo.SeletUserParam">
    select * from user 
    where uname like concat('%',#{u_name},'%')
    and usex = #{u_sex}
</select>

2.2 insert

它的属性与<select>元素的属性大部分相同,它的几个特有属性如下:

属性说明
keyProperty该属性的作用是将插入或更新操作时的返回值赋值给PO类的某个属性,通常会设置为主键对应的属性。如果是联合主键,可以在多个值之间用逗号隔开。
keyColumn该属性用于设置第几列是主键,当主键列不是表中的第一列时需要设置。如果是联合主键时,可以在多个值之间用逗号隔开。
useGeneratedKeys该属性将使MyBatis使用JDBC的getGeneratedKeys()方法获取由数据库内部生产的主键,如MySQL、SQL Server等自动递增的字段,其默认值为false。

启用主键回填(主键自增):

<!-- 添加一个用户,成功后将主键值回填给uid(po类的属性)-->
<insert id="addUser" parameterType="com.po.MyUser"  keyProperty="uid" useGeneratedKeys="true">
    insert into user (uname,usex) values(#{uname},#{usex})
</insert>

如果不支持主键自增使用MyBatis的<selectKey>元素来自定义生成主键

<insert id="insertUser" parameterType="com.po.MyUser">

    <!-- 先使用selectKey元素定义主键,然后再定义SQL语句 -->
    <selectKey keyProperty="uid" resultType="Integer" order="BEFORE">
       select if(max(uid) is null, 1 , max(uid)+1) as newUid from user
    </selectKey>
    
    insert into user (uid,uname,usex) values(#{uid},#{uname},#{usex}) 
</insert>

2.3 update与delete

<!-- 修改一个用户 -->
<update id="updateUser" parameterType="com.po.MyUser">
    update user set uname = #{uname},usex = #{usex} where uid = #{uid}
</update>
<!-- 删除一个用户 -->
<delete id="deleteUser" parameterType="Integer"> 
    delete from user where uid = #{uid}
</delete>

2.4 sql

元素的作用在于可以定义SQL语句的一部分(代码片段),方便后面的SQL语句引用它,比如反复使用的列名。

<!-- 定义一个代码片段 -->
<sql id="comColumns">uid,uname,usex</sql>

<!-- 使用改代码片段 -->
<select id="selectUser" resultType="com.po.MyUser">
    select 
    <include refid="comColumns"/> from user    
</select>

2.5 resultMap

<resultMap>元素表示结果映射集,是MyBatis中最重要也是最强大的元素。主要用来定义映射规则、级联的更新以及定义类型转化器等。

<resultMap type="" id="">
    <constructor>    <!-- 类在实例化时,用来注入结果到构造方法 -->
        <idArg/>     <!-- ID参数,结果为ID -->
        <arg/>       <!-- 注入到构造方法的一个普通结果 -->
    </constructor>
    <id/>      <!-- 用于表示哪个列是主键 -->
    <result/>  <!-- 表示POJO和数据表列的映射关系 -->
    <association property=""/>     <!-- 用于一对一关联 -->
    <collection property=""/>      <!-- 用于一对多、多对多关联 -->
    <discriminator javaType="">    <!-- 使用结果值来决定使用哪个结果映射 -->
        <case value=""/>   <!-- 基于某些值的结果映射 -->
    </discriminator>
</resultMap>

type属性表示需要的POJO,id属性是resultMap的唯一标识。子元素<association><collection><discriminator>用在级联的情况下。

存储查询结果有两种方式:Map,POJO

2.5.1 使用Map存储结果

UserDao.java

package com.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Repository("userDao")
@Mapper
public interface UserDao {
	public List<Map<String,Object>> selectAll();
}

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.dao.UserDao">
	<select id="selectAll" resultType="map">
		select * from user
	</select>
</mapper>

UserController.java

package com.controller;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.dao.UserDao;

@Controller("userController")
public class UserController {
	@Autowired
	private UserDao userDao;
	public void test() {
		List<Map<String,Object>> tmp= userDao.selectAll();
		for (Map<String,Object> myUser : tmp) {
			System.out.println(myUser);
		}
	}
}

2.5.2 使用POJO存储结果

使用POJO结果,可以使用resultType自动映射,但有时候需要更为复杂的映射或级联,这时候就需要使用<select>元素的resultMap属性配置映射集合。

resultMap基本使用如下

  1. 创建POJO类MapUser对应结果集合
package com.pojo;
public class MapUser {
	private Integer m_uid;
	private String m_uname;
	private String m_usex;
	public Integer getM_uid() {
		return m_uid;
	} 
	public void setM_uid(Integer m_uid) {
		this.m_uid = m_uid;
	}
	public String getM_uname() {
		return m_uname;
	}
	public void setM_uname(String m_uname) {
		this.m_uname = m_uname;
	}
	public String getM_usex() {
		return m_usex;
	}
	public void setM_usex(String m_usex) {
		this.m_usex = m_usex;
	}
	@Override
	public String toString() {
		return "User [uid=" + m_uid +",uname=" + m_uname + ",usex=" + m_usex +"]";
	}
}
  1. 在mapper.xml中配置resultMap将POJO类和结果集列对应起来,并在查询时使用该resultMap
<?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.dao.UserDao">


    <!-- 自定义结果集类型 -->
    <resultMap type="com.pojo.MapUser" id="myResult">
            <!-- property是com.pojo.MapUser类中的属性-->
            <!-- column是查询结果的列名,可以来自不同的表 -->
            <id property="m_uid" column="uid"/>
            <result property="m_uname" column="uname"/>
            <result property="m_usex" column="usex"/>
    </resultMap>
    
    
    <!-- 使用自定义结果集类型查询所有用户 -->
    <select id="selectResultMap" resultMap="myResult">
            select * from user
    </select>
</mapper>
  1. 接口方法
public List<MapUser> selectResultMap();

2.6 级联查询

如果表A中有一个外键引用了表B的主键,A表就是子表,B表就是父表。当查询表A的数据时,通过表A的外键,也将表B的相关记录返回,这就是级联查询。例如,查询一个人的信息时,同时根据外键(身份证号)也将他的身份证信息返回。

2.6.1 一对一级联

person表有id,name,age,idcard_id。idcard表有id,code

一对一级联查询有三种实现方式:嵌套查询,嵌套结果,使用POJO

1. 建立PO/POJO

Idcard类对应idcard表

package com.po;
public class Idcard {
	private Integer id;
	private String code;
	//getter, setter, toString方法省略了
}

Person对应person表,同时包括级联查询出的idcard的信息

package com.po;
public class Person {
	private Integer id;
	private String name;
	private Integer age;
	private Idcard card;	//个人身份证关联
	//getter, setter, toString方法省略了
}

SelectPersonById,对应结果表建立的POJO类,用于第三种级联查询方法

package com.pojo;

public class SelectPersonById {
	private Integer id;
	private String name;
	private Integer age;
	private String code;
	//getter, setter, toString方法省略了
}

2. 编写Dao层查询接口

IdCardDao.java

@Repository("idCardDao")
@Mapper
public interface IdCardDao {
	public Idcard selectCodeById(Integer i);
}

PersonDao.java,对应三种一对一级联查询方法

@Repository("personDao")
@Mapper
public interface PersonDao {
	public Person selectPersonById1(Integer id);
	public Person selectPersonById2(Integer id);
	public SelectPersonById selectPersonById3(Integer id);
}

3. 编写IdcardMapper和PersonMapper映射文件

IdcardMapper.xml

<mapper namespace="com.dao.IdCardDao">
	<select id="selectCodeById" parameterType="Integer" resultType="com.po.Idcard">
		select * from idcard where id=#{id}
	</select>
</mapper>

PersonMapper.xml

<mapper namespace="com.dao.PersonDao">

	<!-- 一对一 根据id查询个人信息:第一种方法(嵌套查询) -->
	<resultMap type="com.po.Person" id="cardAndPerson1">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="age" column="age"/>
		<!-- 一对一关联查询 -->
		<association property="card" column="idcard_id" javaType="com.po.Idcard"
		select="com.dao.IdCardDao.selectCodeById"/>
	</resultMap>
	<select id="selectPersonById1" parameterType="Integer" resultMap="cardAndPerson1">
		select * from person where id=#{id}
	</select>
        
        
	<!-- 一对一 根据id查询个人信息:第二种方法(嵌套结果) -->
	<resultMap type="com.po.Person" id="cardAndPerson2">
		<id property="id" column="id"/>
		<result property="name" column="name"/>
		<result property="age" column="age"/>
		<!-- 一对一关联查询 -->
		<association property="card" javaType="com.po.Idcard">
			<id property="id" column="idcard_id"/>
			<result property="code" column="code"/>
		</association>
	</resultMap>
	<select id="selectPersonById2" parameterType="Integer" resultMap="cardAndPerson2">
		select p.*,ic.code 
		from person p, idcard ic 
		where p.idcard_id = ic.id and p.id=#{id}
	</select>
        
        
        
	<!-- 一对一 根据id查询个人信息:第三种方法(使用POJO存储结果) -->
	<select id="selectPersonById3" parameterType="Integer" resultType="com.pojo.SelectPersonById">
		select p.*,ic.code 
		from person p, idcard ic 
		where p.idcard_id = ic.id and p.id=#{id}
	</select>
</mapper>

4. 配置mybatis-config.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>
	<!-- 在使用MyBatis嵌套查询方式进行关联查询时,使用MyBatis的延迟加载在一定程度可以提高查询效率 -->
	<settings>
		<!-- 打开延迟加载的开关 -->
		<setting name="lazyLoadingEnabled" value="true" />
		<!-- 将积极加载改为按需加载 -->
		<setting name="aggressiveLazyLoading" value="false" />
	</settings>

	<mappers><!-- 映射器,告诉 MyBatis到哪里去找映射文件 -->
		<mapper resource="com/mybatis/PersonMapper.xml" />
		<mapper resource="com/mybatis/IdCardMapper.xml" />
	</mappers>
</configuration>

5. 配置application.xml,在这里对MyBatis进行配置,并开启扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:tx="http://www.springframework.org/schema/tx" 
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/tx
		http://www.springframework.org/schema/tx/spring-tx.xsd">
                
    <context:component-scan base-package="com.dao"/>
    <context:component-scan base-package="com.controller"/> 

    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:3306/sql_tmp?characterEncoding=utf8&amp;useSSL=false" />
        <property name="username" value="root" />
        <property name="password" value="20011017lh" />
        <property name="maxTotal" value="30"/>
        <property name="maxIdle" value="10"/>
        <property name="initialSize" value="5"/>
    </bean>
    
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <property name="configLocation" value="classpath:com/mybatis/mybatis-config.xml"/>
    </bean>  
    
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dao"/>
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
    </bean>
</beans>

6. 建立Controller类和测试类 OneToOneController.java

package com.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import com.dao.PersonDao;
import com.po.Person;
import com.pojo.SelectPersonById;
@Controller("oneToOneController")
public class OneToOneController {
	@Autowired
	private PersonDao personDao;
	public void test() {
		Person p1 = personDao.selectPersonById1(1);
		System.out.println(p1);
		System.out.println("=======================");
		Person p2 = personDao.selectPersonById2(1);
		System.out.println(p2);
		System.out.println("=======================");
		SelectPersonById p3 = personDao.selectPersonById3(1);
		System.out.println(p3);
	}
}

TestOneToOne.java

package com.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestOneToOne {
	public static void main(String[] args) {
		@SuppressWarnings("resource")
		ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
		OneToOneController oto = (OneToOneController)appCon.getBean("oneToOneController");
		oto.test();
	}
}

最后输出

Person [id=1,name=陈,age=88,card=Idcard [id=1,code=123456789123456789]]
=======================
Person [id=1,name=陈,age=88,card=Idcard [id=1,code=123456789123456789]]
=======================
Person [id=1,name=陈,age=88,code=123456789123456789]

2.6.2 一对多级联

一个用户可以有多个订单,一对多查询(实现“根据用户id查询用户及其关联的订单信息”的功能)的处理过程如下。

1. 建立PO/POJO

Product.java

package com.po;
public class Product {
	private Integer id;
	private String name;
	private Double price;
	private List<Orders> orders;
	//getter和setter和toString
}

MyUser.java

package com.po;
public class MyUser {
	private Integer uid;//主键
	private String uname;
	private String usex;
	//一对多关联查询,用户关联的订单
	private List<Orders> ordersList;
	//getter和setter和toString
}

Orders.java

package com.po;
public class Orders {
	private Integer id;
	private  String ordersn;
	private List<Product> products;
        //getter和setter和toString
}

SelectUserOrdersById.java

package com.pojo;
public class SelectUserOrdersById {
	private Integer uid;
	private String uname;
	private String usex;
	private Integer id;
	private String ordersn;
	//getter和setter和toString
}

2. 建立Dao层接口提供操作数据库的方法

OrdersDao.java

package com.dao;
@Repository("ordersDao")
@Mapper
public interface OrdersDao {
	public List<Orders> selectOrdersById(Integer uid);
	public List<Orders> selectallOrdersAndProducts();
}

UserDao.java

package com.dao;
@Repository("userDao")
@Mapper

public interface UserDao {
	public MyUser selectUserOrdersById1(Integer uid);
	public MyUser selectUserOrdersById2(Integer uid);
	public List<SelectUserOrdersById> selectUserOrdersById3(Integer uid);
}

3. 编写映射文件提供sql语句映射规则和级联规则

OrdersMapper.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.dao.OrdersDao">
	<!-- 根据用户uid查询订单信息 -->
	<select id="selectOrdersById" parameterType="Integer" resultType="com.po.Orders">
		select * from orders where user_id=#{id}
	</select>
</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.dao.UserDao">


	<!-- 一对多 根据uid查询用户及其关联的订单信息:第一种方法(嵌套查询) -->
	<resultMap type="com.po.MyUser" id="userAndOrders1">
		<id property="uid" column="uid"/>
		<result property="uname" column="uname"/>
		<result property="usex" column="usex"/>
		<!-- 一对多关联查询,ofType表示集合中的元素类型,将uid传递给selectOrdersById-->
		<collection property="ordersList" ofType="com.po.Orders" column="uid" 
		 select="com.dao.OrdersDao.selectOrdersById"/>
	</resultMap>
	<select id="selectUserOrdersById1" parameterType="Integer" resultMap="userAndOrders1">
		select * from user where uid = #{id}
	</select>
        
        
        
	<!-- 一对多 根据uid查询用户及其关联的订单信息:第二种方法(嵌套结果) -->
	<resultMap type="com.po.MyUser" id="userAndOrders2">
		<id property="uid" column="uid"/>
		<result property="uname" column="uname"/>
		<result property="usex" column="usex"/>
		<!-- 一对多关联查询,ofType表示集合中的元素类型 -->
		<collection property="ordersList" ofType="com.po.Orders" >
			<id property="id" column="id"/>
			<result property="ordersn" column="ordersn"/>
		</collection>
	</resultMap>
	<select id="selectUserOrdersById2" parameterType="Integer" resultMap="userAndOrders2">
		select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}
	</select>
        
        
        
	<!-- 一对多 根据uid查询用户及其关联的订单信息:第三种方法(使用POJO存储结果) -->
	<select id="selectUserOrdersById3" parameterType="Integer" resultType="com.pojo.SelectUserOrdersById">
		select u.*,o.id,o.ordersn from user u, orders o where u.uid = o.user_id and u.uid=#{id}
	</select>
</mapper>

4. 配置mybatis-config.xml,配置映射文件的位置,开启按需加载

<mappers><!-- 映射器,告诉 MyBatis到哪里去找映射文件 -->
   <mapper resource="com/mybatis/UserMapper.xml" />
   <mapper resource="com/mybatis/OrdersMapper.xml" />
</mappers>

5. 配置application.xml,包括配置MyBatis和开启扫描

6. 控制层

package com.controller;
@Controller("oneToMoreController")
public class OneToMoreController {
	@Autowired
	private UserDao userDao;
	public void test() {
		//查询一个用户及订单信息
		MyUser auser1 = userDao.selectUserOrdersById1(1);
		System.out.println(auser1);
		System.out.println("===================================");
		MyUser auser2 = userDao.selectUserOrdersById2(1);
		System.out.println(auser2);
		System.out.println("===================================");
		List<SelectUserOrdersById> auser3 = userDao.selectUserOrdersById3(1);
		System.out.println(auser3);
		System.out.println("===================================");
	}
}

7. 测试

package com.controller;
public class TestOneToMore {
	public static void main(String[] args) {
		ApplicationContext appCon = new ClassPathXmlApplicationContext("applicationContext.xml");
		OneToMoreController otm = (OneToMoreController)appCon.getBean("oneToMoreController");
		otm.test();
	}
}

输出

User [uid=1,uname=张三,usex=女,ordersList=[Orders [id=1,ordersn=999999]null, Orders [id=2,ordersn=88888]null]]
===================================
User [uid=1,uname=张三,usex=女,ordersList=[Orders [id=1,ordersn=999999]null, Orders [id=2,ordersn=88888]null]]
===================================
[User [uid=1,uname=张三,usex=女,oid=1,ordersn=999999], User [uid=1,uname=张三,usex=女,oid=2,ordersn=88888]]
===================================

2.6.3 多对多级联

基本流程和上面俩都类似

<!-- 多对多关联 查询所有订单以及每个订单对应的商品信息(嵌套结果) -->
<resultMap type="com.po.Orders" id="allOrdersAndProducts">
	<id property="id" column="id"/>
	<result property="ordersn" column="ordersn"/>
	<!-- 多对多关联 -->
	<collection property="products" ofType="com.po.Product">
		<id property="id" column="pid"/>
		<result property="name" column="name"/>
		<result property="price" column="price"/>
	</collection>
</resultMap>
<select id="selectallOrdersAndProducts" resultMap="allOrdersAndProducts">
	select o.*,p.id as pid,p.name,p.price
	from orders o,orders_detail od,product p
	where od.orders_id = o.id 
	and od.product_id = p.id
</select>

动态SQL

3.1 <if>元素

类似于Java中的if语句

注意where 1=1

<!-- 使用if元素,根据条件动态查询用户信息 -->
<select id="selectUserByIf"  resultType="com.po.MyUser" parameterType="com.po.MyUser">
        select * from user where 1=1        
    <if test="uname !=null and uname!=''">
            and uname like concat('%',#{uname},'%')
        </if>
    <if test="usex !=null and usex!=''">
            and usex = #{usex}
        </if>
</select>

3.2 <choose><when><otherwise>元素

像Java中的 switch 语句

<!-- 使用choose、when、otherwise元素,根据条件动态查询用户信息 -->
<select id="selectUserByChoose"  resultType="com.po.MyUser" parameterType="com.po.MyUser">
        select * from user where 1=1        
    <choose>
        <when test="uname !=null and uname!=''">
            and uname like concat('%',#{uname},'%')
        </when>
        <when test="usex !=null and usex!=''">
            and usex = #{usex}
        </when>
        <otherwise>
            and uid > 10
        </otherwise>
    </choose>
</select>

3.3 <trim><where><set>元素

<trim>元素在自己包含的内容前加上前缀prefix或后缀suffix。prefixOverrides和suffixOverrides会把包含内容的首部或尾部某些内容覆盖。

示例中为添加前缀where,如果包含内容首部带and或者or,prefixOverrides会将其去除

<!-- 使用trim元素,根据条件动态查询用户信息 -->
<select id="selectUserByTrim"  resultType="com.po.MyUser" parameterType="com.po.MyUser">
        select * from user      
    <trim prefix="where" prefixOverrides="and |or">
        <if test="uname !=null and uname!=''">  
                and uname like concat('%',#{uname},'%')
        </if>
        <if test="usex !=null and usex!=''">  
                and usex = #{usex} 
        </if>
    </trim>
</select>

<where>元素输出一个where语句,不需要考虑条件输出是什么。

如果所有的条件都不满足,那么MyBatis就会查出所有的记录。

如果输出后是and或or开头的,MyBatis会忽略;

<where>元素中不需要考虑空格。

<!-- 使用where元素,根据条件动态查询用户信息 -->
<select id="selectUserByWhere"  resultType="com.po.MyUser" parameterType="com.po.MyUser">
        select * from user      
    <where>
        <if test="uname !=null and uname!=''">
                and uname like concat('%',#{uname},'%')
            </if>
        <if test="usex !=null and usex!=''">
                and usex = #{usex}
            </if>
    </where>
</select>

在动态update语句中,用<set>元素动态更新列。 <set>标签既有set关键字的作用,还可以自动去掉拼接后的字符串最后一个“,”

update user  set uname=#{uname} where uid = #{uid} 
<!-- 使用set元素,动态修改一个用户 -->
<update id="updateUserBySet" parameterType="com.po.MyUser">
        update user     
    <set>
        <if test="uname != null">uname=#{uname},</if>
        <if test="usex != null">usex=#{usex}</if>
    </set>
        where uid = #{uid}  
</update>

3.4 <foreach>元素

<foreach>元素主要用在构建in条件中,可以在SQL语句中迭代一个集合。

foreach元素的属性主要有item,index,collection,open,separator,close。

item表示集合中每一个元素进行迭代时的别名,

index指定一个名字,用于表示在迭代过程中,每次迭代到的位置,

open表示该语句以什么开始,

separator表示在每次进行迭代之间以什么符号作为分隔符,

close表示以什么结束。

collection属性是必选的,该属性的值主要有以下3种情况:

  • 传入单参数且参数类型是一个List的时候,collection属性值为list。
  • 传入单参数且参数类型是一个array数组的时候,collection的属性值为array。
  • 传入多个参数时,需要把它们封装成一个Map,当然单参数也可以封装成Map。Map的key是参数名,collection属性值是传入的List或array对象在自己封装的Map中的key。
<!-- 使用foreach元素,查询用户信息 -->
<select id="selectUserByForeach" resultType="com.po.MyUser"  parameterType="List">
        select * from user where uid in     
    <foreach item="item" index="index" collection="list" open="(" separator="," close=")">
        #{item}
    </foreach>
</select>

3.5 <bind>元素

在模糊查询时,用“${}”拼接字符串,则无法防止SQL注入问题。

不同数据库的拼接函数或连接符号不同,如MySQL的concat函数、Oracle的连接符号“||”。比较麻烦,且不利于代码的移植。

MyBatis提供了元素来解决这一问题。

以往的模糊查询方式:

%表示任意个或多个字符。可匹配任意类型和长度的字符。如

select * from user where name like "%zhang%"

在实际的使用中,条件是作为参数传递进来的。 所以我们使用 concat() 函数连接字符串,concat(str1,str2,str3,str4,…); 连接字符串函数,会生成一个字符串str1str2str3str4…

<select id="findByUsername" parameterType="String" resultType="user">
    SELECT * FROM user WHERE username LIKE concat('%',#{username},'%')
</select>

bind元素的引入

<!-- 使用bind元素进行模糊查询 -->
<select id="selectUserByBind" resultType="com.po.MyUser"  parameterType="com.po.MyUser">
    <!-- bind中uname是com.po.MyUser的属性名 -->
    <bind name="paran_uname" value="'%' + uname + '%'"/>
        select * from user where uname like #{paran_uname}  
</select>