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>
映射器
映射器规定了SQL语句的映射规则,有两种实现方法:一是基于接口与XML,一是基于接口与注解(不常用)。XML映射器中常用的元素如下
| 元素名称 | 描述 | 备注 |
|---|---|---|
| select | 查询 | 自定义参数和结果集 |
| insert | 插入 | 返回一个整数,代表插入的行数 |
| update | 更新 | 返回一个整数,代表更新的行数 |
| delete | 删除 | 返回一个整数,代表删除的行数 |
| sql | 定义sql短语,可以在其他位置引用 | 相当于给表名列名起了别名 |
| resultMap | 对结果集进行映射,后面会细讲 | 提供映射规则 |
2.1 select
示例为接收一个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基本使用如下
- 创建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 +"]";
}
}
- 在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>
- 接口方法
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&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>