0
点赞
收藏
分享

微信扫一扫

【Java19】Mybatis:两个xml文件的标签,动态sql的if/choose/where/set/foreach标签,高级查询,注解开发

四月天2021 2022-04-04 阅读 27
mybatisjava

文章目录


1.mybatis-config.xml核心配置文件中标签:test -> interface/impl -> sql

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//jdbc.properties文件,如下前面加上jdbc.是防止如上 ${}字符串拼接 拿到下面参数,没有拿到方法中参数
jdbc.driverClass=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=root
jdbc.password=root
//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>
    <!--
        1.将jdbc.properties配置文件加载到mybatis的环境中。
        2.通过${key}读取配置文件中的配置信息
        properties声明属性的2种方式:1.resource:相对路径引入外部的properties配置文件
       							    2.property子标签来动态声明
        -->
    <properties resource="jdbc.properties">  <!--在下面第二个environment标签里用到-->
      <!--<property name="username" value="root"></property>-->   <!--这行也可以,和maven里版本声明一样,不用外部jdbc.properties文件,优先级最低-->
    </properties>


<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <settings>
<!--开启驼峰映射,经典的映射规范 : 数据库列名A_COLUMN (小写就行) ————> java属性名aColumn-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>


<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->    
    <typeAliases> <!--类型别名:如下两种方式:这样UserMapper.xml中resultType="User"就行-->
        <!-- 第一种配置方式:typeAlias标签配置单个别名 -->
        <!--<typeAlias type="com.itheima.domain.User" alias="User"></typeAlias>-->       

        <!-- 第二种配置方式:常用,包扫描 ,默认类名就是别名-->
        <package name="com.itheima.domain"></package>
    </typeAliases>


<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <!-- 数据源环境:下行default: 默认采用的环境即数据源配置的环境的id,可换成下面test。-->
    <environments default="development">   
    <!-- 配置单个数据源环境,id是当前环境配置的唯一标识。development开发环境,dist生产环境 -->     
        <environment id="development"> 
            <!--
                如下事务管理: type: JDBC or MANAGED                
                JDBC: 采用jdbc的事务管理。 底层connection.commit/.rollback
                MANAGED: 不采用事务。
             -->
            <transactionManager type="JDBC"/>  <!--采用事务-->

<!---->            
            <!--
                如下配置数据源的具体链接参数:                    
                 type: POOLED: 支持连接池配置,除了最基本的数据源连接参数配置,
                       还可以配置连接池相关的参数如:最大连接数,最大空闲连接数...                                
                       UNPOOLED: 不支持连接池配置。
            -->
            <dataSource type="POOLED">   <!--#{}被动传,${}主动取/拼接-->
                <property name="driver" value="${jdbc.driverClass}"/>  
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>

<!--//-->
        <environment id="test">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${driverClass}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="aaa"/>
                <property name="password" value="bbb"/>
            </dataSource>
        </environment>
    </environments>


<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->    
    <mappers>  <!--告知mybatis映射文件的位置,一般一个接口对应一个xxxMapper映射文件-->
<!-- 第一种配置: 相对路径配置映射文件的位置 -->
        <!--<mapper resource="UserMapper.xml"/>-->
<!-- 第二种配置:url绝对路径方式,肯定不用 -->
        <!--  <mapper url="file:///var/mappers/AuthorMapper.xml"/>-->


<!-- 第三种配置:采用接口的全路径配置方式
             此处注意:虽然配置的是类的全路径,但是我们都知道,io流读取资源的本质都是需要知道
                      文件的名字和位置。 
                                                                 
                所以: 我们需要通过接口的全路径 com.itheima.mapper.UserMapper
                      能够知道接口对应的映射文件的  位置  和 名字。

         文件的位置和名字必须得满足2个规范: 1.mapper文件名 必须和 接口的名字 一致。
                                         2.mapper文件 必须和 接口 放在同一个包下。
         所以将UserMapper.xml和UserMapper.java文件放在com.itheima.mapper文件夹下
        -->
       <!-- <mapper class="com.itheima.mapper.UserMapper"></mapper>-->


<!-- 第四种配置:包扫描方式 ,基于第三种的规范。-->   
       <!-- <package name="com.itheima.mapper"></package>-->

        <!--要么第一种,要么第四种,如下第一种-->
        <mapper resource="com/itheima/mapper/UserMapper.xml"></mapper>
        <mapper resource="com/itheima/mapper/commonSql.xml"></mapper> <!--不要忘了引入-->
    </mappers>
</configuration>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2.UserMapper.xml映射文件中增删改查标签:动态代理规定namespace,id

mybatis-config.xml中< typeAliases > 和< mappers > 规定resultType和文件名。

2.1 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.itheima.mapper.UserMapper">
    <!--
        select: 查询的statement(声明),用来编写查询语句
        id: 语句的唯一标识
        resultType:配置返回的结果集类型
        parameterType:传递的参数类型,可以省略
    -->
    <select id="findUserById" resultType="User">
        select * from tb_user where id = #{a}
    </select>

    <!--
        useGeneratedKeys=true, 开启主键的自动回显。(主键必须是自增长的)
        keyProperty="id" 主键属性值回显到的实体的属性名  //user对象的id属性
        keyColumn="id"  主键的列名
     -->
    <insert id="addUser" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
        insert into tb_user(user_name,password,name) values(#{userName},#{password},#{name})
    </insert>

    <!--
            #{} : 预编译的传参方式
            1.如果传递 单个 基本类型参数,sql语句中的参数名可以是任意名称,如上findUserById中#{a}  
            
            2.如果传递的是多个基本类型参数
               a. #{arg0} #{arg1}  或者  #{param1} #{param2} 获取方法传递的参数(不推荐)
               b. 注解方式(推荐),在方法的参数上使用@Param(参数名),
                    在sql语句中 #{参数名} 来引入 方法调用时 传递的参数,两参数名要一样。
                                        
            3.对象类型的参数:#{property}  property就是对象的属性名。                   
            4.Hash类型的参数:#{key}  key就是map集合中的key。

            ${} : 字符串拼接方式,格式和获取properties配置中的参数语法${}一致,所以加jdbc.区分。
#{} 预编译方式,参数在传递时,如果是字符串,会自动添加''。预编译可预防sql注入,但是传的参数是sql语句关键字就不行了。
     -->
    <select id="findUserByPasswordAndSex" resultType="User">
        select * from tb_user where password=#{p} and sex=#{sex}
    </select>

    <select id="findUserByUsername" resultType="User">
        select * from tb_user where user_name = #{username}
    </select>

    <select id="findUserByHash" resultType="User">
        select * from tb_user where password=#{password} and sex=#{sex}
    </select>

    <select id="findUserByTable" resultType="User">
        select * from ${tableName}
    </select>

    <select id="findUserLikeUsername" resultType="User">
        select * from tb_user where user_name like #{username}
    </select>

<!--1111111111111111111111111111111111111111111111111111111111111111111111111111111-->   
    <select id="findUsersBySex" resultMap="myResultMap"> 
        <!-- 自定义结果集映射:resultMap: 自定义结果集的id -->
        select <include refid="commonSql.mySql"></include> from tb_user where sex = #{sex}
    </select>
    
    <!--
            id:自定义结果集的唯一标识
            type: 类型。实体的类型,支持别名写法
        autoMapping="true" 自动映射,
            默认值为true,那么会将列名和属性名一致的进行自动映射。
            值为false,只会将我们配置的列进行映射,没有配置的列不进行映射
     -->
    <resultMap id="myResultMap" type="User" autoMapping="false">
        <!--
              配置主键和属性的映射的
              column:主键的列名
              property:实体的属性名
         -->
        <id column="uid" property="id"></id>
        <!-- 如下配置非主键的列的映射的 -->
        <result column="user_name" property="userName"></result>
        <result column="uage" property="age"></result>
    </resultMap>

<!--11111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <!--
        sql片段:类似抽成函数方法,反复调用
            1.通过<sql>标签来声明一段通用sql
            2.在执行sql时,通过<include refid="namespace.sqlId">来引入声明好的sql
            如下<include refid="mySql"></include>就行
    -->
    <sql id="mySql">
        *,age uage,id uid
    </sql>

<!--11111111111111111111111111111111111111111111111111111111111111111111111111111111-->	
    <select id="findUsersByAge" resultType="User">   <!--xml中不能写<号-->
        select * from tb_user where age <![CDATA[ < ]]> #{age}
        <!-- select * from tb_user where age &lt; #{age} -->
    </select>
</mapper>
//commonSql.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="commonSql">
    <sql id="mySql">
        *,age uage,id uid
    </sql>
</mapper>

2.2 mapper:UserMapper.java

生成订单详情需要订单的标识id,插入数据库才有id,这个id也只存在数据库中。
在这里插入图片描述

package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.Param;
import java.util.HashMap;
import java.util.List;

public interface UserMapper {
    public List<User> findUserByUsername(@Param("username") String username);
    public void addUser(User user);
    public User findUserById(int id);
    public List<User> findUserByPasswordAndSex(@Param("p") String password, @Param("sex") int sex);
    public List<User> findUserByHash(HashMap<String,Object> map);
    // 实际开发中有分表分库,分表:mysql中一张表存储数据是百万级别性能是最好的。
    // 如下1千万信息放一张表性能低,所以分表两张表,根据表名查询用户的信息
    public List<User> findUserByTable(@Param("tableName") String tableName);
    public List<User> findUserLikeUsername(@Param("username") String username);
    // 如下自定义结果集(驼峰映射和起别名不起作用)
    public List<User> findUsersBySex(@Param("sex") int sex);    
    // 如下查询年龄小于某个指定的值的用户信息
    public List<User> findUsersByAge(@Param("age") int age);
}

2.3 test:UserMapperTest.java

package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;

public class UserMapperTest {
    private UserMapper userMapper;
    @Before
    public void setUp() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
    }
    @Test
    public void findUserById() {
        User user = userMapper.findUserById(1);
        System.out.println(user);
    }
    @Test
    public void addUser(){
        User user = new User();
        user.setUserName("zhangwuji");
        user.setPassword("zhaoming");
        user.setName("zhouzhiruo");
        userMapper.addUser(user); //user没有id信息,但UserMapper.xml中配置了主键id回显
        System.out.println(user.getId()); //执行后数据库插入一条id=9, 删除id=9, 插入一条id=10不是9
    }
    @Test
    public void findUserByPasswordAndSex(){
        String password = "123456";
        int sex = 1;
        List<User> userList = userMapper.findUserByPasswordAndSex(password, sex);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUserByUsername(){
        List<User> userList = userMapper.findUserByUsername("lisi");
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUserByHash(){
        HashMap<String,Object> map = new HashMap<>();
        map.put("pwd","123456");
        map.put("sex","1");
        List<User> userList = userMapper.findUserByHash(map);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUserByTable(){
        String tableName = "tb_user_copy";
        List<User> userList = userMapper.findUserByTable(tableName);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUserLikeUsername(){
        String username = "%zhang%";
        List<User> userList = userMapper.findUserLikeUsername(username);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUsersBySex(){
        List<User> userList = userMapper.findUsersBySex(1);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void  findUsersByAge(){
        List<User> userList = userMapper.findUsersByAge(30);
        for(User user:userList){
            System.out.println(user);
        }
    }
}

在这里插入图片描述
如上正确产生如下。
在这里插入图片描述
如下要加引号。
在这里插入图片描述
如下字符串拼接。
在这里插入图片描述

3.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.itheima.mapper.UserMapper">
    <cache></cache>
    
    <!-- if标签,条件判断,test属性写上条件判断的表达式 -->
    <select id="findUsersByUsername" resultType="User">
        select * from tb_user where sex = 1
        <if test="username !=null and username.trim()!=''">  <!-- null空对象,''空串 -->
            and user_name like #{username}
        </if>
    </select>

    <!-- choose when otherwise :从上往下,只会选择其中的第一个满足的条件 -->
    <select id="findUsersByUsernameOrAge" resultType="User">
        select * from tb_user where sex = 1
        <choose>
            <when test="username!=null and username.trim()!=''">
                and user_name like #{username}
            </when>
            <when test="age>0">
                and age &gt; #{age}
            </when>
            <otherwise>
                and user_name = 'zhangsan'
            </otherwise>
        </choose>
    </select>

    <!-- where标签自动添加where关键字在tb_user后,并且自动移除多余的and或者or。也可以去掉where标签并在tb_user后加where 1=1 -->
    <select id="findUsersByUsernameAndAge" resultType="User">
        select * from tb_user
        <where>
            <if test="username!=null and username.trim()!=''">
               and  user_name like #{username}
            </if>
            <if test="age>0">
                and age &gt; #{age}
            </if>
        </where>
    </select>

    <!-- set自动添加set关键字,并且移除多余的 逗号-->
    <update id="updateUser">
        update tb_user
        <set>
            <if test="age>0">
                age = #{age},
            </if>
            <if test="sex>0">
                sex = #{sex},
            </if>
            <if test="name!=null and name.trim()!=''">
                name = #{name}
            </if>
        </set>
        where id = #{id}
    </update>

    <!--
        foreach:遍历集合
        collection: 遍历的集合
        open:拼接的字符以指定的值开头
        close:拼接时以指定的字符结束
        separator:拼接时,间隔符
        item:集合中被遍历时的变量
     -->
    <select id="findUsersByIds" resultType="User">
        select * from tb_user where id  in    <!--(#{id},#{id})预编译成(?,?)-->
        <foreach collection="ids"  open="(" close=")" separator="," item="id" >
            #{id}
        </foreach>
    </select>

    <select id="findUserById" resultType="User">
        select * from tb_user where id = #{id}
    </select>
</mapper>

4.mapper:UserMapper.java

package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;
import java.util.HashMap;
import java.util.List;

public interface UserMapper {
    public User findUserById(@Param("id") int id);
    
    //查询男性用户,如果输入了用户名,按用户名模糊查询,如果没有输入用户名,就查询所有男性用户。
    public List<User> findUsersByUsername(@Param("username") String username);

    // 根据用户名 或者 年龄查询所有男性用户,如果输入了用户名则按照用户名模糊查找,否则就按照年龄查找,
    // 两个条件只能成立一个,如果都不输入就查找用户名为“zhangsan”的用户。
    public List<User> findUsersByUsernameOrAge(@Param("username") String username,@Param("age") int age);

    //查询所有用户,如果输入了用户名按照用户名进行模糊查询,
    // 如果输入年龄,按年龄进行查询,如果两者都输入,两个条件都要成立。
    public List<User> findUsersByUsernameAndAge(@Param("username") String username,@Param("age") int age);

    //修改用户信息,如果参数user中的某个属性为null,则不修改。
    public void updateUser(User user);

    //根据多个id查询用户的信息
    public List<User> findUsersByIds(@Param("ids") List<Integer> ids);

    @Select("select * from tb_user where id = #{id}")
    public User findUserById2(@Param("id") int id);

    @Insert("insert into tb_user(user_name,age) values(#{userName},#{age})")
    @Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id")
    public void addUser(User user);

    /**
     *
     *  Results : 注解的作用和<resultMap></resultMap>,声明结果集映射
     *  Result: 注解的作用和<result><result/> 标签作用一致,配置一组列和属性的映射关系的。
     */
    @Results({
            @Result(column = "uid",property = "id"),
            @Result(column = "uname",property = "userName"),
            @Result(column = "uage",property = "age"),
            @Result(column = "usex",property = "sex")
    })
    @Select("select id uid,user_name uname,age uage,sex usex from tb_user where id = #{id}")
    public User findUserById3(@Param("id") int id);
}

5.test:UserMapperTest.java

package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;

public class UserMapperTest {
    private UserMapper userMapper;
    private UserMapper userMapper2;
    private  SqlSession sqlSession;
    private  SqlSession sqlSession2;
    @Before
    public void setUp() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = sqlSessionFactory.openSession(true);
        sqlSession2 = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper2 = sqlSession2.getMapper(UserMapper.class);
    }
    @Test
   public void findUsersByUsername(){
        String username = "%zhang%";  //不为空
        List<User> userList = userMapper.findUsersByUsername(username);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUsersByUsernameOrAge(){
        String username = "%zhang%";
        int age = 10;
        List<User> userList = userMapper.findUsersByUsernameOrAge(username, age);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void findUsersByUsernameAndAge(){
        String username = "%zhang%";
        int age = 10;
        List<User> userList = userMapper.findUsersByUsernameAndAge(username, age);
        for(User user:userList){
            System.out.println(user);
        }
    }
    @Test
    public void updateUser(){
        User user = new User();
        user.setId(8l);
        user.setName("");
        user.setSex(2);
        user.setAge(55);
        userMapper.updateUser(user);
    }
    @Test
    public void findUsersByIds(){
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        ids.add(4);
        List<User> userList = userMapper.findUsersByIds(ids);
        for(User user:userList){
            System.out.println(user);
        }
    }
    
    /**
     *  mybatis的一级缓存:
     *      1.一级缓存无法关闭,一致存在。
     *      2.sqlSession.clear()清空缓存
     *      3.一级缓存是同一个sqlSession共享。
     *      4.任意的增删改都会清空缓存。
     */
    @Test
    public void testFirstCache(){
      System.out.println("第一次查询:");
      User user1 =  userMapper.findUserById(1);
        System.out.println(user1);       
        User user = new User();        
        user.setId(8l);
        user.setName("");
        user.setSex(2);
        user.setAge(55);
        userMapper.updateUser(user);        
        //sqlSession.clearCache(); //手动清空缓存        
      System.out.println("第二次查询:");
      User user2 =  userMapper2.findUserById(1); //两个userMapper对象也从缓存里查,因为同一个sqlsession
        System.out.println(user2); //没有日志输出就是第二次查询
    }

    /**
     *  mybatis的二级缓存
     *  1.二级缓存需要手动开启   <setting>   xxxMapper.xml中 <cache></>
     *  2.多个sqlSession共享
     *  3.需要调用sqlSession.close()方法来缓存数据
     *  4.任意数据的增删改清空缓存,所以还是需要redis
     *  5.缓存的实体对象需要实现序列化接口
     */
    @Test
    public void testSecondCache(){
        System.out.println("第一次查询:");
        User user = userMapper.findUserById(1);
        
        sqlSession.close();        
        User user3 = new User();
        user3.setId(8l);
        user3.setName("");
        user3.setSex(2);
        user3.setAge(55);
        userMapper2.updateUser(user3); //更新8这个用户

        System.out.println("第二次查询:");
        User user2 = userMapper2.findUserById(1);  //查询1这个用户

    }
    @Test
    public void findUserById2(){
        User user = userMapper.findUserById2(1);
        System.out.println(user);
    }
    @Test
    public void addUser(){
        User user = new User();
        user.setAge(20);
        user.setUserName("aaabbbccc");
        userMapper.addUser(user);
        System.out.println(user.getId());
    }
    @Test
    public void findUserById3(){
        User user = userMapper.findUserById3(1);
        System.out.println(user);
    }
}

如下是findUsersByUsername函数中String username = " "
在这里插入图片描述
如下是findUsersByUsername函数中String username = “%zhang%”
在这里插入图片描述

6.OrderMapper.xml:用u,订o,详d,商i

用户和订单:一对多。订单和商品:多对多
在这里插入图片描述
在这里插入图片描述

<?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.itheima.mapper.OrderMapper">  
     <!--多表关联查询:1.多表关联情况下的实体设计。 2.多表关联的sql语句。-->                
     <!--多表查询 包含 订单表信息 和 用户表信息-->
    <select id="findOrderAndUserByOrderNumber" resultMap="oneToOne">
      select *,u.id uid,o.id oid from tb_user u,tb_order o
          where u.id  = o.user_id
            and o.order_number=#{orderNumber}
    </select>

    <!-- 定义一对一的结果集映射。单表autoMapping自动开启,嵌套结果集要手动开启 -->
    <resultMap id="oneToOne" type="Order" autoMapping="true">
        <id column="oid" property="id"></id>
        <!-- association一对一的配置
                property: 一方的属性即Order的user属性。javaType指定属性类型。
        -->
        <association property="user" javaType="User" autoMapping="true" >
            <id column="uid" property="id"></id>
        </association>
    </resultMap>

<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <select id="findOrderAndUserAndOrderDetailsByOrderNumber" resultMap="oneToMany">
        select *,u.id uid,o.id oid,d.id did
          from  tb_user u,
                tb_order o,
                tb_orderdetail d
            where u.id = o.user_id
            and o.id = d.order_id
            and o.order_number=#{orderNumber}
    </select>

    <resultMap id="oneToMany" type="Order" autoMapping="true" extends="oneToOne">
      <!--  <id column="oid" property="id"></id>    
        <association property="user" javaType="User" autoMapping="true">
            <id column="uid" property="id"></id>
        </association>-->     <!--用了继承,所以注释-->
        
        <!-- collection一对多映射
                property: 多方的属性名
                javaType:属性的类型
                ofType: 集合的泛型
         -->
        <collection property="orderdetailList" javaType="List" ofType="OrderDetail" autoMapping="true">
            <id column="did" property="id"></id>
        </collection>
    </resultMap>

<!--1111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <select id="findOrderAndUserAndOrderDetailsAndItemByOrderNumber" resultMap="manyToMany">
        select *,u.id uid,o.id oid,d.id did,i.id iid
            from tb_user u,
                     tb_order o,
                     tb_orderdetail d,
                     tb_item i
            where
			      u.id = o.user_id
              and  o.id = d.order_id
              and d.item_id = i.id
              and o.order_number = #{orderNumber}
    </select>
    
    <!--
        多对多查询的本质: 还是一对多的配置,借助中间表实现一对多的关系。
     -->
    <resultMap id="manyToMany" type="Order" extends="oneToOne" autoMapping="true">
        <collection property="orderdetailList" javaType="List" ofType="OrderDetail" autoMapping="true">
            <id column="did" property="id"></id>
            <association property="item" javaType="Item" autoMapping="true">
                <id column="iid" property="id"></id>
            </association>
        </collection>
    </resultMap>

<!--111111111111111111111111111111111111111111111111111111111111111111111111111111111-->
    <select id="findOrderLazyUser" resultMap="lazyUser">
        select * from tb_order where order_number = #{orderNumber}
    </select>

    <resultMap id="lazyUser" type="Order" autoMapping="true">
        <id property="id" column="id"></id>
        <!-- 延迟加载
                select : 配置需要执行的sql语句
                column: sql语句执行时需要的参数所在的列,即上一条sql执行某一列值
         -->
        <association property="user" javaType="User" column="user_id" select="com.itheima.mapper.UserMapper.findUserById" autoMapping="true">
            <id column="id" property="id"></id>  <!--findUserById在UserMapper.xml已写,返回user-->
        </association>
    </resultMap>
</mapper>

如下order_number和user_id等满足驼峰映射(mybatis-config.xml已开启),自动映射不要配了。如下将uid映射到user对象id属性,oid映射到order对象的id属性。
在这里插入图片描述
没有多表查询如下,懒/延时加载用两条sql,分开才有先后顺序。
在这里插入图片描述
在这里插入图片描述

7.domain:order.java,Orderdetail .java

package com.itheima.domain;
import java.util.List;

public class Order { //订单表
    private Integer id;
    private Long userId;
    private String orderNumber;
    
    private User user;  //多变关联情况下实体的设计:可以考虑,将关联的表对应的实体类型作为当前的属性。
    private List<Orderdetail> orderdetailList; //订单携带详情,详情里再携带商品

    public List<Orderdetail> getOrderdetailList() {
        return orderdetailList;
    }
    public void setOrderdetailList(List<Orderdetail> orderdetailList) {
        this.orderdetailList = orderdetailList;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public Long getUserId() {
        return userId;
    }
    public void setUserId(Long userId) {
        this.userId = userId;
    }
    public String getOrderNumber() {
        return orderNumber;
    }
    public void setOrderNumber(String orderNumber) {
        this.orderNumber = orderNumber;
    }
    @Override
    public String toString() {  //重新生成有user
        return "Order{" +
                "id=" + id +
                ", userId=" + userId +
                ", orderNumber='" + orderNumber + '\'' +
                ", user=" + user +
                '}';
    }
}
package com.itheima.domain;

public class Orderdetail {    
    private Integer id;    
    private Double totalPrice;    
    private Integer status;
    private Item item;  //携带商品
    public Item getItem() {
        return item;
    }
    public void setItem(Item item) {
        this.item = item;
    }
    public Double getTotalPrice() {
        return totalPrice;
    }
    public void setTotalPrice(Double totalPrice) {
        this.totalPrice = totalPrice;
    }
    public Integer getStatus() {
        return status;
    }
    public void setStatus(Integer status) {
        this.status = status;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "Orderdetail{" +
                "id=" + id +
                ", totalPrice=" + totalPrice +
                ", status=" + status +
                ", item=" + item +
                '}';
    }
}

8.mapper:OrderMapper.java

package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.annotations.Param;

public interface OrderMapper {
    //需求:通过订单编号20140921003查询出订单信息,并查询出下单人信息。
    public Order findOrderAndUserByOrderNumber(@Param("orderNumber") String orderNumber);

    //	需求:通过订单编号20140921001查询订单,并查询出下单人信息以及查询出订单详情。
    public Order findOrderAndUserAndOrderDetailsByOrderNumber(@Param("orderNumber") String orderNumber);

    //通过订单号20140921001查询订单,查询出下单人信息并且查询出订单详情以及商品数据
    public Order findOrderAndUserAndOrderDetailsAndItemByOrderNumber(@Param("orderNumber") String orderNumber);

    //延迟加载需求:通过订单编号20140921001查询order并延迟加载user信息
    public Order findOrderLazyUser(@Param("orderNumber") String orderNumber);
}

9.test:OrderMapperTest.java

package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;

public class OrderMapperTest {
    private OrderMapper orderMapper;
    @Before
    public void setUp() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        orderMapper = sqlSession.getMapper(OrderMapper.class);
    }
    @Test
    public void findOrderAndUserByOrderNumber() {
        Order order = orderMapper.findOrderAndUserByOrderNumber("20140921003");
        System.out.println(order);
    }
    @Test
    public void findOrderAndUserAndOrderDetailsByOrderNumber(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
    @Test
    public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
    @Test
    public void findOrderLazyUser(){
        Order order = orderMapper.findOrderLazyUser("20140921001");
        System.out.println(order.getOrderNumber());
        System.out.println("开始使用用户的信息了");
        System.out.println(order.getUser().getName());
    }
}

findOrderAndUserByOrderNumber()执行结果如下。
在这里插入图片描述
findOrderAndUserAndOrderDetailsByOrderNumber()执行结果如下。
在这里插入图片描述
findOrderAndUserAndOrderDetailsAndItemByOrderNumber()执行结果如下,多个Orderdetail。
在这里插入图片描述
findOrderLazyUser执行结果如下,用的时候才去加载。
在这里插入图片描述

10.mapper:UserMapper.java,OrderMapper.java,OrderDetailMapper.java,ItemMapper.java

xml配置配的东西多,但是所有配置都在一起。注解虽然配的少,但分布在各个地方。
在这里插入图片描述

package com.itheima.mapper;
import com.itheima.domain.User;
import com.itheima.sql.UserSql;
import org.apache.ibatis.annotations.*;
import java.util.HashMap;
import java.util.List;

public interface UserMapper { //注解就不用xxMapper.xml映射文件了
    @Select("select * from tb_user where id = #{id}")
    public User findUserById2(@Param("id") int id);

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Insert("insert into tb_user(user_name,age) values(#{userName},#{age})")
    @Options(useGeneratedKeys = true,keyProperty = "id",keyColumn = "id") //新增主键回显
    public void addUser(User user);

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
    /**
     *  Results : 注解的作用和<resultMap></resultMap>一样,声明结果集映射
     *  Result: 注解的作用和<result><result/> 标签作用一致,配置一组列和属性的映射关系的
     */
    @Results({
            @Result(column = "uid",property = "id"),
            @Result(column = "uname",property = "userName"),
            @Result(column = "uage",property = "age"),
            @Result(column = "usex",property = "sex")
    })
    @Select("select id uid,user_name uname,age uage,sex usex from tb_user where id = #{id}")
    public User findUserById3(@Param("id") int id);  //如上行自定义别名,无法自动映射,需自定义结果集映射

//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    /**
     *  如果用户名不为空,就按照用户名查询, //动态sql注解开发,下面的第3节
     *  如果年龄大于0,就查询年龄大于指定值的用户信息
     */
    @SelectProvider(type = UserSql.class,method = "findUsersByCondition")
    public List<User> findUsersByConditions(User user);
}
package com.itheima.mapper;
import com.itheima.domain.Order;
import com.itheima.domain.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;
import java.util.List;

public interface OrderMapper {
    /**
     *  注解方式的高级查询的sql语句必须分开写,不支持多表查询。
     *  注解一对一
     *      通过@One注解来实现的,
     *              select : 配置需要执行的sql语句
     *              fetchType: 配置是否启用懒加载
     */
    @Results({
            @Result(column = "id",property = "id"),
            @Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id")
    })
    @Select("select * from tb_order where order_number=#{orderNumber}")
    public Order findOrderAndUserByOrderNumber2(@Param("orderNumber") String orderNumber);

//111111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Results({
            @Result(column = "id",property = "id"),
            @Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id"),
            @Result(many = @Many(select = "com.itheima.mapper.OrderDetailMapper.findOrderDetailsByOid"),property = "orderdetailList",javaType = List.class,column = "id")
    })
    @Select("select * from tb_order where order_number=#{orderNumber}")
    public Order findOrderAndUserAndOrderDetailsByOrderNumber2(@Param("orderNumber") String orderNumber);

//11111111111111111111111111111111111111111111111111111111111111111111111111111111111
    @Results({
            @Result(column = "id",property = "id"),
            @Result(one=@One(fetchType= FetchType.EAGER ,select = "com.itheima.mapper.UserMapper.findUserById2"),property = "user",javaType = User.class,column = "user_id"),
            @Result(many = @Many(select = "com.itheima.mapper.OrderDetailMapper.findOrderDetailsByOid"),property = "orderdetailList",javaType = List.class,column = "id")
    })
    @Select("select * from tb_order where order_number=#{orderNumber}")
    public Order findOrderAndUserAndOrderDetailsAndItemByOrderNumber2(@Param("orderNumber") String orderNumber);
}
package com.itheima.mapper;
import com.itheima.domain.Item;
import com.itheima.domain.Orderdetail;
import org.apache.ibatis.annotations.*;
import java.util.List;

public interface OrderDetailMapper {
    @Results({
            @Result(column = "id",property = "id"),
            @Result(property = "item",javaType = Item.class,column = "item_id",
            one = @One(select = "com.itheima.mapper.ItemMapper.findItemById"))
    })
    @Select("select * from tb_orderdetail where order_id = #{oid}")
    public List<Orderdetail> findOrderDetailsByOid(@Param("oid") int oid);
}
package com.itheima.mapper;
import com.itheima.domain.Item;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

public interface ItemMapper {
    @Select("select * from tb_item where id = #{id}")
    public Item findItemById(@Param("id") int id);
}

11.test:UserMapperTest.java,OrderMapperTest.java

package com.itheima.mapper;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import static org.junit.Assert.*;

public class UserMapperTest {
    private UserMapper userMapper;
    private UserMapper userMapper2;
    private  SqlSession sqlSession;
    private  SqlSession sqlSession2;
    @Before
    public void setUp() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        sqlSession = sqlSessionFactory.openSession(true);
        sqlSession2 = sqlSessionFactory.openSession(true);
        userMapper = sqlSession.getMapper(UserMapper.class);
        userMapper2 = sqlSession2.getMapper(UserMapper.class);
    }
    @Test
    public void findUserById2(){
        User user = userMapper.findUserById2(1);
        System.out.println(user);
    }
    @Test
    public void addUser(){
        User user = new User();
        user.setAge(20);
        user.setUserName("aaabbbccc");
        userMapper.addUser(user);
        System.out.println(user.getId());
    }
    @Test
    public void findUserById3(){
        User user = userMapper.findUserById3(1);
        System.out.println(user);
    }
    @Test
    public void findUsersByConditions(){
        User user = new User();
        user.setUserName("%zhang%");
        user.setAge(15);

        List<User> userList = userMapper.findUsersByConditions(user);
        for(User user1:userList){
            System.out.println(user1);
        }
    }
}

findUsersByConditions执行结果:
在这里插入图片描述

package com.itheima.mapper;
import com.itheima.domain.Order;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;
import static org.junit.Assert.*;

public class OrderMapperTest {
    private OrderMapper orderMapper;
    @Before
    public void setUp() throws Exception {
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        orderMapper = sqlSession.getMapper(OrderMapper.class);
    }    
    @Test
    public void findOrderAndUserByOrderNumber() {
        Order order = orderMapper.findOrderAndUserByOrderNumber("20140921003");
        System.out.println(order);
    }
    @Test
    public void findOrderAndUserAndOrderDetailsByOrderNumber(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
    @Test
    public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
    @Test
    public void findOrderLazyUser(){
        Order order = orderMapper.findOrderLazyUser("20140921001");
        System.out.println(order.getOrderNumber());

        System.out.println("开始使用用户的信息了");
        System.out.println(order.getUser().getName());
    }
    @Test
    public void findOrderAndUserByOrderNumber2(){
        Order order = orderMapper.findOrderAndUserByOrderNumber2("20140921003");
        System.out.println(order.getOrderNumber());

        System.out.println("懒加载用户信息:");
        System.out.println(order.getUser().getName());
    }
    @Test
    public void findOrderAndUserAndOrderDetailsByOrderNumber2(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsByOrderNumber2("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
    @Test
    public void findOrderAndUserAndOrderDetailsAndItemByOrderNumber2(){
        Order order = orderMapper.findOrderAndUserAndOrderDetailsAndItemByOrderNumber2("20140921001");
        System.out.println(order);
        System.out.println(order.getOrderdetailList());
    }
}

findOrderAndUserByOrderNumber执行结果:
在这里插入图片描述
findOrderAndUserAndOrderDetailsByOrderNumber执行结果:
在这里插入图片描述
findOrderAndUserAndOrderDetailsAndItemByOrderNumber2执行结果:
在这里插入图片描述

12.动态sql注解开发

package com.itheima.sql;
import com.itheima.domain.User;

public class UserSql {
    public String findUsersByCondition(User user){
        StringBuffer sb = new StringBuffer("select * from tb_user where 1=1 ");
        
        if(user.getUserName()!=null&&user.getUserName().trim()!=""){
            sb.append(" and user_name like #{userName} ");
        }
        if(user.getAge()>0){
            sb.append(" and age>#{age} ");
        }
        return sb.toString();
    }
}

在这里插入图片描述

举报

相关推荐

0 条评论