MyBatis的动态SQL

310 阅读4分钟

if标签

我们可以根据bean类属性的不同取值,来使用不同的SQL语句来进行查询。比如若id值不为空时根据id值查询,若name不为空时还要加入name作为判断条件。

示例

数据表account:

CREATE TABLE `account`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

bean类:

public class Account {
    private Integer id;
    private String name;
    private String password;
    //省略 get/set方法
}

mybatis配置文件:

<?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>
    <properties resource="jdbcConfig.properties">
    </properties>

    <typeAliases>
        <package name="com.on1.bean"/>
    </typeAliases>
    
    <environments default="mysql">

        <environment id="mysql">
            <!--配置事务类型:使用了 JDBC 的提交和回滚设置-->
            <transactionManager type="JDBC"/>
            <!--配置数据池-->
            <dataSource type="UNPOOLED">
                <!--连接数据库的基本信息-->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>

        <mapper resource="com/on1/dao/AccountDao.xml"/>
    </mappers>
</configuration>

映射文件:

<?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.on1.dao.AccountDao">

    <!-- 已在配置文件中通过typeAliases标签为bean包下的类自动起别名,因次直接写类名即可-->
    <!--    根据传入参数条件查询-->
    <select id="findAccountByCondition" parameterType="Account"  resultType="account">
        select * from account where 1 = 1
        <if test="name != null">
            and name = #{name}
        </if>
    </select>
</mapper>

where 1=1; 这个条件始终为True,在不定数量查询条件情况下,1=1可以很方便的规范语句。

dao接口:

public interface AccountDao {
//    根据条件查询
    List<Account> findAccountByCondition(Account account);
}

测试类:

public class day2 {
    InputStream in;
    SqlSession sqlSession;
    AccountDao accountDao;

    @Before
    public void init() throws Exception {
        //        加载配置文件
        in = Resources.getResourceAsStream("mybatisConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        //        获取代理对象
        accountDao = sqlSession.getMapper(AccountDao.class);
    }

    @After
    public void destroy() throws Exception {
        sqlSession.close();
        in.close();
    }

    @Test
    public void testFindAccountByCondition() {
        Account account = new Account();
        account.setName("王adac");
        List<Account> accountList = accountDao.findAccountByCondition(account);
        for(Account tmp : accountList)
            System.out.println(tmp);
    }
}

控制台输出:

如果还希望将password作为条件,则在映射文件在添加:

<if test="password != null">
    and password like #{password}
</if>

测试方法中添加:

account.setPassword("e1e");

控制台输出:

我们可以通过where标签来省略1 = 1语句:

<select id="findAccountByCondition" parameterType="Account"  resultType="account">
        select * from account
        <where>
            <if test="name != null">
                and name = #{name}
            </if>
            <if test="password != null">
                and password = #{password}
            </if>
        </where>
    </select>

若希望进行模糊查询:

 <if test="name != null">
    and name like #{name}
 </if>

测试类方法中:

account.setName("%王%");

foreach标签

有时我们希望传入多个id值来得出多个账户信息,比如:

select * from user where id in (1,3,5);

这样我们就需要将这些多个id值通过一个集合来作为参数添加到sql语句中,此处我们将起包装成一个条件类Bank

public class Bank {
    List<Integer> ids;
    //省略get/set方法
}

在AccountDao接口添加方法:

List<Account> findAccountByIds(Bank bank);

在映射文件中添加:

<!-- 
    foreach标签用于遍历集合
        collection属性表示要遍历的集合元素名,它必须和bean类里的集合对象名相同;
        open属性后面跟着语句的开始部分;
        close属性表示结束部分;item表示集合遍历的每个元素的变量名;
        sperator属性表示分隔符
-->
<select id="findAccountByIds" parameterType="bank" resultType="account">
        select * from account
        <where>
            <if test="ids != null and ids.size() > 0">
                <foreach collection="ids" open="and id in (" close=")" item="aId" separator=",">
                    #{aId}
                </foreach>
            </if>
        </where>
</select>

测试方法:

@Test
    public void testFindInIds() {
        Bank bank = new Bank();
        List<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(5);
        list.add(3);
        bank.setIds(list);

        List<Account> accountList = accountDao.findAccountByIds(bank);
        for(Account tmp : accountList)
            System.out.println(tmp);
    }

控制台输出:

sql标签

在前面的两个例子中,返回的结果都是符合条件的所有属性名,即

select * from account

我们可以通过sql标签将重复的sql语句提取出来,使用时用include标签引用即可

<sql id="returnAllAttributes">
        select * from account
</sql>

<select id="findByName" parameterType="string" resultType="com.on1.bean.Account">
        <include refid="returnAllAttributes"></include>
            where name like #{name}
</select>

<select id="findAll" resultType="aCcouNt">
        <include refid="returnAllAttributes"></include>
</select>