Mybatis学习日志三

Mybatis学习日志三

学习目标

  • 能够使用mybatis提供的连接池
  • 能够掌握mybatis中的动态sql
  • 能够掌握一对多,多对多的配置

1 mybatis中的连接池及事务控制

  • 连接池可以减少我们获取连接所消耗的时间。

  • 连接池就是用于存储连接的一个容器,就是一个集合对象

    • 该集合必须是线程安全的,不能两个线程拿到统一连接
    • 该集合必须实现队列的特性:先进先出

1.1 mybatis中连接池使用及分析

mybatis连接池提供了3种方式配置:

配置位置:主配置文件SqlMapConfig.xml中的dataSource标签。type属性就是表示采用何种连接方式。

type属性取值分别是:

  • POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。

    01

    03

  • UNPOOLED:采用传统的获取连接方式,虽然也实现了javax.sql.DataSource,但是没有实现池的思想。

    02

  • JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的(如果不是web或者maven的war工程是不能使用的。Tomcat服务器采用的连接池就是dbcp连接池)

1.2 mybatis事务控制的分析

  • 什么是事务
  • 事务的四大特性ACID
  • 不考虑隔离性会产生的3个问题
  • 解决问题:四种隔离级别

mybatis中的事务是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚。

sqlSessionFactory.openSession(true);//手动提交事务改为自动提交。(不常用)

2 mybatis基于XML配置的动态SQL语句使用

if 标签:拼接查询语句

  • test属性:填写查询条件满足则拼接。

  • <!-- 根据条件查询 -->
    <select id="findUserByCondition" resultType="domain.User" parameterType="user">
        select * from user where 1=1
        <if test="username != null">
            and username = #{username};
        </if>
    </select>
    

    注意:SQL语句中不区分大小写,#{}、test值中区分大小写,需和实体类中一致。

where标签:使得sql更清晰

<select id="findUserByCondition" resultType="domain.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>

foreach标签:遍历查询

  • collection属性:表示要遍历的集合元素
  • open属性:表示语句的开始
  • close属性:表示结束
  • item属性:每一项生成的变量名,填充到open与close之间
  • separator属性:分隔符
<!-- 根据QueryVo中的Id集合实现查询用户列表 -->
<select id="findUserByIds" resultType="user" parameterType="domain.QueryVo">
    select * from user
    <where>
        <if test="ids != null and ids.size() > 0">
            <foreach collection="ids" open="and id in(" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </if>
    </where>
</select>

注:#{}里的名称必须与item值相同!

sql标签:抽取重复的sql语句内容

  • id属性:该语句唯一标识符

    <!-- 定义查询user的sql -->
    <sql id="RUser">
        select * from user
    </sql>
    

include标签:引用定义好的sql标签内容

  • refid属性:引用sql标签的id值
<!-- 查询所有 -->
<select id="findAll" resultType="domain.User">
    <!-- select * from user -->
    <include refid="RUser"></include>
</select>

3 ※mybatis中的多表操作

表之间的关系有几种:

  • 一对一 一个人只有一个身份证号,一个身份证只属于一个人
  • 一对多 一个老师教多个学生
  • 多对一 多个学生被一个老师教
  • 多对多 一门课程同时有多个学生选修,一个学生可以同时选修多门课程。

3.1 一对多查询(mybatis中的一对一)

查询所有账户的同时获取当前用户的姓名和地址信息

3.1.1 完成Account的一对一查询

在mybatis中把多对一看成了一对一。

示例:用户和账户

  • 一个用户可以有多个账户
  • 一个账户只能属于一个用户(多个账户也可以属于同一个用户)

步骤:

  • 建立两张表:用户表,账户表
    • ​ 让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
  • 建立两个实体类:用户实体类和账户实体类
    • ​ 让用户和账户的实体类能体现出一对多的关系
  • 建立两个配置文件
    • ​ 用户的配置文件
    • ​ 账户的配置文件
  • 实现配置:
    • ​ 当我们查询用户时,也可以同时得到用户下所包含的账户信息
    • ​ 当我们查询账户时,也可以同时得到账户的所属用户信息

方法一:(此方法不常用!)

  1. 在IAccountDao接口中创建findAllAccount()方法

  2. 创建一个AccountUser实体类继承Account类

  3. 在映射文件IAccountDao.xml中创建相应配置

    <!-- 查询所有账户及对应用户的姓名及地址 -->
    <select id="findAllAccount" resultType="domain.AccountUser">
        select a.*,u.username,u.address from account a,user u where u.id = a.uid;
    </select>
    
  4. 在测试类中测试

    01

方法二:

  • 从表实体应该包含一个主表实体的对象引用
  • 在映射文件中需要定义封装从表和主表的resultMap(这里是account和user的resultMap)

**association标签:**用户配置封装主表(一对一)

  • property属性:从表中的引用元素名称
  • column属性:外键是哪个字段
  • javaType属性:封装到哪个实体类
<!-- 定义封装account和user的resultMap -->
<resultMap id="accountUserMap" type="account">
    <id property="id" column="aid"></id>
    <result property="uid" column="uid"></result>
    <result property="money" column="money"></result>
    <!-- 一对一的映射关系,配置封装user -->
    <association property="user" column="uid">
        <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>

<!-- 查询所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from account a,user u where u.id = a.uid;
    </select>
  • 测试类

    /**
     * 测试查询所有操作
     *
     * @throws IOException
     */
    @Test
    public void testFindALL() {
        //1.执行查询所有方法
        List<Account> accounts = accountDao.findAll();
        //2.遍历结果集
        for (Account account : accounts) {
            System.out.println("----用户信息----");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
    

02

3.1.2 完成user的一对多查询
  • 主表实体应该包含从表实体的集合引用以及getset方法
  • 在映射文件中需要定义封装从表和主表的resultMap(这里是account和user的resultMap)

**collection标签:**用于配置user对象中从表的集合(一对多)

  • property属性:值填实体中的集合引用名称

  • oftype属性:集合中元素的类型

<!-- 定义封装account和user的resultMap -->
<resultMap id="allUserAccountMap" 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>
    <!-- 一对一的映射关系,配置封装account -->
    <collection property="accounts" ofType="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
    </collection>
</resultMap>
<!-- 查询用户的同时查询其账户的所有信息 -->
<select id="findAll" resultMap="allUserAccountMap">
	select * from user u left outer join account a on a.uid = u.id;
</select>
  • 测试类
@Test
public void testFindALL() {
    //1.执行查询所有方法
    List<User> users = userDao.findAll();
    //2.遍历结果集
    for (User user : users) {
        System.out.println("----每个用户的信息----");
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}

03

3.2 多对多查询

示例:用户和角色

  • 一个用户有多个角色
  • 一个角色可以赋予多个用户

步骤:

  • 建立两张表:用户表,角色表
    • ​ 让用户表和角色表之间具备多对多的关系:需要使用中间表,中间表中包含各自的主键,在中间表中是外键。
  • 建立两个实体类:用户实体类和角色实体类
    • ​ 让用户和角色的实体类能体现出多对多的关系
    • ​ 各自包含对方一个集合引用
  • 建立两个配置文件
    • ​ 用户的配置文件
    • ​ 角色的配置文件
  • 实现配置:
    • ​ 当我们查询用户时,也可以同时得到用户的角色信息
    • ​ 当我们查询角色时,也可以同时得到符合该角色的用户信息
3.2.1 查询角色时相应查询赋予的用户

与3.1.2中一对多的配置相同,但是sql语句不同。

此时sql语句需要对其角色表-中间表-用户表操作

<resultMap id="roleMap" type="role">
    <id property="roleId" column="role_id"></id>
    <result property="roleName" column="role_name"></result>
    <result property="roleDesc" column="role_desc"></result>
    <collection property="users" ofType="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>
<!-- 查询所有 -->
<select id="findAll" resultMap="roleMap">
    select * from role r left outer join user_role ur on r.role_id = ur.rid left outer join user u on ur.uid = u.id;
</select>

01

3.2.2 查询用户时相应查询对应的角色信息

与3.2.1sql语句的不一样

<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="roles" ofType="role">
        <id property="roleId" column="role_id"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
    </collection>
</resultMap>
<!-- 查询所有 -->
<select id="findAll" resultMap="userMap">
    select *
    from user u
             left outer join user_role ur on u.id = ur.uid
             left outer join role r on r.role_id = ur.rid;
</select>

01

一键转到→Mybatis学习日志四

源自黑马+自我总结,如有错误之处望指出。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值