MyBatis---联合查询、分步查询和动态SQL

MyBatis的增删改之后,一定要提交事物!!!

在MySQL中有个特殊的规定,即不允许使用列别名作为查询条件

一个主人可以养很多条小狗狗,但是一条狗只有一个主人。那主键肯定只能放在dog表里面。

数据库表结构
Alt
Alt


一、联合查询

1、一对一(使用左连接)
	public class Dog {
	    private int id;
	    private String name;
	    private Host host;
	    ...
	}
	public class Host {
	    private int HOST_ID;
	    private String HOST_NAME;
	    private List<Dog> HOST_DOGS;
	    ...
	}
	<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

	<mapper namespace="com.cj.dao.DogDao">
	    <select id="QueryById" resultMap="dogMapping">
	        select d.*,h.* from dog d left join host h on d.DOG_HOST_ID=h.HOST_ID where d.DOG_ID=#{id}
	    </select>
	    <resultMap id="dogMapping" type="com.cj.entity.Dog">
	        <id column="DOG_ID" property="id"></id>
	        <result column="DOG_NAME" property="name"></result>
	<!--        级联封装-->
	<!--        <result property="DOG_HOST.HOST_ID" column="DOG_HOST_ID"></result>-->
	<!--        <result property="DOG_HOST.HOST_NAME" column="HOST_NAME"></result>-->
	
	
	<!--        用javaType指定javaBean的类型-->
	        <association property="host" javaType="com.cj.entity.Host">
	            <id property="HOST_ID" column="HOST_ID"></id>
	            <result property="HOST_NAME" column="HOST_NAME"></result>
	        </association>
	    </resultMap>
	</mapper>
	public interface DogDao {
	    /**
	     * 查询dog表中的主键, 返回单个dog对象
	     * @param id
	     * @return
	     */
	    public Dog QueryById(Integer id);
	}
	@Test
    public void test08() throws IOException {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            sqlSession = sqlSessionFactory.openSession();   //增删改需要设置自动提交, 查询不需要手动设置
            DogDao dogDao = sqlSession.getMapper(DogDao.class);
            Dog dog = dogDao.QueryById(2);
            System.out.println(dog);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

       测试结果:
Alt


2、一对多(不用连接)
	<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

	<mapper namespace="com.cj.dao.HostDao">
	    <select id="QueryByUnionId" resultMap="hostMapping">
	        select h.*,d.* from host h,dog d where h.HOST_ID=d.DOG_HOST_ID and d.DOG_HOST_ID=#{id};
	    </select>
	    <resultMap id="hostMapping" type="com.cj.entity.Host">
	        <id property="HOST_ID" column="HOST_ID"></id>
	        <result property="HOST_NAME" column="HOST_NAME"></result>
	
	<!--        用ofType指定集合的泛型-->
	        <collection property="HOST_DOGS" ofType="com.cj.entity.Dog">
	            <id property="DOG_ID" column="DOG_ID"></id>
	            <result property="DOG_NAME" column="DOG_NAME"></result>
	        </collection>
	    </resultMap>
	</mapper>
	public interface HostDao {
	    /**
	     * 查询dog表中的hostId返回host列表
	     * @param id
	     * @return
	     */
	    public List<Host> QueryByUnionId(Integer id);
	}
	@Test
    public void test09() throws IOException {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            sqlSession = sqlSessionFactory.openSession();   //增删改需要设置自动提交, 查询不需要手动设置
            HostDao hostDao = sqlSession.getMapper(HostDao.class);
            List<Host> hosts = hostDao.QueryByUnionId(1);
            System.out.println(hosts);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

       测试结果:
Alt


二、分步查询(提高性能)

       对于分步查询,MyBatis框架能对性能进行优化,以后多用分步查询吧!

       全局配置文件中开启延迟加载和按需加载:

	<configuration>
	    <settings>
	        <!-- 开启延迟加载开关 -->
	        <setting name="lazyLoadingEnabled" value="true"/>
	        <!-- 开启属性按需加载 -->
	        <setting name="aggressiveLazyLoading" value="false"/>
	    </settings>
	    ...
	</configuration>
	public interface DogDao {
	    /**
	     * 查询dog表中的主键, 返回单个dog对象
	     *
	     * @param id
	     * @return
	     */
	    public Dog QueryById(Integer id);
	
	    /**
	     * 分步查询第一步
	     *
	     * @param id
	     * @return
	     */
	    public Dog QuerySimple(Integer id);
	}

	public interface HostDao {
	    /**
	     * 查询dog表中的hostId返回host列表
	     *
	     * @param id
	     * @return
	     */
	    public List<Host> QueryByUnionId(Integer id);
	
	    /**
	     * 分步查询第二步
	     *
	     * @param id
	     * @return
	     */
	    public Host QuerySimple(Integer id);
	}

	<select id="QuerySimple" resultMap="simpleMapping">
        select * from dog where DOG_ID=#{id}
    </select>
    <resultMap id="simpleMapping" type="com.cj.entity.Dog">
        <id property="DOG_ID" column="DOG_ID"></id>
        <result property="DOG_NAME" column="DOG_NAME"></result>
<!--        select标签指定已经查询出来的host对象, column标签指定传入的参数(第一步查询已经查出来的DOG_HOST_ID)-->
        <association property="DOG_HOST" select="com.cj.dao.HostDao.QuerySimple" column="DOG_HOST_ID"></association>
    </resultMap>
	<select id="QuerySimple" resultType="com.cj.entity.Host">
        select * from host where HOST_ID=#{id}
    </select>

       测试结果:
Alt

三、动态SQL

       数据库表结构
Alt

1、动态拼接where条件
	public class Person {
	    private Integer PERSON_ID;
	    private String PERSON_NAME;
	    private Integer PERSON_GENDER;
	    private Integer PERSON_AGE;
	    ...
	}
	public interface PersonDao {
	    public Person Query(Integer id, String name);
	}
	<select id="Query" resultType="com.cj.entity.Person">
        select * from person
        <where>
            -- 因为传入了多个参数, 所以用paramn取参数, 当传入POJO的时候, 直接用成员变量取值
            <if test="param1!=null and !''.equals(param1)">
--                 只有if没有else, 想用else的情况需要用choose标签
                and PERSON_ID=#{param1}
            </if>
            <if test="param2!=null and !''.equals(param2)">
                and PERSON_NAME=#{param2}
            </if>
        </where>
    </select>
	@Test
    public void test11() throws IOException {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            sqlSession = sqlSessionFactory.openSession();   //增删改需要设置自动提交, 查询不需要手动设置
            PersonDao personDao = sqlSession.getMapper(PersonDao.class);
            Person person = personDao.Query(2, "越前龙马");
            System.out.println(person);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

       测试结果:
Alt
小结
       where标签会自动去除前面的and


2、动态遍历拼接
	public interface PersonDao {
	    public Person Query(Integer id, String name);
	
	    //@Param注解指定参数名
	    public List<Person> QueryByListId(@Param("ids") List<Integer> ids);
	    ...
	}
	<select id="QueryByListId" resultType="com.cj.entity.Person">
        select * from person
        <where>
            PERSON_ID in
            <foreach collection="ids" item="id" open="(" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
	@Test
    public void test12() throws IOException {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            sqlSession = sqlSessionFactory.openSession();   //增删改需要设置自动提交, 查询不需要手动设置
            PersonDao personDao = sqlSession.getMapper(PersonDao.class);
            List<Person> persons = personDao.QueryByListId(Arrays.asList(1, 2));
            System.out.println(persons);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

       测试结果:
Alt
小结
       foreach 标签的separator属性指定分隔符,并且会自动删除某位的分隔符。collection属性指定遍历的集合。


3、动态拼接set语句
	public interface PersonDao {
	    public Person Query(Integer id, String name);
	
	    //@Param注解指定参数名
	    public List<Person> QueryByListId(@Param("ids") List<Integer> ids);
	
	    public int Update(Person person);
	}
	<update id="Update">
        update person
        <set>
            <if test="PERSON_NAME!=null and !''.equals(PERSON_NAME)">
                PERSON_NAME=#{PERSON_NAME},
            </if>
            <if test="PERSON_GENDER!=null and !''.equals(PERSON_GENDER)">
                PERSON_GENDER=#{PERSON_GENDER},
            </if>
            <if test="PERSON_AGE!=null and !''.equals(PERSON_AGE)">
                PERSON_AGE=#{PERSON_AGE},
            </if>
        </set>
        <where>
            PERSON_ID=#{PERSON_ID}
        </where>
    </update>
	@Test
    public void test13() throws IOException {
        String resource = "mybatis-config.xml";
        SqlSessionFactory sqlSessionFactory = null;
        SqlSession sqlSession = null;
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

            sqlSession = sqlSessionFactory.openSession(true);   //增删改需要设置自动提交, 查询不需要手动设置
            PersonDao personDao = sqlSession.getMapper(PersonDao.class);
            Person person = new Person(2, "越前", 1, null);
            int i = personDao.Update(person);
            System.out.println(i);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            sqlSession.close();
        }
    }

       测试结果:
Alt
小结
       set标签会自动删除末尾的逗号,set标签结合if标签可以完成全字段更新引发的问题,替代了ModelAttribute注解!

       要想将MyBatis更新数据的返回值设置为受影响的行数,则需要在URL中加上&amp;useAffectedRows=true。究其根源其实&在xml中无法使用的,需要用转译字符&amp;

发布了33 篇原创文章 · 获赞 5 · 访问量 2277

猜你喜欢

转载自blog.csdn.net/cj1561435010/article/details/104087359