Mybatis(三):连接池、动态SQL和连表

一、Mybatis连接池与事务

1.1 连接池分类

mybatis也有使用连接池技术,不过使用的是mybatis框架提供的。

在 Mybatis 的 SqlMapConfig.xml 配置文件中, 通过<dataSource type="pooled"> 来实现 Mybatis 中连接池的配置

连接池主要分为三类

参数

类型

UNPOOLED

不使用连接池的数据源

POOLED (最常用)

使用连接池的数据源

JNDI

使用 JNDI 实现的数据源

mybatis plus 默认mysql连接池 mybatis有连接池吗_用户信息

1.2 数据源配置

数据源配置在主配置文件SqlSessionConfig.xml

<!--在type属性里配置数据源类型-->
<dataSource type="POOLED">
	<property name="driver" value="${jdbc.driver}"/>
	<property name="url" value="${jdbc.url}"/>
	<property name="username" value="${jdbc.username}"/>
	<property name="password" value="${jdbc.password}"/>
</dataSource>

MyBatis 在初始化时, 根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:

type=”POOLED”: MyBatis 会创建 PooledDataSource 实例

type=”UNPOOLED”: MyBatis 会创建 UnpooledDataSource 实例

type=”JNDI”: MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用

1.3 事务

Mybatis 框架的事务控制方式,本身也是用 JDBC 的setAutoCommit()方法来设置事务提交方式的

之前的 CUD 操作过程中,我们都要手动进行事务的提交,原因是 setAutoCommit()方法,在执行时它的值默认被设置为false,所以我们在 CUD 操作中,必须通过sqlSession.commit()方法来执行提交操作

设置事务自动提交

在使用factory取得seesion时,传递参数true

in = Resources.getResourceAsStream("SqlMapConfig.xml");
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
factory = builder.build(in);

//设置为ture
session = factory.openSession(true);

userDao = session.getMapper(IUserDao.class);

此时事务就设置为自动提交了,同样可以实现CUD操作时记录的保存。

虽然这也是一种方式,但就编程而言,设置为自动提交方式为false 再根据情况决定是否进行提交,这种方式更常用。

因为我们可以根据业务情况来决定提交是否进行提交

二、Mybatis的动态SQL语句

2.1 if标签

根据实体类的不同取值,使用不同的 SQL 语句来进行查询。

比如在 id 如果不为空时可以根据 id 查询,如果 username 不为空时还要加入用户名作为条件。

这种情况在我们的多条件组合查询中经常会碰到。

接口

/**
     * description: 根据传入参数条件查找
     * @param user 查询的条件,有可能有用户名 有可能有性别...还有可能都有
     * @return java.util.List<domain.User>
     */
    List<User> findUserByCondtion(User user);

配置

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

注意:<if>标签的test 属性中写的是对象的属性名,如果是包装类的对象要使用 OGNL 表达式的写法。另外注意 where 1=1 的作用

测试

//测试查询所有
@org.junit.Test
    public void testFindByCondition() {
    User u = new User();
    u.setUsername("老王");
    List<User> all = userDao.findUserByCondtion(u);
    for (User user : all) {
        System.out.println(user);
    }
}

2.2 where标签

为了简化上面 where 1=1 的条件拼装,我们可以采用<where>标签来简化开发。

配置

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

注意:此时where标签会动态判断where关键字是否需要添加到sql语句,而不需要使用1=1

2.3 foreach标签

需求:传入多个 id 查询用户信息,用下边两个 sql 实现

SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND (id =10 OR id =89 OR id=16)
SELECT * FROM USERS WHERE username LIKE ‘%张%’ AND id IN (10,89,16)

这样我们在进行范围查询时,就要将一个集合中的值,作为参数动态添加进来。

在 QueryVo 中加入一个 List 集合用于封装参数

/**
 * @author konley
 * @date 2020-07-21 8:57
 */
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;
    }
}

接口

/**
     * description: 根据queryvo中提供的id集合,查询用户信息
     * @param vo
     * @return java.util.List<domain.User>
     */
    List<User> findUserInIds(QueryVo vo);

配置

<!--根据queryvo中的id集合实现查询用户列表-->
    <select id="findUserInIds" resultType="domain.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>
这里的SQL 语句:
	select 字段 from user where id in (?)
  • <foreach>标签用于遍历集合
  • collection:代表要遍历的集合元素,注意编写时不要写#{}
  • open:代表语句的开始部分
  • close:代表结束部分

测试

//测试查询所有
    @org.junit.Test
    public void testFindInIds() {
        QueryVo vo = new QueryVo();
        List<Integer> ids = new ArrayList<>();
        ids.add(41);
        ids.add(42);
        ids.add(43);
        vo.setIds(ids);

        List<User> users = userDao.findUserInIds(vo);

        for (User user : users) {
            System.out.println(user);
        }
    }

三、Mybaits多表:一对多

3.1 需求

查询所有账户信息,关联查询下单用户信息。

注意:因为一个账户信息只能供某个用户使用,所以从查询账户信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的账户信息则为一对多查询,因为一个用户可以有多个账户 。

使用 resultMap,定义专门的 resultMap 用于映射一对一查询结果。

通过面向对象的(has a)关系可以得知,我们可以在 Account 类中加入一个 User 类的对象来代表这个账户是哪个用户的。

3.2 定义实体类

package domain;

/**
 * @author konley
 * @date 2020-07-21 18:51
 */
public class Account {
    private Integer id;
    private Integer uid;
    private double money;
    /**
     * description: 从表主体包含一个主表实体的引用
     */
    private User user;

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                ", user=" + user +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }

    public User getUser() {
        return user;
    }

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

    public Account() {
    }

    public Account(Integer id, Integer uid, double money, User user) {
        this.id = id;
        this.uid = uid;
        this.money = money;
        this.user = user;
    }
}

3.3 定义接口

package dao;

import domain.Account;

import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 18:53
 */
public interface IAccountDao {
    /**
     * description: 查询所有账户,同时获取到当前账户所属用户信息
     * @param
     * @return java.util.List<domain.Account>
     */
    List<Account> findAll();
}

3.4 定义配置

<?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="dao.IAccountDao">

    <!--定义同时封装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="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>
</mapper>

3.5 定义测试类

import dao.IUserDao;
import domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 19:22
 */
public class UserTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao dao;

    //执行前运行
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IUserDao.class);
    }

    //执行后回收
    @After
    public void destroy() throws IOException {
        sqlSession.close();
        in.close();
    }

    //测试查询操作
    @org.junit.Test
    public void findAll() {
        List<User> all = dao.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }
}

四、Mybatis多表:多对多

多对多关系其实可以看成是双向的一对多关系。

4.1 需求

实现查询所有对象并且加载它所分配的用户信息。

查询角色我们需要用到Role表,但角色分配的用户的信息我们并不能直接找到用户信息,

而是要通过中间表(USER_ROLE 表)才能关联到用户信息。

同理:在user类中包含account,在account类中包含user,形成双向一对多

4.2 实体类

package domain;

import java.io.Serializable;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 20:11
 */
public class Role implements Serializable {
    private Integer roleId;
    private String roleName;
    private String roleDesc;
    /**
     * description:多对多的关系映射:一个角色可以赋予多个用户
     */
    private List<User> users;

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                ", roleDesc='" + roleDesc + '\'' +
                ", users=" + users +
                '}';
    }

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleDesc() {
        return roleDesc;
    }

    public void setRoleDesc(String roleDesc) {
        this.roleDesc = roleDesc;
    }

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

    public void setUsers(List<User> users) {
        this.users = users;
    }
}
package domain;

import java.io.Serializable;
import java.sql.Date;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-20 11:06
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;
    /**
     * description: 多对多的映射,一个用户具备多个角色
     */
    private List<Role> roles;

    public Integer getId() {
        return id;
    }

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

    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;
    }

    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 List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                ", roles=" + roles +
                '}';
    }
}

4.3 接口

package dao;

import domain.Role;

import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 20:13
 */
public interface IRoleDao {
    /**
     * description:查询所有角色
     * @return java.util.List<domain.Role>
     */
    List<Role> findAll();
}
package dao;
import domain.User;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-20 11:14
 * 用户的持久层接口
 */
public interface IUserDao {
    /**
     * description: 查询所有用户
     * @param
     * @return java.util.List<domain.User>
     */
    List<User> findAll();

}

4.4 配置文件

<?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="dao.IRoleDao">

    <resultMap id="roleMap" type="role">
        <id property="roleId" column="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 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>
<?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="dao.IUserDao">

    <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="id"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="roleDesc"></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>

</mapper>

4.5 测试

import dao.IRoleDao;
import domain.Role;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 20:17
 */
public class RoleTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IRoleDao dao;

    //执行前运行
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IRoleDao.class);
    }

    //执行后回收
    @After
    public void destroy() throws IOException {
        sqlSession.close();
        in.close();
    }

    //测试查询操作
    @org.junit.Test
    public void findAll() {
        List<Role> all = dao.findAll();
        for (Role role : all) {
            System.out.println(role);
        }
    }
}
import dao.IUserDao;
import domain.User;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @author konley
 * @date 2020-07-21 19:22
 */
public class UserTest {
    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao dao;

    //执行前运行
    @Before
    public void init() throws IOException {
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        dao = sqlSession.getMapper(IUserDao.class);
    }

    //执行后回收
    @After
    public void destroy() throws IOException {
        sqlSession.close();
        in.close();
    }

    //测试查询操作
    @org.junit.Test
    public void findAll() {
        List<User> all = dao.findAll();
        for (User user : all) {
            System.out.println(user);
        }
    }
}