JavaWeb笔记(21)-mybatis动态sql与多表查询

  1. mybatis中连接池的使用
1. mybatis连接池的3种配置方式:
    a. 配置文件SqlMapConfig.xml中的dataSource标签的type属性
        1. type属性的可选值:
            * POOLED:
                采用传统的javax.sql.DataSource规范中的连接池,mybatis中有对该规范的实现
            * UNPOOLED:
                采用传统的获取连接方式,虽然也实现了javax.sql.DataSource接口,但是没有用池的思想
            * JNDI:
                采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器拿到的DataSource是不一样的
                如果不是web或者maven的war工程,则不能使用该配置
  1. mybatis中的事务
1. mybatis中的事务操作是通过sqlSession对象的commit方法和rollback方法进行提交和回滚
2. 获取sqlSession对象的openSession()方法中存在重载形式,传入true值,可以设置自动提交,不建议
  1. mybatis中动态sql的标签
1. if标签:
    条件查询:当不清楚用户输入的查询条件具体为什么时,使用if标签来包裹该部分条件
    例如:
        通过传入User对象来返回模糊查询的List<User>,该User对象中可能有username,sex等某一些信息,或者都有
        此时,不能确定最终的查询语句,使用if标签来动态生成sql语句
        <select id="findUserByCondition" resultType="cn.mysilent.domian.User" parameterType="user">
            select * from user where 1=1 
            <if test="username != null">
                and username=#{username} 
            </if>
            <if test="sex != null">
                and sex=#{sex} 
            </if>
            ....
        </select>
2. where标签:
    在动态生成sql语句时,避免出现类似1=1的条件,直接将if标签嵌套进where标签中
    例如:
        <select id="findUserByCondition" resultType="cn.mysilent.domian.User" parameterType="user">
            select * from user 
            <where>
                <if test="username != null">
                    and username=#{username} 
                </if>
                <if test="sex != null">
                    and sex=#{sex} 
                </if>
                ....
            </where>
        </select>
3. foreach标签:
    在原始sql语句中,可以正常书写查询id在某个集合中的数据项:
        select * from user where id in (1,2,3,4);
    于是在mybatis中动态生成sql语句需要使用foreach标签
    例如:
        <!--在QueryVo对象中创建一个ArrayList存储查询的id集合成员变量属性名为ids-->
        <select id="findUserByIds" resultType="cn.mysilent.domian.User" parameterType="QueryVo">
            select * from user 
            <where>
                <if test="ids != null and ids.size()>0">
                    <!--仅ids中有值存在时添加该条件-->
                    <foreach collection="ids" open=" and id in (" close=")" item="uid" separator=",">
                        <!--取出遍历的临时变量中的值-->
                        #{uid}
                    </foreach>
                </if>
            </where>
        </select>
        foreach标签的各属性含义
            collection:要遍历的集合对象,不需要#{}
            open:代表语句的开始部分
            close:代表语句的结束
            item:代表遍历时的临时变量
            separator:表示遍历后元素间的分隔符
  1. mybatis中的多表查询
1. 表与表之间关系
    a. 一对一
    b. 一对多
    c. 多对多
    d. 多对一(mybatis中将多对一看作多个一对一)
2. mybatis中实现多表查询:
    示例:用户和账户
            一个用户可以有多个账户
            一个账户只能属于一个用户(多个账户可以属于同一个用户)
    步骤:
        1. 建立两张表:用户表,账户表
            用户(1) : 账户(n)
            需要在n的一方(账户)添加外键列,关联用户表的主键
        2. 建立两个实体类:用户实体类和账户实体类
            需要让两个实体类体现出表之间的关系
            在用户实体类中定义List成员变量存放账户实体类的引用
            在账户实体类中定义用户实体类的引用
        3. 建立两个配置文件:
            用户表操作的配置文件 -- 创建IUserDao接口
            账户表操作的配置文件 -- 创建IAccountDao接口
        4. 实现配置:
            * 当查询用户时,可以同时得到用户下所包含的所有账户信息
            * 当查询账户时,可以同时得到账户所属的用户信息
    配置文件要点:
        1. 一对一:在账户实体类中包含了用户实体类的引用
            原始sql语句:
                select u.*, a.id as aid, a.uid, a.money from account a, user u where u.id=a.uid
                如此可以查询出每一账户关联的用户信息
            IAccountDao配置文件:
                需要将查询出来的结果封装到account类对应的成员变量中和user类引用的对象的成员变量中
                此时需要使用resultMap标签来定制自定义的结果集:
                结果集配置:
                <!--最外层的type依旧为账户类的类型(用户类引用封装在该类中),此处使用了别名-->
                <resultMap id="accountUserMap" type="accout">
                    <!--账户表主键-->
                    <id property="id" column="aid"></id>
                    <!--账户表非主键-->
                    <result property="uid" column="uid"></result>
                    <result property="money" column="money"></result>
                    <!--配置账户表中一对一映射关系,使用association标签,封装user的内容-->
                    <!--其中property为账户类中用户类成员变量的属性名,column属性为关联的对对应的外键列-->
                    <!--javaType表示association标签内的数据封装为的实体类全限定类名(可以使用别名)-->
                    <association property="user" column="uid" javaType="cn.mysilent.domain.User">
                        <!--用户表主键-->
                        <id property="id" column="id"></id>
                        <!--用户表非主键-->
                        <result property="username" column="username"></result>
                        <result property="address" column="address"></result>
                        <result property="sex" column="sex"></result>
                        <result property="birthday" column="birthday"></result>
                    </association>
                </resultMap>
                sql语句配置:
                <select id="findAllAccount" resultMap="accountUserMap">
                    select u.*, a.id as aid, a.uid, a.money from account a, user u where u.id=a.uid
                </select>
            输出结果:
                sout(account);
                sout(assount.getUser());
        2. 一对多:在用户实体类中包含账户对象引用列表
            原始sql语句:查询出用户所有信息并且该用户下所包含的所有账号信息,没有账户的用户账户列为null值
                使用左外连接保证user表中的信息完整
                select 
                    u.*, a.id as aid, a.uid, a.money 
                from 
                    user u 
                left outer join 
                    account a 
                on
                    u.id = a.uid
                由此,可以产生结果集:
                    如果用户没有账户,则该用户数据行账户信息为null
                    如果该用户有账户,则每个账户与用户信息组合为一条数据
            IUserDao配置文件:
                需要将查询出来的结果封装到user类对应的成员变量中和account类引用列表中对象的成员变量中
                此时需要使用resultMap标签来定制自定义的结果集:
                结果集配置:
                <!--最外层的type为用户类的类型(账户类引用列表封装在该类中),此处使用了别名-->
                <resultMap id="userAccountMap" type="user">
                    <!--用户表主键-->
                    <id property="id" column="id"></id>
                    <!--用户表非主键-->
                    <result property="username" column="username"></result>
                    <result property="address" column="address"></result>
                    <result property="sex" column="sex"></result>
                    <result property="birthday" column="birthday"></result>
                    <!--配置用户表中一对多映射关系,使用collection标签,表示封装的是一个集合-->
                    <!--其中property为用户类中账户类列表成员变量的属性名-->
                    <!--ofType表示集合内的数据封装为的实体类全限定类名(可以使用别名)-->
                    <collection property="accounts" ofType="cn.mysilent.domain.Account">
                        <!--账户表主键-->
                        <id property="id" column="aid"></id>
                        <!--账户表非主键-->
                        <result property="uid" column="uid"></result>
                        <result property="money" column="money"></result>
                    </collection>
                </resultMap>
                sql语句配置:
                <select id="findAllUser" resultMap="userAccountMap">
                    select u.*, a.id as aid, a.uid, a.money from user u 
                    left outer join account a on u.id = a.uid
                </select>
            输出结果:
                sout(user);
                sout(user.getAccounts());
3. mybatis中多对多查询:
    示例:用户和角色
            一个用户可以有多个角色
            一个角色可以属于多个用户
    步骤:
        1. 建立两张表:用户表,角色表
            用户(n) : 角色(m)
            需要使用一张中间表,包含各自的主键,在中间表中作为外键
        2. 建立两个实体类:用户实体类和账户实体类
            需要让两个实体类体现出表之间的关系
            在用户实体类中定义List成员变量存放角色实体类的引用
            在角色实体类中定义List成员变量存放用户实体类的引用
        3. 建立两个配置文件:
            用户表操作的配置文件 -- 创建IUserDao接口
            角色表操作的配置文件 -- 创建IRoleDao接口
        4. 实现配置:
            * 当查询用户时,可以同时得到用户下所包含的所有角色信息
            * 当查询角色时,可以同时得到角色所属的所有用户信息
    配置文件要点:
        1. 多对多:在角色实体类中包含用户实体类引用集合
            原始sql语句:查询角色表时,如果该角色有所属用户,则列举所有用户,没有所属则用户信息为null
                select u.*, r.id as rid, r.role_name, r.role_desc from role r
                left outer join user_role ur on r.id=ur.rid
                left outer join user u on u.id=ur.uid
                使用两次左外连接实现效果
            IRoleDao配置文件:
                自定义查询的结果集:
                <!--最外层的type为角色类的类型(用户类引用列表封装在该类中),此处使用了别名-->
                <resultMap id="roleMap" type="role">
                    <!--角色表主键,cloumn在sql语句中起了别名,则此处用别名-->
                    <id property="roleId" column="rid"></id>
                    <!--角色表非主键-->
                    <result property="roleName" column="role_name"></result>
                    <result property="roleDesc" column="role_desc"></result>
                    <!--配置角色表中多对多映射关系,使用collection标签,表示封装的是一个集合-->
                    <!--其中property为用户类中角色类列表成员变量的属性名-->
                    <!--ofType表示集合内的数据封装为的实体类全限定类名(可以使用别名)-->
                    <collection property="users" ofType="cn.mysilent.domain.User">
                        <!--用户表主键-->
                        <id property="id" column="id"></id>
                        <!--用户表非主键-->
                        <result property="username" column="username"></result>
                        <result property="address" column="address"></result>
                        <result property="sex" column="sex"></result>
                        <result property="birthday" column="birthday"></result>
                    </collection>
                </resultMap>
                sql语句配置:
                <select id="findAllRole" resultMap="roleMap">
                    select u.*, r.id as rid, r.role_name, r.role_desc from role r 
                    left outer join user_role ur on r.id=ur.rid 
                    left outer join user u on u.id=ur.uid 
                </select>
            输出结果:
                sout(role);
                sout(role.getUsers());
        2. 多对多:在用户实体类中包含角色实体类引用集合
            原始sql语句:查询用户表时,如果该用户具有角色,列举所包含的角色信息,没有角色则角色信息为null
                select u.*, r.id as rid, r.role_name, r.role_desc from user u 
                left outer join user_role ur on u.id=ur.uid
                left outer join role r on r.id=ur.rid
                使用两次左外连接实现效果
            IUserDao配置文件:
                自定义查询的结果集:
                <!--最外层的type为用户类的类型(用户类引用列表封装在该类中),此处使用了别名-->
                <resultMap id="userMap" type="user">
                    <!--用户表主键-->
                    <id property="id" column="id"></id>
                    <!--用户表非主键-->
                    <result property="username" column="username"></result>
                    <result property="address" column="address"></result>
                    <result property="sex" column="sex"></result>
                    <result property="birthday" column="birthday"></result>
                    <!--配置用户表中多对多映射关系,使用collection标签,表示封装的是一个集合-->
                    <!--其中property为用户类中角色类列表成员变量的属性名-->
                    <!--ofType表示集合内的数据封装为的实体类全限定类名(可以使用别名)-->
                    <collection property="roles" ofType="cn.mysilent.domain.Role">
                        <!--账户表主键,cloumn在sql语句中起了别名,则此处用别名-->
                        <id property="id" column="rid"></id>
                        <!--账户表非主键-->
                        <result property="roleName" column="role_name"></result>
                        <result property="roleDesc" column="role_desc"></result>
                    </collection>
                </resultMap>
                sql语句配置:
                <select id="findAllRole" resultMap="roleMap">
                    select u.*, r.id as rid, r.role_name, r.role_desc from user u  
                    left outer join user_role ur on u.id=ur.uid 
                    left outer join role r on r.id=ur.rid
                </select>
            输出结果:
                sout(user);
                sout(user.getRoles());
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值