1、mybatis的连接池以及事务控制(原理部分了解,应用部分会用)
mybatis的连接池使用及分析
mybatis事务控制的分析
2、mybatis基于XML配置的动态SQL语句使用(会用即可)
mappers配置文件中的几个标签:
<if>
<where>
<foreach>
<sql>
3、mybatis中的多表操作(掌握应用)
一对多
一对一
多对多
--------------------------------------------------------------------------------------------------
1、连接池:
我们在实际开发中都会使用连接池。
因为它可以减少我们获取连接所消耗的时间。
mybatis中的连接池
mybatis连接池提供了3种方式的配置
配置的位置SqlMapConfig.xml中的dataSource标签。
type属性就是表示采用何种连接方式。
type属性的取值:
POOLED:采用传统的javax.sql.DataSource规范中的连接池,mybatis中有针对规范的实现。
UNPOOLED
JNDI:采用服务器提供的JNDI技术实现,来获取DataSource对象。不同服务器所能拿到的DataSource是不一样的。
注意:如果不是web或者maven的war工程,是不能使用的。我们实际开发中使用的是tomcat服务器。采用连接池是dbcp连接池。
--------------------------------------------------------------------------------------------------


事务:在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
事务的四大特性ACID:
A:原子性
C:一致性
I:隔离性
D:持久性
mybatis中的事务是通过sqlsession对象的commit方法和rollback方法实现事务的提交和回滚。

在之前讲解的转账操作中,在一个方法里,多次与数据库交互,如果让每个连接处于独立的
事务提交中,事务肯定是控制不住的。在后面spring的课程中还会拿出来和大家详细的分析。


--------------------------------------------------------------------------------------------------
下面说一下在mybatis中resultMap和resultType的区别,
resultType:当使用resultType作SQL语句返回结果类型时,要求对象属性名和数据库表中的列名相同。
resultMap:当使用resultMap做SQL语句返回结果类型处理时,通常需要在mapper.xml中定义resultMap进行pojo和相应表字段的对应。
而resultMap可以通过在SqlMapConfig.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.dao.IUserDao">

    <resultMap id="userMap" type="user">
        <!--主键字段的对应-->
        <id property="userId" column="id"></id>
        <!--非主键字段的对应-->
        <result property="userName" column="username"></result>
        <result property="userBirthday" column="birthday"></result>
        <result property="userSex" column="sex"></result>
        <result property="userAddress" column="address"></result>
    </resultMap>
    <select id="findAll" resultMap="userMap">
        SELECT * FROM user;
    </select>

    <insert id="saveUser" parameterType="user">
        INSERT INTO user(username,birthday,sex,address) VALUES (#{userName},#{userBirthday},#{userSex},#{userAddress});
    </insert>
</mapper>
--------------------------------------------------------------------------------------------------
mybatis中的动态sql语句
if标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
        SELECT * FROM user WHERE 1=1
        <if test="userName != null">
            and username=#{userName}
        </if>
    </select>
MybatisTest.java
@Test
    public void testFindUserByCondition() {
        User user=new User();
        user.setUserName("老王");
        List<User> users = userDao.findUserByCondition(user);
        for (User user1:users) {
            System.out.println(user1);
        }
    }
where标签
<select id="findUserByCondition" resultMap="userMap" parameterType="user">
        SELECT * FROM user
        <where>
            <if test="userName != null">
                and username=#{userName}
            </if>
            <if test="userSex != null">
                and sex= #{userSex}
            </if>
        </where>
    </select>
foreach标签


com.itheima.domain.Query
package com.itheima.domain;

import java.util.List;

public class Queryvo {
    private User user;
    private List<Integer> ids;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
}
IUserDao.java
    /**
     * 根据Queryvo中提供的id***,查询用户信息
     * @param vo
     * @return
     */
    List<User> findUserInIds(Queryvo vo);
IUserDao.xml
<!--根据Queryvo中的Id***实现查询用户列表-->
    <select id="findUserInIds" resultMap="userMap" parameterType="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>
MybatisTest.java
    @Test
    public void testFindUserInIds() {
        Queryvo vo = new Queryvo();
        List<Integer> list= new ArrayList<Integer>();
        list.add(41);
        list.add(42);
        list.add(43);
        list.add(45);
        list.add(46);
        vo.setIds(list);
        List<User> users = userDao.findUserInIds(vo);
        for (User user1:users) {
            System.out.println(user1);
        }
    }
sql标签
<!--了解的内容:抽取重复的id-->
    <sql id="defaultUser">
        SELECT * FROM user
    </sql>

    <select id="findAll" resultMap="userMap">
        <!--SELECT * FROM user;-->
        <include refid="defaultUser"></include>

    </select>
--------------------------------------------------------------------------------------------------
mybatis中的多表查询
表之间的关系有几种:
一对一
一对多
多对一
多对多
举例:
用户和订单就是一对多
订单和用户就是多对一
人和身份证就是一对一
老师和学生之间是多对多
一个老师可以教多个学生
一个学生可以被多个老师教
mybatis把多对一看成一对一:
一个人可以有很多订单,订单对人就是多对一,
但是拿出每一个订单,他都只能属于一个用户。
所有mybatis就把多对一看成了一对一。

示例:用户和账户
一个用户可以有多个账户
一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1、建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2、建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系。
3、建立两个配置文件:
用户的配置文件
账户的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的账户信息。
当我们查询账户时,可以同时得到账户的所属用户信息。
--------------------------------------------------------------------------------------------------
实战时候的错误:
建好了account表,把account实体类,接口,IAccountDao.xml以及test测试类
都写好了之后发现出错,于是查了一会,最终发现在文件
SqlMapConfig.xml文件中
只写了
<mapper resource="com/itheima/dao/IUserDao.xml">
没有IAccountDao.xml的,
所以以后为了避免这种错误,还是直接在mappers中写package好啊。
<mappers>
    <package name="com.itheima.dao"></package>
</mappers>

如何做到查询所有账户,同时还要获取当前账户的所属用户信息
现在要求查询账户还要附带账户用户的姓名和地址。
方法一:通过写account的子类方式查询
com.itheima.domain.AccountUser.java
package com.itheima.domain;

public class AccountUser extends Account {

    private String username;
    private String address;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return super.toString()+"   "+"AccountUser{" +
                "username='" + username + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
com.itheima.dao.IAccountDao
/**
     * 查询所有账户,并带有用户名称和地址信息
     * @return
     */
    List<AccountUser> findAllAccount();
IAccountDao.xml
<select id="findAllAccount" resultType="accountUser">
        SELECT u.username,u.address,a.* FROM user u,account a WHERE u.id=a.uid;
</select>
test包下的AccountTest
@Test
public void testFindAllAccount() {
    List<AccountUser> accountUsers = accountDao.findAllAccount();
    for (AccountUser account:accountUsers) {
        System.out.println(account);
    }
}
刚才方法一通过写子类的方式不常用。
方法二:建立实体类关系的方式
com.itheima.domain.Account
public class Account implements Serializable {

    private Integer id;
    private Integer uid;
    private Double money;

    //从表实体应该包含一个主表实体的对象引用
    private User user;
IAccountDao.xml
    <!--定义封装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" javaType="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
    </resultMap>
    <!--<select id="findAll" resultType="account">-->
    <select id="findAll" resultMap="accountUserMap">
        <!--SELECT * FROM account;-->
        SELECT u.username,u.address,a.* FROM user u,account a WHERE u.id=a.uid;
    </select>
test包下
AccountTest
    @Test
    public void testFindAll() {
        List<Account> accounts = accountDao.findAll();
        for (Account account:accounts) {
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
--------------------------------------------------------------------------------------------------
完成user一对多的查询
com.itheima.domain.User
    //一对多关系映射:主表实体应该包含从表实体的***引用
    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }
IUserDao.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.dao.IUserDao">

    <!--定义封装User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="birthday" column="birthday"></result>
        <result property="sex" column="sex"></result>
        <result property="address" column="address"></result>
        <!--配置user对象中accounts***的映射-->
        <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="userAccountMap">
        SELECT * FROM user u LEFT OUTER JOIN account a ON u.id=a.uid;
    </select>

</mapper>
UserTest.java
@Test
public void testFindAll() {
    List<User> users = userDao.findAll();
    for (User user:users) {
        System.out.println(user);
        System.out.println(user.getAccounts());
    }
}
--------------------------------------------------------------------------------------------------
mybaits多对多
示例:用户和角色
一个用户可以有多个角色
一个角色可以有多个用户
步骤:
1、建立两张表:用户表,角色表
让用户表和角色表之间具备多对多的关系:需要使用中间表,
中间表中包含各自的主键,在中间表中是外键。
2、建立两个实体类:用户实体类和角色实体类
让用户和角色的实体类能体现出来多对多的关系。
各自包含对方一个***引用。
3、建立两个配置文件:
用户的配置文件
角色的配置文件
4、实现配置:
当我们查询用户时,可以同时得到用户下所包含的角色信息。
当我们查询角色时,可以同时得到角色所赋予的用户信息。

mybatis多对多操作——查询角色获取角色下所属用户信息。
Role.java
public class Role implements Serializable {

    private Integer roleId;
    private String roleName;
    private String roleDesc;

    private List<User> users;

    public List<User> getUsers() {
        return users;
    }
......




select * from role r
left outer join user_role ur on r.id=ur.rid
left outer join user u on u.id=ur.uid;

有两个id,所以起别名
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.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.dao.IRoleDao">

    <!--定义role表的resultMap-->
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></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="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </collection>
    </resultMap>

    <!--查询所有-->
    <select id="findAll" 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>
</mapper>
test包下RoleTest.java
@Test
public void testFindAll() {
    List<Role> roles = roleDao.findAll();
    for (Role role:roles) {
        System.out.println(role);
        System.out.println(role.getUsers());
    }
}