Bootstrap

mybatis_03

Mybatis连接池和事务

  1. 在配置处指定是否使用连接池
MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
type=”POOLED”:MyBatis 会创建 PooledDataSource 实例
type=”UNPOOLED” : MyBatis 会创建 UnpooledDataSource 实例
type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

<!-- 配置数据源(连接池)信息 -->
<dataSource type="POOLED">
	...
</dataSource>
  1. Mybatis 中事务提交方式
    在 JDBC 中我们可以通过手动方式将事务的提交改为手动方式,通过 setAutoCommit()方法,在mybatis中也可以设置事务自动提交。
//4.创建 SqlSession 对象
session = factory.openSession(true);  //传入参数则可以设置事务自动提交

之前的 CUD 操作过程中,我们都要手动进行事务的提交,原因是 setAutoCommit()方法,在执行时它的值被设置为 false 了,所以我们在 CUD 操作中,必须通过 sqlSession.commit()方法来执行提交操作。
设置为自动提交方式为 false 再根据情况决定是否进行提交,这种方式更常用。因为我们可以根据业务情况来决定提交是否进行提交。

@After //用于在测试方法之后执行
    public void destroy() throws Exception {
        //提交事务
        sqlSession.commit(); //执行增删改时会自动提交
        //6 释放资源
        sqlSession.close();
        ...
    }

Mybatis 的动态 SQL 语句

<if>标签

根据实体类的不同取值,使用不同的 SQL 语句来进行查询。比如在 id 如果不为空时可以根据 id 查询,如果 username 不空时还要加入用户名作为条件。
这种情况在我们的多条件组合查询 中经常会碰到。

//注意:<if>标签的 test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。
另外要注意 where 1=1 的作用 --- 拼接字符串
<!--根据条件查询-->
    <select id="findUserByCondition" parameterType="User" resultType="User">
        select * from user where 1=1
        <if test="username != null">
            and username = #{username}
        </if>
        <if test="sex!=null">
            and sex = #{sex}
        </if>
    </select>
//Preparing: select * from user where 1=1 and username = ? and sex = ? 

<where>标签

//就是省略了在每句sql后面加 where 1=1
<select id="findUserByCondition" parameterType="User" resultType="com.itheima.domain.User">
        select * from user
        <where>
            <if test="username != null">...</if>
            <if test="sex!=null">...</if>
        </where>
    </select>

<foreach>标签

传入多个 id 查询用户信息,sql实现:
SELECT * FROM USERS WHERE id IN (10,89,16)
这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。

//在 QueryVo 中加入一个 List 集合用于封装参数
public class QueryVo {
    private User user;
    private List<Integer> ids;

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

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
   ...
} 
//dao配置
<!--根据QueryVo中的Id集合实现查询用户列表-->
    <select id="findUserInIds" resultType="user" parameterType="queryvo">
        select * from user
        <where>
            <if test="ids != null and ids.size()>0">
                <foreach collection="ids" open="and id in (" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>
//测试foreach标签的使用
    @Test
    public void testFindInIds() throws Exception {
        QueryVo vo = new QueryVo();
        List<Integer> list = new ArrayList<Integer>();
        list.add(41);
        list.add(42);
        list.add(43);
        vo.setIds(list);

        //5 执行查询所有
        List<User> users = dao.findUserInIds(vo);
        for (User user : users) {
            System.out.println(user);
        }
    }

了解

 <!--了解的内容,抽取重复的sql语句-->
    <sql id="defaultUser">
        select * from user
    </sql>
    
    //使用include引入
	<select id="findAll" resultType="user">
        <include refid="defaultUser"></include>
        <!--select * from user;-->
    </select>

Mybatis 多表查询

  • 示例:用户和账户
    一个用户可以有多个账户
    一个账户只能属于一个用户(多个账户也可以属于同一个用户)
  • 步骤:
    1 建立两张表,用户表、账户表
    让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
    2 建立连个实体类:用户实体类和账户实体类
    让用户和账户实体类能体现出一对多的关系
    3 建立两个配置文件
    用户配置文件和账户配置文件
    4 实现配置
    当我们查询用户时,可以同时得到用户下所包含的账户信息
    当我们查询账户时,可以同时得到账户所属的用户信息

多对一

//account实体类
//从表实体应该包含一个主表实体的对象引用
    private User user;

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

//测试类
//测试查询账户同时获取用户信息
    @Test
    public void testFindAll() throws Exception {
        //5 执行查询所有
        List<Account> accounts = dao.findAll();
        for (Account account : accounts) {
            System.out.println("--------------------------");
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }

在这里插入图片描述

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

一对多

//user实体类添加字段
   //一对多关系映射,主表实体应该包含从表实体的集合引用
    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }
     public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
<!--定义User的resultMap-->
    <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>
        <!--配置user对象中account集合的映射-->
        <collection property="accounts" ofType="account">
            <!--property对应实体类属性,column是数据库中字段,可以起别名-->
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>

    <!--查询所有用户-->
    <select id="findAll" resultMap="userAccountMap">
        select * from user u LEFT OUTER JOIN account a on u.id = a.uid;
    </select>

多对多

  • 示例:用户和角色
    一个用户可以有多个角色,一个角色也可以赋予多个用户
  • 步骤:
    1 建立两张表,用户表、账户表
    让用户表和角色表之间具备多对多的关系:需要使用中间表,中间表中包含各自的主键。
    2 建立连个实体类:用户实体类和角色实体类
    让用户和角色实体类能体现出多对多的关系
    3 建立两个配置文件
    用户配置文件和角色配置文件
    4 实现配置
    当我们查询用户时,可以同时得到用户下的角色信息
    当我们查询角色时,可以同时得到角色所赋予的用户信息

查询角色包含用户信息

//类似之前配置用户和账户的一对多关系
//多对多的关系映射,一个角色可以赋予多个用户
    private List<User> users;

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

    public void setUsers(List<User> users) {
        this.users = users;
    }
//IRoleDao.xml
<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="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></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>

查询用户得到包含用户角色信息

//与之前的配置类似,在user实体类添加roles集合,更改配置文件映射和sql语句
<!--定义User的resultMap-->
    <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="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>

    <!--查询所有用户-->
    <select id="findAll" resultMap="userMap">
        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>

JNDI

  1. 新建一个maven的webapp项目,导入所需要的jar的坐标
  2. 在webapp下新建一个目录META-INF,建立context.xml用于配置数据库连接的信息
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<!-- 
<Resource 
name="jdbc/eesy_mybatis"						数据源的名称
type="javax.sql.DataSource"						数据源类型
auth="Container"								数据源提供者
maxActive="20"									最大活动数
maxWait="10000"									最大等待时间
maxIdle="5"										最大空闲数
username="root"									用户名
password="root"									密码
driverClassName="com.mysql.jdbc.Driver"			驱动类
url="jdbc:mysql://localhost:3306/eesy_mybatis"	连接url字符串
/>
 -->
<Resource 
name="jdbc/eesy_mybatis"
type="javax.sql.DataSource"
auth="Container"
maxActive="20"
maxWait="10000"
maxIdle="5"
username="root"
password="root"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/eesy_mybatis"
/>
</Context>
  1. 在SqlMapConfig.xml中配置mybatis环境,数据库引用文件
<environments default="mysql">
        <!-- 配置mysql的环境 -->
        <environment id="mysql">
            <!-- 配置事务控制的方式 -->
            <transactionManager type="JDBC"></transactionManager>
            <!-- 配置连接数据库的必备信息  type属性表示是否使用数据源(连接池)-->
            <dataSource type="JNDI">
                <property name="data_source" value="java:comp/env/jdbc/eesy_mybatis"/>
            </dataSource>
        </environment>
    </environments>
  1. 将项目部署在tomcat上
//index.jsp
<%@page language="java" contentType="text/html; charset=utf-8" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<%--jsp中的代码经过服务器,如果使用单元测试,则tomcat中的配置未被使用,会报错--%>
<%
    //1 读取配置文件
    InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
    //2 创建SqlSessionFactory工厂
    SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
    SqlSessionFactory factory = builder.build(in);  //SqlSessionFactory是一个接口,不能直接new
    //3 使用工厂生产一个SqlSession对象
    SqlSession sqlSession = factory.openSession();
    //4 使用SqlSession创建dao接口的代理对象(代理模式 --- 增强方法)
    IUserDao userDao = sqlSession.getMapper(IUserDao.class);
    //5 使用代理对象执行方法
    List<User> users = userDao.findAll();
    for (User user : users) {
        System.out.println(user);
    }
    //6 释放资源
    sqlSession.close();
    in.close();
%>
</body>
</html>

当项目部署完毕,启动服务器访问路径,就会执行jsp中代码,调用findAll方法在控制台打印数据库中user信息。

;