MyBatis框架2

MyBatis框架

今日内容

  • 理解Mybatis连接池与事务操作
  • 掌握Mybatis动态SQL
  • 掌握Mybatis多表关联查询
  • 掌握Mybatis多对多关系

Mybatis连接池

MyBatis配置文件中,配置为使用连接池,那么连接池是在什么时候建立的,什么时候从连接池中获取连接的。

连接池初始化时机

在SqlSessionFactoryBuilder构建SqlSessionFactory的时候初始化连接池,初始化之后放入Configuration对象当中。分析框架源代码:org.apache.ibatis.builder.xml.XMLConfigBuilder类的方法environmentsElement()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZxKf1qT2-1601370775954)(img/1.jpg)]

什么时候从连接池获取连接

在getMapper的时候是不会从数据库连接池获取数据库连接的,在具体操作数据库调用mapper接口方法的时候才会从连接池拿连接。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ipUc1qJT-1601370775956)(img/2.jpg)]

UNPOOLED:不使用数据库连接池(一般不会用)

JNDI:(前提你的Mybatis环境必须是Web应用)(了解)

  • 什么是JNDI

    JNDI:java naming directory interface(java命名目录接口,它是一种服务发布技术),数据源可以以服务的形式发布出去,那么哪个应用想用,就类似于客户端调用远程服务一样去调用即可

  • 为什么必须是web应用

    往往只有tomcat/weblogic服务器中间件才支持JNDI技术

  • 如果在Mybatis当中用,怎么用

    • 第一步:将数据库驱动程序(jar包)放到tomcat安装目录下的lib文件夹下

    • 第二步:在Tomcat的conf/context.xml文件中进行jndi数据源服务配置

      	<Resource name="jndi/mybatis" auth="Container"
      	 type="javax.sql.DataSource"
      	 driverClassName="com.mysql.jdbc.Driver"
      	 url="jdbc:mysql://localhost:3306/mybatis?characterEncoding=utf8"
           username="root" 
           password="root"
      	 maxActive="20"
      	 maxIdle="10"
      	 maxWait="10000">	
      	</Resource>
      

      name:在JNDI中叫做目录名,等同于服务名,此处的jndi/mybatis是自定义的,往往以/连接前后字符串即可。auth和type是固定的,其他都是数据库连接池的具体配置信息。

    • 第三步 :在自己web项目的web.xml中引用Jndi数据源服务。

        <resource-ref>
      	<res-ref-name>jndi/mybatis</res-ref-name>
      	<res-type>javax.sql.DataSource</res-type>
      	<res-auth>Container</res-auth>
        </resource-ref>
      
    • 第四步:在自己web项目的Mybatis配置文件中使用

      <property name="data_source" value="java:comp/env/jndi/mybatis"/>
      

    ​ 配置data_source属性,指向你的数据源引用,java:comp/env/jndi/mybatis中红色部分是固定的,绿色部分是你自己定义的目录名(服务名)。

MyBatis事务控制

通过sqlSession.openSession这种方法操作数据库时候,mybatis默认把事务自动提交给关闭了,注意:数据量非常小可以自动提交,数据量大就应该手动提交。自动提交在openSession方法中传入参数true: SqlSession sqlSession = sqlSessionFactory.openSession(true)

动态SQL标签

where和if标签

需求:根据用户的性别和用户名多条件查询用户信息。

<select id="queryUserByWhere" resultType="user" parameterType="user">
   select * from user where sex=#{sex} and username like #{username}
</select>
@Test
public void queryUserByWhere(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = new User();
    user.setSex("2");
    user.setUsername("%王%");
    List<User> list = mapper.queryUserByWhere(user);
    if(list!=null && list.size()>0){
        for(User user1 : list){
            System.out.println(user1);
        }
    }
}

以上查询是可以查询到相关的数据的,假定不传递sex的值,那么就会出现什么也差不到的结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AYCP1Jdt-1601370775957)(img/4.jpg)]

通过日志可以看出,MyBatis在执行SQL语句的时候,参数sex的值是null,因此没有查询到结果。在以往的做法是判断参数是否为空,并进行字符串的拼接。在MyBatis框架中,提供了where标签和if标签来实现动态SQL语句。

  • where标签:处理SQL语句,自动添加where关键字,并去掉紧跟他后面的一个and或者or

  • if标签,test属性,判断表达式真假

    <select id="queryUserByWhere" resultType="user" parameterType="user">
       select * from user
       <where>
          <if test="sex!=''and sex!=null">
             and sex=#{sex}
          </if>
          <if test="username!=''and username!=null">
             and username like #{username}
          </if>
       </where>
    </select>
    

SQL标签

将SQL语句抽取,其他SQL语句中引入。

<!-- 
  SQL片段抽取
  使用include标签引入
-->
<sql id="commonsSql">
   id,username,sex,birthday,address
</sql>

引入外部xml配置文件中的共享SQL片段时,使用namespace属性值+“.”+sql标签的id属性值。

foreach标签传入集合

删除多条数据的SQL语句,delete from user where id in(1,2,3)

String sql = "delete from user where id in("
for(int i=0; i<list.size();i++) {
	if(i != list.size()-1)
		sql += list.get(i) + ","
	else
    	sql += list.get(i)+")"
}
  • foreach标签遍历拼接SQL语句
    • collection属性:遍历传入的集合,当参数是集合时collection属性值固定为list
    • open属性:遍历拼接前
    • close属性:遍历拼接后
    • separator属性:拼接的符号
    • item属性:遍历到的元素
   <select id="queryUserByIdsList" parameterType="list" resultType="user">
      select * from user
      <foreach collection="list" open="where id in(" close=")" separator="," item="item">
         #{item}
      </foreach>
   </select>
@Test
public void queryUserByIdsList(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<Integer> idsList = new ArrayList<Integer>();
    idsList.add(1);
    idsList.add(2);
    idsList.add(3);
    List<User> list = mapper.queryUserByIdsList(idsList);
    if(list!=null && list.size()>0){
        for (User user : list){
            System.out.println(user);
        }
    }
    sqlSession.close();
}

foreach标签传入数组

  • foreach标签遍历拼接SQL语句
    • collection属性:遍历传入的集合,当参数是数组时collection属性值固定为array
    • open属性:遍历拼接前
    • close属性:遍历拼接后
    • separator属性:拼接的符号
    • item属性:遍历到的元素
<select id="queryUserByIdsArray" parameterType="int[]" resultType="user">
   select * from user
   <foreach collection="array" open="where id in(" close=")" separator="," item="item">
      #{item}
   </foreach>
@Test
public void queryUserByIdsArray(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int[] idsArray= {1,2,3};
    List<User> list = mapper.queryUserByIdsArray(idsArray);
    if(list!=null && list.size()>0){
        for (User user : list){
            System.out.println(user);
        }
    }
    sqlSession.close();
}

foreach标签传入pojo对象

  • foreach标签遍历拼接SQL语句
    • collection属性:遍历传入的pojo对象中的集合,collection属性配置pojo中成员变量名
    • open属性:遍历拼接前
    • close属性:遍历拼接后
    • separator属性:拼接的符号
    • item属性:遍历到的元素
public class QueryVo {
    private List<Integer> idsList;

    public List<Integer> getIdsList() {
        return idsList;
    }

    public void setIdsList(List<Integer> idsList) {
        this.idsList = idsList;
    }
}
<select id="queryUserByQueryVo" parameterType="queryVo" resultType="user">
   select * from user
   <foreach collection="idsList" open="where id in(" close=")" separator="," item="item">
      #{item}
   </foreach>
</select>
@Test
public void queryUserByQueryVo(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    QueryVo queryVo = new QueryVo();
    List<Integer> idsList = new ArrayList<Integer>();
    idsList.add(1);
    idsList.add(2);
    idsList.add(3);
    queryVo.setIdsList(idsList);
    List<User> list = mapper.queryUserByQueryVo(queryVo);
    if(list!=null && list.size()>0){
        for (User user : list){
            System.out.println(user);
        }
    }
    sqlSession.close();
}

MyBatis多表管理查询

多表关联关系分析

多表关联:至少两个表关联。分析多表关系的经验技巧:从一条记录出发,不要从表整体去分析,比如分析A表和B表关系,A表中的一条记录对应B表中的几条记录,如果是一条,那么A到B就是一对一;如果多条,那么A到B就是一对多

  • 一对一,从订单表出发,到用户表,是一对一的关系

  • 一对多,从用户表出发,到订单表,一条用户数据可以在订单表中存在多条记录,这就是一对多。通过主外键来体现一对多的表结构。一的一方是主表,多的一方是从表,从表当中有一个字段是外键,指向了主表的主键

  • 多对多,用户和角色表,一个用户可以有很多角色,一个角色有很多用户,多对多通过中间表来体现

多表关联的SQL语句表达分析

  • 笛卡尔积
    • SELECT *FROM USER,orders
  • 关联查询
    • 内关联 innder join on
      • SELECT * FROM USER u,orders o WHERE u.id=o.user_id
      • SELECT * FROM USER u INNER JOIN orders o ON u.id=o.user_id;
    • 左外连接
      • SELECT * FROM USER u LEFT JOIN orders o ON u.id=o.user_id
    • 右外连接
      • SELECT * FROM USER u RIGHT JOIN orders o ON u.id=o.user_id

一对一查询

需求:查询订单表全部数据,关联查询出订单对应的用户数据(username address)。

Sql语句自己来写,Mybatis只是帮我们执行sql语句同时封装结果集。

SQL语句:

SELECT o.id,o.user_id,o.number,o.note,u.address,u.username FROM orders o LEFT JOIN USER u ON o.user_id=u.id

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pyfdxhZP-1601370775964)(img/5.jpg)]

对于查询结果集,没有对应的pojo对象,因此MyBatis框架也不能封装结果集,但是可以将User对象放在Orders对象中,因为一对一关系,一个Orders对象可以对应一个User对象。需要手动映射方式,实现查询结果集封装。

  • pojo对象
public class Orders {
    private Integer id;

    private Integer userId;

    private String number;

    private Date createtime;

    private String note;

    private User user;

    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 Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public Date getCreatetime() {
        return createtime;
    }

    public void setCreatetime(Date createtime) {
        this.createtime = createtime;
    }

    public String getNote() {
        return note;
    }

    public void setNote(String note) {
        this.note = note;
    }

    @Override
    public String toString() {
        return "Orders{" +
                "id=" + id +
                ", userId=" + userId +
                ", number='" + number + '\'' +
                ", createtime=" + createtime +
                ", note='" + note + '\'' +
                ", user=" + user +
                '}';
    }
}
  • association(联合)标签,实现手动映射
    • propery属性:封装的pojo对象
    • javaType属性:封装的pojo对象类型
<mapper namespace="com.itheima.mapper.OrdersMapper">
    <select id="queryOrdersUser" resultMap="ordersUserResultType" >
        SELECT o.id,o.user_id,o.number,o.note,u.address,u.username FROM orders o LEFT JOIN USER u
        ON o.user_id=u.id
    </select>
    <resultMap id="ordersUserResultType" type="orders">
        <id column="id" property="id"></id>
        <result column="user_id" property="userId"></result>
        <result column="number" property="number"></result>
        <result column="createtime" property="createtime"></result>
        <result column="note" property="note"></result>
	   <!-- 手动映射,配置User对象-->
        <association property="user" javaType="user">
            <id column="user_id" property="id"></id>
            <result column="address" property="address"></result>
            <result column="username" property="username"></result>
        </association>
    </resultMap>
</mapper>
@Test
public void queryOrdersUser(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    OrdersMapper mapper = sqlSession.getMapper(OrdersMapper.class);
    List<Orders> list = mapper.queryOrdersUser();
    if(list != null && list.size() > 0){
        for (Orders orders : list){
            System.out.println(orders);
        }
    }
 	sqlSession.close();
}
  • 往往还有另外一种方式:新创建一个pojo,这个pojo里面增加两个字段username和address,然后使用resultType自动映射即可,但是这种方式不推荐,因为pojo多了之后很混乱,不容易做技术管理,而且这点方式也有点low

一对多查询

查询全部用户数据,关联查询出订单数据。

SQL语句:SELECT u.id,u.username,u.sex,u.birthday,u.address,o.user_id,o.id,o.number,o.createtime,o.note FROM USER u LEFT JOIN orders o ON u.id=o.user_id

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y0fGlppw-1601370775965)(img/6.jpg)]

一个用户对应多个订单数据,因此在pojo中,订单对象是存储在集合中,并保存在User对象中

  • pojo对象
public class User {
    private int id;
    private String username;
    private String sex;
    private Date birthday;
    private String address;

    private List<Orders> ordersList;

    public List<Orders> getOrdersList() {
        return ordersList;
    }

    public void setOrdersList(List<Orders> ordersList) {
        this.ordersList = ordersList;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getAddress() {
        return address;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                ", address='" + address + '\'' +
                ", ordersList=" + ordersList +
                '}';
    }
}
  • collection标签:
    • property属性:封装的对应的属性名
    • ofType属性:已经指定为一个集合List,需要指定集合中的泛型
<select id="queryUserOrders" resultMap="userOrdersResultMap">
   SELECT u.id,u.username,u.sex,u.birthday,u.address,o.user_id,o.id,
   o.number,o.createtime,o.note
   FROM USER u LEFT JOIN orders o
   ON u.id=o.user_id
</select>

<resultMap id="userOrdersResultMap" type="user">
   <id column="id" property="id"></id>
   <result column="username" property="username"></result>
   <result column="sex" property="sex"></result>
   <result column="birthday" property="birthday"></result>
   <result column="address" property="address"></result>

   <collection property="ordersList" ofType="orders">
      <id column="id" property="id"></id>
      <result column="user_id" property="userId"></result>
      <result column="number" property="number"></result>
      <result column="createtime" property="createtime"></result>
      <result column="note" property="note"></result>
   </collection>
</resultMap>
@Test
public void queryUserOrders(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    List<User> list = mapper.queryUserOrders();
    if(list != null && list.size() > 0){
        for(User user : list){
            System.out.println(user);
        }
    }
    sqlSession.close();
}

多对多查询

多对多:双向的一对多,从A表到B表出发是一对多的关系,从B表出发到A表也是一对多的关系

SQL语句:

SELECT r.RID,r.RNAME,r.RDESC,u.id,u.username,u.sex,u.birthday,u.address FROM role r LEFT JOIN user_role ur
ON r.RID=ur.RID LEFT JOIN USER u ON u.id=ur.UID

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RfElyzH9-1601370775967)(img/7.jpg)]

  • pojo对象
public class Role {
    private Integer rid;
    private String rname;
    private String rdesc;
    private List<User> userList;
    public Integer getRid() {
        return rid;
    }

    public void setRid(Integer rid) {
        this.rid = rid;
    }

    public String getRname() {
        return rname;
    }

    public void setRname(String rname) {
        this.rname = rname;
    }

    public String getRdesc() {
        return rdesc;
    }

    public void setRdesc(String rdesc) {
        this.rdesc = rdesc;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    @Override
    public String toString() {
        return "Role{" +
                "rid=" + rid +
                ", rname='" + rname + '\'' +
                ", rdesc='" + rdesc + '\'' +
                ", userList=" + userList +
                '}';
    }
}
  • 手动映射roleMapper.xml
<mapper namespace="com.itheima.mapper.RoleMapper">
    <select id="queryRoleUser" resultMap="roleUserResultMap">
        SELECT r.RID,r.RNAME,r.RDESC,u.id,u.username,u.sex,u.birthday,u.address FROM role r LEFT JOIN user_role ur ON r.RID=ur.RID LEFT JOIN USER u ON u.id=ur.UID
    </select>

    <resultMap id="roleUserResultMap" type="role">
        <id column="rid" property="rid"></id>
        <result column="rname" property="rname"></result>
        <result column="rdesc" property="rdesc"></result>
        <result column="" property=""></result>

        <collection property="userList" ofType="user">
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
            <result column="address" property="address"></result>
        </collection>
    </resultMap>
</mapper>
@Test
public void queryRoleUser(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
    List<Role> roleList = mapper.queryRoleUser();
    if(roleList != null && roleList.size() > 0){
        for (Role role : roleList){
            System.out.println(role);
        }
    }
    sqlSession.close();
}
erty="username"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
            <result column="address" property="address"></result>
        </collection>
    </resultMap>
</mapper>
@Test
public void queryRoleUser(){
    SqlSession sqlSession = sqlSessionFactory.openSession();
    RoleMapper mapper = sqlSession.getMapper(RoleMapper.class);
    List<Role> roleList = mapper.queryRoleUser();
    if(roleList != null && roleList.size() > 0){
        for (Role role : roleList){
            System.out.println(role);
        }
    }
    sqlSession.close();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值